
# CMPT733 사이버보안 실습 II 프로젝트: CVE-2021-3156에서 영감을 받은 힙 익스플로잇용 GDB 플러그인

CMPT733 사이버보안 실습 II 프로젝트
.
├── README.md
├── heaplens.png
├── heaplens.py
├── logs
│ ├── sudoedit-#.txt
│ └── ...
└── tests
├── Makefile
├── env-in-heap
└── ...
README.md: 바로 이 파일입니다!heaplens.py: 메인 스크립트logs/: 개발 및 테스트 중에 수집한 샘플 로그가 포함되어 있습니다tests/: 테스트용 바이너리(및 해당 소스 코드)가 포함되어 있습니다다음은 익스플로잇을 테스트하는 데 사용한 항목(및 버전) 목록입니다. VM에 이미 설치되어 있어야 합니다. 누락된 항목이 있으면 아래 지침을 따르세요.
python 3.8.10glibc 2.34gdb 9.2gef 2022.01
gef가 활성화되지 않은 경우 /root/.gdbinit을 확인하세요~/.gdbinit에 있는 내용을 복사하세요sudo 의존성 (sudo에서 heaplens 실행용)디버깅이 활성화된 sudo 바이너리가 필요합니다. 디버그 심볼이 포함된 사전 빌드 바이너리가 VM에 설치되어 있습니다.
cyberlab@ubuntu:~$ which sudo
/usr/local/bin/sudo
cyberlab@ubuntu:~$ sudo --version
Sudo version 1.8.31
Sudoers policy plugin version 1.8.31
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.31
cyberlab@ubuntu:~$ sudoedit -s /
sudoedit: /: not a regular file # sudo is vulnerable
이 작업은 VM에서 이미 완료되었습니다. 구성이 잘못된 경우 아래 지침에 따라 Heaplens를 로드할 수 있습니다.
gef를 시작하고 구성을 편집합니다:
gef➤ gef config gef.extra_plugins_dir <path to>/heaplens
gef➤ gef save
gef➤ q
이렇게 하면 ~/.gef.rc 또는 /root/.gef.rc(root에서) 파일이 업데이트됩니다.
~/.gdbinit 또는 /root/.gdbinit에 다음 줄을 추가합니다:
source <path to>/heaplens/heaplens.py
권한이 있는 프로그램을 디버깅할 때는 root에서 gdb를 실행하는 것이 좋습니다:
$ sudo su
# gdb
모든 명령에 도움말 메시지가 제공됩니다. GDB에서 <command> -h로 접근할 수 있습니다.
heaplensmalloc, realloc, calloc, free를 포함한 메모리 할당 및 해제 함수에서 힙 정보를 수집합니다.
핵심 아이디어는 이러한 함수를 후킹하여 메모리 할당의 호출 스택과 반환 주소를 확인하고 업데이트하는 과정을 자동화하는 것입니다. 추적을 검사하면 특정 C 파일의 foo()에 의해 어떤 청크가 할당되었는지 확인할 수 있으며, 인접 청크를 확인하는 등 추가 조사를 통해 힙 익스플로잇에 적합한 대상을 찾을 수 있습니다.
또한 사용자가 중간 힙 레이아웃에 관심이 있는 경우 그 사이에 사용자 정의 중단점을 추가하는 것도 지원합니다.
이 명령 자체는 출력이 많지 않으며 결과를 출력하려면 heaplens-dump를 사용해야 합니다.
heaplens -h
usage: [-h] [-b BREAKPOINT] [-v]
Collect heap info from memory (de)allocation functions.
optional arguments:
-h, --help show this help message and exit
-b BREAKPOINT, --breakpoint BREAKPOINT
stop the executions here (execute br {breakpoint} in gdb) (default: None)
-v, --verbose increase output verbosity (default: False)
예시 출력:
gef➤ file sudoedit
gef➤ heaplens -b set_cmnd -- -s '\\' $(python3 -c 'print("A"*65535)')
----------------------------
Initializing Heaplens
----------------------------
Temporary breakpoint 1 at 0x5840: file ../../src/src/sudo.c, line 136.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
usage: sudoedit [-AknS] [-C num] [-g group] [-h host] [-p prompt] [-T timeout] [-u user] file ...
[Inferior 1 (process 82934) exited with code 01]
Setting breakpoint at set_cmnd...
Function "set_cmnd" not defined.
Breakpoint 2 (set_cmnd) pending.
Hooking free function...
Breakpoint 3 at 0x7f25cc163700: free. (2 locations)
Hooking malloc function...
Breakpoint 4 at 0x7f25cc163110: malloc. (2 locations)
Hooking realloc function...
Breakpoint 5 at 0x7f25cc163eb0: realloc. (2 locations)
Hooking calloc function...
Breakpoint 6 at 0x7f25cc164b40: calloc. (2 locations)
Running -s '\' $(python3 -c 'print("A"*65535)')...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, set_cmnd () at ../../../src/plugins/sudoers/sudoers.c:804
804 ../../../src/plugins/sudoers/sudoers.c: No such file or directory.
Removing breakpoints from mem_bkps...
heaplens-dumpHeaplens 로그를 덤프합니다. 결과를 파일로 쓰기, JSON 형식으로 출력, 주소별 청크 정렬 옵션을 제공합니다. 덤프에서 각 청크는 주소, 크기, 역추적 및 관련 메모리 할당 함수가 더 읽기 쉬운 방식으로 기록됩니다.
heaplens-dump -h
usage: [-h] [-o OUTPUT] [--json] [-s]
Dump Heaplens logs. Writes to stdout by default.
optional arguments:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
write to file at path {output} (default: None)
--json dump in json (default: False)
-s, --sort sort the chunks by their addresses (default: False)
예시 출력:
gef➤ heaplens-dump
----------------------------
Dumping...
----------------------------
...
[malloc] Chunk 3 @ 0x55f3908ed2a0 | size 0xc
Trace:
#0 __GI___strdup (s=0x7fff6fb3b8dc "en_US.UTF-8") at strdup.c:44
#1 0x00007f285df363c5 in _nl_load_locale_from_archive (category=category@entry=0xc, namep=namep@entry=0x7fff6fb29f50) at loadarchive.c:464
#2 0x00007f285df351fe in _nl_find_locale (locale_path=0x0, locale_path_len=0x0, category=category@entry=0xc, name=name@entry=0x7fff6fb29f50) at findlocale.c:152
#3 0x00007f285df34925 in __GI_setlocale (locale=<optimized out>, category=<optimized out>) at setlocale.c:337
#4 __GI_setlocale (category=<optimized out>, locale=<optimized out>) at setlocale.c:217
#5 0x000055f3901d5965 in main (argc=0x4, argv=0x7fff6fb2a298, envp=0x7fff6fb2a2c0) at ../../src/src/sudo.c:1430
...
Dump complete.
heaplens-chunksgef의 heap chunks를 약간 수정한 버전을 출력합니다.
이 명령은 GEF의 heap chunks(청크의 주소, 플래그, 크기 및 메타데이터를 표시)를 확장하여 heap bins(glibc bins에서 이전에 할당되고 해제된 청크를 나열)의 해제된 청크 정보를 통합합니다. GEF는 우리가 언급한 두 가지와 같은 힙 검사에 도움이 되는 기능을 제공하지만, 이 둘을 결합하는 것은 번거롭습니다. 높은 수준에서 이 명령은 후자에서 해제된 청크의 주소를 수집하고 전자의 결과에 레이블을 지정합니다.
heaplens-chunks -h
usage: [-h] [--nocolor]
A modified `heap chunks` with info about free chunks.
optional arguments:
-h, --help show this help message and exit
--nocolor disable ANSI color codes
예시 출력:
gef➤ heaplens-chunks
Showing current heap info with freed chunks:
...
Chunk(addr=0x55dd7f91ddb0, size=0xed0, flags=PREV_INUSE) ← free chunk
[0x000055dd7f91ddb0 e0 fb ba e1 f8 7f 00 00 e0 fb ba e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f91ec80, size=0x50, flags=! PREV_INUSE)
[0x000055dd7f91ec80 2f 75 73 72 2f 6c 6f 63 61 6c 2f 73 62 69 6e 3a /usr/local/sbin]
Chunk(addr=0x55dd7f91ecd0, size=0x4010, flags=PREV_INUSE) ← free chunk
[0x000055dd7f91ecd0 f0 02 bb e1 f8 7f 00 00 f0 02 bb e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f922ce0, size=0x50, flags=! PREV_INUSE)
[0x000055dd7f922ce0 90 02 91 7f dd 55 00 00 00 00 00 00 00 00 00 00 .....U.........]
Chunk(addr=0x55dd7f922d30, size=0x2da0, flags=PREV_INUSE) ← free chunk
[0x000055dd7f922d30 d0 02 bb e1 f8 7f 00 00 d0 02 bb e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f925ad0, size=0x110, flags=! PREV_INUSE) ← free chunk
[0x000055dd7f925ad0 00 00 00 00 00 00 00 00 10 f0 90 7f dd 55 00 00 .............U.]
Chunk(addr=0x55dd7f925be0, size=0x30, flags=PREV_INUSE)
[0x000055dd7f925be0 00 00 00 00 00 00 00 00 d2 78 b7 7e dd 55 00 00 .........x.~.U.]
Chunk(addr=0x55dd7f925c10, size=0x20, flags=PREV_INUSE)
[0x000055dd7f925c10 65 6e 5f 55 53 2e 55 54 46 2d 38 00 00 00 00 00 en_US.UTF-8....]
Chunk(addr=0x55dd7f925c30, size=0xa3e0, flags=PREV_INUSE) ← top chunk
heaplens-clearheaplens가 수집하고 사용하는 모든 내부 로그/데이터를 지웁니다.
heaplens-clear -h
usage: [-h] [-v]
Clear Heaplens logs.
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
heaplens-list-env힙에 저장되고 해제되는 환경 변수를 나열합니다. 이러한 변수는 힙 레이아웃에 영향을 줄 수 있으므로 힙 그루밍을 수행하려는 경우 특히 유용합니다.
heaplens-list-env -h
usage: [-h] [-v] [--prefix PREFIX] [--suffix SUFFIX] [-b BREAKPOINT] [-s SKIP]
List environment variables that might affect the heap layout.
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
--prefix PREFIX environment variable value prefix
--suffix SUFFIX environment variable value suffix
-b BREAKPOINT, --breakpoint BREAKPOINT
stop the executions here (execute br {breakpoint} in gdb)
-s SKIP, --skip SKIP skip this environment variable
예시 출력:
gef➤ file sudoedit
Reading symbols from sudoedit...
gef➤ heaplens-list-env -s LC_ALL -b set_cmnd --prefix C.UTF-8@ -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...
1st execution. Found following environment variable:
['LOCPATH', 'LC_ALL', 'LC_IDENTIFICATION', 'LANG', 'LC_MEASUREMENT', 'LC_TELEPHONE', 'LC_ADDRESS', 'LC_NAME', 'LC_PAPER', 'LC_MESSAGES', 'LC_MONETARY', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC', 'LC_CTYPE', 'TZ', 'SHELL', 'LANGUAGE']
...
2nd execution. Possible environment variables for heap grooming:
['LC_IDENTIFICATION', 'LC_COLLATE', 'TZ', 'LC_TIME', 'LANGUAGE', 'LC_NAME', 'LOCPATH', 'LC_MESSAGES', 'LC_NUMERIC', 'LC_ADDRESS', 'LC_TELEPHONE', 'LC_MONETARY', 'LC_MEASUREMENT', 'LC_CTYPE', 'LC_PAPER']
테스트 케이스 스크립트를 빌드하려면 (VM에 빌드됨)
$ cd tests
$ make all
tests/heap-dump 힙 레이아웃 덤프gef➤ file tests/heap-dump
gef➤ heaplens -b breakme
gef➤ heaplens-dump
sudoedit 힙 레이아웃을 output.txt로 덤프gef➤ file sudoedit
gef➤ heaplens -b set_cmnd -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
gef➤ heaplens-dump -o output.txt
tests/env-in-heap에서 힙 그루밍용 환경 변수 나열gef➤ file tests/env-in-heap
gef➤ heaplens-list-env
...
----------------------------
2nd execution. Possible environment variables for heap grooming:
['ENV_IN_HEAP']
----------------------------
sudoedit에서 힙 그루밍용 환경 변수 나열gef➤ file sudoedit
gef➤ heaplens-list-env -s LC_ALL -b set_cmnd --prefix C.UTF-8@ -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...
----------------------------
1st execution. Found following environment variable:
['LOCPATH', 'LC_ALL', 'LC_IDENTIFICATION', 'LANG', 'LC_MEASUREMENT', 'LC_TELEPHONE', 'LC_ADDRESS', 'LC_NAME', 'LC_PAPER', 'LC_MESSAGES', 'LC_MONETARY', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC', 'LC_CTYPE', 'TZ', 'SHELL', 'LANGUAGE']
----------------------------
...
----------------------------
2nd execution. Possible environment variables for heap grooming:
['LC_CTYPE', 'LC_PAPER', 'LC_MONETARY', 'TZ', 'LC_ADDRESS', 'LC_MEASUREMENT', 'LC_IDENTIFICATION', 'LC_COLLATE', 'LC_NUMERIC', 'LC_MESSAGES', 'LC_TIME', 'LANGUAGE', 'LC_NAME', 'LOCPATH', 'LC_TELEPHONE']
----------------------------
자세한 내용은 Issues 페이지를 참조하세요.