SQLi


免责声明

本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.


大纲

  • 注入检测

  • MySQL

  • MSSQL

  • Oracle

  • H2 database

  • BigQuery

  • SQLite


描述

注入攻击的本质,是程序把用户输入的数据当做代码执行。这里有两个关键条件,第一是用户能够控制输入;第二是用户输入的数据被拼接到要执行的代码中从而被执行。sql 注入漏洞则是程序将用户输入数据拼接到了 sql 语句中,从而攻击者即可构造、改变 sql 语义从而进行攻击。

教程

payload

在线 SQLi 测试

  • http://demo.testfire.net/

  • https://juice-shop.herokuapp.com/#/search

  • https://sqlchop.chaitin.cn/demo/

相关工具

  • sqlmap

    • sqlmap 笔记

提权工具


SQL 注入常规利用思路

注入的分类

  • 基于响应类型

    • 报错

    • 联合查询

    • 堆叠注入

    • 盲注

      • 基于布尔

      • 基于时间

  • 基于数据类型

    • 字符型

    • 数字型

    • 搜索型

  • 基于语句类型

    • 查询型

    • 插入型

    • 删除型

  • 基于程度和顺序

    • 一阶注入 : 指输入的注入语句对 WEB 直接产生了影响,出现了结果;

    • 二阶注入 : 类似存储型 XSS,是指输入提交的语句,无法直接对 WEB 应用程序产生影响,通过其它的辅助间接的对 WEB 产生危害,这样的就被称为是二阶注入.

  • 基于注入点的位置

    • 通过用户输入的表单域的注入

    • 通过 cookie 注入

    • 通过服务器变量注入 : 例如基于头部信息的注入


注入检测

可以通过多种方式检测注入。其中最简单的方法是在各种参数后添加 '" 从而得到一个从 Web 服务器返回的数据库报错信息。

