0x01 前言
在渗透测试过程中,SQL注入依然是最常见的漏洞之一。通过对目标网站的不断探索和漏洞分析,我们发现了该站点的SQL注入问题,并通过一系列绕过手段成功获取了数据库信息。本文记录了从发现漏洞到成功利用的整个过程,分享了一些典型的绕过技巧和方法,希望能为有类似测试需求的同仁提供参考。
参考文章:https://xz.aliyun.com/news/17055、https://xz.aliyun.com/news/17077
现在只对常读和星标的公众号才展示大图推送,建议大家把渗透安全HackTwo“设为星标”,否则可能就看不到了啦!
末尾可领取挖洞资料文件
0x02 漏洞详情
访问站点
打开burpsuite,配置代理等完成一系列抓取流量的配置操作后,开始访问目标系统
发现只有一个登录框。
我们随便输入账号密码,点击登录,观察请求包和响应包
发现提示账号不存在(其实一个小漏洞,用户名遍历已到手)。
注意此时我们的路径是/dev-api/auth/login。
注册接口猜测
根据我们登录接口,猜测一下注册接口是在/dev-api/auth/register。
如何验证猜测,使用浏览器打开站点,F12打开开发者工具,全局搜索
**/register**
发现确实存在/auth/register。
按照相同的格式和搜索方法,我们再搜索一下/auth/login。
发现就在旁边。
接着在burpsuite修改接口访问路径,尝试访问注册接口:
成功!响应码返回200(可能是restful api规定的一个统一响应),并且响应体里显示服务器内部错误500并提示当前系统没有开启注册功能。
接下来我们修改username、password的长度,发现皆有提示为:
账户长度必须在2到20个字符之间。
用户密码长度必须在5到20个字符之间。
于是我们可以确认,注册接口是存活的,但是注册功能没有开启,因为我们的请求体的数据,确实后端处理,并返回给我们结果。
注册接口sql注入
此时其实可以大胆猜测,前面我的login处无法进行sql注入,因为后端可能重点关注的是用户名和密码并做了强过滤,很难找到注入点。
但是,注册接口已经被禁止了,并且提示是当前系统没有开启注册功能,可以得到的结论是,我们的请求体一定发送到了后端,那么后端有以下2种逻辑:
先将请求体传递给服务器处理,创建账号并存入数据库,
检查是否开启注册功能,如果没有开启,则账号不启用,并返回没有开启注册功能。
注意,以上都涉及到了检查操作,如果是第一种情况,那么我们的请求体,肯定也会被sql语句加载进数据库进行查询,比如是否重复注册、符合规范等等。
如果是第二种情况,数据库里可能有表项是用于设置是否开放注册的,比如register:value,value可能是0或1,也可能是false或true。
接下来,构造请求包
{"tenantId":"'","username":"1sssss","password":"sdsdawdssx.","rememberMe":true,"clientId":"e5cd7e4891bf95d1d19206ce24a7b32e","grantType":"password"}
提示报错,很明显的报错注入,并且sql语句为:
SQL: SELECT config_id, config_name, config_key, config_value, config_type, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time FROM sys_config WHERE (config_key = ?) AND tenant_id = '''
发现共有12列,开始使用union尝试找出数据库名
payload:
{"tenantId":"'UNION SELECT 1,2,3,4,5,6,7,8,9,database(),11,12 -- -","username":"1sssss","password":"sdsdawdssx.","rememberMe":true,"clientId":"e5cd7e4891bf95d1d19206ce24a7b32e","grantType":"password"}
得到root@localhost,成功注入。
接下来就是保存请求到本地,使用sqlmap一把梭
0x03 SQL注入的绕过
在功能点的某处发有几个数据包出现了报错。同时,发现报错信息中返回了SQL语句。最后在逐步测试中,确认了这个包的参数存在注入:
哎,那很好了。通过上图的报错信息我们可得,最后面的报错信息是:in(''),说明呢,这一段语句原来应该是:
select * from xlz whereidin ($id);
我就简单还原一下,大致是这样基本没有问题了。那么同时,单引号被转换成了
反斜杠+单引号,说明这里有函数对单引号进行转义。经过测试呢,这个位置出现单引号、双引号、斜杠之类的会直接报错:
接下来,在数据库里造一下语句给大家展示一下:
那么我们后续的Payload,基于这个格式就包没有问题。
长度判断
经过构造构造构造,最后使用的Payload如下所示:
11)AND(CASE+WHEN(1=1)+THEN+1+ELSE+exp(710)+END
很显然没毛病,接下来二分法判断库名长度:14
接下来,尝试截取字符串,获取库名。但是,显然某个地方出现了问题,我盲猜一波,有东西被过滤了:
手拿把掐
依照我一坤年的注入经验来看,前面的语句都没有问题,但是来到substr()函数时爆炸了。那么,大概率是逗号被干掉了,那么我们可以:
可以用from for来代替逗号,如下:
让我们套进数据包,发包看看怎么事:
果然我的经验没毛病,接下来直接改一下再往里套:
又忘了件事,出现单引号会被转义。但是获取库名时,字符串是需要被引号包裹的。此时引号又不能用怎么办?那就改造Payload,加入Ascii码函数来转换为十进制:
11)AND(CASE+WHEN(ascii(Substr(database()+from+1+for+1))=1)+THEN+1+ELSE+exp(710)+END
没问题了,直接开爆:
库名已出
0x04 总结
有时隐藏的、功能关闭的接口,未必是无法访问的,并且我们可以在请求体里fuzz多测试一些payload等。另外,http请求的响应为200也未必代表sql没有出错,restful api的风格有可能将真正的错误码放置在响应体里。多思考有哪些东西,是需要后端数据库进行查询的,凡数据,皆查询。喜欢的师傅可以点赞转发支持一下谢谢!
原文始发于微信公众号(渗透安全HackTwo):如何利用隐藏功能点发现SQL注入漏洞和注入绕过技巧|挖洞技巧
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论