what is master canary & fs_base
우리가 평소에 자주 봐았던
Dump of assembler code for function main:
0x0000000000400b05 <+0>: push %rbp
0x0000000000400b06 <+1>: mov %rsp,%rbp
0x0000000000400b09 <+4>: sub $0x60,%rsp
0x0000000000400b0d <+8>: mov %edi,-0x54(%rbp)
0x0000000000400b10 <+11>: mov %rsi,-0x60(%rbp)
0x0000000000400b14 <+15>: mov %fs:0x28,%rax
0x0000000000400b1d <+24>: mov %rax,-0x8(%rbp)
함수의 프롤로그 부분이다. 여기서
0x0000000000400b14 <+15>: mov %fs:0x28,%rax
이 부분이 canary를 담는 부분인 것은 다 알것이다. 그럼 이제 이 부분이 어떻게 작동되는지 fs가 뭔지에 대해 알아보도록 하자
%fs:0x28 이 말은 fs 레지스터의 값에 0x28을 더한 주소의 값을 의미한다.
fs 레지스터 값은 fs_base의 값이 들어간다.
즉, fs_base + 0x28의 위치한 8바이트를 가져온다고 보면 된다.
일반적인 우분투 버전의 Pwngdb 에서는
pwndbg> p/x $fs_base
$3 = 0x7ffff7fad740다음과 같이 fs_base 를 확인 할 있고
다음이나 일반적인 우분투 버전의 일반 gdb에서도
pwndbg> i r
rax 0x400b05 4197125
rbx 0x7fffffffe208 140737488347656
rcx 0x400c90 4197520
rdx 0x7fffffffe218 140737488347672
rsi 0x7fffffffe208 140737488347656
rdi 0x1 1
rbp 0x7fffffffe0e0 0x7fffffffe0e0
rsp 0x7fffffffe0e0 0x7fffffffe0e0
r8 0x400d00 4197632
r9 0x7ffff7fca380 140737353917312
r10 0x7ffff7c140c8 140737350025416
r11 0x7ffff7c2a200 140737350115840
r12 0x1 1
r13 0x0 0
r14 0x0 0
r15 0x7ffff7ffd000 140737354125312
rip 0x400b09 0x400b09 <main+4>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
k0 0x100010 1048592
k1 0x402010 4202512
k2 0x0 0
k3 0x0 0
k4 0x0 0
k5 0x0 0
k6 0x0 0
k7 0x0 0
fs_base 0x7ffff7fad740 140737353799488
gs_base 0x0 0info reg 명령어로 쉽게 알아낼 수 있다.
하지만 16.04 우분투에서는 안된다. 따라서
pwndbg> p/x $fs_base
$1 = Value can't be converted to integer.
pwndbg> fsbase
0x7ffff7fed700
pwndbg> fsbase 명령어로 해야 한다.
fs_base를 알았으면, 다음과 같이 바로 master canary 값을 볼 수가 있다.
pwndbg> p/x $fs_base
$1 = 0x7ffff7fad740
pwndbg> x/gx 0x7ffff7fad740 + 0x28
0x7ffff7fad768: 0xd1d621876d961200
pwndbg>
참고로,
pwndbg> vmmap 0x7ffff7fad740
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x7ffff7e05000 0x7ffff7e12000 rw-p d000 0 [anon_7ffff7e05]
► 0x7ffff7fad000 0x7ffff7fb0000 rw-p 3000 0 [anon_7ffff7fad] +0x740
0x7ffff7fb0000 0x7ffff7fb1000 r--p 1000 0 /usr/lib/x86_64-linux-gnu/libpthread.so.0
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x400000 0x401000 r-xp 1000 0 /home/amemoyoi/pwn_venv/master_canary
0x601000 0x602000 r--p 1000 1000 /home/amemoyoi/pwn_venv/master_canary
0x602000 0x603000 rw-p 1000 2000 /home/amemoyoi/pwn_venv/master_canary
0x7ffff7c00000 0x7ffff7c28000 r--p 28000 0 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7c28000 0x7ffff7db0000 r-xp 188000 28000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7db0000 0x7ffff7dff000 r--p 4f000 1b0000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7dff000 0x7ffff7e03000 r--p 4000 1fe000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7e03000 0x7ffff7e05000 rw-p 2000 202000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7e05000 0x7ffff7e12000 rw-p d000 0 [anon_7ffff7e05]
0x7ffff7fad000 0x7ffff7fb0000 rw-p 3000 0 [anon_7ffff7fad]
0x7ffff7fb0000 0x7ffff7fb1000 r--p 1000 0 /usr/lib/x86_64-linux-gnu/libpthread.so.0
0x7ffff7fb1000 0x7ffff7fb2000 r-xp 1000 1000 /usr/lib/x86_64-linux-gnu/libpthread.so.0
0x7ffff7fb2000 0x7ffff7fb3000 r--p 1000 2000 /usr/lib/x86_64-linux-gnu/libpthread.so.0
0x7ffff7fb3000 0x7ffff7fb4000 r--p 1000 2000 /usr/lib/x86_64-linux-gnu/libpthread.so.0
0x7ffff7fb4000 0x7ffff7fb5000 rw-p 1000 3000 /usr/lib/x86_64-linux-gnu/libpthread.so.0
0x7ffff7fbd000 0x7ffff7fbf000 rw-p 2000 0 [anon_7ffff7fbd]
0x7ffff7fbf000 0x7ffff7fc3000 r--p 4000 0 [vvar]
0x7ffff7fc3000 0x7ffff7fc5000 r-xp 2000 0 [vdso]
0x7ffff7fc5000 0x7ffff7fc6000 r--p 1000 0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fc6000 0x7ffff7ff1000 r-xp 2b000 1000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ff1000 0x7ffff7ffb000 r--p a000 2c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffb000 0x7ffff7ffd000 r--p 2000 36000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffd000 0x7ffff7fff000 rw-p 2000 38000 /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]이 fs_base 주소는 TLS( Thread Local Storage ) 영역을 가리키므로 므로 커널상에서 mmap으로 매핑되어 있는 anon_7ffff7fad → 익명 영역임을 알 수 있다.
TLS 영역은 스레드 마다 존재하며 메인스레드에서 TLS 영역은 상당히 떨어져 있지만,
이후에 사용자에 의해 생긴 스레드의 TLS 영역은 스레드의 스택 영역의 근처의 위치하게 된다. 따라서 스레드 스택에서 TLS 영역을 침범하여 master canary를 leak을 하거나 스레드 상에서만 canary overwrite이 가능해진다.
링크
thread 마다 fs_base의 위치가 다르다.
fs_base는 TLS ( Thread Local Storage ) 영역을 가리키고 있기에 당연하게도
thread 마다 fs_base값이 다르다.
pwndbg> threads
global_num name status pc symbol
------------ ------------- -------- -------- --------------
1 master_canary stopped 0x400bb4 main+175
3 master_canary stopped 0x400a5b thread_routine
Showing 2 of 2 threads.
pwndbg> thread 3
[Switching to thread 3 (Thread 0x7ffff70006c0 (LWP 1741248))]
#0 0x0000000000400a5b in thread_routine ()
pwndbg> p/x $fs_base
$2 = 0x7ffff70006c0
pwndbg> thread 1
[Switching to thread 1 (Thread 0x7ffff7fad740 (LWP 1740526))]
#0 0x0000000000400bb4 in main ()
pwndbg> p/x $fs_base
$3 = 0x7ffff7fad740