---
# System prepended metadata

title: SQL期中報告

---

# SQL期中報告

[toc]


---
java -jar webgoat-server-8.2.1.jar --server.port=8080 --server.address=localhost

• http://localhost:8080/WebGoat

---
{PAGE 1}
## 前言

今天我要介紹的主題是SQL Injection (中文翻譯是SQL注入)

那為何選擇這個主題呢?
身為資管系的學生，在大二大多都有修過資料庫和網頁程式設計。
也學過了SQL語言，它是管理和查詢資料庫的關鍵工具。我們了解了資料庫是如何運作的，以及如何儲存和擷取數據。

而SQL注入攻擊能讓駭客對我們的資料庫造成資料外洩和損害。
這讓我開始思考，我們在課堂上學習到的技能，要如何應對現實世界中的資安挑戰。

---

{PAGE 2}
## 什麼是SQL Injection?

SQL Injection是指利用Web應用程式中的漏洞，將惡意SQL語句注入到資料庫中，進而竊取、修改或刪除敏感資料。這種攻擊方式已經成為網際網路上最常見的攻擊技巧之一。

---
{PAGE 3}
SQL injection和我們的生活並沒有那麼有距離
舉例來說:
大家可能習慣使用社群軟體來分享生活，如果這些社交平台受到SQL注入攻擊，
駭客就可以**竊取你的個人資料和帳號**，並在網絡上以你的名義進行不當的活動。
> EX:像是盜用你的facebook帳號賣airpod來詐騙XD

那相信大家也經常網購吧~不管是在蝦皮、淘寶、momo，或是
 
「哇~
這個韓國海苔看起來好好吃!
上百萬種，韓國美國，人氣選品
價格超划算~又免運!」

恩對，在網購平台上，有些人會綁定信用卡。那如果網購平台受到SQL注入攻擊呢?
我們可能會被竊取信用卡資訊，導致金融訊息和個資的洩漏。

---
{PAGE 4}
## SQL injection (intro) 
### 特殊字符

