[Dreamhack] small_counter

Chris Kim·2024년 10월 12일

리버싱

목록 보기
10/10

0. 목표

flag_gen() 함수를 실행하는 것이 목표다. 이게 왜 목표지?

1. 동적분석

일단 냅다 실행부터 해보자

음 일단 모르겠다.

2. 정적분석

2.1 IDA 디컴파일

main함수 디컴파일 내용만 보면 방금 출력은 납득이 된다. 근데 저 IM{...}은 복사만 되고 어디에 들어가지를 않는다.
IDA 왼쪽에는 Function name을 찾을 수 있다. 저기 flag_gen이 보인다.

일단 이게 flag를 생성하는 거 같다. rax에 result를 반환하는 것 같다.

2.2 gdb 디버깅

gdb로 디버깅을 해보자.

$ gdb chall

일단 main 함수를 살펴보자

$ disassemble main
Dump of assembler code for function main:
   0x0000000000001494 <+0>:	endbr64
   0x0000000000001498 <+4>:	push   rbp
   0x0000000000001499 <+5>:	mov    rbp,rsp
   0x000000000000149c <+8>:	sub    rsp,0xf0
   0x00000000000014a3 <+15>:	mov    DWORD PTR [rbp-0x4],0x0
   0x00000000000014aa <+22>:	lea    rax,[rip+0xb53]        # 0x2004
   0x00000000000014b1 <+29>:	mov    rdi,rax
   0x00000000000014b4 <+32>:	call   0x1090 <puts@plt>
   0x00000000000014b9 <+37>:	mov    DWORD PTR [rbp-0x4],0xa
   0x00000000000014c0 <+44>:	jmp    0x15a0 <main+268>
   0x00000000000014c5 <+49>:	mov    eax,DWORD PTR [rbp-0x4]
   0x00000000000014c8 <+52>:	mov    esi,eax
   0x00000000000014ca <+54>:	lea    rax,[rip+0xb41]        # 0x2012
   0x00000000000014d1 <+61>:	mov    rdi,rax
   0x00000000000014d4 <+64>:	mov    eax,0x0
   0x00000000000014d9 <+69>:	call   0x10b0 <printf@plt>
   0x00000000000014de <+74>:	cmp    DWORD PTR [rbp-0x4],0x3
   0x00000000000014e2 <+78>:	jne    0x159c <main+264>
   0x00000000000014e8 <+84>:	movabs rax,0x38383830357b4d49
   0x00000000000014f2 <+94>:	movabs rdx,0x6a37386a32336a39
   0x00000000000014fc <+104>:	mov    QWORD PTR [rbp-0xf0],rax
   0x0000000000001503 <+111>:	mov    QWORD PTR [rbp-0xe8],rdx
   0x000000000000150a <+118>:	movabs rax,0x3035363435676a39
   0x0000000000001514 <+128>:	movabs rdx,0x6a68383234303438
   0x000000000000151e <+138>:	mov    QWORD PTR [rbp-0xe0],rax
   0x0000000000001525 <+145>:	mov    QWORD PTR [rbp-0xd8],rdx
   0x000000000000152c <+152>:	movabs rax,0x6838306969326968
   0x0000000000001536 <+162>:	movabs rdx,0x3833356a68693437
   0x0000000000001540 <+172>:	mov    QWORD PTR [rbp-0xd0],rax
   0x0000000000001547 <+179>:	mov    QWORD PTR [rbp-0xc8],rdx
   0x000000000000154e <+186>:	movabs rax,0x3667376a33343568
   0x0000000000001558 <+196>:	movabs rdx,0x68696a386b6a356b
   0x0000000000001562 <+206>:	mov    QWORD PTR [rbp-0xc0],rax
   0x0000000000001569 <+213>:	mov    QWORD PTR [rbp-0xb8],rdx
   0x0000000000001570 <+220>:	mov    DWORD PTR [rbp-0xb0],0x7d663232
   0x000000000000157a <+230>:	mov    BYTE PTR [rbp-0xac],0x0
   0x0000000000001581 <+237>:	lea    rcx,[rbp-0xf0]
   0x0000000000001588 <+244>:	lea    rax,[rbp-0x50]
   0x000000000000158c <+248>:	mov    edx,0x45
   0x0000000000001591 <+253>:	mov    rsi,rcx
   0x0000000000001594 <+256>:	mov    rdi,rax
   0x0000000000001597 <+259>:	call   0x10c0 <memcpy@plt>
   0x000000000000159c <+264>:	sub    DWORD PTR [rbp-0x4],0x1
   0x00000000000015a0 <+268>:	cmp    DWORD PTR [rbp-0x4],0x0
   0x00000000000015a4 <+272>:	jg     0x14c5 <main+49>
   0x00000000000015aa <+278>:	cmp    DWORD PTR [rbp-0x4],0x5
   0x00000000000015ae <+282>:	jne    0x15fe <main+362>
   0x00000000000015b0 <+284>:	lea    rax,[rip+0xa5f]        # 0x2016
   0x00000000000015b7 <+291>:	mov    rdi,rax
   0x00000000000015ba <+294>:	call   0x1090 <puts@plt>
   0x00000000000015bf <+299>:	mov    eax,DWORD PTR [rbp-0x4]
   0x00000000000015c2 <+302>:	mov    DWORD PTR [rbp-0x8],eax
   0x00000000000015c5 <+305>:	mov    edx,DWORD PTR [rbp-0x8]
   0x00000000000015c8 <+308>:	lea    rcx,[rbp-0xa0]
   0x00000000000015cf <+315>:	lea    rax,[rbp-0x50]
   0x00000000000015d3 <+319>:	mov    rsi,rcx
   0x00000000000015d6 <+322>:	mov    rdi,rax
   0x00000000000015d9 <+325>:	call   0x11c9 <flag_gen>
   0x00000000000015de <+330>:	lea    rax,[rbp-0xa0]
   0x00000000000015e5 <+337>:	mov    rsi,rax
   0x00000000000015e8 <+340>:	lea    rax,[rip+0xa2d]        # 0x201c
   0x00000000000015ef <+347>:	mov    rdi,rax
   0x00000000000015f2 <+350>:	mov    eax,0x0
   0x00000000000015f7 <+355>:	call   0x10b0 <printf@plt>
   0x00000000000015fc <+360>:	jmp    0x160d <main+377>
   0x00000000000015fe <+362>:	lea    rax,[rip+0xa1c]        # 0x2021
   0x0000000000001605 <+369>:	mov    rdi,rax
   0x0000000000001608 <+372>:	call   0x1090 <puts@plt>
   0x000000000000160d <+377>:	mov    eax,0x0
   0x0000000000001612 <+382>:	leave
   0x0000000000001613 <+383>:	ret

