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  

No comments:

Post a Comment