64비트 리눅스에서 스택카나리는 %FS:0x28 에서부터 가져오며, 이를 스택에 저장하고 함수가 끝나기전에 다시 %FS:0x28 과 비교한다. 그렇다면 %FS:0x28 은 정확히 어디에 있는것인가?? GDT 를 덤프떠서 %FS 의 base 를 얻기는 너무 어렵고 귀찮다.
그래서 프로세스 풀메모리 스캐닝을 하는 GDB 스크립트를 하나 만들어서 아래와 같이 테스트 해보았다.
다음과 같이 간단한 카나리가 있는 static linked x64 바이너리를 가지고 실험을 해보자.
(gdb) shell cat a.c
#include <stdio.h>
int main(){
char buf[8];
printf("asdf\n");
return 0;
}
GDB 상에서 조사한 카나리는 아래와 같다.
0x127466d230bc8200
자, 이걸 전체 메모리스캐닝을해서 찾아보자.
(gdb) mem_scan $z
Pattern not found.
Pattern not found.
0x6c78a9
1 pattern found.
Pattern not found.
0x7fffffffe1e9
0x7fffffffe291
0x7fffffffe57a
3 patterns found.
Pattern not found.
4개의 값이 검출되었다.
힙에 하나..
(gdb) x/20wx 0x6c78a0
0x6c78a0: 0x00000000 0x00000000 0x30bc8200 0x127466d2
0x6c78b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78e0: 0x00000000 0x00000000 0x00000000 0x00000000
스택에 3개... 이중하나는 저장된 값이니 당연히 있는값이고
결국 FS:0x28 에 저장된 다른 사본의 후보는 힙에 1개, 스택에 2개가 있다.
(gdb) x/10wx 0x7fffffffe1e0
0x7fffffffe1e0: 0x00401a40 0x00000000 0x30bc8200 0x127466d2
0x7fffffffe1f0: 0x00000000 0x00000000 0x00401334 0x00000000
0x7fffffffe200: 0x00000000 0x00000000
(gdb) x/10wx 0x7fffffffe290
0x7fffffffe290: 0x30bc8200 0x127466d2 0x00000000 0x00000000
0x7fffffffe2a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe2b0: 0x00000000 0x00000000
(gdb) x/10wx 0x7fffffffe570
0x7fffffffe570: 0x00000000 0x00000000 0xbc82a000 0x7466d230
0x7fffffffe580: 0xfaeca712 0x8f0cf2b2 0x36387886 0x0034365f
0x7fffffffe590: 0x00000000 0x762f0000
(gdb) i r $rsp
rsp 0x7fffffffe1e0 0x7fffffffe1e0
일단 힙에 있는 값을 변조시켜보자.
(gdb) set *0x6c78ac=0x41414141
(gdb) x/20wx 0x6c78a0
0x6c78a0: 0x00000000 0x00000000 0x30bc8200 0x41414141
0x6c78b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78e0: 0x00000000 0x00000000 0x00000000 0x00000000
(gdb) c
Continuing.
asdf
*** stack smashing detected ***: /var/www/a terminated
======= Backtrace: =========
[0x418ec5]
[0x418e8e]
[0x40119e]
[0x401334]
[0x401081]
======= Memory map: ========
00400000-004c2000 r-xp 00000000 08:01 1186663 /var/www/a
006c1000-006c4000 rw-p 000c1000 08:01 1186663 /var/www/a
006c4000-006ea000 rw-p 00000000 00:00 0 [heap]
7ffff7ffc000-7ffff7ffe000 rw-p 00000000 00:00 0
7ffff7ffe000-7ffff7fff000 r-xp 00000000 00:00 0 [vdso]
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Program received signal SIGABRT, Aborted.
0x0000000000462dc5 in raise ()
(gdb)
오호라... 힙에 저장된것이 비교대상의 원본이었다.
그렇다는것은 FS base 는 아래와 같다는뜻...
각각 필드가 무슨의미일까?
(gdb) x/30wx 0x6C7880
0x6c7880: 0x006c7880 0x00000000 0x006c3770 0x00000000
0x6c7890: 0x006c7880 0x00000000 0x00000000 0x00000000
0x6c78a0: 0x00000000 0x00000000 0x16128a00 0x7f2e1d08
0x6c78b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78e0: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c78f0: 0x00000000 0x00000000
(gdb)
나머지 포인터들은 자기자신을 가리키고있을뿐이고, 눈에띄는건 6c3770...
(gdb) x/30wx 0x6c3770
0x6c3770 <static_dtv+16>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c3780 <static_dtv+32>: 0x006c7820 0x00000000 0x00000001 0x00000000
0x6c3790 <static_dtv+48>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c37a0 <static_dtv+64>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c37b0 <static_dtv+80>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c37c0 <static_dtv+96>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c37d0 <static_dtv+112>: 0x00000000 0x00000000 0x00000000 0x00000000
0x6c37e0 <static_dtv+128>: 0x00000000 0x00000000
(gdb)
뭐지이게?? 구글링해보자.
Initialization code for TLS in statically linked application ...
https://stuff.mit.edu/afs/sipb/project/gcc-3.2/OldFiles/...2.../libc-tls.c
static dtv_t static_dtv[3]; static struct { struct dtv_slotinfo_list si; /* The dtv_slotinfo_list data structure does not include the actual informatin since it is defined as an ...
즉 static 링킹된 바이너리에서의 TLS(thread Local Storage) 관련 자료구조다.
윈도우자와 마찬가지로 TLS 자료구조 속에 카나리 원본을 보관하고 있다.
그런데 어차피 ASLR 걸려있으면 이부분의 주소를 런타임이 아닌이상 알 수는 없으므로
안전하겠지만 만약 메모리릭으로 이 위치를 알고난뒤에 원하는데로 덮어쓰기까지 할수있다면
ASCII Armoring 의 상황에서도 카나리 우회가 가능해지는 일이 벌어지겠군 -_- ㅋㅋ
혹시모르니 스택에 있는 카나리들도 조작하고 어떻게되는지 보자.
(gdb) x/20wx 0x7fffffffe291
0x7fffffffe291: 0x0816128a 0x007f2e1d 0x00000000 0x00000000
0x7fffffffe2a1: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe2b1: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffe2c1: 0x00000000 0x81000000 0x00004010 0xd8000000
0x7fffffffe2d1: 0xffffffe2 0x0000007f 0x00000000 0x01000000
(gdb) set *0x7fffffffe291=0x41414141
(gdb) x/10wx 0x7fffffffe57a
0x7fffffffe57a: 0x0816128a 0x137f2e1d 0xf523cb1c 0x783771cd
0x7fffffffe58a: 0x365f3638 0x00000034 0x00000000 0x7261762f
0x7fffffffe59a: 0x7777772f 0x5300612f
(gdb) set *0x7fffffffe57a=0x41414141
(gdb) c
Continuing.
asdf
[Inferior 1 (process 2176) exited normally]
(gdb)
역시 아무일없다..? 그게 아니라
entry point 에서부터 브포걸고 확인해보면. 이상태에서 이미 스택에 canary 의 초기값이 들어가있고
__libc_start_main 에서 이 스택에 있는 값을 가져다가 하위 1바이트 마스킹해서 쓴것이었음...
(gdb) x/10gx 0x7fffffffe329
0x7fffffffe329: 0x23f76c019b2b325c 0x65648d3fbac9c919
0x7fffffffe339: 0x000034365f363878 0x0000000000000000
0x7fffffffe349: 0x2f706d742f000000 0x54565f4744580061
0x7fffffffe359: 0x48535300373d524e 0x505f544e4547415f
0x7fffffffe369: 0x00393038323d4449 0x535345535f474458
(gdb) disass main
Dump of assembler code for function main:
0x000000000040105e <+0>: push %rbp
0x000000000040105f <+1>: mov %rsp,%rbp
0x0000000000401062 <+4>: sub $0x70,%rsp
0x0000000000401066 <+8>: mov %fs:0x28,%rax
0x000000000040106f <+17>: mov %rax,-0x8(%rbp)
0x0000000000401073 <+21>: xor %eax,%eax
0x0000000000401075 <+23>: movb $0x1,-0x70(%rbp)
0x0000000000401079 <+27>: mov -0x8(%rbp),%rax
0x000000000040107d <+31>: xor %fs:0x28,%rax
0x0000000000401086 <+40>: je 0x40108d <main+47>
0x0000000000401088 <+42>: callq 0x437060 <__stack_chk_fail>
0x000000000040108d <+47>: leaveq
0x000000000040108e <+48>: retq
End of assembler dump.
(gdb) b *main+17
Breakpoint 2 at 0x40106f
(gdb) c
Continuing.
Breakpoint 2, 0x000000000040106f in main ()
(gdb) i r $rax
rax 0x23f76c019b2b3200 2591658864729076224
(gdb)
이게 entry point 에서 메인가기전에 __libc_start_main 이 세팅해줌
0x000000000040117e <+238>: mov 0x2bddfb(%rip),%rax # 0x6bef80 <_dl_random>
0x0000000000401185 <+245>: test %rax,%rax
0x0000000000401188 <+248>: je 0x401321 <__libc_start_main+657>
0x000000000040118e <+254>: mov (%rax),%rdx
0x0000000000401191 <+257>: mov %rdx,%rsi
0x0000000000401194 <+260>: mov %rdx,0x20(%rsp)
0x0000000000401199 <+265>: and $0x0,%sil
0x000000000040119d <+269>: mov %rsi,%fs:0x28
그러면 이 스택에 있는 값이 원본인건데사실상... 이건 커널이 세팅해준듯함.
아무튼 이제 Dynamic Linking 된 64비트 ELF 에서는 어떻게 되는지 확인해보자.
(gdb) i r $rax
rax 0x8e58ce56dac8f700 -8189569049940134144
(gdb) ni
0x000000000040057b in main ()
(gdb) set $z="\xf7\xc8\xda"
(gdb) set $z[3]=0x56
(gdb) mem_scan $z
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
warning: Unable to access target memory at 0x7ffff7bd2e83, halting search.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7ffff7fe3729
1 pattern found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7fffffffe1f9
0x7fffffffe57a
2 patterns found.
Pattern not found.
(gdb)
흠... 비슷하게 나오는듯하다.
0x7ffff7fe3729
이부분에 원본이 있는데
(gdb) shell cat /proc/2240/maps
00400000-00401000 r-xp 00000000 08:01 1186663 /var/www/a
00600000-00601000 r--p 00000000 08:01 1186663 /var/www/a
00601000-00602000 rw-p 00001000 08:01 1186663 /var/www/a
7ffff7a1a000-7ffff7bcf000 r-xp 00000000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7bcf000-7ffff7dcf000 ---p 001b5000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dcf000-7ffff7dd3000 r--p 001b5000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dd3000-7ffff7dd5000 rw-p 001b9000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dd5000-7ffff7dda000 rw-p 00000000 00:00 0
7ffff7dda000-7ffff7dfc000 r-xp 00000000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffff7fe2000-7ffff7fe5000 rw-p 00000000 00:00 0
7ffff7ff9000-7ffff7ffb000 rw-p 00000000 00:00 0
7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00022000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffff7ffd000-7ffff7fff000 rw-p 00023000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
(gdb)
뭔가 이름없는 RW 매핑영역이다...
(gdb) x/10wx 0x7ffff7fe3720
0x7ffff7fe3720: 0x00000000 0x00000000 0xdac8f700 0x8e58ce56
0x7ffff7fe3730: 0x22eb1cea 0x641af660 0x00000000 0x00000000
0x7ffff7fe3740: 0x00000000 0x00000000
(gdb) set *0x7ffff7fe3729=0x41414141
(gdb) c
Continuing.
asdf
*** stack smashing detected ***: /var/www/a terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7ffff7b24f47]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x0)[0x7ffff7b24f10]
/var/www/a[0x40059e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffff7a3b76d]
/var/www/a[0x4004a9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 1186663 /var/www/a
00600000-00601000 r--p 00000000 08:01 1186663 /var/www/a
00601000-00602000 rw-p 00001000 08:01 1186663 /var/www/a
00602000-00623000 rw-p 00000000 00:00 0 [heap]
7ffff7804000-7ffff7819000 r-xp 00000000 08:01 134737 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7819000-7ffff7a18000 ---p 00015000 08:01 134737 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7a18000-7ffff7a19000 r--p 00014000 08:01 134737 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7a19000-7ffff7a1a000 rw-p 00015000 08:01 134737 /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7a1a000-7ffff7bcf000 r-xp 00000000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7bcf000-7ffff7dcf000 ---p 001b5000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dcf000-7ffff7dd3000 r--p 001b5000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dd3000-7ffff7dd5000 rw-p 001b9000 08:01 132002 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff7dd5000-7ffff7dda000 rw-p 00000000 00:00 0
7ffff7dda000-7ffff7dfc000 r-xp 00000000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffff7fe2000-7ffff7fe5000 rw-p 00000000 00:00 0
7ffff7ff7000-7ffff7ffb000 rw-p 00000000 00:00 0
7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00022000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffff7ffd000-7ffff7fff000 rw-p 00023000 08:01 134927 /lib/x86_64-linux-gnu/ld-2.15.so
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Program received signal SIGABRT, Aborted.
0x00007ffff7a50425 in raise () from /lib/x86_64-linux-gnu/libc.so.6
(gdb)
조작하면 역시나 SSP 에 걸린다. 결론은 뭐 비슷하다.
그렇다면 메모리 leak 이 가능할때 이 주소를 언제나 알아내는게 가능할까??
(gdb) x/100wx 0x7FFFF7FE3700
0x7ffff7fe3700: 0xf7fe3700 0x00007fff 0xf7fe2010 0x00007fff
0x7ffff7fe3710: 0xf7fe3700 0x00007fff 0x00000000 0x00000000
0x7ffff7fe3720: 0x00000000 0x00000000 0x41414100 0x8e58ce41
0x7ffff7fe3730: 0x22eb1cea 0x641af660 0x00000000 0x00000000
0x7ffff7fe3740: 0x00000000 0x00000000 0x00000000 0x00000000
이 부분의 주소를 다시 메모리스캐닝 해보자.
(gdb) set $q="\x37\xfe"
(gdb) set $q[2]=0xf7
(gdb) mem_scan $q
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
warning: Unable to access target memory at 0x7ffff7bd2e82, halting search.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7ffff7fe3701
0x7ffff7fe3711
2 patterns found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
(gdb) info proc map
쳇 자기자신 가리키는 포인터 빼고는 안나온다.
그럼 ASLR 있을때 이 TLS 구조체가 로딩되는 위치가 뭔가 다른 라이브러리에 상대적으로 고정된 위치에 있는지 등등을 확인해보자.
Case1.
0x0000000000400515 in main ()
(gdb) x/20wx $rsp
0x7ffff5db0890: 0xf5db0980 0x00007fff 0x8ead5a00 0x2a734544
0x7ffff5db08a0: 0x00000000 0x00000000 0x926d776d 0x00007f19
0x7ffff5db08b0: 0x00000000 0x00000000 0xf5db0988 0x00007fff
0x7ffff5db08c0: 0x00000000 0x00000001 0x004004f4 0x00000000
0x7ffff5db08d0: 0x00000000 0x00000000 0x8c218a60 0xff4b4ded
(gdb) info proc map
process 3671
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /var/www/a
0x600000 0x601000 0x1000 0x0 /var/www/a
0x601000 0x602000 0x1000 0x1000 /var/www/a
0x7f19926b6000 0x7f199286b000 0x1b5000 0x0 /lib/x86_64-linux-gnu/libc-2.15.so
0x7f199286b000 0x7f1992a6b000 0x200000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7f1992a6b000 0x7f1992a6f000 0x4000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7f1992a6f000 0x7f1992a71000 0x2000 0x1b9000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7f1992a71000 0x7f1992a76000 0x5000 0x0
0x7f1992a76000 0x7f1992a98000 0x22000 0x0 /lib/x86_64-linux-gnu/ld-2.15.so + 20A729
0x7f1992c7f000 0x7f1992c82000 0x3000 0x0
0x7f1992c95000 0x7f1992c98000 0x3000 0x0
0x7f1992c98000 0x7f1992c99000 0x1000 0x22000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7f1992c99000 0x7f1992c9b000 0x2000 0x23000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7ffff5d92000 0x7ffff5db3000 0x21000 0x0 [stack]
0x7ffff5dff000 0x7ffff5e00000 0x1000 0x0 [vdso]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb) define mem_scan
Type commands for definition of "mem_scan".
End with a line saying just "end".
> find 0x400000, 0x400fff, $arg0
> find 0x600000, 0x600fff, $arg0
> find 0x601000, 0x601fff, $arg0
> find 0x7f19926b6000, 0x7f199286afff, $arg0
> find 0x7f199286b000, 0x7f1992a6afff, $arg0
> find 0x7f1992a6b000, 0x7f1992a6efff, $arg0
> find 0x7f1992a6f000, 0x7f1992a70fff, $arg0
> find 0x7f1992a71000, 0x7f1992a75fff, $arg0
> find 0x7f1992a76000, 0x7f1992a97fff, $arg0
> find 0x7f1992c7f000, 0x7f1992c81fff, $arg0
> find 0x7f1992c95000, 0x7f1992c97fff, $arg0
> find 0x7f1992c98000, 0x7f1992c98fff, $arg0
> find 0x7f1992c99000, 0x7f1992c9afff, $arg0
> find 0x7ffff5d92000, 0x7ffff5db2fff, $arg0
> find 0x7ffff5dff000, 0x7ffff5dfffff, $arg0
> find 0xffffffffff600000, 0xffffffffff600fffL, $arg0
>end
(gdb)
(gdb) set $a="\x5a\xad"
(gdb) set $a[2]=0x8e
(gdb) mem_scan $a
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
warning: Unable to access target memory at 0x7f199286ee82, halting search.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7f1992c80729
1 pattern found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7ffff5db0899
0x7ffff5db0c0a
2 patterns found.
Pattern not found.
Pattern not found.
(gdb)
Case2.
(gdb) x/20wx $rsp
0x7fffac87d790: 0xac87d880 0x00007fff 0x39925f00 0xac3b5af6
0x7fffac87d7a0: 0x00000000 0x00000000 0xee24576d 0x00007faf
0x7fffac87d7b0: 0x00000000 0x00000000 0xac87d888 0x00007fff
0x7fffac87d7c0: 0x00000000 0x00000001 0x004004f4 0x00000000
0x7fffac87d7d0: 0x00000000 0x00000000 0x857966e3 0xf4877941
(gdb) info proc map
process 3650
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /var/www/a
0x600000 0x601000 0x1000 0x0 /var/www/a
0x601000 0x602000 0x1000 0x1000 /var/www/a
0x7fafee224000 0x7fafee3d9000 0x1b5000 0x0 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee3d9000 0x7fafee5d9000 0x200000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5d9000 0x7fafee5dd000 0x4000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5dd000 0x7fafee5df000 0x2000 0x1b9000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5df000 0x7fafee5e4000 0x5000 0x0
0x7fafee5e4000 0x7fafee606000 0x22000 0x0 /lib/x86_64-linux-gnu/ld-2.15.so + 20A729
0x7fafee7ed000 0x7fafee7f0000 0x3000 0x0
0x7fafee803000 0x7fafee806000 0x3000 0x0
0x7fafee806000 0x7fafee807000 0x1000 0x22000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7fafee807000 0x7fafee809000 0x2000 0x23000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7fffac85e000 0x7fffac87f000 0x21000 0x0 [stack]
0x7fffac8c9000 0x7fffac8ca000 0x1000 0x0 [vdso]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb) define mem_scan
Type commands for definition of "mem_scan".
End with a line saying just "end".
> find 0x400000, 0x400fff, $arg0
> find 0x600000, 0x600fff, $arg0
> find 0x601000, 0x601fff, $arg0
> find 0x7fafee224000, 0x7fafee3d8fff, $arg0
> find 0x7fafee3d9000, 0x7fafee5d8fff, $arg0
> find 0x7fafee5d9000, 0x7fafee5dcfff, $arg0
> find 0x7fafee5dd000, 0x7fafee5defff, $arg0
> find 0x7fafee5df000, 0x7fafee5e3fff, $arg0
> find 0x7fafee5e4000, 0x7fafee605fff, $arg0
> find 0x7fafee7ed000, 0x7fafee7effff, $arg0
> find 0x7fafee803000, 0x7fafee805fff, $arg0
> find 0x7fafee806000, 0x7fafee806fff, $arg0
> find 0x7fafee807000, 0x7fafee808fff, $arg0
> find 0x7fffac85e000, 0x7fffac87efff, $arg0
> find 0x7fffac8c9000, 0x7fffac8c9fff, $arg0
> find 0xffffffffff600000, 0xffffffffff600fffL, $arg0
>end
(gdb)
(gdb) set $a="\x5f\x92"
(gdb) set $a[2]=0x39
(gdb) mem_scan $a
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
warning: Unable to access target memory at 0x7fafee3dce82, halting search.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7fafee7ee729
1 pattern found.
Pattern not found.
Pattern not found.
Pattern not found.
0x7fffac87d799
0x7fffac87db0a
2 patterns found.
Pattern not found.
Pattern not found.
(gdb) x/10wx 0x7fafee7ee720
0x7fafee7ee720: 0x00000000 0x00000000 0x39925f00 0xac3b5af6
0x7fafee7ee730: 0xbca0c2bc 0xb371fa43 0x00000000 0x00000000
0x7fafee7ee740: 0x00000000 0x00000000
(gdb) info proc map
process 3650
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /var/www/a
0x600000 0x601000 0x1000 0x0 /var/www/a
0x601000 0x602000 0x1000 0x1000 /var/www/a
0x7fafee224000 0x7fafee3d9000 0x1b5000 0x0 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee3d9000 0x7fafee5d9000 0x200000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5d9000 0x7fafee5dd000 0x4000 0x1b5000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5dd000 0x7fafee5df000 0x2000 0x1b9000 /lib/x86_64-linux-gnu/libc-2.15.so
0x7fafee5df000 0x7fafee5e4000 0x5000 0x0
0x7fafee5e4000 0x7fafee606000 0x22000 0x0 /lib/x86_64-linux-gnu/ld-2.15.so
0x7fafee7ed000 0x7fafee7f0000 0x3000 0x0
0x7fafee803000 0x7fafee806000 0x3000 0x0
0x7fafee806000 0x7fafee807000 0x1000 0x22000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7fafee807000 0x7fafee809000 0x2000 0x23000 /lib/x86_64-linux-gnu/ld-2.15.so
0x7fffac85e000 0x7fffac87f000 0x21000 0x0 [stack]
0x7fffac8c9000 0x7fffac8ca000 0x1000 0x0 [vdso]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb)
오오 ㅋㅋ 실험해보니 /lib/x86_64-linux-gnu/ld-2.15.so 의 R-X 세그먼트 베이스주소에서 항상 일정한 오프셋에 떨어져있다.
오프셋은. 20A720
이건아마 시스템마다 다르겠지만...
근데 ld.so 의 베이스주소는 어떻게 알아낼수있나?
뭐 당연히 PLT 의 최상단에 있는 다이나믹 로더의 주소가 ld.so 내부를 포인팅하므로 여기서부터 TLS 까지의 오프셋도 고정일것이다. ㅋㅋ
0x600fe0: 0x00000000 0x00000000 0x00600e50 0x00000000
0x600ff0 <_GLOBAL_OFFSET_TABLE_+8>: 0x92c9a2c8 0x00007f19 0x92a8b200 0x00007f19
0x601000 <puts@got.plt>: 0x92726ce0 0x00007f19 0x926d7680 0x00007f19
0x601010 <data_start>: 0x00000000 0x00000000 0x00000000 0x00000000
0x601020 <completed.6531>: 0x00000000 0x00000000 0x00000000 0x00000000
즉, ld.so 의 버전을 정확히 알고 GOT 릭할수있으면 카나리값을 알수있을뿐만 아니라 메모리 쓰기가 가능하다면 조작까지 가능하다. 아마 x86 도 거의 비슷하겠지...
'Programming' 카테고리의 다른 글
How Linux kernel implements raw_spin_lock (0) | 2014.12.10 |
---|---|
DWARF Byte code in Linux exception handling (4) | 2014.12.08 |
QEMU and timer interrupt (0) | 2014.12.02 |
Install z3 for python from source (0) | 2014.11.12 |
QEMU Kernel Debugging Error : packet reply is too long (0) | 2014.11.06 |