Profile

youngsouk

youngsouk

[TRUST-CTF 2020] Fast Restaurant 출제자 writeup

main 함수 부분입니다.
전형적인 힙문제입니다.

setup에서는 버퍼링과 환영 메시지를 띄어주게 됩니다.

그 다음에는 이 코드들이 실행되는데

1. 0x100, 0x10크기 할당

2. 0x100 free -> 0x100 크기 청크는 unsorted bin에 들어감

3. backup에 unsorted bin에 들어가 있는 청크의 fd, 즉 main_arena + 88의 주소값을 저장

4. 0x10 청크를 free -> fastbin에 이 0x10 크기 청크가 들어감.

5. 0x200 청크를 할당 & 해제 -> free 함수 내부에서 1번에서 할당한 2개의 청크가 모두 병합됨.

즉 저 코드는 backup에 main_arena + 88의 주소를 저장하기 위한 과정입니다.


0번째 메뉴 Clean입니다.

backup = main_arena + 88의 주소 = &unsorted bin - 0x10

_QWORD = 8바이트

따라서

backup + 2 = &unsorted bin - 0x10 + 0x10 = unsorted bin의 fd

backup + 3 = &unsorted bin - 0x10 + 0x18 = unsorted bin의 bk

이 됩니다. 즉 저 코드는 unsorted bin을 초기화 해주는 함수입니다.


다음은 1번 메뉴인 Order 메뉴입니다.

처음에 EatSize라는 전역변수를 16으로 설정하게 됩니다.

이 함수에서 1을 입력하게 되면

1. Freed라는 배열에서 free 여부를 확인

2. 0x38만큼 할당 & 입력 받음 -> 이 포인터는 FastFood 전역 변수에 저장

2를 입력하게 되면

1. Freed라는 배열에서 free 여부 && SmallFood에 값 여부 확인

2. 0x100만큼 할당 & 입력 받음

즉 fastbin 크기의 청크는 원하는 횟수만큼 할당이 가능하지만

smallbin 크기의 청크는 최대 3개까지만 동시에 할당할 수 있습니다.


다음은 2번 메뉴인 Cancel입니다.

Order과 마찬가지로 1번 2번으로 나뉘게 되는데

1번을 입력하면

1. FastFood를 free 합니다.

여기서 취약점이 발생하는데 바로 제한 없이 free 시킬 수 있다는 것입니다. 즉 fastbin 크기의 청크를 double free 가능하다는 것입니다.

2번을 입력하면

1. 입력받은 index값에 따라 SmallFood를 free.

2. SmallFood 포인터 배열의 값 초기화

3. Freed배열의 값을 1로 바꿈

이 부분에서는 딱히 취약점을 찾을 수 없습니다.


다음은 eating 부분입니다.

이 함수에서도 1번과 2번이 나뉘게 되는데

1번을 입력하면

1. check 함수에 FastFood의 값을 넘김

2. 반환값이 1이라면 EatSize만큼 출력

2번을 입력하면

1. index를 입력받음

2. index에 따라 check 함수에 SmallFood의 값을 넘김.

3. 반환값이 1이라면 EatSize만큼 출력

이렇게 됩니다.

여기서 취약점이 발생하는데 그 이유는 출력 크기를 전역변수를 통해 관리하기 때문입니다.

즉 이 값만 변경할 수 있다면 출력되는 크기를 마음대로 지정할 수 있습니다.

그런데 1번과 2번 모두 check라는 함수에 출력할 포인터를 넘겨주는데

check라는 함수에서는

1. 16바이트만큼 0x7f가 있는지 확인합니다.

2. 인자가 security의 주소 이전인지 확인합니다.

즉 stdout구조체를 통해 libc 릭을 할 수는 없다는 것을 알 수 있습니다.

또한 0x10바이트만 0x7f를 검사하므로 출력할 주소 + 0x10 뒤에 libc 주소가 있어야 합니다.


마지막 4번메뉴인 Change 입니다.

이 함수도 1번이냐 2번으로 나뉘는데

1번을 입력하면

1. check함수를 통해 수정할 주소를 확인 && Freed[0]이 0인지 확인

2. 할당한 크기(0x38)만큼 입력받음

그런데 || (OR) 연산자로 연결되어 있지만,

check함수에서 조건에 통과하지 못하면 exit함수를 호출하기 때문에 유의해야합니다.

2번을 입력하면

1. check함수를 통해 수정할 주소를 확인 && Freed 배열의 값이 0인지 확인

2. 할당한 크기(0x100)만큼 입력받음


이렇게 이 바이너리의 모든 함수를 분석했는데 발견한 취약점은

1. fastbin double free

2. 전역변수로 출력 크기 관리

이렇게 됩니다.

이것을 통한 익스 방법은

1. smallbin 크기의 청크를 통해 malloc_consolidate 호출 -> fastbin 청크가 unsorted bin으로 이동

2. fastbin 크기의 청크 free -> fastbin으로 들어감

3. fastbin 청크를 다시 할당 -> FastFood를 unsafe unlink 할 준비

4. unsafe unlink 실시 -> FastFood = &FastFood - 0x18.

5. EatSize 변수값(출력 갯수) 수정 && FastFood = &FastFood + 0x10

6. eating(출력) 이용 -> heap base leak

7. FastFood + 0x10(&SmallFood)의 값을 수정(change 메뉴) &Fake chunk 3 개 제작&free

8. 7번에서 free한 청크 주소 - 0x10부터 출력 -> libc leak

9. __free_hook을 system으로 덮음 && free("/bin/sh"); 호출

 

1번 과정에 대해서는

2020/02/25 - [힙(heap)] - malloc_consolidation_without_large_bin

이 글에 나와있습니다.

 

 

그래서 최종 코드는 이렇게 된다.

'CTF write-up' 카테고리의 다른 글

[hacktmctf] trip_to_trick  (0) 2020.02.07
[Hitcon 2016] Secret Holder  (0) 2020.01.25
[wargame.0x0.site] babyheap 라이트업  (0) 2019.10.12
Tokyo Western CTF 2017 - Parrot  (0) 2019.10.02
[hackingcamp2019]bonus  (0) 2019.08.25