목록Write-ups (15)
rsp-∞
// Name: rop.c// Compile: gcc -o rop rop.c -fno-PIE -no-pie#include #include int main() { char buf[0x30]; setvbuf(stdin, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); // Leak canary puts("[1] Leak Canary"); write(1, "Buf: ", 5); read(0, buf, 0x100); printf("Buf: %s\n", buf); // Do ROP puts("[2] Input ROP payload"); write(1, "Buf: ", 5); read(0, buf, 0x100); return 0;} rop.c의 코드이다. 카..
Return to Library는 공격자들로 하여금 실행 권한이 있는 영역의 주소를 반환시키는 공격 기법을 구현하게 한다. 이전에 드림핵에서 강의한 NX로 인해 셸 코드의 실행은 어려우나, 공격자들에게는 코드 영역과 라이브러리 영역에 대한 실행 권한이 남아 있다. 라이브러리는 여러 함수의 집합이므로 공격자의 입장에서는 당연히 코드 영역보다 라이브러리 영역에 집중할 수밖에 없는데, 카나리처럼 이 라이브러리 안에 있는 함수로 NX를 우회하고 셸을 획득하는 방법을 고안해 내고 그 이름을 Return to Library, 이하 RTL이라고 했다. // Name: rtl.c// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie#include #include #include const c..
$ checksec ssp_001 Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) checksec 명령어를 사용하여 ssp_001 함수에서 canary 보호 기법이 적용되어 있음을 알 수 있다. (해당 워게임 Environment에서도 확인 가능) #include #include #include #include void alarm_handler() { puts("TIME OUT"); exit(-1);}void initialize() { setvbuf(stdin, NULL, _IONBF, 0); ..
카나리는 프로세스가 시작될 때 그 값을 TLS 영역에 저장하는데, 조금 더 간단하게는 TLS 영역을 가리키는 fs가 있으므로 이 fs의 값을 알면 TLS 영역의 주소를 알 수 있다. fs는 레지스터이지만 호출을 위해서는 다른 레지스터와 다르게 syscall을 사용해야 한다. fs의 값을 설정할 때 호출되는 시스템 콜인 arch_prctl(int code, unsigned long addr)에 breakpoint를 걸어 fs에 어떤 값이 할당되는지 알 수 있다. 이전 canary.c 동적 실습에서 다루었던 파일을 똑같이 gdb -q ./canary로 실행시키고, gdb에서 특정한 이벤트가 발생했을 때 실행을 멈추는 catch 명령어를 사용한다. pwndbg> catch syscall arch_prctlC..
#include int main() { char buf[8]; read(0, buf, 32); return 0;} 드림핵에서 제공하는 canary.c의 코드이다. 이를 gcc -o no_canary canary.c -fno-stack-protector 명령어로 컴파일해 주면서 no_canary 옵션을 집어넣으면 스택 버퍼 오버플로우 여부를 검증하는 canary 기능이 없도록 컴파일된다. 실행하면 별다른 출력 없이 사용자로부터 입력을 받도록 되어 있는데, 위 canary.c의 코드를 보면 알 수 있듯 스택 버퍼 오버플로우가 발생하는 구조의 코드이기 때문에 no_canary를 실행하고 무작위의 긴 입력값을 집어넣으면 아래와 같은 결과가 나온다.$ ./no_canaryAAAAAAAAAAAAAAAAAAAA..
pwndbg> disassemble phase_4Dump of assembler code for function phase_4: 0x000000000040100c : sub rsp,0x18 0x0000000000401010 : lea rcx,[rsp+0xc] 0x0000000000401015 : lea rdx,[rsp+0x8] 0x000000000040101a : mov esi,0x4025cf 0x000000000040101f : mov eax,0x0 0x0000000000401024 : call 0x400bf0 0x0000000000401029 : cmp eax,0x2 0x000000000040102c : jne 0x401035 ..
// Compile: gcc -o shell_basic shell_basic.c -lseccomp// apt install seccomp libseccomp-dev#include #include #include #include #include #include #include #include #include void alarm_handler() { puts("TIME OUT"); exit(-1);}void init() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(10);}void banned_execve() { scmp_filt..
#include #include #include #include void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); } int main(int argc, char *argv[]) { char buf[0x80]; initialize(); printf("buf = (%p)\n", buf); scanf("%141s", buf); return 0; } basic_exploitation_000의 c코드를 먼저 보면, 이번에도 역시 입력값의 길..
#include #include #include #include void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); } void read_flag() { system("cat /flag"); } int main(int argc, char *argv[]) { char buf[0x80]; initialize(); gets(buf); return 0; } basic_exploitation_001의 c 코드 파일이다. main에서 길이를 체..
#include #include void init() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); } void get_shell() { char *cmd = "/bin/sh"; char *args[] = {cmd, NULL}; execve(cmd, args, NULL); } int main() { char buf[0x28]; init(); printf("Input: "); scanf("%s", buf); return 0; } rao.c 코드를 먼저 보자. buf의 크기가 0x28로 설정되어 있고, main 함수의 하단에 scanf를 사용하여 buf의 값을 입력받는다. rao.c의 취약점은 이 scanf 함수이다. 입력받는 값의 길이를 체크하지 않는 함수이..