1

Disclaimer: I am asking this question solely for educational purposes.

I am trying to chain some function calls using return-oriented programming, exploiting a vulnerable binary which uses strcpy(). One of these function calls should be a call to system() (in order to execute some shell command). Unfortunately, the address of system() contains a NULL byte which will lead for strcpy() to stop copying the payload once this byte is observed.

My question therefore is: what is the best approach to solve this issue?

I've already checked libc for functions similar to system(), but have found nothing. Another idea of mine would be to call fork(), exec(), and wait() subsequently. This would however increase the complexity of the payload.

1

Is there some reason you need to leave the original process alive when your shellcode executes? Just call execve directly (assuming you can control the stack well enough), or one of its helper functions, which will turn the current process into your target process.

A trickier approach that might work is to use dlsym to retrieve a pointer to system, which you could then call with your target command. You might have to call dlopen first, though; I'm not sure about the semantics of dlsym. The corresponding Windows function GetProcAddress takes the base address of the loaded module (library or executable) as the first pointer, and dlsym might do the same; since you're using ROP you presumably aren't bothered by ASLR so that address should be predictable.

Finally, since you're using ROP, you can simply find one or more gadgets that let you arithmetically produce the desired address. There are many combinations of operands (constants in your shellcode, registers or addresses with known values at exploit-time, etc.) and operations (add, subtract, or, xor, etc.) that could be used to produce a specific value that contains a NULL byte from pieces that don't contain one, and ALU ops are short so it shouldn't be hard to find suitable gadgets.

  • I've though about using other gadgets (maybe a shift operation, as the NULL byte is the most significant one). However, how do I simply use these gadgets or operations if they are not immediately followed by a ret instruction, which would let me control the program control flow again, but other instructions instead? – foobar Nov 20 '18 at 11:02
  • Depends what the following operations are. If they're effectively no-ops, or do something that doesn't matter to you (say, write a value to a memory location that is writable and that you don't need to preserve), then you can go on to the next operation. If they do something that interferes with program flow (say, modify a register or do a branch), look at what the change is and see if there's a way to either use it or make it not matter. In some cases, you may be able to use the following operation even if it isn't a ret, for example if it calls the address you just set up. – CBHacking Nov 21 '18 at 5:44
  • Also, while setting up a ROP chain by hand is good practice for knowing what is really going on, there are tools that will do it for you (as in, you provide a short C program and a binary that you're executing in, and it emits the full ROP chain for you to "run" that program). Generally speaking, any non-trivial program will, either in itself or its libraries, have the gadgets you need (though possibly not the first ones you look for). Also, another gadget you could use: an operation that NULLs out a single byte. No need to set the whole address at once; x86 is byte-addressable. – CBHacking Nov 21 '18 at 5:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.