이번 가을 CTF용으로 만든 문제다.
개요
일단은 기본적으로 보호기법은 PIE 빼고 다 걸어놨다. PIE는 디버깅 하는 사람들을 위한 배려이기도 하고, 가젯을 주기 위함이다. 사실 Relro는 Partial만 주려고 했는데, 이론상 언인텐디드가 나올 수도 있을 것 같아서 걸었다.
맨날 풀때기같은 초록색만 덕지덕지 칠해진 것을 보다가 빨간색을 보니 기분이 좋다.
seccomp whitelist 이다. mprotect이용해 orw 하는것을 유도.
친절하게 바이너리에 힌트도 있다. calloc 으로 rop하는 것을 저 lazyhouse 문제에서 배웠기 때문이다.
본 문제는 기본적으로는 calloc 의 취약점을 이용하여 푸는 문제이다. Calloc 의 내부 과정을 보면
이런 과정이 있는데 [1]에서는 rbp에 rdi를 옮기고 [2]에서는 rbp*rsi 한 값을 rbp에 저장한다.
이를 이용해서 malloc_hook에 leave_ret을 넣어주면 ROP가 가능한 것이다.
그런데 본 문제에서는 calloc의 size를 변조할 수 있는 방법이 정상적인 방법으로는 없다.
그러나 쓰지 않는 함수 중 하나가 이 기능을 제공해 준다. 그러면 이 함수를 이용하기 위해서는 어떻게 해야 할까?
malloc_hook에 덮게 되면 leave_ret가젯을 사용할 수 없으니, free_hook에 덮어야 한다. 그런데 또 재밌는 기능이 있다.
malloc.h의 __free_hook을 이용하면 bss영역으로 __free_hook이 이동하고 이를 이용해 free_hook을 사용자가 변조했는지 알 수 있는데, free를 하기 전에 free_hook이 덮여있으면 exit 해버린다. 그러면 어떻게 해야 할까?
정답은 exit 함수다. main에서 exit하기 전에도 힌트를 제공했었는데 exit함수의 내부 루틴에서는 free를 하는 부분이 존재한다.
initial+0 부분을 0이아닌 아무 값이나 , initial+8부분을 0으로 덮어주면 free를 하는 루틴이 있다.
자세한 것은 아래 블로그 참조. 설명을 잘 해놓았다.
그래서 전체적인 시나리오는 malloc_hook -> leave ret , free_hook -> 0x400d80(calloc을 해주는 부분), initial 변조 뒤 exit를 호출해서 free 호출 후 rop를 하는 것이다.
자 그래서 이걸 어떻게 덮을까를 고민해보면..
malloc_hook-35 에는 0x7f짜리 size가 존재한다. -> fastbin attack
free_hook 은 ?
뭐 여기 적을 수 있는 정상적인 방법은 없다. 그리고 heap이 아닌 영역에 fastbin 이 아닌 것으로 쓰기는 힘들다.
일단은 한칸 땡기면 0x200이 있다.
initial도 마찬가지, 0x100이 있다.
그래서 이걸 왜 보여줬냐? global_max_fast를 변조해서 이 청크들 다 fake로 넣어줄 것이다. bins에 .
global_max_fast변조는 unsorted bin attack으로 할 것이고, unsorted bin attack은 double free와 unsafe unlink를 이용할 것이다. global_max_fast 변조하는 문제를 한번 만들어 보고 싶었다 ㅎㅎ .
이 문제는 io_buf_end조작을 통하여 setcontext 가젯을 이용하는 것을 막기위해 모든 입력은 read로 구성되어있다.
취약점
일단 구조체 구조이다. 깔끔하게 그림으로 정리해 왔다.
일단 첫번째 name을 꽉채우면 뒤의 힙주소까지 같이 출력 된다. [1]
눈여겨 볼점은 Is_removed라는 놈이있는데, 청크가 삭제되면 저 removed flag가 1이 되고, removed 된 청크는 view를 통해 보거나 edit을 통해 수정할 수 없다.
그러나 delete를 할 때에는 이 removed를 검사하지 않아서 double free가 막된다! [2]
그리고 또 다른 취약점으로는 make burger 부분이 있다.
여기서는 마음대로 malloc을 통해 원하는 사이즈를 할당 받을 수 있다, 일단 이것도 큰 문제긴 한데, 저기 빵사이에 재료를 끼우는 부분에서 oob가 난다. index에 음수를 넣어주면 할당받은 부분 뒷 부분에 값을 넣어 줄 수 있다. [3]
와아~ 이거 쓰면 bad system call 난다. seccomp 걸어놔서 ORW로 풀어야 한다.
일단 먼저 main_arena leak을 하는 방법이다.
unsafe unlink를 위해서 청크를 다음과 같이 배치가 되어야 한다. make_burger가 원하는 사이즈의 청크를 malloc해주는 것을 이용하면 쉽게 이 상태를 만들 수 있다.
이렇게 consolidate를 통한 double free를 해주면 prev_inuse플래그가 fastbin 으로 할당 받을 때에는 바뀌지 않아서 unsafe unlink를 터트려 줄 수 있다.
보라색으로 된놈이 타겟 청크다. unsafe unlink가 되면 저녀석이 0x16b8938로 바뀐다.
그 후 청크가 합병이 되서 0xf1짜리 free 청크가 unsorted bin 에 들어갔고 description addr은 0x16b8938이 되었다. 이를 이용해 description addr을 0x16b8970 으로 바꿔서 unsorted bin을 가르키게 한후 leak, 그리고 bk를 global_max_fast-0x10으로 바꾸어 global_max_fast를 main_arena+88으로 만들어버린다.
그리고 그 후로 smallbin이 오염 됬기 때문에 unsafe unlink를 쓰기는 힘들어 보인다. 이렇게 청크가 배치된 이유는 unsafe unlink를 통해 이상한 위치에서 fake chunk가 free되었는데, 기존에 우리가 미리 free한 청크와 범위가 겹치기 때문이다. 잘 하면 될지도?
이제 global maxt fast값이 변조되었으니 fast bin attack을 하자, 시작에 앞서 앞에서 청크의 corrupt 문제도 이
있곻 하니 미리 앞에서 각 사이즈의 청크들을 만들어 주었다.
이를 이용해 앞에서 표기한 malloc_hook, free_hook, initial을 다 덮어준다.
먼저 initial 값이다. 가장 독립적이기 때문에 먼저 하겠다.
initial은 fastbin에 넣어준뒤 make burger에서 음수 인덱스에 값을 집어넣을 수 있다는 취약점을 이용해서 initial+8은 0으로 initial은 값을 넣어주었다.
free hook은 기존의 위치가 아닌 bss 영역에 넣어줘야 한다. 이상태에서 exit를 해주면 free hook -> calloc ->leave_ret 순으로 실행 된다. 그리고 이 청크들을 구성할때 미리 ROP 코드를 넣어줘야 한다.
이렇게 말이다. 그리고 마지막으로는 RBP값을 지정해주는데, rop 코드가 적힌 값 -8 을 넣어줘야 한다. leave 하면서 rsp가 이동하기 때문에.. (Input this 라고 적힌 값은 jump할 힙주소를 적어준 것이다! )
*충격적인 unintended가 있었다. 아무래도 땜빵식 코딩을 하다 보니 오버플로 체크를 못한듯..*
'전공쪽 > 동아리 관련' 카테고리의 다른 글
앞으로 스스로 공부할 것 (1) | 2020.10.24 |
---|---|
동아리 가을 CTF write up (0) | 2020.10.11 |
FSB를 위한 함수 (0) | 2020.08.31 |
StackPivot 문제 (1) | 2020.07.31 |
[동아리 CTF] 문제 CheckSum (0) | 2020.07.31 |