xmitm: xml man in the middle
This post is a result of ideas and tools developed during the review of client-side applications that use the XMPP protocol to communicate with a server (opening a raw socket, not using HTTP as a transport).
The only way we could think of getting our hands on the communication was to write a small set of scripts to trick the client and encapsulate the communication inside HTTP requests that we could then manipulate using standard proxy tools such as burp.
Although the information and scripts described in this post are focussed on intercepting a XML communication, the same principles apply to man in the middle any ASCII protocol such as smtp, ftp or pop.
update: slides available here
The first step is to trick the client to connect to our local box instead of connecting to the remote server, this is done by adjusting the hosts file.

A ruby script will sit in the middle of the communication and will be able to intercept and modify messages sent and received by the client:-

Once this is done, our attack will need three elements:
- the xmitm script.
- an external web proxy tool.
- a dummy web server.
The script will intercept the connection and send the data to the proxy. We need the dummy server (the body of the response will be the body of the request) to close the loop with the proxy (I will add some nice graphs to clarify this soon).

The original XML message is encapsulated in an HTTP request and passed through the proxy. The user can inspect and modify the message using a standard web proxy tool. The request is then forwared to a dummy *echo* web server that replies with the same payload that was requested. The script can extract the modified payload and forward it to the server.
The same process is applied to incoming messages.
Below is the main body of the script (you can also grab the code):-
# create a server that accepts connections from the client server = TCPServer.new($local_host, $local_port) while(local = server.accept ) do # everytime we accept a connection for the client, we open a connection # with the server to stablish the dialog. remote = TCPSocket.new($remote_host, $remote_port) # if one of the ends of the communication closes the socket, we # toggle this flag alive = true while alive do # see the explanation below result = select([local, remote], nil, nil) if result != nil then for socket in result[0] # detect if one end of the connection is closed and # close the other end if (socket.eof?) local.close remote.close alive = false break end # read the information that one peer wants to send to the other data = socket.gets($eom) # encapsulate the data into an HTTP proxy request res = Net::HTTP.new($proxy_host, $proxy_port).start do |http| req = Net::HTTP::Post.new("http://#{$dummyhttp_host}:#{$dummyhttp_port}/") req.body= data http.request(req) end modified_data = res.body.chomp # send the modified data to the other end of the connection if (socket == local) remote.puts(modified_data) else local.puts(modified_data) end socket.flush end end end end
What the script does can be summarized in the following steps:
- Create a TCP server, listening on the port the client is expecting.
- For each connection accepted:
- Open a connection with the remote server.
- Wait until one end of the communication (first the client, then the server, then the client, etc.) has something to transmit.
- Grab the XML message.
- Put that message as a payload of a new Net::HTTP::Post request.
- Send the request to the external web proxy.
- Grab the body of the response given by the proxy (already modified by the user using the external proxy).
- Send the modified request to the other end of the line.
The most interesting piece of the code is the one regarding Kernel#select function that waits for data to become available from input/output devices.
A note regarding the specifics of the protocol we were dealing with, each peer ends its messages using a special character (a NULL byte), that caracter is defined in the $eom variable and the script keeps reading the socket until that end of message character is read.
The last piece of the puzzle is the dummy HTTP server. I coded two flavours: a ruby version and a java version (not yet available for download based on the SingleFileHTTPServer example). You can pick your choice. Here is the ruby one:-
require 'webrick' include WEBrick # create the server, no output, disable logging s = HTTPServer.new( :Port => 2000, :Logger => Log.new(nil, BasicLog::FATAL), :AccessLog => [] ) # the *echo* functionality s.mount_proc("/") do |req, res| res.body = req.body res['Content-Type'] = req['Content-Type'] end # clean tear down trap('INT') { s.shutdown } s.start
And this completes the XML protocol man-in-the-middle DIY kit. Hope you find it useful. ![]()




December 18th, 2007 at 12:28 pm
Great tool! I’m looking forward to try it in a test!
Keep posting cool staff!
December 22nd, 2007 at 2:49 am
[...] etd’s linux Dos and Dont’s » Blog Archive » xmitm: xml man in the middle Ataque de MITM em XML (tags: xml ataques pentest) [...]