Last Updated: 2019-05-30 16:03:05 UTC
by Didier Stevens (Version: 1)
Yesterday, reader Alex submitted a PowerShell script he downloaded from a website. Xavier, handler on duty, showed him the script launched shellcode that tried to establish a TCP connection.
Xavier used scdbg, a very useful tool to analyze win32 32-bit shellcode. I've written a couple of diary entries about this tool, and today, and I want to show more features of this tool.
Here is the script:
It contains base64 data, that can be easily decoded with my tool base64dump.py:
This PowerShell script contains shellcode: this can be deduced from the 0x.. values and VirtualAllox, CreateThread and memset functions. I can extract this shellcode with re-search.py:
And then convert it to binary data and have it emulated by scdbg, like this:
So this confirms that this is 32-bit Windows shellcode, and that it connects via TCP to private IP address 192.168.1.100 port 53.
Until now, there's nothing really new here: we have talked about this in previous diary entries.
But what if you want to take it further, and want to figure out why this shellcode is trying to establish a TCP connection? In this case, we can't just connect to TCP 53 port, because it's a private IPv4 address.
However, scdbg has many features that can help us further analyze this shellcode. For example, we can let the scdbg emulator connect to a server we are running ourself and then observe what happens.
I'm using my Python TCP honeypot tcp-honeypot.py to setup a small local server, to serve string ABCDEFGHIJKLMNOPQRSTUVWXYZ on TCP port 53. Here is the definition of such a listener on TCP port 53:
And then I can pass this on as argument to tcp-honeypot.py:
scdbg's option -i enables interactive hooks: this means that file and network operations are also emulated. If I run scdbg with this particular shellcode and option -i, scdbg will try to connect to IPv4 address 192.168.1.100 on TCP port 53. My test machine however, has a different IPv4 address. This problem can be solved by using scdbg's option -redir: it allows us to redirect network traffic to another IP address (and also a different port, if needed). So here I'm running with interactive hooks and redirecting to my localhost:
What we see here, is that the shellcode reads 4 bytes from the TCP connection that has been established.
Then it allocates memory with a size of 0x44434241 bytes long.
And then it tries to read again from the TCP connection: 0x44434241 bytes (these values are reset by scdbg).
0x44434241 is DCBA in ASCII: this corresponds to the first 4 bytes of the honeypot data (ABCDEFG...) parsed as a little-endian integer.
So it looks like this shellcode first reads the size of the payload from the TCP connection, and then the payload itself. Let's test this with a size value of 8 bytes and a payload of 8 bytes, like this:
Indeed: the shellcode reads 4 bytes, allocates 8 bytes, and then reads 8 bytes. And then there's an error at stepcount 1527446. Let's run this again, but with more verbosity 10 steps before the error (1527446 - 10 = 1527436), to try to understand what happens:
What we get from this output, is that:
- 8 bytes of memory are allocated at address 0x600000
- 8 bytes are read from the TCP connection
- these 8 bytes are written to 0x600000
- these 8 bytes are being executed starting from 0x600000
You can see this in the instructions starting address 0x600000: 41, 42, 43, ..., or in ASCII: A, B, C, ...
So it looks like the shellcode handles our payload as machine language that is downloaded and executed. Let's try this with a small payload of 1 byte and instruction INT 3 (or 0xCC, the interrupt instruction used for debugging breakpoints):
Indeed, this time, the shellcode emulator tries to execute instruction INT3 (0xCC), and stops because it does not support this instruction.
As a last test, I'm going to serve my own shellcode that displays a message box:
This last test confirms our hypothesis: this shellcode, is first stage shellcode, that downloads a second stage and executes it from memory.
First it reads 4 bytes from the TCP connection, interprets that as the length of the payload to download, allocates enough memory, downloads the payload to the allocated memory, and then executes it.
This is typical first stage shellcode.