Exploit Tech: Use After Free 강의 설명이 너무 빈약한 것 같습니다..ㅠㅠ

https://dreamhack.io/learn/119#7

해당 강의에서 custom 함수를 통해 라이브러리 주소를 유출하고 Robot, Human에서 uaf를 발생시켜 one_gadget을 실행한다는 익스플로잇 설계는 이해했습니다만 custom 함수를 통한 라이브러리 유출에 대한 내용이 너무 빈약한 것 같습니다..

해당 강의에서는 단순히 "libc가 매핑된 주소의 오프셋은 gdb로 쉽게 구할 수 있습니다." 라고만 하고 넘어가네요.. ㅠㅠ

gdb를 통해 libc가 매핑된 주소를 어떻게 구할 수 있는지, fd와 bk에 정확히 어떤 정보가 어떤 형태로 들어가게 되는지, 해당
익스플로잇 코드에서 커스텀 함수를 통한 heap 할당을 왜 4번이나 하는지, -1을 입력하는 것은 그냥 영역을 해제하지 않겠다는
의미가 맞는지 모르겠습니다..ㅠㅠ

작성자 정보
답변 5
avatar
Sechack
CTF First Place

small bin이상의 크기의 힙 청크를 해제하게 되면 unsorted bin에 들어가게 되고 unsorted bin의 fd, bk에는 보통 main_arena + 88과 같은 main_arena 영역의 주소가 들어갑니다. 그리고 이 main_arena영역은 libc에 있으므로 해당 주소를 출력할 수만 있다면 libc leak을 진행할 수 있는겁니다.(왜 main_arena영역의 주소가 들어가는지는 malloc.c분석을 제대로 안해봐서 저도 잘 모르겠네요. glibc는 오픈소스니까 궁금한거 생기시면 소스코드 분석해보시는것도 좋을것 같습니다. ㅎㅎ) 하지만 보통은 unsorted bin으로 leak을 진행하다 보면 pwntools로 libc.sym["main_arena"] 이런식으로 심볼을 찾으려고 하면 해당 심볼이 존재하지 않는 경우가 많이 있습니다. 따라서 이럴경우에는 가까이에 있는 __malloc_hook의 심볼을 이용하여 먼저 릭된 주소에서 malloc hook의 offset을 빼준 후에 malloc hook과 main_arena의 offset을 이용하여 최종적으로는 libc base를 구하는 방법을 저는 많이 사용합니다.

커스텀 함수에 -1을 전달한것은 인덱스 검증 과정이 취약해서 oob취약점이 터지고 해당 취약점을 악용하고자 전달한것 같습니다. 왜 커스텀 함수를 4번이나 사용했느냐는 예제 소스코드를 잘 이해하고 익스플로잇 설계 부분을 잘 읽어보시면 충분히 이해하실 수 있을것 같습니다.

2021.09.06. 23:31
xl4sh
강의 수강: 10

윗분이 잘 설명해 주셨는데 약간의 첨언과 정정을 해드리겠습니다.
우선 unsorted bin을 memory leak에 이용하는 부분이 더 궁금하시다면 https://dreamhack.io/learn/16#45 여기를 참고하시면 될듯합니다.
링크와는 다르게 현재는 tcache를 사용하기 때문에 tcache를 다 채우지 않는다면 청크크기가 0x420이상이 되어야 free후 unsorted bin에 들어가게 된다는것만 추가로 알고보시면 됩니다.

libc가 매핑된 주소, 즉 libcbase부분은 pwndbg나 peda 등을 사용하실경우에는 바이너리를 실행하신 후 vmmap을, 바닐라 gdb를 사용중이시라면, info proc mappings 명령어를 사용하시면 다음과 같이 /proc/<pid>/maps 에서 보실수 있는 형태의 매핑된 정보들이 나옵니다.

process 2420
Mapped address spaces:

        Start Addr           End Addr       Size     Offset objfile
          0x400000           0x401000     0x1000        0x0 /mnt/f/test
          0x600000           0x601000     0x1000        0x0 /mnt/f/test
          0x601000           0x602000     0x1000     0x1000 /mnt/f/test
          0x602000           0x623000    0x21000        0x0 [heap]
    0x7fffff030000     0x7fffff065000    0x35000        0x0 /lib/x86_64-linux-gnu/libc-2.23.so
    ...
    0x7fffff3f4000     0x7fffff3f6000     0x2000   0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7fffff3f6000     0x7fffff3fa000     0x4000        0x0
    0x7fffff400000     0x7fffff403000     0x3000        0x0 /lib/x86_64-linux-gnu/ld-2.23.so
    0x7fffff403000     0x7fffff404000     0x1000     0x3000 /lib/x86_64-linux-gnu/ld-2.23.so
    ...
    0x7fffff626000     0x7fffff627000     0x1000    0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
    ...
    0x7fffff7ef000     0x7ffffffef000   0x800000        0x0 [stack]
    0x7ffffffef000     0x7fffffff0000     0x1000        0x0 [vdso]

