본문 바로가기
CTF/Dreamhack

[Dreamhack] System Hacking STAGE 3 - gdb, pwntools

by 8희 2022. 10. 11.

Tool: gdb

디버거

- 디버거는 문자 그대로 버그를 없애기 위해 사용하는 도구

- 디버거는 프로그램을 어셈블리 코드 단위로 실행하면서, 실행결과를 사용자에게 보여준다. 

- gdb는 리눅스의 대표적인 디버거 중 하나!

 

gdb

- gdb(GNU debugger)는 리눅스의 대표적인 디버거

- 오픈 소스로 개발되어 무료로 설치할 수 있으며, 역사가 오래된만큼 다양한 플러그인들이 개발되어 있다.

- Ubuntu 18.04에는 기본적으로 설치되어 있다.

 

* pwndbg 

- gdb 플러그인 중에서 바이너리 분석 용도로 사용되는 것 중 하나

 

https://github.com/pwndbg/pwndbg

-> 위 설치 가이드를 보고 설치

 

git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

- pwndbg 설치 명령어

 

설치 성공 확인

 

gdb 실습 예제

- debugee.c 파일 생성 후 gdb debugee로 디버깅 시작

 

#include <stdio.h>
int main(void) {
  int sum = 0;
  int val1 = 1;
  int val2 = 2;
  sum = val1 + val2;
  printf("1 + 2 = %d\\n", sum);
  return 0;
}

- debugee.c 파일

 

 

start

ELF: 리눅스 실행파일의 형식

- ELF는 헤더와 여러  섹션들로 구성

- ELF 헤더 중엔 진입점(Entry Point, EP) 필드가 있다. 운영체제는 ELF를 실행할 때, 진입점의 값부터 프로그램을 실행

 

- readelf로 확인 결과, debugee의 진입점은 0x540이다.

 

- gdb의 start 명령어는 진입점부터 프로그램을 분석할 수 있게 해주는 gdb 명령어

 

- DISASM 영역의 화살표가 가리키는 주소는 현재 rip 값으로 start 명령어를 실행하고 보면 이는 프로그램의 진입점 주소와 일치한다. 

 

context

- pwndbg는 주요 메모리들의 상태를 프로그램이 실행되고 있는 맥락(Context)이라고 부른다.

- context는 크게 4개의 영역으로 구분

  1. registers: 레지스터의 상태를 보여준다.
  2. disasm: rip부터 여러 줄에 걸쳐 디스어셈블된 결과를 보여준다.
  3. stack: rsp부터 여러 줄에 걸쳐 스택의 값들을 보여준다.
  4. backtrace: 현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지 보여준다.

 

break & continue & run

- break: 특정 주소에 중단점(break oint)를 설정하는 기능

continue: 중단된 프로그램을 계속 실행시키는 기능

run: 단순히 실행만 시키는 기능, 중단점을 설정해놓지 않는다면 프로그램이 끝까지 멈추지 않고 실행된다. 중단점 설정 시 run 명령어를 실행해도 중닩ㅁ에서 실행이 멈춘다.

 

disassembly

- gdb는 기계어를 disassemble(디스어셈블)하는 기능을 기본적으로 탑재

- 추가적으로 pwndbg에는 디스어셈블된 결과를 가독성 좋게 출력해 주는 기능도 탑재

 

nevigate

- ni와 si: 명령어를 한 줄 씩 자세히 분석하는 명령어 / 어셈블리 명령어를 한 줄 실행

call 등을 통해 서브루틴을 호출하는 경우 ni는 서브루틴의 내부로 들어가지 않지만, si는 서브루틴의 내부로 들어간다.

 

- nexti(ni): 명령어 실행, 함수 내부로는 들어가지 않는다.

- stepi(si): 명령어 실행, 함수 내부로 들어간다.

 

telescope

- telescope은 pwndbg가 제공하는 강력한 메모리 덤프 기능

- 특정 주소의 메모리 값들을 보여주는 것에서 그치지 않고, 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여준다.

 

 

vmmap

