_environ troubleshooting
Python
iofile_stdout = libc_e.symbols[b'_IO_2_1_stdout_']
__environ = libc_e.symbols[b'__environ']
print(iofile_stdout - __environ)
root@a0b2cea1050c:/home/environ/environ# python3 exploit.py
-27264이것의 결과는 libc 상의 Offset 을 계산한 것이다. 결과가 -27264
Python
pwndbg> p &__environ
$1 = (char ***) 0x7ffff7ffe2d0 <environ>
pwndbg> p stdout
$2 = (FILE *) 0x7ffff7fa9780 <_IO_2_1_stdout_>
pwndbg> p &_IO_2_1_stdout_
$3 = (struct _IO_FILE_plus *) 0x7ffff7fa9780 <_IO_2_1_stdout_>
pwndbg> p 0x7ffff7ffe2d0 - 0x7ffff7fa9780
$4 = 346960그런데 gdb 상에서 계산을 해보면 346960 라는 완전히 다른 결과가 나온다. 뭐가 문제일까?
Python
pwndbg> vmmap 0x7ffff7ffe2d0 <environ>
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x7ffff7ffb000 0x7ffff7ffd000 r--p 2000 37000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
► 0x7ffff7ffd000 0x7ffff7fff000 rw-p 2000 39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +0x12d0
0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack]
pwndbg> vmmap 0x7ffff7fa9780 <_IO_2_1_stdout_>
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x7ffff7fa4000 0x7ffff7fa8000 r--p 4000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
► 0x7ffff7fa8000 0x7ffff7faa000 rw-p 2000 219000 /usr/lib/x86_64-linux-gnu/libc.so.6 +0x1780그러던 중 이상한 점을 발견했다. environ의 위치가
/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 으로 되어 있는것
Python
root@a0b2cea1050c:/home/environ/environ# objdump -tT libc.so.6 | grep environ
0000000000221200 w DO .bss 0000000000000008 GLIBC_2.2.5 _environ
0000000000221200 g DO .bss 0000000000000008 GLIBC_2.2.5 __environ
0000000000221200 w DO .bss 0000000000000008 GLIBC_2.2.5 environbss 섹션에 있어야 할 얘가 완전하 이상한 곳에 위치해 있다.
Python
pwndbg> x/gx 0x7ffff7fa9780 + 27264
0x7ffff7fb0200 <environ>: 0x00007fffffffe698
pwndbg> x/gx 0x00007fffffffe698
0x7fffffffe698: 0x00007fffffffe8c3
pwndbg> p &_environ
$2 = (char ***) 0x7ffff7ffe2d0 <environ>
pwndbg> p 0x7ffff7ffe2d0
$3 = 140737354130128
pwndbg> x/gx 0x7ffff7ffe2d0
0x7ffff7ffe2d0 <environ>: 0x00007fffffffe698
pwndbg>
따라서 내가 임의로 27264 값을 더한 위치를 찾아보니
엥? 0x7ffff7fb0200 <environ>: 0x00007fffffffe698 해당 위치에도 역시 같은 값이 존재한다.
Python
root@a0b2cea1050c:/home/environ/environ# objdump -tT /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 | grep environ
0000000000000000 l df *ABS* 0000000000000000 dl-environ.c
0000000000000000 l df *ABS* 0000000000000000 environ.c
000000000003b2d0 l O .bss 0000000000000008 _environ
000000000003b2d0 l O .bss 0000000000000008 __environ
000000000003b2d0 l O .bss 0000000000000008 environ위를 보면 알 수 있듯이 로더인 ld-linux-x86-64.so.2 에도 똑같은 __environ 이 존재하는 것을 알 수 있다.
그렇다면 __environ 은 언제 누구에 의해 결정되는 것일까?
Python
b _start // 로더가 시작할때 bp 설정
r이렇게 한뒤
Python
pwndbg> p environ
$1 = (char **) 0x0
pwndbg> p &environ
$2 = (char ***) 0x7ffff7ffe2d0 <environ>보면 아직 값이 안정해져 있다. 그리고
Python
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x555555554000 0x555555555000 r--p 1000 0 /home/environ/environ/environ
0x555555555000 0x555555556000 r-xp 1000 1000 /home/environ/environ/environ
0x555555556000 0x555555557000 r--p 1000 2000 /home/environ/environ/environ
0x555555557000 0x555555559000 rw-p 2000 2000 /home/environ/environ/environ
0x7ffff7fbd000 0x7ffff7fc1000 r--p 4000 0 [vvar]
0x7ffff7fc1000 0x7ffff7fc3000 r-xp 2000 0 [vdso]
0x7ffff7fc3000 0x7ffff7fc5000 r--p 2000 0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fc5000 0x7ffff7fef000 r-xp 2a000 2000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fef000 0x7ffff7ffa000 r--p b000 2c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffb000 0x7ffff7fff000 rw-p 4000 37000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack]
0xffffffffff600000 0xffffffffff601000 --xp 1000 0 [vsyscall]
보면 아직 libc는 올라와 있지도 않다.
Python
pwndbg> watch environ
Hardware watchpoint 2: environ
pwndbg> c
Continuing.
Hardware watchpoint 2: environ
Old value = (char **) 0x0
New value = (char **) 0x7fffffffe698
_dl_sysdep_start (start_argptr=start_argptr@entry=0x7fffffffe680, dl_main=dl_main@entry=0x7ffff7fe48e0 <dl_main>) at ../elf/dl-sysdep.c:110watch 명령어로 확인해 보니
Python
0x00007ffff7fe246d <+45>: mov DWORD PTR [rip+0x1a655],edx # 0x7ffff7ffcac8 <_dl_argc>
0x00007ffff7fe2473 <+51>: movsxd rdx,edx
0x00007ffff7fe2476 <+54>: lea rdi,[rax+rdx*8+0x8]
0x00007ffff7fe247b <+59>: mov QWORD PTR [rip+0x1be4e],rdi # 0x7ffff7ffe2d0 <environ>
=> 0x00007ffff7fe2482 <+66>: cmp QWORD PTR [rdi],0x0
다음 위치에서 바뀜을 확인할 수 있었다. 즉, 로더에서 먼저 바뀌는 것은 확실하다. 로더가 이미 올라와 있는 프로그램을 통해 environ을 계산한뒤 결정한다. 그리고 이값이 그대로 libc에 있는 bss 영역에도 옮겨 진다.
즉, gdb로 계산하지 말고 그냥 objdump로 오프셋 계산이 가장 안전하고 확실하다.