0x7fffff030000 0x7fffff065000 0x35000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
이부분으로 부터 libcbase addr은 0x7fffff030000 이라는것을 알 수 있습니다.
그렇다면 leaked_addr == libcbase_addr + offset 이므로 offset을 구할 수 있습니다.

마지막으로 custom_func에서의 -1을 입력하는 부분은 처음 생각하신 대로 free를 하지 않겠다 라는 의미가 맞습니다.
아래 코드를 보시면

int custom_func() {
  unsigned int size;
  unsigned int idx;
  ...
    printf("Free idx: ");
    scanf("%d", &idx);
    if (idx < 10 && custom[idx]) {
      free(custom[idx]);
      custom[idx] = NULL;
    }
  }
  c_idx++;
}

unsigned int idx; 여기서 idx변수가 unsigned라는 것을 확인 할 수 있고, scanf로 -1을 입력받으면, idx = -1; 과 같은 형태가 되는데, idx는 unsigned로 선언 되었으므로, 실제로 idx변수는 0xffffffff라는 양수값을 갖게됩니다. 따라서 if 조건을 만족하지 못하게 되어 free를 하지 않게됩니다.

2021.09.07. 00:41
avatar
juno2
답변 등록: 25

유저님의 의견 반영해, 해당 코스에서 Tool: gdb를 참고할 수 있도록 하이퍼링크 추가하였습니다.

2021.09.07. 11:19
동키
대표 업적 없음

저도 -1의 의미에 대해서 고민하고 있었습니다. unsigned 로 설정되어 있는걸 지금봤네요.
그리고, libc의 base address를 구하는 부분에서 고민하고 있습니다.
unsorted bin의 bk에서 data segment의 main arena의 위치는 찾아지는것 같은데,
offset의 위치를 구하는 과정이 위에 설명해주신 것 처럼 malloc_hook 주소에서 -0x10을 하면 된다고 하는데.. 이 부분에 대해서 좀더 설명을 부탁드립니다.
문제로 제공된 libc의 main_arena를 확인해봐도 0x3ebc40으로 나오는데.. offset을 0x3ebc42로 설정한 과정을 부탁드립니다.
[+]libc version : glibc 2.27
[+]build ID : BuildID[sha1]=ce450eb01a5e5acc7ce7b8c2633b02cc1093339e
[+]main_arena_offset : 0x3ebc40

2022.04.12. 01:07
avatar
Dreamhack
대표 업적 없음

안녕하세요,
의견 주신 부분 정말 감사드리며, 8개월이나 지났지만 뒤늦게 답변을 달아보고자 합니다.

말씀하신대로 leak이 왜 발생하는지에 대한 설명이 자세한 데이터 없이 줄글로만 이루어진 부분이 있어 처음 공부할 때 이해하기 어려운 부분이 있습니다.
더군다나, 이 leak이 온전한 값이 아니라 user 가 입력하는 input이 libc leak의 가장 하위 바이트를 덮는다는 특징이 있고, 이런것들이 결합되어 상당히 이해하기 어려운 강의가 되었습니다.

우선은 libc leak에 user input이 들어가있다는 점을 추가적으로 설명하였습니다.
초심자가 이를 제대로 확인하기 위해서는 동적으로 디버깅(gdb 의 attach 기능)하는 방법을 알고 있어야 하기 때문에 설명을 보고 이해하기까지는 상당히 어려운 부분이 여전히 존재합니다.

물론 이 내용이 tool: gdb 강의에 들어있지 않은 점도 이 문제의 data leak을 이해하는데에 있어서 약간 부족한 것이 사실입니다.

또한 주어진 libc 만으로는 (강의 내용에서 코드를 제공하지 않는다면) 다른 Ubuntu 환경에서는 정확한 offset을 찾는데에도 어려움이 있을 것입니다. 따라서 이 부분은 문제 자체를 수정해야 하는 방향으로 진행하는 것이 맞다고 생각합니다. 추가적으로는 이를 정확히 이해할 수 있는 도구(gdb)의 사용법을 적절한 곳에 배치해야겠지요.

다만 저희에게도 시간이라는 장벽이 있어 이를 즉시 실행하지는 못할 것이라는 점에 미리 여러 사용자분들께 양해를 구합니다.

수정이 완료되지도 않은 채 뒤늦게 답변을 드리는 이유는
(^오^)님 께서 느끼신 의문이 당연한 것이었음을 말씀드리기 위해서입니다.
(^오^)님이 공부를 덜 했거나, 부족한 부분이 있으셔서 위에 질문을 쓰신게 아니라, 부족한 강의의 완성도로 인해 당연하게 느끼셨을 부분이라는 점을 말씀드리고 싶었습니다.

감사합니다.

2022.04.20. 20:08
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기