問題原因:漏洞的根源在于unserialize()函數(shù)的參數(shù)可控徽惋。如果反序列化對象中存在魔術(shù)方法儡炼,而且魔術(shù)方法中的代碼或變量用戶可控擎浴,就可能產(chǎn)生反序列化漏洞伦吠,根據(jù)反序列化后不同的代碼可以導致各種攻擊,如代碼注入惹骂、SQL注入憔涉、目錄遍歷等等。
魔術(shù)方法:PHP的類中可能會包含一些特殊的函數(shù)叫魔術(shù)函數(shù)析苫,魔術(shù)函數(shù)命名是以符號__開頭的; 有以下的魔術(shù)方法: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set(), _state(), __clone(), __debugInfo()
參考文章
http://www.reibang.com/p/631606cc5b76
https://www.freebuf.com/vuls/116705.html
https://blog.csdn.net/qq_42196196/article/details/81217375
https://blog.spoock.com/2016/11/08/hitcon-babytrick-writeup/
<?php
include "config.php";
class HITCON{
private $method;
private $args;
private $conn;
//私有類型:該類型的屬性或方法只能在該類中使用兜叨,在該類的實例、子類中衩侥、子類的實例中都不能調(diào)用私有類型的屬性和方法
public function __construct($method, $args) {
//__construct:當使用 new 操作符創(chuàng)建一個類的實例時国旷,構(gòu)造方法將會自動調(diào)用
$this->method = $method;
$this->args = $args;
$this->__conn();
}
function show() {
list($username) = func_get_args();//func_get_args()返回一個包含函數(shù)參數(shù)列表的數(shù)組,即傳入show()函數(shù)的參數(shù)
$sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
//sprintf()把百分號(%)符號替換成一個作為參數(shù)進行傳遞的變量
$obj = $this->__query($sql);
if ( $obj != false ) {
$this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
} else {
$this->__die("Nobody Nobody But You!");
}
}
function login() {
global $FLAG;
list($username, $password) = func_get_args();
$username = strtolower(trim(mysql_escape_string($username)));//strtolower()轉(zhuǎn)小寫trim()去空格mysql_escape_string()轉(zhuǎn)義在 SQL 語句中使用的字符串中的特殊字符。
$password = strtolower(trim(mysql_escape_string($password)));
$sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password);
if ( $username == 'orange' || stripos($sql, 'orange') != false ) { //特殊字符?繞過;
//stripos() 函數(shù)查找字符串在另一字符串中第一次出現(xiàn)的位置(不區(qū)分大小寫)
$this->__die("Orange is so shy. He do not want to see you.");
}
$obj = $this->__query($sql);
if ( $obj != false && $obj->role == 'admin' ) {
$this->__die("Hi, Orange! Here is your flag: " . $FLAG);
} else {
$this->__die("Admin only!");
}
}
function source() {
highlight_file(__FILE__);
}
function __conn() {
global $db_host, $db_name, $db_user, $db_pass, $DEBUG;
if (!$this->conn)
$this->conn = mysql_connect($db_host, $db_user, $db_pass);
mysql_select_db($db_name, $this->conn);
if ($DEBUG) {
$sql = "CREATE TABLE IF NOT EXISTS users (
username VARCHAR(64),
password VARCHAR(64),
role VARCHAR(64)
) CHARACTER SET utf8";
$this->__query($sql, $back=false);
$sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')";
$this->__query($sql, $back=false);
}
mysql_query("SET names utf8"); //使用utf8編碼方式
mysql_query("SET sql_mode = 'strict_all_tables'");//嚴格模式
}
function __query($sql, $back=true) {
$result = @mysql_query($sql);//mysql_query() 函數(shù)執(zhí)行一條 MySQL 查詢茫死。
if ($back) {
return @mysql_fetch_object($result);
}
}
function __die($msg) {
$this->__close();
header("Content-Type: application/json");
die( json_encode( array("msg"=> $msg) ) );
}
function __close() {
mysql_close($this->conn);
}
function __destruct() {
$this->__conn(); //將數(shù)據(jù)寫入數(shù)據(jù)庫跪但;
if (in_array($this->method, array("show", "login", "source"))) {
@call_user_func_array(array($this, $this->method), $this->args);
} else {
$this->__die("What do you do?");
}
$this->__close();
}
function __wakeup() {
foreach($this->args as $k => $v) {
$this->args[$k] = strtolower(trim(mysql_escape_string($v)));
}
}
}
if(isset($_GET["data"])) { //偵測有無data的get獲取峦萎;
@unserialize($_GET["data"]); //跳過 __wakeup()函數(shù)屡久;調(diào)用析構(gòu)函數(shù)
} else {
new HITCON("source", array());
}
?>