우분투에 도커 등 설치 완료 후 UAF 고고~
https://velog.io/@leejiwon317/Dreamhack-Exercise-Docker-1nnyeqrt
Dreamhack - Exercise: Docker
Install Docker Engine on Ubuntu🔼위 링크를 참고하여 설치하였습니다.이렇게 뜨면 도커 설치 성공!이번 문제는 Dockerfile로 이미지를 빌드하고 컨테이너를 실행해 보기 위한 실습 문제!!!문제 파일을 다
velog.io
[Dreamhack] uaf_overwrite - write up
Index문제보호기법 확인uaf_overwrite.c코드 분석전역 변수 선언human_func()robot_func()custom_func()문제 풀이Libc LeakLocal Exploit Issue 익스플로잇 uaf_overwriteDescription Exploit Tech: Use After Free에서 실습하는 문제입
she11.tistory.com
// Name: uaf_overwrite.c
// Compile: gcc -o uaf_overwrite uaf_overwrite.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct Human {
char name[16];
int weight;
long age;
};
struct Robot {
char name[16];
int weight;
void (*fptr)();
};
struct Human *human;
struct Robot *robot;
char *custom[10];
int c_idx;
void print_name() { printf("Name: %s\n", robot->name); }
void menu() {
printf("1. Human\n");
printf("2. Robot\n");
printf("3. Custom\n");
printf("> ");
}
void human_func() {
int sel;
human = (struct Human *)malloc(sizeof(struct Human));
strcpy(human->name, "Human");
printf("Human Weight: ");
scanf("%d", &human->weight);
printf("Human Age: ");
scanf("%ld", &human->age);
free(human);
}
void robot_func() {
int sel;
robot = (struct Robot *)malloc(sizeof(struct Robot));
strcpy(robot->name, "Robot");
printf("Robot Weight: ");
scanf("%d", &robot->weight);
if (robot->fptr)
robot->fptr();
else
robot->fptr = print_name;
robot->fptr(robot);
free(robot);
}
int custom_func() {
unsigned int size;
unsigned int idx;
if (c_idx > 9) {
printf("Custom FULL!!\n");
return 0;
}
printf("Size: ");
scanf("%d", &size);
if (size >= 0x100) {
custom[c_idx] = malloc(size);
printf("Data: ");
read(0, custom[c_idx], size - 1);
printf("Data: %s\n", custom[c_idx]);
printf("Free idx: ");
scanf("%d", &idx);
if (idx < 10 && custom[idx]) {
free(custom[idx]);
custom[idx] = NULL;
}
}
c_idx++;
}
int main() {
int idx;
char *ptr;
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
while (1) {
menu();
scanf("%d", &idx);
switch (idx) {
case 1:
human_func();
break;
case 2:
robot_func();
break;
case 3:
custom_func();
break;
}
}
}
전역 변수
struct Human {
char name[16];
int weight;
long age;
};
struct Robot {
char name[16];
int weight;
void (*fptr)();
};
struct Human *human;
struct Robot *robot;
char *custom[10];
int c_idx;
두 구조체의 자료형을 보면 동일한 메모리 크기를 사용하는 것을 알 수 있다.
UAF(Use After Free 문제인 만큼 Human→age에 주소 값을 입력하고 해제하고 Robot 구조체로 재 할당하면, 재 할당 받은 Robot→fptr로 원하는 코드 흐름을 실행시킬 수 있을 것 같다. 또한, 주소를 담고 있는 custom 배열과 이를 참조하는 c_idx가 선언된다.
human_func()
void human_func() {
int sel;
human = (struct Human *)malloc(sizeof(struct Human));
strcpy(human->name, "Human");
printf("Human Weight: ");
scanf("%d", &human->weight);
printf("Human Age: ");
scanf("%ld", &human->age);
free(human);
}
robot_func()
void robot_func() {
int sel;
robot = (struct Robot *)malloc(sizeof(struct Robot));
strcpy(robot->name, "Robot");
printf("Robot Weight: ");
scanf("%d", &robot->weight);
if (robot->fptr)
robot->fptr();
else
robot->fptr = print_name;
robot->fptr(robot);
free(robot);
}
Robot(2번) 메뉴를 선택하면 robot_function함수가 실행된다. Robot 구조체 1개를 동적할당 하고, weight를 입력받아 데이터를 저장한다. fptr에 대한 입력은 없지만, robot→fptr의 값이 NULL이 아니라면 fptr의 주소로 점프한다.
위의 두개의 함수를 통해 Human→age에 원하는 주소를 입력해두고, robot_func()을 실행하면 robot→fptr에 앞서 저장해준 Human→age값으로 robot→fptr()이 실행된다. 그렇다면 Human→age에 원샷 가젯의 주소를 넣으면 셸을 얻을 수 있을 것이다. 하지만 우리는 libc를 모르기 때문에, 메모리 릭을 통해 libc를 먼저 구해야 한다.
custom_func()
int custom_func() {
unsigned int size;
unsigned int idx;
if (c_idx > 9) {
printf("Custom FULL!!\n");
return 0;
}
printf("Size: ");
scanf("%d", &size);
if (size >= 0x100) {
custom[c_idx] = malloc(size);
printf("Data: ");
read(0, custom[c_idx], size - 1);
printf("Data: %s\n", custom[c_idx]);
printf("Free idx: ");
scanf("%d", &idx);
if (idx < 10 && custom[idx]) {
free(custom[idx]);
custom[idx] = NULL;
}
}
c_idx++;
}
마지막으로 Custom(3번) 메뉴를 선택하면 custom_func함수가 실행된다. 먼저 첫 if문의 c_idx는 앞서 선언했던 전역변수이다. 이 함수가 실행될 때마다 마지막에 c_idx++를 해주므로, 총 10번을 실행할 수 있다.
입력받은 size가 0x100보다 크다면 custom[c_idx]에 size만큼의 동적할당을 해주고, 데이터를 입력받는다.
char *custom[10];
printf("Data: %s\n", custom[c_idx]);
데이터를 입력받은 후, custom[c_idx]에 값을 출력해준다. 이 Data 부분에는 Unsorted bin을 free 했을 때 남아있던 fd 값이 출력된다. unsorted bin에 들어간 청크의 fd와 bk은 main 의 주소이고, 이 오프셋을 통해서 libc를 구할 수 있다.
unsigned int idx;
...
if (idx < 10 && custom[idx]){
free(custom[idx]);
custom[idx] = NULL;
}
...
idx가 unsigned int자료형으로 선언되었다. 만약 idx에 -1(음수)를 입력하게 되면 0xffffffff와 같은 형식으로 메모리에 입력된다. 그러면 할당된 메모리를 free하지 않는다.
'시스템' 카테고리의 다른 글
onone_gadget 설치 및 사용법 (펌) (0) | 2025.02.02 |
---|---|
peda, pwndbg, gef 같이 쓰기 (펌) (0) | 2025.02.02 |
pwnable.kr UAF (리마인드) (0) | 2025.01.31 |
protostar net3 (0) | 2025.01.31 |
protostar net1 (0) | 2025.01.31 |