HackTheBox - Dusty Alleys
- Challenge Scenario
In the dark, dusty underground labyrinth, the survivors feel lost and their resolve weakens. Just as despair sets in, they notice a faint light: a dilapidated, rusty robot emitting feeble sparks. Hoping for answers, they decide to engage with it.
Background
- Nginx
- SSRF
Recon
這一題和nginx的config以及feature有關,我真的很不喜歡這類型的題目,因為…誰會知道啊,web很容易出這種冷門的題目
首先,先分析local folder,看Dockerfile的寫法
1 | |
從以上的內容看得出來大部分是常規的操作,重點是SECRET_ALLEY這個環境變數和nginx的config file有關,所以繼續看default.conf
1 | |
我們知道幾件事情
- nginx有兩個virtual host,但是具體的server_name和前面提到的環境變數有關
- 有幾個directory,包含
/,/alley,/think,/guardian - 除了
/以外,其他幾個directory request package會丟給localhost:1337處理,也就是index.js - 丟過去處理的時候會帶上
Host等等header
到這邊為止,我們大概知道這一台web server的網路架構,但還不知道實際如何處理request
1 | |
從index.js中看得出來是用ejs render所以可能會有SSTI的問題,並且實際處理routes的request是./routes/guardian.js這個file
1 | |
看起來很複雜,但其實只要按照route的部分trace就會比較有概念
/alley: render./views/index.ejs,看起來沒有什麼用,實際去看會發現clickStart the Gamebutton會redirect to/guardianwith 404 status code,所以我猜這只是一個引導解題的人的功能性的page/think: respone request header with json format,這個就比較有意思了,這場不會這樣寫,他就像是一個oracle一樣,會leak出一些server info”的感覺”1
return res.json(req.headers);/guardian: 一般來說如果request這個directory,會return 404,那是因為前面的nginx config設定成只有Host: guardian.$SECRET_ALLEY的前提下才能request,但沒關係,可以先trace code,我發現他有一個SSRF的問題,他是用GET method的方式request帶著quote參數,而這個參數一定要是localhost才能往下,然後只要正確的request,就會回傳Flag,而正確的request有兩個前提- 我要能夠request這個directory,也就是我要知道
$SECRET_ALLEY是什麼 - 進入
/guardian之後要能夠自動讓response帶上Key這個header並且回傳回來
- 我要能夠request這個directory,也就是我要知道
Exploit
有關於第二個難點,我覺得可以先在local deploy server後嘗試,那就是利用/think會自動return request header的特性
1 | |
代表這個request是成立的
現在難的地方是要如何知道$SECRET_ALLEY,我卡了超久,我知道這一定和nginx的config或feature有關,畢竟之前也有寫過某種nginx feature的題目1,但真的想不出來,我知道一定是透過/think route回傳回來,所以參考2的解析
However, according to the HTTP/1.0 standard, the Host header is optional and not mandatory. By sending an HTTP/1.0 request directly to the challenge’s IP:PORT without a Host header, Nginx defaults to routing the request to alley.$SECRET_ALLEY, as this vhost is configured with default_server.
By sending an HTTP/1.0 request to the /think endpoint without the Host header, I can get the value of SECRET_ALLEY from the leaked information.
所以完整的command如下,如果Host header不完整,只要指定HTTP為1.0版本,nginx就會自動帶上完整的default_server的server_name
1 | |
Flag: HTB{DUsT_1n_my_3y3s_l33t}