- vmmap은 가상 메모리의 레이아웃을 보여준다.

- 어떤 파일이 매핑된 영역일 경우, 해당 파일의 경로까지 보여준다.

 

 


Tool: pwntools

pwntools

- pwntools는 파이썬 모듈로 이것 덕분에 익스플로잇 제작이 간단하고 쉬워졌다.

 

$ apt-get update
$ apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
$ python3 -m pip install --upgrade pip
$ python3 -m pip install --upgrade pwntools

- pwntools 설치 명령어

 

설치 성공 확인

pwntools API 사용법

1. process & remote

process 함수는 익스플로잇을 로컬 바이너리를 대상으로 할 때 사용하는 함수이고, remote 함수는 원격 서버를 대상으로 할 때 사용하는 함수이다. 전자는 보통 익스플로잇을 테스트하고 디버깅하기 위해, 그리고 후자는 대상 서버를 실제로 공격하기 위해 사용한다.

 

2. send

send는 데이터를 프로세스에 전송하기 위해 사용한다. pwntools에는 관련된 다양한 함수가 정의되어 있다.

 

3. recv

recv는 프로세스에서 데이터를 받기 위해 사용합니다. 마찬가지로 pwntools에는 관련된 다양한 함수가 정의되어 있다. Figure8에서 주의해서 봐야 할 것은 recv()와 recvn()의 차이점이다. recv(n)은 최대 n 바이트를 받는 것이므로, 그만큼을 받지 못해도 에러를 발생시키지 않지만, recvn(n)의 경우 정확히 n 바이트의 데이터를 받지 못하면 계속 기다린다.

 

4. packing & unpacking

익스플로잇을 작성하다 보면 어떤 값을 리틀 엔디언의 바이트 배열로 변경하거나, 또는 역의 과정을 거쳐야 하는 경우가 자주 있다. pwntools에는 관련된 함수들이 정의되어 있다.

 

5. interactive

셸을 획득했거나, 익스플로잇의 특정 상황에 직접 입력을 주면서 출력을 확인하고 싶을 때 사용하는 함수다. 호출하고 나면 터미널로 프로세스에 데이터를 입력하고, 프로세스의 출력을 확인할 수 있다.

 

6. ELF

ELF 헤더에는 익스플로잇에 사용될 수 있는 각종 정보가 기록되어있다. pwntools를 사용하면 이 정보들을 쉽게 참조할 수 있다. 

 

7. context.log

익스플로잇에 버그가 발생하면 익스플로잇도 디버깅해야 한다. pwntools에는 디버그의 편의를 돕는 로깅 기능이 있으며, 로그 레벨은 context.log_level변수로 조절할 수 있다.

 

8. context.arch

pwntools는 셸코드를 생성하거나, 코드를 어셈블, 디스어셈블하는 기능 등을 가지고 있는데, 이들은 공격 대상의 아키텍처에 영향을 받는다. 그래서 pwntools는 아키텍처 정보를 프로그래머가 지정할 수 있게 하며, 이 값에 따라 몇몇 함수들의 동작이 달라진다.

 

9. shellcraft

pwntools에는 자주 사용되는 셸 코드들이 저장되어 있어서, 공격에 필요한 셸 코드를 쉽게 꺼내 쓸 수 있게 해준다. 매우 편리한 기능이지만 정적으로 생성된 셸 코드는 셸 코드가 실행될 때의 메모리 상태를 반영하지 못한다. 또한, 프로그램에 따라 입력할 수 있는 셸 코드의 길이나, 구성 가능한 문자의 종류에 제한이 있을 수 있는데, 이런 조건들도 반영하기 어렵다. 따라서 제약 조건이 존재하는 상황에서는 직접 셸 코드를 작성하는 것이 좋다.

여기에서 x86-64를 대상으로 생성할 수 있는 여러 종류의 셸 코드를 찾아볼 수 있다.

 

10. asm

pwntools는 어셈블 기능을 제공한다. 이 기능도 대상 아키텍처가 중요하므로, 아키텍처를 미리 지정해야 한다.