Pwnstar

Pwnable.kr unlink 본문

Pwnable.kr/Toddler's Bottle

Pwnable.kr unlink

포너블처돌이 2020. 3. 20. 03:12

저번 문제와 이어서 힙 문제이다.

 

우선,

 

32비트 바이너리이고, NX와 partial relro만 걸려있다.

 

소스코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagOBJ{
	struct tagOBJ* fd;
	struct tagOBJ* bk;
	char buf[8];
}OBJ;

void shell(){
	system("/bin/sh");
}

void unlink(OBJ* P){
	OBJ* BK;
	OBJ* FD;
	BK=P->bk;
	FD=P->fd;
	FD->bk=BK;
	BK->fd=FD;
}
int main(int argc, char* argv[]){
	malloc(1024);
	OBJ* A = (OBJ*)malloc(sizeof(OBJ));
	OBJ* B = (OBJ*)malloc(sizeof(OBJ));
	OBJ* C = (OBJ*)malloc(sizeof(OBJ));

	// double linked list: A <-> B <-> C
	A->fd = B;
	B->bk = A;
	B->fd = C;
	C->bk = B;

	printf("here is stack address leak: %p\n", &A);
	printf("here is heap address leak: %p\n", A);
	printf("now that you have leaks, get shell!\n");
	// heap overflow!
	gets(A->buf);

	// exploit this unlink!
	unlink(B);
	return 0;
}

 

메인함수를 보면 A,B,C 객체들이 double linked list와 같은 형태로 되어있고, A의 스택 주소와, 힙 주소를 출력해주며 A->buf에 입력을 받는 다는 것을 알 수 있다.

 

그 후 unlink라는 함수를 통해 쉘을 따면 될 것 같은데 음 우선 buf의 크기가 8개 이니 8개 입력을 주고, gdb를 통해 heap 구조가 어떻게 되어있는 지 살펴봐야할 것 같다.

 

우선은 unlink함수가 실행되기 직전에 bp를 걸고 실행해보았다.

입력값은 A*8를 준 상태이다.

 

빨간색, 파란색, 노란색은 각각 A,B,C의 부분일 것이다.

그렇다면 A->buf를 gets함수로 입력받고 있으니 B의fd와 bk를 조작할 수 있을텐데 이 부분을 어떻게 조작할 지가 관건일 것 같다.

 

unlink함수가 실행되고 난 직후에 bp를 걸고 계속 해 보았다.

A->fd = B;
B->bk = A;
B->fd = C;
C->bk = B;

기존에 이렇게 되어있던 구성에서 A의 fd가 C를 가리키고, C의 bk가 A를 가리키고 있다.

 

A->fd = C;
B->bk = A;
B->fd = C;
C->bk = A;

이렇게 변한 형태

 

.이제 unlink함수가 어떻게 돌아가는지 자세히 알아보자..

 

정말 중요한 unlink 함수. 이 부분에서 ebp를 내 마음대로 조절할 수 있다.

**입력값은 A16+B4+C*4개를 준 상황이다.

+9까지 진행하고 나면 eax레지스터에 CCCC가 들어가있다.

 

즉 B의 bk가 eax에 들어가있는 상황 그리고, eax를 ebp-0x4에 넣는다.

좀 더 진행해서 unlink+20에서는

 

eax에 들어있는 BBBB가 ebp-0x8에 들어간다. 즉, B의 fd는 ebp-0x8에 들어간다.

unlink+26, +29 부분이다.

 

 

현재 eax에는 (BBBB)가 있다. unlink+26에서는 ebp-0x4에 있는 B→bk(CCCC)를 edx에 넣고 edx를 eax+0x4에 넣는다.

이후 unlink+32와 unlink+35에서는 ebp-0x4에 있는 B→bk(CCCC)를 eax에 넣고, ebp-0x8에 있는 B→fd(BBBB)를 edx에 넣는다. 이 과정에서 A→fd는 C를 가리키게 되고, C→bk는 A를 가리키게 된다.

 

unlink함수를 통해 ebp의 값을 조정할 수 있다는 것을 알 수 있다.

unlink함수를 종료하고 나서의 main함수를 살펴보자.

 

 

unlink함수를 종료하고, leave ret이 실행되는데 이제까지 봐왔던 leave ret과는 다른 양상을 보인다.

ebp-0x4의 값을 ecx에 넣고 leave를 실행한 후, esp에 ecx-0x4를 넣는다.

이 부분은 다시 실행한 후 스택의 구성이다.

 

 

A의 주소는 0xffa91c84이며 ebp-0x14와 같다. 조작해야하는 ebp-0x4는 A의 주소와 0x10차이이다.

 

결과적으로는 ebp-0x4의 주소에 있는 값 - 0x4의 주소에 있는 값을 ret한다.

 

페이로드는 다음과 같다.

 

쉘주소 + "A"*12 + (heap주소 + 0xC) + (stack주소 + 0x10)→(ebp-0x4)

 

이렇게 페이로드를 주게 되면 B→bk에는 stack주소 +0x10이 들어간다(ebp-0x4)

그 다음 그 주소 - 0x4한 주소(B→fd)에는 heap 영역의 쉘주소 + 4의 주소가 들어가는데

여기서 한번 더 - 0x4한 위치의 주소가 ret되기 때문에 위와같이 payload를 짜면 된다.

 

 

하...이게 뭐라고 이해하는데 얼마나 걸렸는지 모른다...

이해하는데 많은 라이트업들을 찾아봤다..

 

이제 익스 짜보자...

 

 

나중에 다시 풀어보기 위해 익스코드는 올려놓지 않겠다.

'Pwnable.kr > Toddler's Bottle' 카테고리의 다른 글

Pwnable.kr horcruxes  (0) 2020.03.21
Pwnable.kr blukat  (0) 2020.03.21
Pwnable.kr uaf  (0) 2020.03.17
Pwnable.kr lotto  (0) 2020.03.16
Pwnable.kr blackjack  (0) 2020.03.16
Comments