Adventures in Shellcode Obfuscation! Part 13: Calculating Offsets
文章介绍了一种通过计算相邻字节偏移来隐藏shellcode的技术。该方法生成偏移数组并重建原始shellcode,在VirusTotal上仅被两个引擎检测到。 2024-9-13 16:0:13 Author: redsiege.com(查看原文) 阅读量:1 收藏

by Mike Saunders, Principal Security Consultant

This blog is the thirteenth in a series of blogs on obfuscation techniques for hiding shellcode. You can find the rest of the series here. If you’d like to try these techniques out on your own, you can find the code we’ll be using on the Red Siege GitHub.

When I was discussing writing this series with Senior Security Consultant Corey Overstreet, he proposed an interesting idea of obfuscation shellcode by calculating and storing byte offsets rather than storing shellcode directly. You can find Corey’s blog about this technique here. Let’s take a look at how his technique works.

Calculating Offsets

By calculating offsets, I mean calculating the numerical difference between one byte of shellcode and another. We’ll use the Python code below to generate our offsets. We start out by reading in our raw shellcode and calculating the length of that shellcode.

Now we’ll define a few variables. First, we create an empty list to store our calculated offsets. We’ll store the first byte of our shellcode in previous_byte. We’ll use this variable to keep track of the last byte we operated on through our loop. remaining_idx is an index variable used for iterating through our shellcode. We start at index 1 as there’s no delta to calculate for the first byte of shellcode.

Throughout this series, we’ve been using Metasploit Meterpreter reverse_http shellcode. The shellcode started out with the following bytes: 0xfc, 0x48, 0x83, 0xe4. Now it’s time to start calculating offsets. When we enter the loop, we’re starting at the second byte of shellcode – 0x48. We calculate the delta by subtracting previous_byte (0xfc) from our current position in the shellcode. We then test to see if the result is negative. If we subtract 0xfc from 0x48, the result will be negative, so we add 256 to get the corresponding positive value, which would be 0x4c.

Now that we have the delta, we append that value to our offset array. Finally, we’ll set previous_byte to 0x48, increment our index, and start the loop over again.

def get_offsets(input_file):
    # read in our raw shellcode and get the length
    raw_sc = get_raw_sc(input_file)
    sc_len = len(raw_sc)

    offset_arr = [] # stores the calculated offsets
    previous_byte = raw_sc[0] # Store previous byte we processed.
    remaining_idx = 1 # starts at 1 - second byte of shellcode
    
    # Loop through remaining bytes of shellcode
    while remaining_idx < sc_len:
        # Subtract previous byte from current byte to get the offset
        current_byte = raw_sc[remaining_idx] - previous_byte

        # Add 256 if value is negative to wrap around.
        if current_byte < 0:
            current_byte = current_byte + 256

        # Add current byte of offset array
        offset_arr.append(current_byte)

        # Update previous byte to current shellcode byte
        previous_byte = raw_sc[remaining_idx]
        remaining_idx += 1

Using this logic, our offset array will start out with 0x4c, 0x3b, 0x61. The C Code will look like the code below. We have a variable to store our first byte of shellcode, first_byte. Next, we have an unsigned char array, delta. This array contains our calculated offsets. We use an unsigned char array versus a signed as the only possible values are 0 to 255. This will make our lives easier when we’re reconstructing our shellcode. If the value is greater than 255, it will automatically wrap around without having to subtract 256. Finally, we’ll create an empty array to store the reconstructed shellcode.

unsigned char first_byte = 0xfc;
unsigned char delta[597] = { 0x4c, 0x3b, 0x61, 0xc ... };
unsigned char shellcode[598] = { 0x00 };

We’ll declare an integer to store the size of our delta array:

int cap = sizeof(delta) / sizeof(delta[0]);

Now, we’ll populate the first byte of the shellcode array with the value of first_byte.

shellcode[0] = first_byte;

We’ll declare two index variables. These will be used to keep track of where we’re at in the shellcode and delta arrays.

unsigned int delta_idx, shellcode_idx;

Finally, it’s time to rebuild our shellcode with a simple for loop. Inside the loop, we set the shellcode index to delta_idx + 1. The first time we enter the loop, shellcode_idx will be 1. We need to start at index 1, because we previously wrote the first byte of shellcode into the array.

The first time we enter the loop, delta_idx will be 0. To calculate the next byte of shellcode, we’ll read the value at shellcode[0], which is 0xfc, and add the first value from the delta array – 0x4c. Because we’re using unsigned characters, this becomes 0x48 instead of 0x148. Only the right-most two bits are saved.

for (delta_idx = 0; delta_idx < cap; delta_idx++)
{
    shellcode_idx = delta_idx + 1;
    shellcode[shellcode_idx] = shellcode[delta_idx] + delta[delta_idx];
}

And that’s it. The for loop will reconstruct our shellcode back to the original values. How does this technique fare on VT? Incredibly well! Only two engines alerted on this payload at the time this blog was written. This technique is tied with using XOR with a multibyte key for the best score in the series.

Offset Technique VT Score

Try it Yourself

You can find the example code for this article as well as the other articles in this series at the Red Siege GitHub.

Stay Tuned

This blog is part of a larger series on obfuscation techniques. Stay tuned for our next installment!


About Principal Security Consultant Mike Saunders

Mike Saunders is Red Siege Information Security’s Principal Consultant. Mike has over 25 years of IT and security expertise, having worked in the ISP, banking, insurance, and agriculture businesses. Mike gained knowledge in a range of roles throughout his career, including system and network administration, development, and security architecture. Mike is a highly regarded and experienced international speaker with notable cybersecurity talks at conferences such as DerbyCon, Circle City Con, SANS Enterprise Summit, and NorthSec, in addition to having more than a decade of experience as a penetration tester. You can find Mike’s in-depth technical blogs and tool releases online and learn from his several offensive and defensive-focused SiegeCasts. He has been a member of the NCCCDC Red Team on several occasions and is the Lead Red Team Operator for Red Siege Information Security.

Certifications:
GCIH, GPEN, GWAPT, GMOB, CISSP, and OSCP

Connect on Twitter & LinkedIn

Red Siege at Wild West Hackin’ Fest Mile High 2025 – What to Expect!

By Red Siege | February 2, 2025

The Red Siege train is heading to Denver, Colorado, for the first-ever Wild West Hackin’ Fest @ Mile High from February 5-7, 2025! If you’re a cybersecurity professional who loves […]

Learn More

Red Siege at Wild West Hackin’ Fest Mile High 2025 – What to Expect!

Security Posture Review and Penetration Testing

By Red Siege | January 31, 2025

Ever wondered if your organization is truly secure or if your teams are just crossing items off a checklist? A Security Posture Review (SPR) is a solid way to answer […]

Learn More

Security Posture Review and Penetration Testing

Security Posture Review: The Process

By Red Siege | January 28, 2025

The Security Posture Review (SPR) is the newest addition to our suite of security offerings at Red Siege. We’ve combined our collective experiences in red team, blue team, and security […]

Learn More

Security Posture Review: The Process


文章来源: https://redsiege.com/blog/2024/09/adventures-in-shellcode-obfuscation-part-13-calculating-offsets/
如有侵权请联系:admin#unsafe.sh