问题原因:漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术方法中的代码或变量用户可控,就可能产生反序列化漏洞,根据反序列化后不同的代码可以导致各种攻击,如代码注入、SQL注入、目录遍历等等。
魔术方法:PHP的类中可能会包含一些特殊的函数叫魔术函数,魔术函数命名是以符号__开头的; 有以下的魔术方法: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set(), _state(), __clone(), __debugInfo()
参考文章
https://www.jianshu.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/
method = $method;
$this->args = $args;
$this->__conn();
}
function show() {
list($username) = func_get_args();//func_get_args()返回一个包含函数参数列表的数组,即传入show()函数的参数
$sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
//sprintf()把百分号(%)符号替换成一个作为参数进行传递的变量
$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()转小写trim()去空格mysql_escape_string()转义在 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() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)
$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() 函数执行一条 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(); //将数据写入数据库;
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()函数;调用析构函数
} else {
new HITCON("source", array());
}
?>