Return to VDSO using ELF Auxiliary Vectors leck
http://v0ids3curity.blogspot.kr/2014/12/return-to-vdso-using-elf-auxiliary.html
2016/11/21 - [System/etc] - Memory Layout, Segment / Stack layout
Linux Stack Layout with Auxiliary Vectors
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
0x7fffffffe0e8: 0x00007ffff7a36f45 ( main's ret )
0x7fffffffe0f0: 0x0000000000000000 ( argc )
0x7fffffffe0f8: 0x00007fffffffe1c8 ( \*\*argv )
....................
0x7fffffffe1c0: 0x0000000000000000 ( argc )
0x7fffffffe1c8: 0x00007fffffffe5a7 ( argv[0] )
0x7fffffffe1d0: 0x0000000000000000 ( last argv[n] == NULL )
0x7fffffffe1d8: 0x00007fffffffe5d5 ( envp[0] )
0x7fffffffe1e0: 0x00007fffffffe67f ( envp[1] )
..........envp[]..........
0x7fffffffe420: 0x0000000000000000 ( last envp[n] == NULL )
/\*\*\*\*\* auxv[] \*\*\*\*\*/
key value
0x7fffffffe428: 0x0000000000000021 0x00007ffff7ffa000 // AT\_SYSINFO\_EHDR
0x7fffffffe438: 0x0000000000000010 0x000000001f8bfbff
0x7fffffffe448: 0x0000000000000006 0x0000000000001000
0x7fffffffe458: 0x0000000000000011 0x0000000000000064
0x7fffffffe468: 0x0000000000000003 0x0000000000400040
0x7fffffffe478: 0x0000000000000004 0x0000000000000038
0x7fffffffe488: 0x0000000000000005 0x0000000000000009
0x7fffffffe498: 0x0000000000000007 0x00007ffff7dda000
0x7fffffffe4a8: 0x0000000000000008 0x0000000000000000
0x7fffffffe4b8: 0x0000000000000009 0x0000000000400490
0x7fffffffe4c8: 0x000000000000000b 0x00000000000003e8
0x7fffffffe4d8: 0x000000000000000c 0x00000000000003e8
0x7fffffffe4e8: 0x000000000000000d 0x00000000000003e8
0x7fffffffe4f8: 0x000000000000000e 0x00000000000003e8
0x7fffffffe508: 0x0000000000000017 0x0000000000000000
0x7fffffffe518: 0x0000000000000019 0x00007fffffffe559 // AT\_RANDOM
0x7fffffffe528: 0x000000000000001f 0x00007fffffffefca
0x7fffffffe538: 0x000000000000000f 0x00007fffffffe569
0x7fffffffe548: 0x0000000000000000 0x0000000000000000
0x7fffffffe558
....................
0x7fffffffe5a7: "filename" ( argv strings )
..........
0x7fffffffe5d5: "ENV=value" ( envp strings )
....................
program name (== argv[0] string )
NULL
....................
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ set env LD\_SHOW\_AUXV=1
$ r
AT\_SYSINFO\_EHDR: 0x7ffff7ffa000 // VDSO addr
AT\_HWCAP: 1f8bfbff
AT\_PAGESZ: 4096
AT\_CLKTCK: 100
AT\_PHDR: 0x400040
AT\_PHENT: 56
AT\_PHNUM: 9
AT\_BASE: 0x7ffff7dda000
AT\_FLAGS: 0x0
AT\_ENTRY: 0x400490 // Entry point of program
AT\_UID: 1000
AT\_EUID: 1000
AT\_GID: 1000
AT\_EGID: 1000
AT\_SECURE: 0 // secure-execution mode
AT\_RANDOM: 0x7fffffffe559 // point to end of AUXV table
AT\_EXECFN: /home/ubuntu/workspace/study/heap/fastbin\_dup
AT\_PLATFORM: x86\_64
AT_RANDOM
을 이용해 stack offset을 계산하는 것은 remote라면 거의 불가능하다. 서버 측 쉘의 환경변수가 얼마나 있는지도 모르고, 각 stack frame size같은 것도 정확히 맞출 수 없기 때문에 어느 정도는 추측해야 한다.
sys_read-sys_write leak
#1 sys_read
1
rax : 0x0 / rsi : (stack) / rdi : (stdin, 0) / rdx : size ( x86\_64 )
* rdi
에서 읽어서, rsi
에 쓰게 된다. 결과적으로 read하는 곳이 stdin
이라 rdi : stdin
위와 같은 상태에서 syscall
해서 sys_read
를 호출한 다음 rax=0x1
로 만들기 위해 \n
만 전송한다.
#2 sys_write
sys_read
가 끝난 이후 레지스터 상태는 다음과 같다.
1
rax : 0x1 / rsi : (stack) / rdi : (stdin, 0) / rdx : size ( x86\_64 )
* rsi
에서 읽어서, rdi
에 쓰게 된다. 결과적으로 write하는 곳이 stdin
이라 rdi : stdin
stdin이든 stdout이든 stderr이든 입출력에 아무거나 사용해도 되기 때문에 이대로 sys\_write
를 호출하면 sys_read
에서 데이터를 저장해놓은 지점부터 size
만큼 leak.
이를 AUXV
leak에 사용할 수 있다.
Return to vDSO
gadget server 측에서 사용하는 vDSO page를 알고 있을 때 사용할 수 있기 때문에 제약이 꽤 크다. server OS를 알고 있다면 vDSO page도 알아낼 수는 있을 듯.
64bit에서는 parameter push를 위해 rdi, rsi, rdx
를 조작할 수 있어야 하는데, Ubuntu 14.04.5 LTS에는 다음을 제외하면 적당한 gadget이 없다.
1
2
3
4
0x7ffff7ffa9d6: syscall
0x7ffff7ffa9d8: pop rbx
0x7ffff7ffa9d9: pop rbp
0x7ffff7ffa9da: ret
아무튼, vDSO를 사용할 수 있는 환경이라면 이런 유용한 gadget들을 찾아보는게 도움이 된다.
vDSO addr
fork()
하는 경우 vDSO addr이 매번 같기 때문에AT\_SYSINFO_EHDR
leak 하면 바로 알아낼 수 있다.- vDSO page는 random하게 결정되지만, randomize range가 그리 크지 않아 brute force가 불가능한 수준은 아닌 듯.