Protostar Heap0
About
This level introduces heap overflows and how they can influence code flow.
This level is at /opt/protostar/bin/heap0
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct data {
char name[64];
};
struct fp {
int (*fp)();
};
void winner()
{
printf("level passed\n");
}
void nowinner()
{
printf("level has not been passed\n");
}
int main(int argc, char **argv)
{
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = nowinner;
printf("data is at %p, fp is at %p\n", d, f);
strcpy(d->name, argv[1]);
f->fp();
}
문제를 풀기 전에 스택과 힙에 대해서 비교하면 아래와 같다.
스택 | 힙 | |
메모리 할당 방법 | 정적 메모리 | 동적 메모리 |
메모리의 무작위 위치에 데이저 저장하고 포인터로 데이터에 접근 | FIFO 방식 | |
할당 주체 | 메모리 상단에 자동 할당 | 프로그래머에 의해서 할당 |
할당 | 작은 메모리에 할당 (크기에 제한이 있음) |
큰 메모리에서 할당 (malloc, class) |
주소 | 아래에서 위로 (높은 주소에서 낮은 주소) |
위에서 아래로 |
관리 | EBP, ESP | 헤더 |
힙은 구조가 있음.
struct area_header{
size_t type;
size_t size; /*다음 항목의 위치도 제공*/
struct free_arena_header *next, *prev;
}
main함수에서
struct data와 fp를 선언하고 d에는 struct data, f에는 fp가 malloc으로 동적으로 메모리 할당이 된다.
👉 그러면 Heap영역에 해당 데이터가 저장된다.
strcpy(d->name, argv[1]);
그러고 나서 strcpy 에서 함수인자값(argv[1])이 d->name으로 덮어쓰기 되는데
👉 여기서 힙 오버플로우가 발생
문제의 목표는,
f->fp에 의해서 해당 위치에는 nowinner 함수의 주소가 들어가 있는데, 이 부분은 winner함수 주소로 바꾸는 게 목표이다.
문제를 실행하면 data와 fp의 주소를 알려준다.
heap에는 header가 있기 때문에 해당 위치에서 -0x8을하여 header부터 확인이 가능하다.
strcpy함수가 발생한 다음에 breakpoint를 잡고나서 (b *main+107)
인자값으로 AAAA를 주어서 실행해 보았다. (r AAAA)
x/100x 0x804a008 - 0x8
data 주소에서 - 0x8을 한뒤 메모리 구조를 보게 되면,
0x414141앞에 8bytes가 헤더이고 뒤에 64bytes가 data구간이다.
바로 뒤에 fp가 할당된 부분도 볼 수 있다. data부분에는 nowinner함수의 주소가 들어가 있다.
👉 이부분을 winner 주소로 덮어쓰면 될 거 같다.
페이로드 :
data의 64bytes + fp header 8bytes + winner주소
./heap0 $(python -c 'print "A"*64+"B"*8+"\x64\x84\x04\x08"')
성공!