CTF學習筆記(三)php部分
三、常見PHP用法與漏洞
(〇)php的備份文件與phps
php的備份文件一般是*.php.bak,在根目錄下輸入/index.php.bak, 下載 備份文件。
phps文件就是php的源代碼文件,通常用于提供給用戶(訪問者)查看php代碼,因為用戶無法直接通過Web瀏覽器看到php文件的內容,所以需要用phps文件代替。其實,只要不用php等已經在服務器中注冊過的MIME類型為文件即可,但為了國際通用,所以才用了phps文件類型。
(一)php_文件包含
文件包含的函數的參數沒有經過過濾或者是嚴格的定義,并且參數可以被用戶所控制,這樣就可能包含非預期的文件。
1.文件包含漏洞常見的函數(默認都以php腳本為準啊)
①include: 包含并運行指定的文件,Include在出錯的時候產生警告,腳本會繼續運行
②include_once:在腳本執行期間包含并運行指定文件。該函數和include 函數類似,兩者唯一的區別是 使用該函數的時候,php會加檢查指定文件是否已經被包含過,如果是,則不會再被包含。
③require :包含并運行指定文件。require在出錯的時候產生E_COMPLE_ERROR級別的錯誤,導致腳本終止運行。
④require_once: 和require函數完全相同。區別類似include和include_once。
文件包含漏洞示例(文件名稱include.php)
無限制:沒有為包含文件指定特定的前綴或者.php .html 等擴展名
<?php
?
$filename=$_GET['filename'];
?
Include($filename);
?
?>
有限制:(隨便加一個擴展名上去)
<?php
?
$filename=$_GET['filename'];
?
Include($filename.".html");
?
?>
2.本地包含漏洞
①無限制本地包含漏洞 1)常見的敏感信息路徑
window系統: \boot.ini 系統版本信息
\php.ini PHP配置信息
\my.ini MYSQL配置信息
\httpd.conf Apache配置信息
linux系統:
/etc/passwd linux系統賬號信息
/etc/httpd/conf/httpd.conf Apache配置信息
/etc/my.conf MYSQL配置信息
/usr/etc/php.ini PHP配置信息 2)漏洞利用
讀取文件內容(還未糾正)
通過目錄遍歷可以獲取系統中的文件:
http://XXX.X.X.X./include.php?finame= (傳路徑即可)
例:我們要訪問四級目錄中的1.php文件
那就是 http://XXX.X.X.X./include.php?finame=../../../1.php
利用無限制本地包含漏洞執行代碼
利用無限制本地包含漏洞,可以通過文件包含功能執行擴展名的文件中的代碼
Os:學到這里的時候終于解惑之前的一個疑惑:在做文件上傳的題目時,為什么我上傳一個圖片馬,訪問該圖片用蟻劍無法連接。原因當然是:圖片馬里面的php代碼沒有辦法解析,如果要解析的話可以配合文件包含漏洞,那樣就可以解析圖片馬里面的php代碼(死靶文件隨便加加減減唄)
例:Test.txt文件內容是<?php phpinfo(); ?>
利用文件包含漏洞test.txt 文件,就可以執行文件中的php代碼并輸出phpinfo信息
②有限制本地包含漏洞
如下:
繞過方法: 1)%00截斷文件包含
漏洞利用條件: php版本要低于5.3.4
Magic_quotes_gpc=off
測試:http://127.0.0.1/include.php?filename=1.txt%00 2)路徑長度截斷文件包含
操作系統存在最大路徑長度的限制。可以通過輸入超過最大路徑的長度的目錄,這樣系統就會將后面的的路徑給舍棄,導致擴展名截斷。
漏洞利用條件:
window系統目錄下的最大路徑長度是256B
Linux系統目錄下的最大路徑長度是4096B
測試:http://127.0.0.1/include.php?finame=1.txt/../../../../../../../../../../../../../../../../../../../../../../../../../../../(省略不想打了) 3)點號截斷文件包含
和‘路徑長度文件截斷文件包含’同理
3.遠程包含漏洞
①無限制遠程文件包含漏洞
無限制遠程文件包含是指包含文件的位置并不是在本地服務器,而是通過URL的形式包含其他服務器上的文件,執行文件中的惡意代碼。
漏洞利用條件:
allow_url_fopen=on
allow_url_include=on 漏洞利用:
直接傳參文件的url即可,就不做演示了。 ②有限制遠程文件包含漏洞(后面再補圖)
繞過方法: 1)問號繞過
可以在問好(?)后面添加HTML字符串,問號后面的擴展名.html會被當成查詢,從而繞或擴展名過濾 2)井號繞過
可以在井號(#)后面添加HTML字符串,#號會截斷后面的擴展名.html,從而逃過擴展名過濾。#號的URL編碼為%23 3)空格繞過
在payload的最后對空格進行URL編碼 %20 四.PHP偽協議 ①常見的php偽協議
1)file:// 訪問本地文件系統
2)http:// 訪問HTTP(S)網址
3)ftp:// 訪問FTP(S)URL
4)php:// 訪問各個輸出輸入流
5)zlib:// 處理壓縮流
6)data:// 讀取數據
7)glob:// 查找匹配的文件路徑模式
8)phar:// PHP歸檔
9)rar:// RAR數據壓縮 ②php://偽協議
php://偽協議是php提供的一些輸入輸出流訪問功能,允許訪問php的輸入輸出流,標準輸入輸出和錯誤描述符,內存中,磁盤備份的臨時文件流,以及可以操作其他讀取和寫入文件的過濾器。
1)php://filter
php://filter是元封裝器,設計用于了數據流打開時的篩選過濾應用,對本地磁盤文件進行讀寫。
以下兩種用法相同:
名稱 描述 resource=<要過濾的數據流> 該參數是必需的。指定要過濾的數據流 read=<讀鏈的篩選器列表> 該參數可選。可以設定一個或者多個篩選器名稱,以管道符(|分隔 write=<寫鏈的篩選器列表> 該參數可選。可以設定一個或者多個篩選名稱,以管道符(|)分隔
(二)MD5繞過
MD5消息摘要算法,屬Hash算法一類。MD5算法對輸入任意長度的消息進行運行,產生一個128位的消息摘要(32位的數字字母混合碼)。
md5()函數有一個漏洞,如果md5函數的參數是一個數組值,會導致函數返回false。除了md5之外sha1函數也有這個特性。 則這里get一個a[]=1 post一個b[]=1即可。
除了利用md5函數的漏洞,還可以構造md5值相同的倆條不同數據。md5值相同的字符串沒有找到,但可以構造md5值相同的二進制數據
附:常見MD5 0e開頭的字符串
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
240610708
0e462097431906509019562988736854
314282422
0e990995504821699494520356953734
571579406
0e972379832854295224118025748221
903251147
0e174510503823932942361353209384
1110242161
0e435874558488625891324861198103
1320830526
0e912095958985483346995414060832
1586264293
0e622743671155995737639662718498
2302756269
0e250566888497473798724426794462
2427435592
0e067696952328669732475498472343
2653531602
0e877487522341544758028810610885
3293867441
0e471001201303602543921144570260
3295421201
0e703870333002232681239618856220
3465814713
0e258631645650999664521705537122
3524854780
0e507419062489887827087815735195
3908336290
0e807624498959190415881248245271
4011627063
0e485805687034439905938362701775
4775635065
0e998212089946640967599450361168
4790555361
0e643442214660994430134492464512
5432453531
0e512318699085881630861890526097
5579679820
0e877622011730221803461740184915
5585393579
0e664357355382305805992765337023
6376552501
0e165886706997482187870215578015
7124129977
0e500007361044747804682122060876
7197546197
0e915188576072469101457315675502
7656486157
0e451569119711843337267091732412
QLTHNDT
0e405967825401955372549139051580
QNKCDZO
0e830400451993494058024219903391
EEIZDOI
0e782601363539291779881938479162
TUFEPMC
0e839407194569345277863905212547
UTIPEZQ
0e382098788231234954670291303879
UYXFLOI
0e552539585246568817348686838809
IHKFRNS
0e256160682445802696926137988570
PJNPDWY
0e291529052894702774557631701704
ABJIHVY
0e755264355178451322893275696586
DQWRASX
0e742373665639232907775599582643
DYAXWCA
0e424759758842488633464374063001
GEGHBXL
0e248776895502908863709684713578
GGHMVOE
0e362766013028313274586933780773
GZECLQZ
0e537612333747236407713628225676
NWWKITQ
0e763082070976038347657360817689
NOOPCJF
0e818888003657176127862245791911
MAUXXQC
0e478478466848439040434801845361
MMHUWUV
0e701732711630150438129209816536
注意:php8不支持數組繞過
(三)is_numeric漏洞
會忽視0x這種十六進制的數
容易引發sql注入操作,暴漏敏感信息
echo json_encode([
is_numeric(233333),
is_numeric('233333'),
is_numeric(0x233333),
is_numeric('0x233333'),
is_numeric('233333abc'),
]);
結果如下
16進制數0x61646D696EASII碼對應的值是admin
如果我們執行了后面這條命令的話:SELECT * FROM tp_user where username=0x61646D696E,結果不言而喻
[
true,
true,
true,
false,
false
]
(四)in_array漏洞
in_array中是先將類型轉為整形,再進行判斷
轉換的時候,如果將字符串轉換為整形,從字符串非整形的地方截止轉換,如果無法轉換,將會返回0
<?php
var_dump(in_array("2%20and%20%", [0,2,3]));
結果如下
bool(true)
(五)switch漏洞
switch中是先將類型轉為整形,再進行判斷
轉換的時候,如果將字符串轉換為整形,從字符串非整形的地方截止轉換,如果無法轉換,將會返回0
(六)命令注入攻擊
PHP中可以使用下列5個函數來執行外部的應用程序或函數 system、exec、passthru、shell_exec、“(與shell_exec功能相同) 函數原型 string system(string command, int &return_var) command 要執行的命令 return_var 存放執行命令的執行后的狀態值 string exec (string command, array &output, int &return_var) command 要執行的命令 output 獲得執行命令輸出的每一行字符串 return_var 存放執行命令后的狀態值 void passthru (string command, int &return_var) command 要執行的命令 return_var 存放執行命令后的狀態值 string shell_exec (string command) command 要執行的命令
漏洞實例
例1: //ex1.php
<?php
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al ".$dir);
echo "</pre>";
}
?>
我們提交http://www.sectop.com/ex1.php?dir=| cat /etc/passwd 提交以后,命令變成了 system("ls -al | cat /etc/passwd");
(七)常見的弱類型比較繞過
<?php
echo` `0 == ``'a'` `;``// a 轉換為數字為 0 重點注意
// 0x 開頭會被當成16進制54975581388的16進制為 0xccccccccc
// 十六進制與整數,被轉換為同一進制比較
'0xccccccccc'` `== ``'54975581388'` `;
// 字符串在與數字比較前會自動轉換為數字,如果不能轉換為數字會變成0
1 == ``'1'``;
1 == ``'01'``;
10 == ``'1e1'``;
'100'` `== ``'1e2'` `;
// 十六進制數與帶空格十六進制數,被轉換為十六進制整數
'0xABCdef'` `== ``' 0xABCdef'``;
echo` `'0010e2'` `== ``'1e3'``;
// 0e 開頭會被當成數字,又是等于 0*10^xxx=0
// 如果 md5 是以 0e 開頭,在做比較的時候,可以用這種方法繞過
'0e509367213418206700842008763514'` `== ``'0e481036490867661113260034900752'``;
'0e481036490867661113260034900752'` `== ``0'` `;
var_dump(md5(``'240610708'``) == md5(``'QNKCDZO'``));
var_dump(md5(``'aabg7XSs'``) == md5(``'aabC9RqS'``));
var_dump(sha1(``'aaroZmOk'``) == sha1(``'aaK1STfY'``));
var_dump(sha1(``'aaO8zKZF'``) == sha1(``'aa3OFF9m'``));
?>
(八)通配符在文件查詢中的妙用
通配符是一種特殊語句,主要有星號()和問號(?),用來模糊搜索文件。當查找文件夾時,可以使用它來代替一個或多個真正字符;當不知道真正字符或者懶得輸入完整名字時,常常使用通配符代替一個或多個真正的字符。 實際上用“Not?pad”可以對應Notepad\MyNotepad【*可以代表任何字符串;?僅代表單個字符串,但此單字必須存在】;Notep[ao]d可以對應Notepad\Notepod【ao代表a與o里二選一】,其余以此類推。
(九)Linux下內部分隔符${IFS}可以代替空格
(十)反序列化漏洞
1.什么是序列化和反序列化
序列化是將對象轉換為字符串以便存儲傳輸的一種方式。而反序列化恰好就是序列化的逆過程,反序列化會將字符串轉換為對象供程序使用。在PHP中序列化和反序列化對應的函數分別為serialize()和unserialize()。
2.什么是反序列化漏洞
當程序在進行反序列化時,會自動調用一些函數,例如wakeup(),destruct()等函數,但是如果傳入函數的參數可以被用戶控制的話,用戶可以輸入一些惡意代碼到函數中,從而導致反序列化漏洞。
3.序列化函數(serialize)
當我們在php中創建了一個對象后,可以通過serialize()把這個對象轉變成一個字符串,用于保存對象的值方便之后的傳遞與使用。
測試代碼
<?php
class Stu{
public $name = 'aa';
public $age = 18;
public function demo(){
echo "你好啊";
}
$stu = new Stu();
echo "<pre>";
print_r($stu);
//進行序列化
$stus = serialize($stu);
print_r($stus);
}
?>
查看結果:
4.反序列化(unserialize)
unserialize()可以從序列化后的結果中恢復對象(object)為了使用這個對象,在下列代碼中用unserialize重建對象.
測試代碼:
<?php
//定義一個Stu類
class Stu
{
//定義成員屬性
public $name = 'aa';
public $age = 19;
//定義成員方法
public function demo()
{
echo '你吃了嗎';
}
}
//實例化對象
$stu = new Stu();
//進行序列化
$stus = serialize($stu);
print_r($stus);
echo "<br><pre>";
//進行反序列化
print_r(unserialize($stus));
?>
5.PHP魔術方法
魔術方法是PHP面向對象中特有的特性。它們在特定的情況下被觸發,都是以雙下劃線開頭,利用魔術方法可以輕松實現PHP面向對象中重載(Overloading即動態創建類屬性和方法)。 問題就出現在重載過程中,執行了相關代碼。
1、__get、__set
?
這兩個方法是為在類和他們的父類中沒有聲明的屬性而設計的
?
__get( $property ) 當調用一個未定義的屬性時訪問此方法
?
__set( $property, $value ) 給一個未定義的屬性賦值時調用
?
這里的沒有聲明包括訪問控制為proteced,private的屬性(即沒有權限訪問的屬性)
?
2、__isset、__unset
?
__isset( $property ) 當在一個未定義的屬性上調用isset()函數時調用此方法
?
__unset( $property ) 當在一個未定義的屬性上調用unset()函數時調用此方法
?
與__get方法和__set方法相同,這里的沒有聲明包括訪問控制為proteced,private的屬性(即沒有權限訪問的屬性)
?
3、__call
?
__call( $method, $arg_array ) 當調用一個未定義(包括沒有權限訪問)的方法是調用此方法
?
4、__autoload
?
__autoload 函數,使用尚未被定義的類時自動調用。通過此函數,腳本引擎在 PHP 出錯失敗前有了最后一個機會加載所需的類。
?
注意: 在 __autoload 函數中拋出的異常不能被 catch 語句塊捕獲并導致致命錯誤。
?
5、__construct、__destruct
?
__construct 構造方法,當一個對象被創建時調用此方法,好處是可以使構造方法有一個獨一無二的名稱,無論它所在的類的名稱是什么,這樣你在改變類的名稱時,就不需要改變構造方法的名稱
?
__destruct 析構方法,PHP將在對象被銷毀前(即從內存中清除前)調用這個方法
?
默認情況下,PHP僅僅釋放對象屬性所占用的內存并銷毀對象相關的資源.,析構函數允許你在使用一個對象之后執行任意代碼來清除內存,當PHP決定你的腳本不再與對象相關時,析構函數將被調用.
?
在一個函數的命名空間內,這會發生在函數return的時候,對于全局變量,這發生于腳本結束的時候,如果你想明確地銷毀一個對象,你可以給指向該對象的變量分配任何其它值,通常將變量賦值勤為NULL或者調用unset。
?
6、__clone
?
PHP5中的對象賦值是使用的引用賦值,使用clone方法復制一個對象時,對象會自動調用__clone魔術方法,如果在對象復制需要執行某些初始化操作,可以在__clone方法實現。
?
7、__toString
?
__toString方法在將一個對象轉化成字符串時自動調用,比如使用echo打印對象時,如果類沒有實現此方法,則無法通過echo打印對象,否則會顯示:Catchable fatal error: Object of class test could not be converted to string in,此方法必須返回一個字符串。
?
在PHP 5.2.0之前,__toString方法只有結合使用echo() 或 print()時 才能生效。PHP 5.2.0之后,則可以在任何字符串環境生效(例如通過printf(),使用%s修飾符),但 不能用于非字符串環境(如使用%d修飾符)
?
從PHP 5.2.0,如果將一個未定義__toString方法的對象 轉換為字符串,會報出一個E_RECOVERABLE_ERROR錯誤。
?
8、__sleep、__wakeup
?
__sleep 串行化的時候用
?
__wakeup 反串行化的時候調用
?
serialize() 檢查類中是否有魔術名稱 __sleep 的函數。如果這樣,該函數將在任何序列化之前運行。它可以清除對象并應該返回一個包含有該對象中應被序列化的所有變量名的數組。
?
使用 __sleep 的目的是關閉對象可能具有的任何數據庫連接,提交等待中的數據或進行類似的清除任務。此外,如果有非常大的對象而并不需要完全儲存下來時此函數也很有用。
?
相反地,unserialize() 檢查具有魔術名稱 __wakeup 的函數的存在。如果存在,此函數可以重建對象可能具有的任何資源。使用 __wakeup 的目的是重建在序列化中可能丟失的任何數據庫連接以及處理其它重新初始化的任務。
?
9、__set_state
?
當調用var_export()時,這個靜態 方法會被調用(自PHP 5.1.0起有效)。本方法的唯一參數是一個數組,其中包含按array(’property’ => value, …)格式排列的類屬性。
?
10、__invoke
?
當嘗試以調用函數的方式調用一個對象時,__invoke 方法會被自動調用。PHP5.3.0以上版本有效
?
11、__callStatic
?
它的工作方式類似于