找注入点

  • GET - HTTP Request

    在常见的 HTTP GET 请求(以及大多数请求类型)中,有一些常见的注入点。例如:网址参数(下面的请求的 id),Cookie,host 以及任何自定义 headers 信息。然而,HTTP 请求中的任何内容都可能容易受到 SQL 注入的攻击。

  • POST - Form Data

    在具有 Content-Type 为 application/x-www-form-urlencoded 的标准 HTTP POST 请求中,注入将类似于 GET 请求中的 URL 参数。它们位 于HTTP 头信息下方,但仍可以用相同的方式进行利用。

  • POST - JSON

    在具有 Content-Type 为 application/json 的标准 HTTP POST 请求中,注入通常是 JSON{"key":"value"} 对的值。该值也可以是数组或对象。虽然符号是不同的,但值可以像所有其他参数一样注入。(提示:尝试使用 ',但要确保 JSON 使用双引号,否则可能会破坏请求格式。)

  • POST - XML

    在具有 Content-Type 为 application/xml 的标准 HTTP POST 请求中,注入通常在一个内部。虽然符号是不同的,但值可以像所有其他参数一样注入。(提示:尝试使用 '

检测注入

通过在应用程序中触发错误和布尔逻辑,可以最轻松地检测易受攻击的参数。提供格式错误的查询将触发错误,并且使用各种布尔逻辑语句发送有效查询将触发来自Web服务器的不同响应。

注:True 或 False 语句应通过 HTTP 状态码或 HTML 内容返回不同的响应。如果这些响应与查询的 True/False 性质一致,则表示存在注入。

  • 万能密码

  • 逻辑测试

    • 1.php?id=1 or 1=1 -- true

    • 1.php?id=1' or 1=1 -- true

    • 1.php?id=1" or 1=1 -- true

    • 1.php?id=1 and 1=2 -- false

    • 1.php?id=1-false

    • 1.php?id=1-true

  • 算术

    • 1.php?id=1/1 -- true

    • 1.php?id=1/0 -- false

  • 基于盲注

  • 基于错误

判断数据库类型

  • 注释符判断 /* 是 MySQL 中的注释符,返回错误说明该注入点不是 MySQL,继续提交如下查询字符:- 是 Oracle 和 MSSQL 支持的注释符,如果返回正常,则说明为这两种数据库类型之一。继续提交如下查询字符:;是子句查询标识符,Oracle 不支持多行查询,因此如果返回错误,则说明很可能是 Oracle 数据库。

  • 函数判断 and (select count()from MSysAccessObjects)>0 返回正常说明是 access 数据库, and (select count()from sysobjects)>0 返回正常说明是 mssql 数据库 and length(user())>10 返回正常说明是 Mysql Oracle 可以根据 from dual 虚拟库判断


MYSQL

靶场

  • https://github.com/Audi-1/sqli-labs

    • sqli-labs

相关文章

资源

监控工具

MySQL 基础

  • MySQL

注释

数据库名

表名

列名

根据列名查询所在的表

条件语句

延时函数

order by 后的注入

简单判断

order by 由于是排序语句,所以可以利用条件语句做判断,根据返回的排序结果不同判断条件的真假。一般带有 order 或者 order by 的变量很可能是这种注入,在知道一个字段的时候可以采用如下方式注入:

宽字节注入

国内最常使用的 GBK 编码,这种方式主要是绕过 addslashes 等对特殊字符进行转移的绕过。反斜杠 \ 的十六进制为 %5c,在你输入 %bf%27 时,函数遇到单引号自动转移加入 \,此时变为 %bf%5c%27,%bf%5c 在 GBK 中变为一个宽字符「縗」。%bf 那个位置可以是 %81-%fe 中间的任何字符。不止在 SQL 注入中,宽字符注入在很多地方都可以应用。

oob

如果不成功,可能是访问 oob 域名的流量被拦截了,也可能是由于没开启文件导入导出

文件导出

正则表达式攻击

在 MYSQL 5+ 中 information_schema 库中存储了所有的库名,表名以及字段名信息。

  1. 判断第一个表名的第一个字符是否是 a-z 中的字符,其中 blind_sqli 是假设已知的库名。

注:正则表达式中 ^[a-z] 表示字符串中开始字符是在 a-z 范围内

  1. 判断第一个字符是否是 a-n 中的字符

  1. 确定该字符为 n

  1. 表达式的更换如下

这时说明表名为 news ,要验证是否是该表名 正则表达式为 '^news$',但是没这必要 直接判断 table_name = 'news' 即可。

  1. 接下来猜解其它表了

regexp 匹配的时候会在所有的项都进行匹配。例如:security 数据库的表有多个,users,email 等

实验表名:在 limit 0,1 下,regexp 会匹配所有的项。我们在使用 regexp 时,要注意有可能有多个项,同时要一个个字符去爆破。类似于上述第一条和第二条。而 limit 0,1 对于 where table_schema='security' limit 0,1 来说 table_schema='security' 已经起到了限定作用了,limit 有没有已经不重要了。

bypass 技巧

常见的绕过技巧

函数替换

  • 连接

  • benchmark 代替 sleep

  • 字符串截取函数

  • 字符串连接函数

  • 字符转换/编码

函数与括号之间

执行语句之间

括号包裹

省略空格

注释配合换行符

绕过引号限制

绕过字符串黑名单

json 函数

MySQL 5.7.8 开始新增了很多操作 json 数据的函数

提权/GETSHELL

  • Mysql提权


MSSQL

基于ASP / ASPX的应用程序一般都是 MSSQL。

学习资源

靶场

相关文章

相关案例

相关工具

MSSQL 基础

  • MSSQL

基本参数

查询密码HASH

正则表达式攻击

MSSQL 所用的正则表达式并不是标准正则表达式 ,该表达式使用 like 关键词

该查询语句中,select top 1 是一个组合,不要看错了。

如果要查询其它的表名,由于不能像 mysql 那样用 limit x,1,只能使用 table_name not in (select top x table_name from information_schema.tables) 意义是:表名没有在前 x 行里,其实查询的就是第 x+1 行。

例如查询第二行的表名:

表达式的顺序:

之所以表达式 news[a-z] 查询后返回正确是应为 % 代表 0-n 个字符,使用 "_" 则只能代表一个字符。故确认后续是否还有字符可用如下表达式

同理可以用相同的方法获取字段,值。这里就不再详细描述了。

bypass 技巧

select from 后的位置

  • 空白符号

    需要做 urlencode,sqlserver 中的表示空白字符比较多,靠黑名单去阻断一般不合适.

  • 注释符号

    Mssql 也可以使用注释符号 /**/

  • . 符号

  • :

select from 之间的位置

  • 空白符号

  • 注释符号

  • :

and 之后的位置

  • 空白符号

  • 注释符号

  • :

  • %2b

常见过滤函数

  • 字符串截取函数

  • 字符串转换函数

  • Mssql 支持多语句查询,因此可以使用;结束上面的查询语句,然后执行自己构造的语句.动态执行.

    使用 exec 的方式:

    使用 sp_executesql 的方式:

提权/GETSHELL

  • MSSQL提权


oracle

用于是否是判断 oracle 数据库的方法

相关案例

bypass 技巧

oracle 中文版中,中文括号 ( )可以代理英文且不报错


H2 database

相关文章


BigQuery

相关文章

Playground

  • https://console.cloud.google.com/bigquery

信息收集


SQLite

SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,你不需要在系统中配置。

SQLite 数据库的特点是它每一个数据库都是一个文件,当你查询表的完整信息时会得到创建表的语句。

相关文章

SQLite 基础

  • https://www.runoob.com/sqlite/sqlite-commands.html

注释

查看版本

查询表名和列名

布尔盲注

布尔盲注通过查询正确和错误返回的页面不同来判断数据内容。

SQLite不支持ascii,所以直接通过字符去查询,这里和mysql不同,这个区分大小写。也没有mid,left等函数。

时间盲注

SQLite没有sleep()函数,但可以用randomblob(N)函数,randomblob(N) 函数,其作用是返回一个 N 字节长的包含伪随机字节的 BLOG。N 是正整数。可以用它来制造延时。SQLite没有if,所以需要使用case……when来代替。

写 webshell

SQLite 的 ATTACH DATABASE 语句是用来选择一个特定的数据库,使用该命令后,所有的 SQLite 语句将在附加的数据库下执行。

如果附加数据库不存在,就会创建该数据库,如果数据库文件设置在web目录下,就可以写入webshell。


Postgresql

相关文章

Postgresql 基础

  • Postgresql

忽略

||

|| 可用于将数据附加到同一行的输出中

通过延时判断是否是 Postgresql 数据库的方法

SELECT

FROM

WHERE

HAVING

OFFSET

当注入点在 WHERE 时

可以配合 ||

bypass 技巧

注释

代替引号

query_to_xml

query_to_xml 可以将结果返回在一行里,不必担心限制或多行

DATABASE_TO_XML

使用 xml 帮助程序通过单个查询转储整个数据库

提权/GETSHELL

  • Postgresql提权