仿生人正在看著網頁山羊吃草,但不知道哪個沒良心的人在牠吃的其中一根草上貼了一張[草,接著飛上天空爆炸]的標籤......今天的煙火真美啊
昨天我們已經了解到了SQL一些基本指令的用法,所以今天我們可以來正式說明SQL injection了
SQL Injection 是一種由於程式設計時使用字串拼接這種不安全的編寫方法所導致的漏洞,從而使有心人可以透過特定的輸入方法進行滲透
假設我們有一個名叫做USERS的資料表格,裡面存有兩個人的資料,第一個叫STEVE,第二個叫ALEX
我們用字串拼接寫查詢方法的話大概會長這樣
String sql = "SELECT * FROM USERS WHERE user_name = '" + username_input + "'";
如果正常輸入STEVE的話,資料庫會執行
SELECT * FROM USERS WHERE user_name = 'STEVE';
資料庫執行指令時,就會拿每筆資料中user_name裡面的資料進行比對
對於資料1:這欄的user_name值是'STEVE',正確,輸出這列所有資料
對於資料2:這欄的user_name值是'ALEX',錯誤,不輸出資料
看起來有正常運行對吧? 但如果有心人輸入了' OR '1' = '1 這種惡意輸入的話,資料庫內就會執行下面的指令
SELECT * FROM USERS WHERE user_name = '' OR '1' = '1';
前面輸入的'會和程式設計者指令的第一個'結合在一起變成一個空字串''
後面的OR '1' = '1會和指令結尾的'結合成為WHERE的新的一個判斷標準OR '1' = '1'
這樣的話就會導致
對於資料1:
這欄的user_name的值'STEVE'不等於'',但是'1' = '1'恆為TRUE,FALSE OR TRUE,所以會輸出資料1的所有資料
對於資料2:
這欄的user_name的值'ALEX'不等於'',但是'1' = '1'恆為TRUE,FALSE OR TRUE,所以也會輸出ALEX的所有資料
現在我們知道SQL injection發生的基本原理了,讓我們來進入實戰!

這題算是小試身手了,畢竟甚至連指令都不用自己手打
題目要我們將下面的選項換到拼起來剛好是SQL injection的,那我們就先來看原始程式碼
"SELECT * FROM user_data WHERE first_name = 'John' AND last_name = '" + lastName + "'";
在SQL資料庫裏面跑的時候就會變成這樣
SELECT * FROM user_data WHERE first_name = 'John' AND last_name = 'lastName'
看起來是不是和我們的範例長很像? 我們只要讓lastName的內容輸入後可以讓WHERE的條件達成恆TRUE就好了,那麼應該會需要讓他長這樣
SELECT * FROM user_data WHERE first_name = 'John' AND last_name = 'Smith' OR '1' = '1'
所以第一項選擇 Smith' ,第二項選擇or ,第三項選擇'1'='1

這題開始就要自己手打了
我們一樣先來看代碼
"SELECT * FROM user_data WHERE login_count = " + Login_Count + " AND userid = " + User_ID;
在SQL資料庫內會變成
SELECT * FROM user_data WHERE login_count = Login_Count AND userid = User_ID;
可以看到和我們以前的範例有點不太一樣了,輸入的值並沒有被用'包起來,說明這次我們要輸入的地方預設不是字串,而是數字
也許你會想問:可是我們要讓條件恆正不就一定要輸入OR之類的字串嗎?
沒錯,所以我們要測試看看哪裡沒有設好一定只能輸入數字的限制


從這兩張圖片可以看到,Login_Count這一格就只能輸入數字,而User_ID則是沒有這個限制,所以我們要從User_ID下手,輸入 1 OR 1=1
讓他變成
SELECT * FROM user_data WHERE login_count = 1 AND userid = 1 OR 1=1;
由於AND的優先級比較高,所以這指令的條件會被理解成
查詢(login_count = AND userid = 1 ) OR (1=1)(恆正)的資料
login_count和userid會被強制拼接成一種條件,1=1又是另一種條件
FALSE OR TRUE = TRUE; 所以我們可以拿到資料


題目依然為我們準備好了原始代碼
"SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = '" + auth_tan + "'";
在資料庫內會變成
SELECT * FROM employees WHERE last_name = 'name' AND auth_tan = 'auth_tan';
看起來也和之前的代碼差不多,那我們就用相同的方法來解,
在last_name隨便輸入一些東西
在auth_tan輸入 1' OR '1' = '1 把它變成
SELECT * FROM employees WHERE last_name = '1' AND auth_tan = '1' OR '1' = '1'

有時候攻擊者不只想要查詢資料,也會想對資料庫做一些操作
可以看到,這一題中我們要改變表格中的資料,但我們目前只有SELECT這個程式設計者給我們的查詢指令能用,
所以我們要另闢蹊徑了,這個方法叫做Query chaining(查詢串接) 本質上來說就是在查詢指令中再插入另外一個指令,這裡就拿這題的代碼做例子
SELECT * FROM employees WHERE last_name = '1' AND auth_tan = '1' OR '1' = '1'
SELECT * FROM employees WHERE last_name = '1' AND auth_tan = '1' OR '1';
UPDATE employees SET salary = 999999 WHERE last_name = 'John'
看到了嗎? 我們沒有刪除任何一個原本程式設計者打的東西,卻讓資料庫可以執行兩個指令
我們會使用;讓資料庫知道這個指令已經完成了,接著打入我們想要的另一個指令,讓資料庫以為有兩個指令要執行
在Employee_name這個輸入欄中隨便輸入一些東西
在Authentication TAN這個輸入欄中輸入1' OR '1' = '1'; UPDATE employees SET SALARY = 999999 WHERE first_name = 'John
讓他變成我們上面範例的指令,並且驗證看看有沒有成功

可以看到,我們的salary變成了999999,這說明我們的輸入成功的讓原先只能SELECT的指令變成了兩個指令

總算來到最後一題啦,要我們刪除access_log這張表
讓我們看看題目給我們的代......碼?
看起來這題沒給我們代碼,要我們自己判斷看看了
先輸入看看OR,這個我們常用來SQL injection的字串試試看

從這個,我們就能知道這個指令的大致結構了,應該是
SELECT * FROM access_log WHERE ACTION LIKE '%action%'
%是用來進行模糊搜尋用的字元,這裡用兩個%包起來代表會搜尋裡面包含action的所有結果
LIKE則是和%綁定的運算子
這整個指令就像在對資料庫說
請查詢所有access_log這張表內ACTION這欄內容裡包含了action的資料並輸出
也符合我們查詢OR之後跳出來的結果,的確是所有包含OR的都跳出來了
但重點是'%action%'的那兩個'
這說明我們又可以進行SQL injection和query chainning了!
讓我們輸入看看';DROP TABLE access_log;

?!?! 怎麼報錯了
讓我們來看看這指令在資料庫中會變成甚麼樣子
SELECT * FROM access_log WHERE ACTION LIKE '';
DROP TABLE access_log;'
看到了嗎? 後面多出了一個我們不想要的'
但我們可以靠在後面多加--的方式把他解決掉

為什麼可以這樣做呢?
因為在SQL中--就代表了註解,後面的'會被註解掉讓資料庫不會讀到,指令讀取到的部分就會變成
SELECT * FROM access_log WHERE ACTION LIKE '';
DROP TABLE access_log;
變回了一般的指令,沒有多餘的'自然就可以運行了
這題答案便是
';DROP TABLE access_log;--
今天,我們解完了SQL injection的(intro)
接下來就要開始解(advanced)了!