flag_genmain+325에 보인다. 근데 main+264부터 main+282를 보면
[rbp-4]에서 1을 빼고 0과 비교해서 rip를 이동시키는 것을 볼 수 있다. 아마 main함수의 for문에서 --i를 수행하고 0과 비교하는 부분인것 같다.

근데 i를 갑자기 5하고 비교하고 같지 않으면 rip를 main+362로 날려버린다.(이후 프로그램 종료) 그 결과 flag_gen함수를 건너뛰어버리니 함수를 실행하지 않는 것이다.

그래서 IDA로 main+282jne에서 je로 바꾸어 flag를 실행했으나, IM{...}이 출력된다.
플래그는 DH{}형식이다. Nice를 외쳐주니 일단 함수 호출은 이뤄진 것 같다. 이후 조금 힌트를 얻어보니 flag_gen함수가 인자를 3개 받는다고 한다.

IDA 디컴파일 내용을 보니 진짜 그렇다. 다음부터는 함수의 인자를 잘 살펴보아야겠다.

실제로 main+299부터 살펴보면 rbp-4, 즉 i 를 edx에 옮기는 걸 볼 수있다.
즉 앞에서 5하고 i를 비교하는 것은 5를 함수 인자로 넘기기 위한 것이다.

방금 IDA에서 수정한 내용을 원상 복구하고, 프로그램을 실행하면서 바이너리 패치를 수행해보자.

2.3 바이너리 패치

먼저 분기점 main+282의 앞에 중단점을 설정하고 실행하자

$ b *main+278
$ r

일단 rbp의 주소를 알아보자

pwndbg> info registers rbp
rbp            0x7fffffffdd30      0x7fffffffdd30

오케이 그러면 rbp-4의 값을 5로 바꿔주자

pwndbg> set *(int*)(0x7fffffffdd30-4) = 5


무사히 넘어갔다 무사히 넘어간 것을 확인했으니, c로 나머지를 실행하면

pwndbg> c
Continuing.
Nice!

DH{...}

이 나온다.

3. 마무리

(1) gdb, IDA 다루는 법이 아직 서툴다. 바이너리 패치하는 방법을 찾는데 들인 시간이 생각보다 컸다.
(2) 함수를 보면 어떤 인자를 받는지도 잘 살펴보고, 코드에서 작성자의 의도를 잘 살펴보아야겠다. 단순히 jne를 수정해서 넘어갔는데도 플래그가 나오지 않아서 당황스러웠다. i가 인자로 들어간다는 것을 알았으면 좀 더 빨리 풀 수 있었을 것이다.
(3) 다음에는 완전히 혼자만의 힘으로 문제를 풀 수 있기를 바란다.

profile
회계+IT=???

0개의 댓글