SQL注入漏洞

学习:

https://mp.weixin.qq.com/s?__biz=MzA4NDk5NTYwNw==&mid=2651425615&idx=1&sn=d75b69e686537f274416bb5e30a2232a&chksm=84239037b354192146f295cf438aa4ce2f01c2a5cbba862a0199edc36e7f907b3695f0b98208&mpshare=1&scene=23&srcid=1130R4Ef9ZTWSGMrQNzl92ok

本博文为公众号推文中SQL注入漏洞使用语句的原理学习,具体实践可查看博主以前的SQL注入博文,谢谢~

SQL语句

SQL(Structured Query Language)结构化的查询语言,是关系型数据库通讯的标准语言。

查询:SELECT statement FROM table WHERE condition

删除记录:DELETE FROM table WHERE condition

更新记录:UPDATE table SET field=value WHERE condtion

添加记录:INSERT INTO table field VALUES(values)

SQL注入漏洞产生的原因

个人理解,就是代码的健壮性不够

SQL注入步骤

  1. 判断注入点
  2. 判断注入点类型
  3. 判断数据库类型
  4. 获取数据库数据库,提权

判断注入点

http://host/test.php?id=100 and 1=1 返回成功 

http://host/test.php?id=100 and 1=2 返回失败 

第一个会返回成功,而第二个是返回失败的原因是:

假设我们网站的SQL查询的语句是这样的,SELECT * FROM news WHERE id=$id$id是用户提交的),如果输入“100 and 1=1”,语句就会变成SELECT * FROM news WHERE id=100 and 1=1。这个SQL语句and左边是返回成功的,因为我们是在有这个id的情况下后面加上我们的注入语句,如果这个id不存在,那就没法测试。而在and右边,1=1也是恒成立的,所以整个语句返回的是成功。如果后面改成了1=2的话,因为1=2是不成立的,and语句的判断逻辑是只要有一个不成立,就返回失败,所以1=2最后会返回的是失败。

字符型注入点的判断:

测试方法:

http://host/test.php?name=man' and '1'='1 返回成功 

http://host/test.php?name=man' and '1'='2 返回失败 

假设我们网站的SQL语句是这样的:SELECT * FROM news WHERE name='$name',当我们构造输入为下面这个的时候“man' and '1'='1”,语句就变成了SELECT * FROM news WHERE name='man' and '1'='1'。此时这个SQL已经闭合了这里and的左边是一定成立的,而and右边也是一样的成立,所以and逻辑之后,整个语句返回成功。同理可知如果后面是1'='2就会返回失败,当然,这里不一定非要是1或者2,因为是字符型,所以我们可以输入任何字符。比如

http://host/test.php?name=man' and 'a'='a 返回成功 

http://host/test.php?name=man' and 'a'='b 返回失败 

 

搜索型注入点的判断

测试方法

http://host//test.php?keyword=python%' and 1=1 and '%'=' 

http://host//test.php?keyword=python%' and 1=2 and '%'='

假设SQL查询语句是这样的:SELECT * FROM news WHERE keyword like '%$keyword%'($keyword是用户的输入),当输入以下语句的时候“python%' and 1=1 and '%'='”,最终得到的语句是这样的SELECT * FROM news WHERE keyword like '%python%' and 1=1 and '%'='%'

可以把这个语句分为三段

SELECT * FROM news WHERE keyword like '%python%'

and 1=1

and '%'='%'

上面的判断结果一定是成功的。

但是如果把第二句换成1=2,那么这个语句肯定就会返回失败了。

内联式SQL注入

内联注入是指查询注入SQL代码后,原来的查询仍然全部执行

假设网站SQL查询语句是这样的:SELECT * FROM admin WHER username='$name' AND password ='$passwd'。假如我们构造如下语句提交到登录框中的username为' or ''=',或者提交到password框里面,这两种提交方法是不一样的,我们下面就来分析一下这两个提交方法:

提交到username我们的语句就会成为这样:SELECT * FROM admin WHER username='' or ''='' AND password ='hello',hello是我们随便输入的字符串。

而提交到password则会是这样的:SELECT * FROM admin WHER username='hello' AND password ='' or ''=''

SQL语句中,AND的优先级是大于OR的,于是会先计算AND,然后之后才会计算OR,所以这里我们的语句会被OR分为两段SQL语句

username框的

SELECT * FROM admin WHER username=''

or

''='' AND password ='hello'

password框的

SELECT * FROM admin WHER username='fuzz' AND password =''

or

''=''

首先计算AND之后

SELECT * FROM admin WHER username=''  返回失败

or

''='' AND password ='fuzz' 返回失败

