-
dreamhack stage 3 - Tool:gdb보안/SYSTEM HACKING 2024. 3. 15. 13:02
STAGE 3
Tool:gdb
1. 디버거
- 버그(bug): 실수로 발생한 프로그램의 결함
- 디버거(Debugger)
: 버그를 없애기 위해 사용하는 도구
만든 배경: 버그를 잡는 어려움을 해결하기 위해 개발된 도구
작동 과정: 프로그램을 어셈블리 코드 단위로 실행 + 실행 결과를 사용자에게 보여줌 -> 개발자는 디버거를 사용해 코드의 문제점을 찾을 수 있다.
그런데, 디버거로 인해 누구나 버그 탐색의 효율을 높일 수 있게 되었지만 버그 발견이 쉬워지면서 해커들은
취약점을 발견하기 쉬워졌다.
2. gdb & pwndbg
2-1. 정의와 설치, 예제
- gdb (GNU debugger)
: 리눅스의 대표적인 디버거
- 다양한 플러그인들이 개발되었고 Ubuntu 18.04에는 기본적으로 설치되어 있다.
- pwndbg - 바이너리 분석 용도로 사용
- gdb 설치
GitHub - pwndbg/pwndbg: Exploit Development and Reverse Engineering with GDB Made Easy 를 참고하여 설치한다.
실행 결과
gdb를 입력했을 때 다음과 같이 출력되면 된다.
- gdb 실습 예제
Ubuntu C언어로 프로그래밍하기 ( 컴파일 ) (tistory.com)
[Linux] 리눅스환경(Ubuntu)에서 C언어 코딩하기 (tistory.com) 참고
코드 작성:
실행 결과
2-2. 리눅스의 ELF
리눅스는 실행파일의 형식으로 ELF ( Executable and Linkable Format) 를 규정하고 있다.
ELF 는 헤더와 여러 섹션으로 구성되어 있다.
- 헤더 -- 실행에 필요한 여러 정보
- 섹션 -- 컴파일된 기계어 코드, 프로그램 문자열 등의 여러 데이터
ELF의 헤더 중 진입점(Entry Point, EP) 가 있다.
운영체제는 ELF를 실행할 때 진입점의 값부터 프로그램을 실행한다.
readlf 로 확인해보면 진입점은 Entry point address 에 적힌 0x400400 이다.
- START 명령어
: 진입점부터 프로그램을 분석할 수 있게 해주는 gdb의 명령어
- DISASM 영역의 화살표가 가리키는 주소는 현재 rip의 값, start 명령어를 실행하고 보면 0x400400 이다.
- Context ( 맥락)
: pwndbg에서 주요 메모리들의 상태를 프로그램이 실행되고 있는 맥락이라고 한다.
가독성 있게 표현할 수 있는 인터페이스도 갖추고 있다.
- 배경: 디버거를 이용해 프로그램의 실행 과정을 자세히 관찰하려면 컴퓨터의 각종 메모리를 한눈에 파악하는
이 좋다.
- context의 영역
1. registers: 레지스터의 상태를 보여준다.
2. dissam: rip부터 여러 줄에 걸쳐 디스어셈블된 결과를 보여준다.
3. stack: rsp부터 여러 줄에 걸쳐 스택의 값을 보여준다.
4. backtrace: 현재 rip에 도달할 때까지 어떤 함수가 중첩되어 호출됐는지 보여준다.
--> 어셈블리를 실행할 때마다 갱신되어 실행한 어셈블리 명령어가 어떤 영향을 줬는지 파악하기 쉽다.
context
- Break & Continue
- break: 특정 주소에 중단점(breakpoint)를 설정하는 기능)
- continue: 중단된 프로그램을 계속 실행시키는 기능
- 장점: break로 원하는 함수에 중단점 설정하고 프로그램 계속 실행하면 해당 함수까지 멈추지 않고 실행된 후
중단된다. 따라서 중단된 지점부터 다시 세밀하게 분석할 수 있다.
- 배경: 코드를 한 줄씩 실행시키며 main 함수에 도달해야 하면 디버깅은 효율적이지 못하다.
중단된 start 함수부터 main 함수까지 실행
- run
: 단순히 실행만 시킨다.
중단점을 설정해놓지 않았다면 프로그램이 끝까지 멈추지 않고 실행된다.
- gdb의 명령어 축약 ( 자주 사용되는 명령어들의 단축키)
- b: break
- c: continue
- r: run
- si: step into
- ni: next instruction
- i: info
- k: kill
- pd: pdisas
- disassemble
: gdb가 기본적으로 제공하는 디스어셈블 명령어
- 배경 :gdb는 프로그램을 어셈블리 코드 단위로 실행하고 프로그램은 기계어로 이루어져있다.
--> gdb는 기계어를 디스어셈블(disassemble)하는 기능을 기본적으로 가지고 pwndbg에는 디스어셈블된
결과를 가독성 좋게 출력해주는 기능이 있다.
함수 이름을 인자로 전달하면 함수가 반환될 때까지 전부 디스어셈블하여 보여준다.
+ u, nearpc, pdisassemble: pwndbg에서 제공하는 디스어셈블 명령어
가독성 좋게 출력
- navigate
관찰하고자 하는 함수의 중단점에 도달-> 그 지점부터 명령어를 한 줄씩 자세히 분석
- ni 와 si 사용
공통점: 모두 어셈블리 명령어를 한 줄 실행
차이점: 서브루틴을 호출하는 경우 ni는 서브루틴의 내부로 들어가지 않는다.
si는 서브루틴의 내부로 들어간다.
확인해보자) main 함수에서 printf 함수 호출 지점까지 실행하자.
ni를 입력하면 printf 다음에 rip 가 이동했다는 것을 알 수 있다.
+ printf가 출력할 문자열은 stdout의 버퍼에서 대기한 후 출력한다.
+ 버퍼: 데이터가 목적지로 이동하기 전에 잠시 저장되는 저장소, 특정 조건 만족 시에만 데이터를 목적지로 이동
printf 실행했을 때 문자열이 출력되지 않는 이유는 아래의 조건을 하나도 만족하지 않을 때이다.
1. 프로그램이 종료될 때
2. 버퍼가 가득 찼을 때
3. fflush와 같은 함수로 버퍼를 비우도록 명시했을 때
4. 개행문자가 버퍼에 들어왔을 때
- Step into
- si: 프로그램 분석 중 함수의 내부를 알고 싶을 때
- ni: 프로그램 분석 중 함수의 내부를 알지 않아도 될 때
- finish
: 함수의 끝까지 한 번에 실행할 수 있다.
- 언제 사용?
step into로 함수 내부에서 다 분석했는데 함수 규모가 커서 ni를 사용해 원래 실행의 흐름으로 돌아가기
어려울 때 함수의 끝까지 한 번에 실행하기 위해서 사용한다.
- examine
프로그램을 분석하다 가상 메모리에 존재하는 임의 주소의 값을 관찰해야할 때가 있다.
gdb에서는 명령어 'x' 제공 -> 특정 주소에서 원하는 길이만큼 데이터를 원하는 형식으로 인코딩하여
볼 수 있다.
예시)
1. rsp 부터 80바이트를 8바이트씩 hex 형식으로 출력
2. rip부터 5wnfdml djtpaqmffl audfuddj cnffur
3. 특정 주소의 문자열 출력
- telescope
: pwndbg가 제공하는 강력한 메모리 덤프 기능
특정 주소의 메모리 값을 보여줌 + 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여
값을 보여줌
- vmmap
: 가상 메모리의 레이아웃 보여줌
파일이 매핑된 영역일 경우 해당 파일의 경로까지 보여준다.
+ 파일 매핑: 어떤 파일을 메모리에 적재하는 것
+ 리눅스에서 ELF 실행 시 ELF코드와 여러 데이터를 가상 메모리에 매핑하고 ELF에 링크된 공유 오브젝트를
추가로 메모리에 매핑한다.
+ 공유 오브젝트에 이미 구현된 함수를 호출할 때 매핑된 메모리에 존재하는 함수를 대신 호출한다.
2-3. gdb와 python의 사용
- gdb와 python
- gdb를 통해 디버깅할 때 직접 입력할 수 없는 경우
: 파이썬으로 입력값 생성 후 사용
- gdb와 python argv
run 명령어의 인자로 $()와 파이썬 코드를 입력하면 값을 전달할 수 있다.
printf 를 통해 출력한 값을 run 명령어의 인자로 전달하는 명령어
- gdb와 python input
$()과 파이썬 코드를 입력하면 값을 입력할 수 있다. 입력값으로 전달하기 위해서 <<< 을 사용한다.
argv[1]에 임의의 값을 전달하고 값을 입력하는 명령어
3. 결론
- start: 진입점에 중단점을 설정하고, 실행
- break(b): 중단점 설정
- continue(c): 계속 실행
- disassemble: 디스어셈블 결과 출력
- u, nearpc, pd: 디스어셈블 결과 가독성 좋게 출력
- x: 메모리 조회
- run(r): 프로그램 처음부터 실행
- context: 레지스터, 코드, 스택, 백트레이스의 상태 출력
- nexti(ni): 명령어 실행, 함수 내부로는 들어가지 않음
- stepi(si): 명령어 실행, 함수 내부로 들어감
- telescope(tele): 메모리 조회, 메모리값이 포인터일 경우 재귀적으로 따라가며
모든 메모리값 출력
- vmmap: 메모리 레이아웃 출력
'보안 > SYSTEM HACKING' 카테고리의 다른 글
dreamhack stage 4 - Exploit Tech:Shellcode (0) 2024.03.15 dreamhack stage 3 - Tool:pwntools (0) 2024.03.15 dreamhack stage 2 - x86 Assembly (0) 2024.03.15 dreamhack stage 2 - Computer Architecture (0) 2024.03.15 dreamhack stage 2 - Linux Memory Layout (0) 2024.03.15