uaf관련 ctf문제가 처음이여서 굉장히 많이 삽질했다.

 

우선 main문을 보면 6개 정도의 case가 존재하는 것 같다.

create_pet_recode함수를 보면 pet recode를 생성하는 함수인 것 같다. 

PET은 구조체이고, 이런식으로 되어있는 것 같다.(char *name, char *kind, int age)

edit_pet_record함수는 이미 존재하는 record의 id를 가져와 내용을 변경해주는 함수인 것 같다. 그런데 마지막 조건문을 보면 'n'일 경우 `::ptr`(전역변수)을 free해준다. 하지만 `::ptr`=NULL; 하는 부분이 없음으로 `::ptr`은 여전히 free된 chunk주소를 가르키고 있다. 여기서 uaf가 발생한다.

 

heap구조를 분석해보자.

`gdb -q Cat`을 입력하고 `r`을 한 뒤,

이런식으로 입력하고, `control+c`를 하면 프로그램이 멈추면서 디버깅을 할 수 있다.

`heapinfo`를 이용해 fastbin구조를 볼 수 있다.

free된 chunk 주소가 `0x603000`근처임으로 해당 주소를 보면 heap구조를 볼 수 있다.

heap구조

----------------

&AAAA, &BBBB

----------------

AAAA

----------------

BBBB

----------------

0

----------------

&0x603060

----------------

&0x603080

----------------

top chunk

----------------

이제 create_pet_recode함수를 이용해 다시 `malloc`을 불러오면 어떻게 구조가 변하는지 보자.

이런식으로 입력한 뒤

heap구조를 보면

heap구조

----------------

&AAAA, &BBBB

----------------

AAAA

----------------

BBBB

----------------

DDDD

----------------

CCCC

----------------

&CCCC, &DDDD

----------------

top chunk

----------------

이런식으로 값이 들어간다. (fastbin은 LIFO구조임으로.)

여기서 다시 edit_pet_record함수를 접근하면 `::ptr`은 아까와 똑같은 chunk구조를 가지고 있다고 생각하며 동작한다.(heap구조 맨 위 &AAAA, &BBBB를 생각하며 이해) 그 결과 값 `DDDD`를 주소로 인식해 `&DDDD`로 접근해 값을 대입하고, 그 뒤로 텅 비어있음으로 &0000에 접근해 값을 대입하려다 실패하고 `Segmentation fault (core dumped)`를 띄운다.

이제 모든 분석이 끝났다. 공격 시나리오는 두번째 create_pet_recode함수호출에서 kind위치에 PET[3](id = 2)의 주소+bss공간 주소를 넣은 뒤, edit_pet_record함수를 호출해 name위치에 bss공간주소를 넣고, kind위치에 잘 안쓰이는 puts함수 got주소를 넣어주자.

그 후 print_record함수를 호출해(case 3) id에 2을 입력하면 name에 puts_got실제주소가 출력되 leak이 가능하다.

다시 create_pet_recode함수를 호출하고 kind위치에 atoi함수의 got주소를 넣고, 모양을 맞춰주기 위해 대충 bss공간 주소를 넣어준 뒤, edit_pet_record함수를 호출해 name위치에 leak한 system_got값을 넣고, bss공간주소를 대충 넣어주면 될 것같다.

 

IDA를 보면 0x6020A0에 PET배열이 들어가는 것을 볼 수 있다. 

보면 id = 2의 주소가 0x6020b0인 것을 알 수 있다.

이런식으로 payload를 작성했다....

이번엔 uaf관련 문제인것 같다. 

코드가 C++로 작성되었다.

우선 중요한 부분은  Human class의 give_shell()과 main문 인것 같다. 해석해보면 1번으로 소개를 하고, 2번으로 원하는 값을 동적할당 할 수 있으며, 3번으로 해제가 가능한 것 같다. 일단 선언되어있는 m과 w를 해제해주고, 2번으로 give_shell()의 주소를 잘 올리면, 1번으로 해당 주소를 실행시켜 쉘을 얻을 수 있을 것 같다.

 

우선 쉘코드를 보기 위해 switch 1번 부분 어셈을 봐준다. 참고로 글이 깨져서 나옴으로 'set print asm-demangle on' 명령어를 써주자.

코드를 보면 0x0000000000400fcd주소에 break를 걸어주면 될꺼같다.

`ni`로 진행을 해주다 rax에 0x8을 더하기 직전에 멈춘다.

현재 rax에 쓰여있는 주소를 봐주고 해당 주소가 가르키는 값을 보면 0x0040117a를 가르킨다. 그럼 0x401578은 0x004012d2를 가르키는 것을 알 수 있다. 각각의 주소를 들여다 보면 0x0040117a에 우리가 원하는 give_shell()의 주소가 써있는 것을 알 수 있다. 

그렇다면 우리는 0x12b4c50에 있는 0x00401570을 0x00401568로 덮어야 한다.

이런식으로 하면 쉘이 따인다.

'war game > pwnable.kr' 카테고리의 다른 글

[Toddler's Bottle]-flag  (0) 2019.07.05
[Toddler's Bottle]-bof  (0) 2019.07.05
[Toddler's Bottle]-collision  (0) 2019.07.04
[Toddler's Bottle]-fd  (0) 2019.07.04

+ Recent posts