数据库是不会存在usernameNULL的字段的,第一句失败,第三句中,因为password是很可能不会存在的,AND之后,第三句也是失败的,所以整个语句返回失败的。

password情况:

SELECT * FROM admin WHER username='fuzz' AND password =''

or

''=''

第一句是失败的,但是第二句''=''是返回成功的,OR逻辑是有一个是成功就返回成功,整个语句就会返回成功,返回成功之后我们就会绕过登录表单直接登录系统了。

终止式SQL注入

终止式SQL语句注入是指攻击者在注入SQL代码时,通过注释剩下的查询来成功结束该语句,被注释的查询不会被执行。

若在username框内填入' or ''=',程序是不会返回成功的但如果使用终止式注入,还是上面那个SQL查询语句

SELECT * FROM admin WHER username='$name' AND password ='$passwd'

这里构造如下username输入' or ''='' --,就可以得到如下的查询语句

SELECT * FROM admin WHER username='' or ''='' --' AND password ='fuzz'

fuzz是我们随便输入的,--是注释符

这样,语句就可以分为三个部分:

SELECT * FROM admin WHER username=''

or ''='' 返回成功

--' AND password ='fuzz'

可以成功通过在username做这个手脚来绕过登录。

常见的终止字符串:

 -- , #, %23, %00, /* 

终止方法:

 -- , ‘-- , ‘)-- , ) -- , ‘)) --, ))--

注入点位置的判断

所有的输入只要和数据库进行交互的,都有可能触发SQL注入

常见的包括:

Get参数触发SQL注入

POST参数触发SQL注入

Cookie触发SQL注入

常见网站架构:

asp + access

asp + mssql

asp.net + mssql

php + mysql

Jsp + oracle

Jsp + mysql

常用的注入方法有:

1.UNION注入

UNION是数据库管理员经常使用且可以掌控的运算符之一,可以使用它连接两条或多条SELECT语句的查询结果

其基本语法如下:

SELECT colum1,colum2,colum3,…,columN FROM table1

UNION

SELECT colum1,colum2,colum3,…,columN FROM table2

如果应用返回第一个(原始)查询得到的数据,那么通过在第一个查询后注入一个UNION运算符,并添加另一个任意查询,便读取到数据库用户有权限访问的任何一张表。

使用规则为:

  1. 两个查询返回的列数必须相同
  2. 两个SELECT语句返回的数据库对应的列必须类型相同或兼容
  3. 通常只有终止式注入时,可较快猜解并利用,否则要知道原始的SQL语句才能比较方便的利用

UNION语句的构建

(1)确定列数量

UNION SELECT null,null,null,…,null FROM dual

使用逐步增加null数量,直到匹配原语句的列数量,成功匹配后返回正常页面

这是利用了<两个查询返回的列数必须相同>这个原理

使用ORDER BY确定原语句列数量, 可使用折半查找法提高猜测效率

(2)确定列类型

UNION SELECT 1,’2’,null,…,null FROM dual

先猜测第一列为数字,如果返回结果不正确,则判断为字符

如果还是不正确则保持null不变(可能为二进制类型),之后依次完成部分或全部类型的判断

Union不适用的地方

注入语句无法截断,且不清楚完整的SQL查询语句

Web页面中有两个SQL查询语句,查询语句的列数不同

枚举数据库

1.SQL Server

获取当前用户名

id=12 UNION SELECT null, null, user, null FROM master..sysdatabases

获取数据库列表

id=12 UNION SELECT null, null, name,null FROM master..sysdatabases

获取当前数据库名

id =12 UNION SELECT null,null,db_name(),null FROM master..sysdatabases

获取表名

id=12 UNION SELECT null,null,name,null FROM sysobjects where xtype=‘u’

获取字段名

id =12 UNION SELECT null,null,col_name(object_id(‘table_name’), 1), null FROM sysobject

2.MySQL

获取当前用户

SELECT user()

获取数据库列表

SELECT schema_name FROM information_schema.schemata

获取当前数据库

SELECT database()

获取表名

SELECT table_name FROM information_schema.tables WHERE table_schema='some_db'

获取字段名

SELECT  some_columns  FROM information_schema.columns WHERE table_name='some_name' 

3.Oracle

Oracle只能访问一个数据库,无法枚举数据库

获取当前用户表名

SELECT table_name FROM user_tables

获取所有表名及拥有者

SELECT owner, table_name FROM all_tables

获取字段名

SELECT column_name FROM user_tab_columns WHERE table_name='table'

猜你喜欢

转载自blog.csdn.net/qq_37865996/article/details/84668916