HackCTF Handray Write-Up

juuun0·2022년 1월 26일
1
post-thumbnail

Analyze Target

문제 파일을 다운로드 받으면 64bit ELF 파일임을 확인할 수 있었습니다. 먼저 프로그램을 실행할 경우 아래 내용을 출력해준 뒤 동작을 종료하는 것을 확인할 수 있었습니다.

persian@Code-PAPA  /tmp  ./handray 
flag를 뛰어넘었습니다!

인자를 전달해야 하는 문제인가 싶어 임의의 값도 입력해 보았으나 유효한 결과를 얻진 못하였습니다.

GDB를 통해 먼저 사용되는 함수의 목록을 살펴보았으나 main() 함수 외에 특별한 함수는 찾을 수 없었습니다. main() 함수를 분석하던 중 flag와 관련되어 보이는 값을 확인할 수 있었습니다.

   0x0000000000400577 <+81>:	mov    esi,0x6010e0
   0x000000000040057c <+86>:	mov    edi,0x400638
   0x0000000000400581 <+91>:	mov    eax,0x0
   0x0000000000400586 <+96>:	call   0x400400 <printf@plt>

위 명령을 실행하기 위해서는 몇 가지 조건을 맞춰줄 필요가 있었으며 사용되는 인자를 바탕으로 아래 값임을 유추할 수 있었습니다.

flag is  A]`j?NCz?eiHb:R^CkdA.jaP+F+..jb!}

이 값에서 마지막 문자가 '}'로 끝나는 것을 보아 encoding 된 flag 값이지 않을까 생각하게 되었고 프로그램의 흐름을 역으로 따라가며 분석하였습니다.

   0x0000000000400544 <+30>:	mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000400547 <+33>:	cdqe   
   0x0000000000400549 <+35>:	movzx  eax,BYTE PTR [rax+0x6010e0]
   0x0000000000400550 <+42>:	mov    edx,eax
   0x0000000000400552 <+44>:	mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000400555 <+47>:	cdqe   
   0x0000000000400557 <+49>:	mov    eax,DWORD PTR [rax*4+0x601060]
   0x000000000040055e <+56>:	add    eax,edx
   0x0000000000400560 <+58>:	mov    edx,eax
   0x0000000000400562 <+60>:	mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000400565 <+63>:	cdqe   
   0x0000000000400567 <+65>:	mov    BYTE PTR [rax+0x6010e0],dl
   0x000000000040056d <+71>:	add    DWORD PTR [rbp-0x8],0x1
   0x0000000000400571 <+75>:	cmp    DWORD PTR [rbp-0x8],0x1e
   0x0000000000400575 <+79>:	jle    0x400544 <main+30>

위 코드에서 기존 encoding 값과 비슷한 위치에서 참조하는 다른 값이 있는 점을 확인할 수 있었고 확인한 결과 4 Byte 단위로 다른 값이 있는 것을 보아 int 값임을 추측할 수 있었습니다.

gdb-peda$ x/50wx 0x601060
0x601060 <array>:	0x00000007	0x00000004	0x00000003	0x00000001
0x601070 <array+16>:	0x00000004	0x00000006	0x00000003	0x00000001
0x601080 <array+32>:	0x00000009	0x0000000a	0x0000000b	0x0000000c
0x601090 <array+48>:	0x0000000d	0x0000000e	0x0000000f	0x00000010
0x6010a0 <array+64>:	0x00000001	0x00000001	0x00000001	0x00000002
0x6010b0 <array+80>:	0x00000002	0x00000002	0x00000003	0x00000004
0x6010c0 <array+96>:	0x00000005	0x00000002	0x00000005	0x00000002
0x6010d0 <array+112>:	0x00000002	0x00000002	0x00000002	0x00000002
0x6010e0 <string>:	0x6a605d41	0x7a434e3f	0x4869653f	0x5e523a62
0x6010f0 <string+16>:	0x41646b43	0x50616a2e	0x2e2b462b	0x21626a2e
0x601100 <string+32>:	0x0000007d

두 변수를 호출하는 것과 add와 같이 연산하는 과정이 있는 것을 토대로 연관성 있는 값이라고 판단되어 가설을 바탕으로 exploit code를 작성하였습니다.


Exploit

Exploit code를 작성할 때 가장 처음의 가설은 실제 flag 값에서 array의 값을 각 글자에 더한 값이 string의 값이라고 추정하였습니다. 그 근거로 array에는 총 32개의 숫자가, string에는 33자가 있기에 마지막 '}' 문자는 영향을 받지 않았을 거라 판단했기 때문입니다.

따라서 처음에는 string에서 array의 값을 뺄셈으로 진행하였습니다. 그러나 그럴듯한 값을 얻을 수 없었고 이에 덧셈으로 진행하여 flag 값을 획득할 수 있었습니다. Flag 형식에 맞는 값을 구하였음에도 인증에 실패하여 다시 확인한 결과 cmp DWORD PTR [rbp-0x8],0x1e 명령으로 인해 30(0x1e)번째까지만 encoding을 진행하는 점을 확인할 수 있었습니다.

따라서 이러한 내용들을 모두 반영하여 최종적으로 아래와 같은 exploit code를 작성하였습니다.

#!/usr/bin/python3

import struct

_string_offset = 0x000010D8+0x8
_array_offset = 0x00001054+0xc
salt = [0]*33
dec_flag = ""

with open("/tmp/handray", "rb") as f:
    data = f.read()
    enc_flag = data[_string_offset:_string_offset+33].decode('utf-8')
    array = data[_array_offset:_array_offset+120]

def toTheNumeric(array):
    for i in range(int(len(array)/4)):
        salt[i] = struct.unpack("<I", array[i*4:i*4+4])[0]

def decoding(enc_flag, salt):
    enc = list(enc_flag)
    global dec_flag
    for i in range(len(enc_flag)):
        dec_flag += chr(ord(enc[i]) + salt[i])

toTheNumeric(array)
decoding(enc_flag, salt)
print(dec_flag)

위 코드에서 offset의 경우 hexedit을 통해 구하였습니다.

profile
To be

0개의 댓글