[护网杯 2018]easy_tornado (SSTI)

[护网杯 2018]easy_tornado

0x00 嘗試

有三個超鏈接,分別看看裏面的內容。

/flag.txt
flag in /fllllllllllllag

/welcome.txt
render

/hints.txt
md5(cookie_secret+md5(filename))

flag的位置已經給我們了,然後可以注意到url的格式都是filename&filehash的形式,那麼我們的payload應該是

/file?filename=/fllllllllllllag&filehash=?

filehash應該是md5(cookie_secret+md5(fllllllllllllag)),但是還有一個cookie_secret不知道。

我想到的辦法是,利用前面三個超鏈接裏的filehash,解md5,再去掉末尾的文件名md5哈希值得到cookie_secret,接着就再md5加密就得到需要的filehash了。

然而cmd5查了三個filehash都找不的原文,這方法行不通,應該是有別的解法。

訪問了下我們構造的url,給了個Error,不過觀察它跳轉到的url

/error?msg=Error

這裏顯然有一個傳參的過程。

把Error改成hello world,頁面就輸出了hello world,這裏應該有一個輸出函數。

問題是怎麼閉合這個函數,然後執行我們的命令呢?

亂試一通都沒用,還看看大佬WP好惹。

0x01 SSTI(Server-Side Template Injection)

tornado

大佬說看到題目叫tornado,再看到welcome寫了個render就知道是SSTI了,還知道是python。

然後我去搜了下tornado,官網第一句話。

Tornado is a Python web framework and asynchronous networking library.

大佬就是大佬,見多識廣。

tornado和python了解了,那render和SSTI是怎麼一回事?

我繼續在tornado官網搜了下render,然後搜出一篇Structure of a Tornado web application,讀了下。

tornado web app大概是這樣的:

  • main()函數啓動服務器(讓Application監聽端口),啓動io循環。

  • Application對象給不同的URL路由分配到對應的RequestHandler。

  • RequestHandler通過get()或post()方法來處理對應的HTTP請求,一般通過write()或者render()方法產生HTTP Response返回給用戶。

  • write()和render()的區別是,render()會根據參數加載模板,而write()用在不基於模板的輸出。

  • RequestHandler.render(template_name: str,kwargs) → Future[None]

頁面是render()通過模板渲染後返回給我們的,也就說,之前給我們猜測輸出內容給我們的函數就是render()。

Tornado Template

既然是模板注入,那就得繼續學習下它的模板是怎樣的。Template syntax

  • Tornado模板就是HTML加了些Python控制語句或者表達式。
  • 模板裏,Control statements被{% %}包裹,或多或少映射到一些python的控制語句,像if,for,while,try,最後以{% end %}結束。
  • Expressions被{{ }}包裹,可以是任何Python表達式,包括function call。

了解了模板,就得想辦法獲得Cookie了,只要獲得了Cookie,我們就能自己md5加密出filehash,getflag.

獲取Cookie

繼續在官方查Cookie,基本都是RequestHandler的一些方法和屬性。

試着寫下payload

/error?msg={{ RequestHandler.cookies }} => 500: Internal Server Error
/error?msg={{ self.request.cookies }} => 500: Internal Server Error
/error?msg={{ RequestHandler.get_cookie() }} => ORZ
/error?msg=get_cookie() =>ORZ

也就說,它屏蔽了get_cookie()方法,然後RequestHandler對象不能直接這樣調用。

沒耐心繼續試了,看大佬的WP。

payload:/error?msg={{ handler.settings }}

大佬給的解釋是,handler指向RequestHandler,RequestHandler.settings指向self.application.settings。

也就說handler.settings指向RequestHandler.application.settings,而這個設置裏面就有我們要的cookie_secret。

構造payload

獲得了cookie,接下來就可以根據hint構造payload了。

'cookie_secret': '2a3ce894-8cba-42db-8ad4-5ec7125a7c31'

/hints.txt
md5(cookie_secret+md5(filename))

filename:/fllllllllllllag

md5(filename):3bf9f6cf685a6dd8defadabfb41a03a1

cookie_secret+md5(filename):2a3ce894-8cba-42db-8ad4-5ec7125a7c313bf9f6cf685a6dd8defadabfb41a03a1

filehash:b55d6e5192a3c8f973d3a9189c15e3f7

payload:
/file?filename=/fllllllllllllag&filehash=b55d6e5192a3c8f973d3a9189c15e3f7

獲得flag!

0x02 總結

  • 題目 還有題目給出的提示肯定是有用的 得用上 (比如這題裏的 tornado render 暗示了SSTI)
  • 第一次認真的去讀官方文檔,收獲很多,而且其實這個過程很簡單,但卻很有幫助,之後得多讀文檔

0x03 參考和感謝

posted @ 2020-02-18 16:28  rpish  阅读(334)  评论(0编辑  收藏  举报