【技术分享】BROP Attack之Nginx远程代码执行漏洞分析及利用

时间:17-01-16 来源: 作者: 点击:

作者: k0pwn_ko

预估稿费:700RMB

投稿方式:发送邮件至 linwei#360.cn ,或登陆 网页版 在线投稿

前言

Blind ROP是一种很有意思的攻击方式,其实很多国外文章,以及原来乌云知识库中的一篇文章都有介绍,我把这些参考文章都放在结尾位置,感兴趣的小伙伴可以一起学习交流一下。作为Flappy pig战队的脑残粉,我也会时时关注CTF的动态,听说Blind ROP也出现在了今年的HCTF的pwn题中,文后我会附上z神的github,里面有HCTF的这道BROP pwn题。

最近也跟着joker师傅和muhe师傅一起看了看关于Blind ROP的东西,这是个非常有意思的利用方式,虽然比较复杂,但同时也很佩服这个利用的脑洞,攻防对抗就是不断在这种精彩的利用和缓解中提升的。

对于CTF我不是特别了解,但是在学习的过程中,通过一个Nginx的老洞,总算“认识”了Blind ROP,受益匪浅,同时也感谢joker师傅,muhe师傅,swing师傅在学习过程中的讨论和指导。

下面我将就Nginx漏洞原理,以及这个Nginx漏洞的Exploit来全方位浅析BROP这种利用方式,关于这个漏洞的原理,网上有详细说明,这里我将结合Exploit的利用来讲解整个过程。文中有失误的地方还请师傅们多多包含,多多批评指正(毕竟通读2000+行ruby太痛苦T.T)。

Nginx漏洞分析(CVE-2013-2028)

这是一个Nginx的栈溢出漏洞,我的分析环境是在x86下,而利用是在x86_64下,我本来是不想这样的,但是之前在x86下用msf复现了Nginx这个漏洞,顺道进行了分析,然后拿到Exploit的时候又在x86_64下进行了BROP的利用研究,不过这个系统版本不影响我们对漏洞的理解,利用的分析。

关于漏洞环境以及Nginx安装搭建这里我就不多说了,文后的参考文章中,我会提供一个搭建环境,按那个搭没错,这里漏洞分析我的环境是Ubuntu 13.04 x86,利用分析环境是Kali 2.0。

搭建好环境之后用“#/usr/local/nginx/nginx”运行nginx服务,有的环境下是“#/usr/local/nginx/sbin/nginx”,运行服务后,用gdb attach方法附加,之后通过msf方法发送Exploit,这里我碰到过一种情况,就是msf发送Exploit的时候,会提示ERRCONNECT,这时候可以通过set target 0的方法设置好目标对象,而不用auto target,应该就可以了。发送Exploit之后,首先我们来看一下发送的数据包。

一共发送了两个GET包,在后面的畸形字符串前,包含了一个Encoding字段,值为chunked,而第一个数据包,同样也包含了一个值为chunked,但不带畸形数据,后面会解释为什么要发送两个,这时Nginx捕获到了崩溃。

崩溃状况下,通过bt的方法回溯一下堆栈调用。

gdb-peda$ bt #0 0xb77d5424 in __kernel_vsyscall () #1 0xb7596b1f in raise () from /lib/i386-linux-gnu/libc.so.6 #2 0xb759a0b3 in abort () from /lib/i386-linux-gnu/libc.so.6 #3 0xb75d3ab5 in ?? () from /lib/i386-linux-gnu/libc.so.6 #4 0xb766ebc3 in __fortify_fail () from /lib/i386-linux-gnu/libc.so.6 #5 0xb766eb5a in __stack_chk_fail () from /lib/i386-linux-gnu/libc.so.6 #6 0x0807b4c3 in ngx_http_read_discarded_request_body (r=r@entry=0x83f7838) at src/http/ngx_http_request_body.c:676 #7 0x0807bdf7 in ngx_http_discard_request_body (r=r@entry=0x83f7838) at src/http/ngx_http_request_body.c:526 #8 0x08087a98 in ngx_http_static_handler (r=0x83f7838) at src/http/modules/ngx_http_static_module.c:211 #9 0x0806fb2b in ngx_http_core_content_phase (r=0x83f7838, ph=0x84022b8) at src/http/ngx_http_core_module.c:1415

这里问题出在stack_chk_fail,也就是canary的检查失败了,导致了程序异常中断,这个bt回溯内容很长,这里我就不讲述回溯过程了,我们直接来正向动静结合分析一下整个漏洞的成因。首先我们发送的数据包包含chunked字段。这样会进行一次if语句比较,然后给一个r在结构体的headers_in的chunked成员变量赋值。src/http/ngx_http_request.c:1707:

ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { if (r->headers_in.transfer_encoding) { if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) { r->headers_in.content_length = NULL; r->headers_in.content_length_n = -1; r->headers_in.chunked = 1; }

如果看之前的bt回溯可以看到,这个r结构体经常会作为参数被引用到,这个r结构体是一个Nginx HTTP请求的结构体,其定义如下:

typedef struct ngx_http_request_s ngx_http_request_t;

通过这种定义,我们能直接用p命令来打印整个结构体的内容。

gdb-peda$ p *(struct ngx_http_request_s*)0x83f7838 $1 = { headers_in = { headers = { last = 0x83f7870, part = { }, size = 0x18, nalloc = 0x14, pool = 0x83f7810 }, host = 0x83f7d9c, connection = 0x0, if_modified_since = 0x0, if_unmodified_since = 0x0, if_match = 0x0, if_none_match = 0x0, user_agent = 0x0, referer = 0x0, content_length = 0x0, content_type = 0x0, range = 0x0, if_range = 0x0, transfer_encoding = 0x83f7db4, expect = 0x0, upgrade = 0x0, accept_encoding = 0x0, via = 0x0, authorization = 0x0, keep_alive = 0x0, x_forwarded_for = { }, user = { }, passwd = { }, cookies = { }, server = { l }, headers_out = {

这里我列举了成员变量headers_in的内容,除了这个成员变量还有很多,感兴趣的小伙伴可以直接在源码中找到,在这个漏洞中,我们只关心headers_in中的部分成员,因此后续分析中,我只列举关键的成员变量值,结构体名字太长,后面都称之为r结构体。。

声明:本文转载于网络,文章链接:http://www.nd9p.com/9834.html