- 註釋 ->把後半段需要閉合的引號
![](https://hackmd.io/_uploads/B1DcN_8GT.png)
	```
	SELECT * FROM users WHERE name = 'admin' -- AND pass = 'pass'
	等同於
	SELECT * FROM users WHERE name = 'admin'
	```
---
{PAGE 5}
- 分號 ->把前面的SQL語句中斷，後面可以連接新的語句
	![](https://hackmd.io/_uploads/r1Jn4d8za.png)
	```
	SELECT * FROM users; DROP TABLE users;
	等同於
	SELECT * FROM users;
	DROP TABLE users;
	```
---
{PAGE 6}

### 簡單介紹SQL注入方式
假設一個網頁的欄位，它讓使用者輸入名字就可以查看使用者資訊。
使用者的輸入會被傳送到伺服器並插入 SQL 查詢中，然後由 SQL interpreter進行處理並回傳資料。

![](https://hackmd.io/_uploads/S1zhmsIM6.png)

**變數userName會儲存使用者的輸入，並將其「注入」到查詢中。**
> 如果輸入是 Smith，則查詢名為 Smith 的使用者的所有資料

SQL注入的用途不止能讀取使用者的資料。
以下是其他範例：
1. 運用類似'1'='1'的true/false判斷式
![](https://hackmd.io/_uploads/ByOgRy8Ga.png)
將傳回使用者表中的所有項目
> 輸入被傳送到伺服器並插入 SQL 查詢中，然後由 SQL interpreter進行處理。

2.  用分號或注釋功能去新增新sql式在後方
![](https://hackmd.io/_uploads/S1jf0yIM6.png)
連結多個 SQL 命令，可以 DROP users table並刪除audit_log table中的所有項目

---
### 情境題
1. 假如今天有兩張Table: 分別是 **user_data** 和 **user_system_data**

![](https://hackmd.io/_uploads/ByenwwmGT.png)

2. 想從表格中select所有資料，以及拿到Dave的帳號密碼

![](https://hackmd.io/_uploads/ryZ08xLGa.png)

有兩種做法，可以使用 UNION，也可以在原本的輸入後面加上新的 SQl 語句。

3. 在輸入框輸入:
`abc'; SELECT * from user_system_data--`
就可以得到user_system_data的資料了

![](https://hackmd.io/_uploads/Hka0DP7z6.png)

> 建議可以利用瀏覽器的開發者工具，把想好的sql句直接填入HTML裡邏輯會比較好懂。

## 特殊語法
### Union
「Union」可以把將兩個 SQL 語句的結果合併起來，但有一個限制是:
**兩個 SQL 語句所產生的欄位需要是同樣的資料種類** 
![](https://hackmd.io/_uploads/SklZ7n8Mp.png)

### 情境題
1. 假如今天有兩張table，要我們想用union的方式爆出Dave的密碼
![](https://hackmd.io/_uploads/S1S3wv7zp.png)

我們需要用到user_system_data的資料，這裡有兩點需要注意:
1. 使用UNION SELECT 需要**前後兩張table的總列數相符**。
2. user_data(第一個table)有7個欄位，所以接在union後的SQL式也必須要列出7個欄位。
3. 由於題目中已知user_system_data(第二個table)只有4個欄位，剩下的3個欄位要跟第一張表格(user_data)的最後三個欄位資料種類。

> 一開始寫的是`UNION SELECT`,結果可以看到報錯為: `duplicate column name in derived table`。 是因為兩張表中都有userid列，而第二張表的userid還是主鍵。 所以我們需要在*前指定表名。

2. 用單引號’把last_name給閉合，後面用union select來查詢:
`d' and 1=2 UNION SELECT user_system_data.*,NULL,NULL,NULL from user_system_data --`

![](https://hackmd.io/_uploads/HyL09PXfa.png)
-> 取得table的內容和Dave的密碼，成功爆出資料

---
## Blind (盲注)
前面提到的狀況中，網頁會返回完整的信息，包括**資料庫的報錯還有完整的查詢結果**。 
但在現實的大多數情況下，**資料庫只會回傳查詢是成功還是失敗**，獲得的資訊減少會增加了SQL注入的難度。

接著來介紹一種叫做Blind SQL Injection(中文翻譯為盲注)的技術
之前介紹的方式是:
透過利用系統因為讀取到錯誤SQL式的報錯，來決定要寫什麼SQL語法

盲注則不一樣:
**系統不會有明確的錯誤訊息，要靠觀察伺服器有沒有回應來判斷SQL式是不是有用。**


### 情境題
1. 有個網站的網址是「hxxps://my-shop.com?article=4」，可以先推測這個網址的含意是要顯示資料庫中第4篇文章。

2. 在資料庫進行查詢的SQL式可能會是：
`SELECT * from articles where article_id = 4`

3. 要如何驗證呢？
透過把參數改為「4 AND 1 = 1」，看看網頁的反應。
這時資料庫中的SQL式可能就變成：
`SELECT * from articles where article_id = 4 AND 1 = 1`

4. 如果發現顯示的頁面跟原本的一樣，就可以進行下一個驗證步驟。
如果顯示的頁面不一樣(ex:出現404 Page not found或其他的錯誤)，就代表這個網頁沒辦法應用盲注的技術。

5. 把參數改為「4 AND 1 = 2」看網頁的反應
這時資料庫中的SQL式可能就變成如下：
`SELECT * from articles where article_id = 4 AND 1 = 2`
如果發現頁面資料無法正常顯示，就可以更加肯定這裡是可以應用盲注的技術，因為上述的SQL語法的邏輯是錯誤的，所以就會導致頁面無法正常顯示。

## Demo

:::info
目標: 以 tom 帳戶登錄系統，目前我們並不知道 tom帳號名稱 以及 table 的結構。
有兩個頁面:
1.登入頁面(需要輸入使用者名稱和密碼)
2.註冊頁面(需要使用者名稱、密碼、信箱)
![](https://hackmd.io/_uploads/r1YSpd8f6.png)

![](https://hackmd.io/_uploads/HJoQpuLGT.png)
:::

### 方法

1.  先看登入頁面能不能直接登入
回傳:No results matched. Try Again.

![](https://hackmd.io/_uploads/Skcy3xLMT.png)

看了登入帳號頁面的sourse code，發現使用預編譯(prepared statement)功能，也使用了問號對sql語句進行了佔位(place holder)，因此是這個登入介面比是較安全的。

![](https://hackmd.io/_uploads/B1_9J64zp.png)

查看註冊帳號頁面的source code，發現輸入的參數是直接嵌入到SQL語句中，比較不安全。
這裡有個式子判斷新用戶輸入的名字是否是tom，可以猜測SQL注入點就是這裡，因為**正常情況下是不會有參數+單引號的判斷句**

![](https://hackmd.io/_uploads/Sy0tAnVfp.png)


2.  用tom的名字註冊帳號
註冊後系統回傳"tom已經存在"，說明題目中的tom帳號的使用者名稱就是tom。

3. 在輸入用戶名的欄位填入`tom' and 1=1 --`
系統表示"帳戶已經存在"：
`User {0} already exists please try to register with a different username.`

![](https://hackmd.io/_uploads/ryTj9iVG6.png)

> 這個{0}看著相當可疑…感覺可能是個能夠利用的點。

4. 測試` tom' and 1=2 --`
系統表示"帳戶成功建立"，說明這部分應該是一個注入點。
因為後端的判斷條件執行了 and 1=1和and 1=2，1=2的條件不成立，所以後端認為這個帳戶原本是不存在的。

5. 使用BurpSuite截取請求
配置burpsuite的代理後訪問webgoat的這道題目，然後在proxy的歷史裡面找到這個request並儲存到本機

6. 用 sqlmap 進行注入的測試。
sqlmap顯示了"基於true/false的盲注"和"time-base的盲注"。
> 雖然可以使用SQL Map這類的工具來幫助我們完成一些自動化的SQL注入操作，但對於SQL語句基本原理的理解可以最大化發揮工具的價值。

7. 透過true/false來猜密碼

我需要得知密碼的"欄位"和"長度"
密碼的欄位可以猜一下，從burp suite在註冊頁面捕捉到的內容，能看到密碼欄位是password_reg，猜測密碼是password

![](https://hackmd.io/_uploads/H1bmxDBG6.png)

先註冊一個使用者叫zhouss的帳號，然後猜測密碼欄位名稱為password
在使用者名稱的輸入框填入:
`username_reg=zhouss' or length(password)=1--`
> 這裡用length來判斷密碼長度只是為了驗證password這個欄位是否存在，因為使用的是or來連接兩個條件，所以只要使用者名稱是tom，那麼最終後端的語句執行結果都會是true
 
![](https://hackmd.io/_uploads/BkJjSwBfa.png)

系統回傳"帳號已經存在"，說明 password這個欄位 是存在的。
如果不存在，伺服器會回傳沒找到這個欄位而報錯。

### Final
`' UPDATE sql_challenge_users SET password = '12345';--`

![](https://hackmd.io/_uploads/ry5hTk_Gp.png)

![](https://hackmd.io/_uploads/H1GCa1_z6.png)

---
8. 猜測tom帳號的密碼長度
填入了:
`username_reg=tom' and length(password)=1--`

因為需要判斷tom的密碼長度，所以換成and來連接，也就是兩個條件都得滿足，伺服器才會回傳帳號已經存在。
先從長度為1開始嘗試輸入，伺服器回傳"成功創建帳號"。
也就是代表length(password)=1這個條件失敗，需要繼續增加password欄位長度，直到回傳"帳戶已經存在"。

![](https://hackmd.io/_uploads/SyJ1UwSM6.png)

試到密碼長度為23的時候終於顯示"帳號已經存在"
![](https://hackmd.io/_uploads/ryykNvHMp.png)


9. 爆破密碼
在知道了tom的密碼長度後，就可以透過substring函數來產生true/false判斷

傳回的結果如果顯示"帳戶已經存在"，代表密碼對應位置的值判斷成功，反之判斷失敗。

先來簡單測試，在輸入框填入：
`substring(password,1,1)='1' --`
對password的第一位開始的第一個字元進行判斷，考慮到後面爆破的時候可能會有字母或特殊字，所以判斷的值用引號，實測能匹配數字1。 
![](https://hackmd.io/_uploads/SkucVDrMT.png)

> Burp Suite 是一款暴力破解密碼的軟體，運用不斷的嘗試來獲取密碼

這裡加入了兩個變量:
一個是密碼的位置從1-23，一個是密碼位置對應的值。
attack type選擇爆破模式，也就是每個變量的payload都會和其他payload進行逐一匹配

![](https://hackmd.io/_uploads/rkeYdwHf6.png)

第一個payload配置數字1-23

![](https://hackmd.io/_uploads/H1GTFwBM6.png)


第二個payload配置大小寫的英文字母和常見的特殊字符

![](https://hackmd.io/_uploads/HkGSrUSGa.png)

為了查看結果方便，配置grep match過濾匹配，把response裡包含 "already exists"的結果標記
> 因為傳回的結果顯示"帳戶已經存在"，代表密碼對應位置的值判斷成功。

![](https://hackmd.io/_uploads/rkDdrIHMa.png)

11. 對結果進行排序
開始攻擊以後終於顯示結果了，對grep的結果進行排序
![](https://hackmd.io/_uploads/HyCa5vSG6.png)

剩下的就是依序拿答案了，抄出來的結果是 thisisasecretfortomonly

測試登入： 用tom的帳號密碼登入成功!

![](https://hackmd.io/_uploads/HkvGuISMT.png)

---
#### 結語:
基本上，現在已經有很多好用的研究工具了，採用好的自動化工具對避免SQL注入攻擊很有效。
我認為深入學習SQL injection，並了解如何預防注入攻擊，有助於我們在寫程式的時候不容易產生相關漏洞，能夠保護我們的個人信息。

我的報告到這邊差不多結束了，期末我會在介紹有關防禦SQL注入的部分，希望大家有因此對SQL注入的原理更加了解。

---
#### 參考資料
https://ithelp.ithome.com.tw/articles/10207336
https://youtu.be/yusJWttsD5o?si=801gq8wxI0nU6T8P
https://www.hacksplaining.com/exercises/sql-injection#/first-login-attempt
https://blog.csdn.net/weixin_44023403/article/details/112550339
https://hackmd.io/@foxo-tw/slides/%2Fp%2FHkdGf-naE
