目錄
1. CRLF注入漏洞
?Bottle HTTP頭注入漏洞
2.目錄穿越漏洞
3. http add_header被覆蓋
本篇要復現的漏洞實驗有一個網站直接為我們提供了Docker的環境,我們只需要下載下來就可以使用:
Docker環境的安裝可以參考:Docker安裝
漏洞環境的搭建具體步驟如下:
(1)首先我們需要下載環境的源碼:
https://github.com/vulhub/vulhub/archive/master.zip
(2)將下載的源碼上傳到centos環境中
(3)然后進入/root/vulhub-master/nginx目錄中,這就是該文件為我們提供的有關nginx的一些漏洞環境
(4)然后我們就可以移動到對應的環境中使用一下命令來拉取環境
docker compose up -d
然后就可以正常使用了?
1. CRLF注入漏洞
CRLF注入漏洞,也叫做HTTP頭部注入漏洞
在HTTP頭部每一行的結尾都會有一個 \r \n
下面兩種情景十分常見:
用戶訪問http://example.com/aabbcc,自動跳轉到https://example.com/aabbcc (自動將http->https)
用戶訪問http://example.com/aabbcc,自動跳轉到http://www.example.com/aabbcc(自動增加一級域名)
第二個場景主要是為了統一用戶訪問的域名,更加有益于SEO優化。
在跳轉的過程中,我們需要保證用戶訪問的頁面不變,所以需要從Nginx獲取用戶請求的文件路徑。
查看Nginx文檔,可以發現有三個表示uri的變量:
$uri
$document_uri
$request_uri
1和2表示的是解碼以后的請求路徑,不帶參數;3表示的是完整的URI(沒有解碼)。
錯誤的配置文件示例(原本的目的是為了讓http的請求跳轉到https上):
location / {return 302 https://$host$uri;
}
#因為$uri是解碼以后的請求路徑,所以就會包含換行符,就有可能造成CRLF漏洞 這個CRLF注入漏洞,導致固定漏洞、設置cookie引發的csrf漏洞或者xss漏洞,其中,我們可以注入兩個\r \n即可控制HTTP體進行xss,但是因為瀏覽器會認為這是一個300跳轉,所以并不會顯示我們注入的內容
Payload: http://your-ip:8080/%0d%0aSet-Cookie:%20a=1,可注入Set-Cookie頭。
這種情況下,我們可以使用一些技巧:比如使用CSP頭來ifame的地址,這樣瀏覽器并不會跳轉,進而執行我們插入的HTML
下面我簡單的使用這個漏洞環境中的/root/vulhub-master/nginx/insecure-configuration環境來演示一下CRLF漏洞
(1)首先我們移動到對應的環境下
(2)使用docker compose up -d來拉取環境
[root@centos111 insecure-configuration]# docker compose up -d
[+] Running 1/1? Container insecure-configuration-nginx-1 Started
注:拉取環境的前提是我們安裝了Docker
(3)可以使用dokcer ps 來查看一下容器是否運行:
可以看到正常的運行了?
(4)現在可以做一個簡單的測試,在shell中使用curl來嘗試在頭部增加一個%0d%0d,也就是\r\n,然后插入一條語句
curl -I http://127.0.0.1:8080/%0d%0aSet-cookie:%20a=1
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.13.0
Date: Fri, 24 Nov 2023 01:25:36 GMT
Content-Type: text/html
Content-Length: 161
Connection: keep-alive
Location: http://127.0.0.1:8080/
Set-cookie: a=1
可以看到我們利用%0d%0a成功的在頭部增加了一行Set-cookie:a=1?
(5)那么我們現在就可以使用Burpsuite來抓一個這個網頁的包,嘗試使用CRLF注入
在本機上打開BP軟件,開啟代理,然后打開本機的代理
我們可以構造一個反彈性xss的腳本插入到頭部中:
<script>alert(1)</script>
可以看到我們成功的利用%0d%0a在頭部插入了script彈窗代碼,使用兩個%0d%0a的原因是因為第一個是讓我們來到新的一行,第二個換行是為了與頭部分割一行,否則就無法正常插入
下面用這樣一個案例來舉例Python中的一個CRLF漏洞
?Bottle HTTP頭注入漏洞
這時我們要運行的bottle_demo.py代碼
import bottle
from bottle import route,run, template,request,response
@route('/')
def index():path = request.query.set('path','http://www.xianoupeng.com')return bottle.redirect(path)if __name__ == '__main__':bottle.debug(True)run(host='localhost', port=8081)
?因為redirect函數是向response中插入一個HTTP頭,也就是Location: xxx
,所以存在頭注入。
(1)我們運行這個python腳本,然后嘗試使用\r\n的方式進行彈窗
?但實際測試的過程中遇到了一個有趣的問題,看看redirect函數的實現:
def redirect(url, code=None):""" Aborts execution and causes a 303 or 302 redirect, depending onthe HTTP protocol version. """if not code:code = 303 if request.get('SERVER_PROTOCOL') == "HTTP/1.1" else 302res = response.copy(cls=HTTPResponse)res.status = coderes.body = ""res.set_header('Location', urljoin(request.url, url))raise res</pre>
其中使用了一個urljoin,將當前url和我傳入的path進行了一次"join",經過這個操作事情就變得很微妙了:Location
頭一定有一個值。這種情況下,瀏覽器就不會渲染頁面,會直接跳轉到Location頭指向的地址。也就是說,如果我要利用CRLF構造XSS的話,這里是不會觸發的。
回想上面提到過的新浪的那個CRLF,那個漏洞的Location
是可以為空的,如果瀏覽器發現Location
為空就不會進行跳轉,進而渲染了后面注入的HTML,造成XSS。
(2)可以使用一下兩種方式來解決這個問題
方法1:將跳轉的url端口設為<80
http://localhost:8081/?path=www.oupeng.com:0%0d%0aX-XSS-Protection:0%0d%0a%0d%0a%3Cscript%3Ealert(location.href)%3C/script%3E
python中確實收到了請求?
但是頁面還是告訴我們無法訪問?
注:這種方法在現在的瀏覽器中無法正常實現,如果需要復現,需要降低瀏覽器的版本
方法2:使用CSP禁止iframe的跳轉
可以在運行Python腳本的前提下去在本地新建一個web.php代碼,通過訪問php文件使用iframe將httpL//localhost:8081頁面嵌入,從而實現彈窗。
php代碼:
<?php
header("Content-Security-Policy: frame-src http://localhost:8081/"); //這里設置了CSP
?>
<iframe src="http://localhost:8081/?path=http://www.baidu.com/%0a%0dX-XSS-Protection:0%0a%0d%0a%0d<script>alert(location.href)</script>"></iframe>
?通過嘗試發現Firefox可以彈窗,但是Chrome不能。
如果python代碼是這樣的則上面的兩種方式均可以實現
import bottle
from bottle import route,run, template,request,response@route('/')
def index():server = bottle.request.query.get('server') # 接收Server參數bottle.response.add_header('Server', server)return bottle.responseif __name__ == '__main__':bottle.debug(True)bottle.run(host='localhost', port=8081)
總結一下,安全的做法應該為:
不安全:
location / {return 302 https://$host$uri;
}
安全
location / {return 302 https://$host$request_uri; //Request不會對%0d%0a解碼,所以無法換行
}
2.目錄穿越漏洞
這個常見于nginx做反向代理的情況,動態的部分被proxy_pass傳遞給后端端口,而靜態的文件需要nginx來處理。
假設靜態文件存儲在/home/目錄下,而該目錄在url中名字為files,那么就需要用alias設置目錄的別名:
Nginx在配置別名(Alias)的時候,如果忘記加/
,將造成一個目錄穿越漏洞。
錯誤的配置文件示例(原本的目的是為了讓用戶訪問到/home/目錄下的文件):
location /files { #這里沒有 /alias /home/; #因為真正的文件在/home下,所以這里設置了別名/home/
}
此時我們的dokcer環境中的文件配置就是這樣的:
server {listen 8081;root /usr/share/nginx/html;index index.html;server_name _;autoindex on;location /files {alias /home/;}
}
此時訪問192.168.159.200:8081,就可以獲取到/files/help.txt文件
?但是我們注意到,url上/files沒有加后綴/ ,而alias設置的/home/是有后綴/ 的,這個 / 就導致我們可以從 /home/ 目錄穿越到它的上層目錄:
Payload: http://your-ip:8081/files../
此時我們就可以看到我們可以移動到/目錄下,這時就會出現任意文件下載的危險漏洞
解決方案:必須保證location和alias的值都有后綴/ 或者都沒有這個后綴
我們修改配置文件為:
server {listen 8081;root /usr/share/nginx/html;index index.html;server_name _;autoindex on;location /files/ {alias /home/;}
}
重啟docker:
docker restart 你的鏡像編號
?然后再次嘗試路徑穿越訪問:
可以看到已經無法完成路徑穿越了。
3. http add_header被覆蓋
CSP:(Content-Security-Policy) 可以防御xss注入
Nginx配置文件子塊(server、location、if)中的add_header
,將會覆蓋父塊中的add_header
添加的HTTP頭,造成一些安全隱患。
如下列代碼,整站(父塊中)添加了CSP頭:
server{
add_header Content-Security-Policy "default-src 'self'"; #default-src用來設置上面各個選項的默認值。
#上面代碼限制所有的外部資源,都只能從當前域名加載。
?
add_header X-Frame-Options DENY;
//這里會覆蓋父類的CSP,CSP就失效了
location = /test1 {rewrite ^(.*)$ /xss.html break;
}
?
?
location = /test2 {add_header X-Content-Type-Options nosniff;rewrite ^(.*)$ /xss.html break;
}
#這里的location會將前面的location覆蓋
}
但/test2
的location中又添加了X-Content-Type-Options
頭,導致父塊中的add_header
全部失效,
所以XSS可以被觸發:
可以看到我輸入的js代碼中的標簽被瀏覽器轉義,這里并沒有成功,那么可以嘗試在低版本的瀏覽器中測試一下:
可以看到,在低版本中我們是可以利用這個錯誤配置正常彈窗的。