[Dreamhack] dungeon-in-1983

pandas·2024년 9월 25일
0

Dreamhack

목록 보기
5/14
post-thumbnail

00. 문제 파일

01. 바이너리 분석

main함수
윗 부분은 배열의 값이다 (STAGE별 이름)


총 10번, 즉 10단계까지 있다


ptr값을 가져온다


ptr을 이리 저리 변환시켜서 출력한다
sub_138D를 분석하자

이런 모양새로 출력이 된다

처음에는 이게 뭔지 몰랐다

HIWORD, (unsigend __int8), BYTE1, BYTE2...이 뜻하는 것이 무엇인지 아는 것이 중요했다

HIWORD : 값의 상위 1바이트
unsigned __int8 : 값의 하위 1바이트
BYTE1 : 가장 낮은 비트 옆 1바이트
...

예시 : 0x11223344
unsigned __int8 == LOBYTE : 0x44
BYTE1 : 0x33
BYTE2 : 0x22
BYTE3 : 0x11
HIBYTE : 0x11

출력된 결과를 잘 조합해서 ptr을 조합해주면 된다


if1이면 실패하고, 0이면 성공한다
0으로 만들기 위해서는 sub_1407(s, ptr)1이여야 한다
suser_input이다

sub_1407

뭔소린지 몰라서 python으로 정리해봤다

v7a2와 같아야 한다
a2ptr이다

목표 : v7 == a2(ptr)

이 코드가 하는 일은 단순하다

A : v7에 1을 더한다
B : v7에 2를 곱한다
나머지 : ERROR

이 두 연산을 사용해서 v7 = 0에서 ptr까지 만들면 된다

02. Exploit

int형 숫자를 입력하고 이를 A,B 연산으로 역연산 하는 함수를 만들었다

def reverse(n):
    result = ""
    while n != 0:
        if n % 2 == 0:
            result += "B"
            n //= 2
        else:
            result += "A"
            n -= 1
    return "".join([i for i in reversed(result)])
print(reverse(int(input())))

그냥 이건 PS다

이 문제는 reversing이지만 pwntools를 사용해야 된다

ptr을 조합하기 위해서 이 숫자들을 입력받아야 한다

p.recvuntil(b"HP:")
hp = int(p.recvuntil(b",")[:-1])
print(f"HP  : {hp} / {hex(hp)}")

p.recvuntil(b"STR:")
dungeon_str = int(p.recvuntil(b",")[:-1])
print(f"STR : {dungeon_str} / {hex(dungeon_str)}")

p.recvuntil(b"AGI:")
agi = int(p.recvuntil(b",")[:-1])
print(f"AGI : {agi} / {hex(agi)}")

p.recvuntil(b"VIT:")
vit = int(p.recvuntil(b",")[:-1])
print(f"VIT : {vit} / {hex(vit)}")

p.recvuntil(b"INT:")
dungeon_int = int(p.recvuntil(b",")[:-1])
print(f"INT : {dungeon_int} / {hex(dungeon_int)}")

p.recvuntil(b"END:")
end = int(p.recvuntil(b",")[:-1])
print(f"END : {end} / {hex(end)}")

p.recvuntil(b"DEX:")
dex = int(p.recvuntil(b"\n")[:-1])
print(f"DEX : {dex} / {hex(dex)}")

그럼 이들을 조합해야 한다

아까의 HIBYTE, LOBYTE, BYTE1, BYTE2... 개념을 활용하야 이를 비트 쉬프트 연산으로 조합하면 된다

ptr = ((hp<<48) | (dex<<40) | (end<<32) | (dungeon_int<<24) | (vit<<16) | (agi<<8) | dungeon_str)

ptr까지 구했다!

payload = reverse(ptr)
p.sendlineafter(b": ", payload)

reverse(ptr)을 구해서 pwntool로 전송해주면 된다

전체 익스 코드

from pwn import *

p = remote("host3.dreamhack.games", [PORT])

def reverse(n):
    result = ""
    while n != 0:
        if n % 2 == 0:
            result += "B"
            n //= 2
        else:
            result += "A"
            n -= 1
    return "".join([i for i in reversed(result)])

def check(result):
    num = 0
    for i in result:
        if i == "A":
            num += 1
        elif i == "B":
            num *= 2
        #print(i, num)
    return num


for i in range(10):
    p.recvuntil(b"HP:")
    hp = int(p.recvuntil(b",")[:-1])
    print(f"HP  : {hp} / {hex(hp)}")

    p.recvuntil(b"STR:")
    dungeon_str = int(p.recvuntil(b",")[:-1])
    print(f"STR : {dungeon_str} / {hex(dungeon_str)}")

    p.recvuntil(b"AGI:")
    agi = int(p.recvuntil(b",")[:-1])
    print(f"AGI : {agi} / {hex(agi)}")

    p.recvuntil(b"VIT:")
    vit = int(p.recvuntil(b",")[:-1])
    print(f"VIT : {vit} / {hex(vit)}")

    p.recvuntil(b"INT:")
    dungeon_int = int(p.recvuntil(b",")[:-1])
    print(f"INT : {dungeon_int} / {hex(dungeon_int)}")

    p.recvuntil(b"END:")
    end = int(p.recvuntil(b",")[:-1])
    print(f"END : {end} / {hex(end)}")

    p.recvuntil(b"DEX:")
    dex = int(p.recvuntil(b"\n")[:-1])
    print(f"DEX : {dex} / {hex(dex)}")

    ptr = ((hp<<48) | (dex<<40) | (end<<32) | (dungeon_int<<24) | (vit<<16) | (agi<<8) | dungeon_str)

    payload = reverse(ptr)
    p.sendlineafter(b": ", payload)


p.interactive()


냠냠

03. Review

분석이 그렇게 어렵지는 않았다...?

ptr을 쪼개놓고 다시 비트 쉬프트 연산으로 합치는 것이 어려웠다

reverse()함수를 짜는게 PS같아서 좋았다

시험기간이 아니였다면 이틀정도? 갈아넣으면 풀 수 있었을 거 같은데 시험기간이라 오래 걸린점이 아쉬웠다

BYTE 매크로를 무시하고 ptr을 구하려다가 시간을 너무 날렸다

리버싱에서 pwntool을 써서 새로웠다

포너블하면서 자주 썼더니 여기서 막히지는 않았다

문제가 재밋었다

맛도리

profile
KDMHS 23 WP

0개의 댓글

관련 채용 정보