Backdooring Portable Executables: Code Caves and threading failure

To start off, let’s take care of the issue with the code cave. We don’t want to add another section to the PE, we want to modify the executable as little as possible to prevent possible detection. We can use the Memory Map tool in Immunity Debugger to manually review the sections for large, uninterrupted spaces of nulls. This blog shows a pretty succinct process for backdooring executables (and is my primary source for the next portion on threading) and introduces a tool called Cminer. Using Cminer on putty.exe, we find two potential caves:

Using Cminer to locate code caves in putty.exe of 350 bytes or more

These are actually rather small at 500ish bytes a piece, and may not work for encoded shellcode, requiring a jump from one cave to the other. But for unencoded shellcode, we are looking at about 350 bytes so this is plenty of space. Also note, manual inspection of the memory space will show that there is a ton more null space in the .xdata segment, it does not end with 0x4b8800. Whether this is some kind of issue with the tool or user error, I’m not sure. The good news is that if needed we can fit plenty of encoded shellcode in there. The bad news, I tested several different open source tools and none really provided reliable results. In fact, manual inspection revealed huge portions of null space in every section in the putty.exe PE, so, yeah I don’t know, probably a rabbit hole that it would be good to go down eventually and figure out how to accurately do this using automation. For right now, manual inspection is needed but Cminer did accurately provide two code cave locations so there is that. It should be noted that even though there are huge areas of null space, trying to overwrite some of those areas will cause the debugger to complain, so it’s a trial and error thing to find a suitable area.

So uhhh… about that nullspace ending at 0x004b8800…

From here it proceeds the same as with the previous example. Step into the code cave, save the program state, place the shellcode (this time generated using msfvenom with EXITFUNC=seh), adjust the stack, and close it out by loading the saved program state from the stack and proceeding with program execution.

For threading, I used a few different resources, the most easy to read was here, but was not successful. OSCE course starts in two days so I’m not going to spend anymore time on it, I’m close but it’s not quite working out.

Backdooring Portable Executables: Fixing execution

The best part of writing things down here is that inevitably 5 minutes later, I find someone with the same problem. When backdooring putty.exe, I came across an issue with the EXITFUNC code appended onto the end of msfvenom code. The code ends with a CALL EBP, which goes off into the shellcode and eventually to ntdll.KiFastSystemCallRet where it terminates the program.

We got a shell, but the program terminates here…

Not ideal. So one solution was to change that CALL EBP instruction to NOPs. Skipping that call allows execution to proceed, everything is right with the world, except the gnawing feeling that it’s just gross.

so dirty…

But hey, it works. Turns out though, Capt Meelo had the same issue and came up with a couple of solutions. His first solution was the same as the one up here, turn that CALL instruction into NOPs and the program executes as expected. Kind of reassuring to see that someone came up with the same fix, even if it’s not ideal. But his second solution was kind of a head-slapper moment. Just create the shellcode using the EXITFUNC=seh option:

generating shellcode

A closer inspection of the shellcode reveals they’re identical, as you’d expect since looking at the metasploit github shows you that EXITFUNC is determined by code tacked on to the end of the shellcode. The real difference is in a value moved into EBX at 0x004c3127 shown below.

Left: EXITFUNC=seh Right: EXITFUNC=none

So, lesson learned. If there’s an issue with a particular part of the shellcode, maybe try all the options associated with that shellcode first before manually NOPing out instructions. Using EXITFUNC=seh resumes execution like a charm. There is one remaining issue, though. Putting simple shellcode like popping calc will always work, but in the case of a reverse shell we find that the program does not execute unless a listener is configured on the correct port. This is not ideal. So on the agenda: redirecting to existing null space int he code rather than adding a section and fixing the last remaining execution issue.

Backdooring Portable Executables

Prepping for OSCE, lots of shellcoding and debugging going on. Shellcoding is particularly frustrating today so to change gears for a bit I’m going to write up backdooring PEs. Examples are x86, tested on Windows XP SP3, using the x86 putty executable available here. I also used Stud_PE, Immunity Debugger, and a great blog post over at Sector876 that helped me get the basics down. There’s a couple of different methods, let’s start with the first, we’ll add a section.

