[Protostart] Heap1
About
This level takes a look at code flow hijacking in data overwrite cases.
This level is at /opt/protostar/bin/heap1
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct internet {
int priority;
char *name;
};
void winner()
{
printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
struct internet *i1, *i2, *i3;
i1 = malloc(sizeof(struct internet));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct internet));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
함수를 보면,
internet 구조체는 priority (4bytes), name (4bytes)으로 구성되어 있었고,
i1, i2은 internet이라는 구조체가 할당 됨.
그리고 나서 i1, i2는 각각 argv[1], argv[2]가 strcpy 함수로 복사 됨.
strcpy 함수가 heap overflow를 발생시킴.
👉 heap overflow를 발생시켜 하고자하는 목표는 winner 함수를 실행시키는 것이다!
heap1 파일을 gdb로 확인하면,
$eax에 malloc되는 값이 들어간다.
두번째로 strcpy가 되는 곳(main+161)에 breakpoint를 걸어서 $eax-0x8의 값을 확인해 본다.
internet 구조체 i1, malloc(8)으로 i1->name,
internet 구조체 i2, malloc(8)으로 i2->name 이렇게 4개가 heap에 할당되어 있다.
여기서 문제를 해결하기 위해서,
1) i1->name부분에서 overflow해서 i2의 구조체에서 header와 priority까지 덮어씌우고나서
2) *name 부분에 GOT overwirte를 한다.
👉 main 함수를 보면 printf가 있는게 아니라 puts함수가 있다.
(인터넷에 찾아보니까 컴파일을 최적화한 결과라고 한다.)
이부분의 got주소를 확인하기 위해서
disass 0x80483cc 명령어를 치면 got 주소를 구할 수 있다.
바로 plt에서 바로 got로 jmp를 하기때문에, 맨 첫줄에 jmp하는 부분이 got 주소이다.
👉 0x8049774
plt(Procedure Linkage Table) :
ELF 파일의 동적 링킹에 사용되는 메커니즘입니다. 프로그램이 실행되면, 컴파일러는 모든 함수에 대해 해당 함수를 호출하는 코드를 생성합니다. 이 호출 코드에는 함수의 직접 주소가 아닌, 함수를 찾기 위한 간접적인 접근 방법이 포함됩니다. plt는 이러한 간접 접근 방법을 구현하는 테이블입니다. plt 항목은 함수를 호출하기 위한 간접적인 점프 명령을 포함하고 있습니다. 이때, plt에 존재하는 항목의 주소는 동적 링킹으로 인해 실행 시간에 변화할 수 있습니다.
got(Global Offset Table) :
ELF 파일의 전역 데이터를 저장하는 테이블입니다. 일반적으로 C 언어에서 전역 변수를 사용할 때, 해당 변수는 데이터 섹션에 저장됩니다. 그러나 동적 링킹을 사용하는 경우, 전역 변수의 위치가 변할 수 있습니다. 이때, 컴파일러는 해당 변수에 접근하기 위해 got를 사용합니다. got는 전역 변수의 주소를 가지고 있으며, 이 주소는 실행 시간에 동적 링킹에 의해 변경될 수 있습니다.
출처 : chatgpt
그리고 winner의 주소도 구하면 아래와 같다.
👉 winner 주소 : 0x8048494
winner 함수를 열기위해서 그린 메모리 구조이다.
첫번째 인자로 A*20 + puts의 got 주소, 두번째 인자로 winner함수 주소를 넣으면 된다.
그러면 puts함수의 인자로 winners의 주소가 들어가 면서 실행이 된다.
./heap1 $(python -c 'print "A"*20+"\x74\x97\x04\x08"') $(python -c 'print "\x94\x84\x04\x08"')