First, let’s start by opening the program in Stud_PE. Select the Sections tab and you can see all of the sections present in the executable. Right click and choose “New Section” and adjust the size. Ensure you’ve added enough space to fit your shellcode in, and select the option to fill the space with null bytes. After you save, run the executable to ensure it still functions and nothing is broken.

adding a section with Stud_PE

Open the executable in the debugger and inspect the sections, in Immunity this is easily found in the Memory Map tab. If you inspect the section, you should find it filled with null bytes. Note the memory address that the section starts at, in this instance we see 0x004c3000.

our new section, all filled with nulls

We will need to redirect program execution to this address, where we will eventually put shellcode. For now, note the existing instructions at the program’s entry point. We will need these for redirecting back to normal execution for the program.

our initial instructions

After saving these addresses, it is time to redirect execution. In Immunity we do this by right clicking the instruction and selecting Assemble, then inputting our jump instruction. We want to jump to 0x004c3000 in this case.

assembling our jmp instruction

After assembling the instruction should update in the debugger to exactly what we need.

jmp to…

Hit F7 in Immunity to move to the next instruction and you should see the new section we added, filled with nulls.

nulls, nulls everywhere

The first thing that should be done at this point is to save the executable. After saving, in the new section overwrite the first two instructions with PUSHAD and PUSHFD instructions. This saves the program state before we pass it our shellcode. Press F7 twice to move ahead and then note the location of ESP. We will need this location after the shellcode to adjust the stack prior to normal program execution. In this instance, ESP is at 0x0012FFA0 following the two instructions added.

ready for shellcode now

Use msfvenom to create shellcode. In this instance we’re creating a reverse tcp shell for Windows in hex format, no bad chars specified. In Immunity, this is placed in the executable by selecting enough memory locations to hold our shellcode starting with the instruction following the PUSHFD, then right clicking and performing a binary paste.

generating shellcode

Once the shellcode is pasted in, place a breakpoint on the last instruction of the shellcode and press F9 to continue execution. Note that if the shellcode is a reverse shell, unless you have a listener set up it will take execution off into an exception, and that you’ll have to close the listener to hit your breakpoint. Once at the breakpoint, note the address at ESP. In this case it is 0x0012fd9c.

ESP location after shellcode execution

The determine the ESP offset, we subtract the initial ESP value from the ending value, so 12ffa0 – 12fd9c, and our offset is 0x204. in order to get ESP back where it belongs for normal program execution, we need to add 0x204 to ESP, so we right click the instruction immediately following the shellcode and input ADD ESP, 0x204. The next two instructions should be POPFD followed by POPAD to resume the program’s saved state from before the shellcode.

Perfect! Or was it…

At this point, it doesn’t work. You get your shell, the program doesn’t open, you close your shell, the program crashes. Frustrating. What we want is for the program to open and for you to get your shell at the same time. And for it to not crash when we close out of our shell. First things first. The opening issue has already been solved for us.

The offending code

So we found it. It’s near the bottom, in the blog linked above he links to the metasploit github where you can find it for yourself. So we update it…

Easy enough

Still not quite right though, normal program execution doesn’t happen. Over at the metasploit github page, you can view the code for the exitfunc portion. This code is appended to the end of your msfvenom-generated code even if you choose EXITFUNC=none, right at the end. Check out this part is particular:

very last line of your shellcode

If you trace it in the debugger, your shellcode calls EBP which takes it off back into the shellcode and eventually out into ntdll.KiFastSystemCallRet which… ok, turning into a rabbit hole. Researching this, figuring out why it is doing this, is a priority. But for right now, quick and dirty, oh so dirty, just overwrite that call with NOPs and it works.

this is a gross solution and I should feel bad…

On the agenda is creating a backdoor using existing null space within the application and figuring out this business with the EXITFUNC in msfvenom.

program’s running…
shell’s working… it’s still gross though