A recent intrusion investigated by Huntress shows a technique every defender running Oracle behind a web application needs to understand: attackers exploited a SQL injection flaw in a public-facing web app, then achieved Windows SYSTEM-level command execution without writing a single executable to disk. They did it by feeding Java source code through the database connection, letting Oracle's own JVM compile it into stored schema objects, and invoking OS commands from inside the database engine. Huntress tracks this post-exploitation toolkit as khunt.
This is a fileless-by-design tradecraft that sidesteps most EDR coverage focused on dropped binaries and script files. If your SOC's detection strategy for database servers is "alert on weird executables," you are blind to this attack. This post breaks down the chain, the observable artifacts it does leave behind, and the specific detections and hardening steps that shut it down.
Technical Analysis
Attack Chain
The intrusion unfolded in three stages, each of which is individually detectable:
Stage 1 — SQL Injection in a public-facing web application. The attackers identified an injectable parameter in a web application backed by an Oracle database. SQL injection remains one of the most reliably exploited web vulnerability classes precisely because it inherits the full privileges of the application's database account. No CVE has been publicly attributed to this specific injection point — it is a classic application-layer flaw, not an Oracle product vulnerability.
Stage 2 — In-database compilation of the khunt toolkit. Rather than exfiltrating data or dropping a webshell, the attackers submitted Java source code through the injected SQL channel. Oracle Database ships with an embedded JVM (Oracle JVM / DBMS_JAVA), and it permits privileged sessions to create Java stored procedures using CREATE OR REPLACE AND RESOLVE JAVA SOURCE statements. Oracle compiled the attacker's source into schema objects — the "malware" now lives as rows in SYS.OBJ$ and DBA_OBJECTS of type JAVA SOURCE and JAVA CLASS, never as a file on the Windows filesystem.
Stage 3 — OS command execution as SYSTEM. The compiled Java classes wrapped calls to Runtime.exec() (or equivalent), exposed through a PL/SQL call spec. Because the Oracle database service on Windows conventionally runs as NT AUTHORITY\SYSTEM (or a high-privilege domain service account), every command executed through the Java stored procedure inherits that context. The attackers now have arbitrary SYSTEM-level command execution on the database host — full host compromise achieved through a web form.
Why This Evades Traditional Controls
- No executable on disk: AV/EDR file scanning has nothing to inspect. The payload exists only as compiled Java bytecode in database datafiles.
- Trusted process ancestry: OS commands spawn from
oracle.exe— a process most EDR policies treat as a high-noise, low-scrutiny database binary. - Legitimate network channel: All C2-adjacent traffic flows over the existing application-to-database connection (TCP 1521/TNS). There is no new egress session to flag.
- Credential inheritance: The attack uses the application's own authenticated database session; authentication logs show a "valid" connection.
Prerequisites the Attackers Needed
For a defender, the preconditions are the control points. Executing this technique requires the injected database account to hold privileges that a web application account should never have:
CREATE PROCEDURE/CREATE JAVA SOURCEobject creation rights- Execute access on
DBMS_JAVA(or grants permitting Java stored procedure creation) - Effectively, a schema-owning or DBA-adjacent account — which tells you the application was connecting to Oracle with grossly excessive privileges
This is the single most important takeaway: khunt is only possible because the application's database identity was over-privileged. Least privilege at the database layer is the kill switch.
Exploitation Status
This is confirmed in-the-wild activity documented by Huntress in an active intrusion response engagement. The khunt tooling circulates as a post-exploitation kit specifically targeting Oracle-backed environments. Any organization with Oracle behind a web tier — common in ERP, healthcare, financial, and government stacks — should treat this as an active threat, not a theoretical one.
Detection & Response
The strongest telemetry points are (1) oracle.exe spawning command interpreters, (2) creation of Java source/class objects in the database, and (3) SQL injection patterns in web-tier logs. The rules below target exactly those.
---
title: Oracle Database Process Spawning Command Interpreter
title_fr: N/A
id: 3f8a1c94-2b6d-4e7a-9c15-8d2e4f6a1b30
status: experimental
description: Detects oracle.exe spawning cmd.exe, powershell.exe, or other command interpreters — the signature behavior of OS command execution via Java stored procedures (khunt-style post-exploitation). Oracle should never legitimately spawn shells on Windows under normal operations.
references:
- https://thehackernews.com/2026/08/attackers-compile-khunt-inside-oracle.html
- https://attack.mitre.org/techniques/T1059/
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/08/10
tags:
- attack.execution
- attack.t1059
- attack.initial_access
- attack.t1190
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith: '\oracle.exe'
selection_child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
- '\rundll32.exe'
- '\wmic.exe'
- '\bitsadmin.exe'
- '\certutil.exe'
- '\whoami.exe'
- '\net.exe'
- '\net1.exe'
- '\ipconfig.exe'
- '\systeminfo.exe'
condition: selection_parent and selection_child
falsepositives:
- Rare legacy Oracle scheduler jobs invoking OS commands via DBMS_SCHEDULER external jobs — inventory and baseline these explicitly
level: critical
---
title: Web Server Process Spawning Database Client or Shell After Suspected SQLi
id: 8c2e5b17-4d9f-4a36-b802-1e7c3a5d9f42
status: experimental
description: Detects IIS worker processes or other web server processes spawning command shells or scripting engines — a common indicator when SQL injection post-exploitation pivots back to the web tier or when in-memory execution flows through the application process.
references:
- https://thehackernews.com/2026/08/attackers-compile-khunt-inside-oracle.html
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/08/10
tags:
- attack.initial_access
- attack.t1190
- attack.execution
- attack.t1059
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\w3wp.exe'
- '\httpd.exe'
- '\nginx.exe'
- '\tomcat9.exe'
- '\java.exe'
selection_child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\certutil.exe'
- '\bitsadmin.exe'
condition: selection_parent and selection_child
falsepositives:
- Legacy applications that shell out from app code — rare in modern stacks and should be inventoried per app pool identity
level: high
Oracle-side auditing (defense in depth): Process ancestry rules catch the effect; database auditing catches the cause. Enable and forward Oracle Unified Auditing for Java object creation so the compilation event itself becomes an alert. This query hunts for khunt-style artifacts already resident in a database:
-- Run as a DBA/audit account: find recently created Java objects
-- Legitimate apps rarely create JAVA SOURCE/JAVA CLASS at runtime
SELECT owner, object_name, object_type, created, last_ddl_time, status
FROM dba_objects
WHERE object_type IN ('JAVA SOURCE', 'JAVA CLASS')
AND created > SYSDATE - 30
ORDER BY created DESC;
-- Check who holds Java execution privileges (should be a short, known list)
SELECT grantee, privilege
FROM dba_tab_privs
WHERE table_name IN ('DBMS_JAVA', 'DBMS_JAVA_TEST')
ORDER BY grantee;
-- Identify accounts able to create procedures (web app accounts should NOT appear)
SELECT grantee FROM dba_sys_privs
WHERE privilege IN ('CREATE PROCEDURE', 'CREATE ANY PROCEDURE', 'DBA')
AND grantee NOT IN ('SYS', 'SYSTEM');
Ensure an audit policy exists, e.g. CREATE AUDIT POLICY java_obj_creation ACTIONS CREATE JAVA SOURCE, CREATE JAVA CLASS; (or the equivalent Unified Auditing action on DBMS_JAVA execution), and ship audit records to your SIEM.
// Hunt: Oracle service spawning command interpreters (khunt Java stored proc execution)
// Works with MDE DeviceProcessEvents; for Sysmon/CEF ingestion use SecurityEvent/Event 4688
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName =~ "oracle.exe"
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe", "cscript.exe",
"mshta.exe", "rundll32.exe", "wmic.exe", "bitsadmin.exe", "certutil.exe",
"whoami.exe", "net.exe", "net1.exe", "ipconfig.exe", "systeminfo.exe",
"nltest.exe", "quser.exe", "tasklist.exe", "sc.exe", "reg.exe")
| project TimeGenerated, DeviceName, AccountName = InitiatingProcessAccountName,
ChildProcess = FileName, ProcessCommandLine,
InitiatingProcessCommandLine, ReportId
| order by TimeGenerated desc;
// Companion hunt: web server processes spawning shells (SQLi stage / pivot behavior)
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName in~ ("w3wp.exe", "httpd.exe", "nginx.exe", "tomcat9.exe", "java.exe")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "certutil.exe", "bitsadmin.exe")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
| order by TimeGenerated desc;
-- Velociraptor hunt: enumerate Oracle-spawned child processes and any
-- shell processes whose ancestry traces to oracle.exe
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE Name =~ '(?i)oracle\.exe'
OR CommandLine =~ '(?i)(cmd\.exe|powershell|pwsh|wscript|cscript|mshta|certutil|bitsadmin|whoami|net\.exe|ipconfig|systeminfo)'
For corroboration, join endpoint findings against web-tier logs. SQL injection attempts feeding this attack typically contain Oracle-specific tokens — UNION SELECT, UTL_HTTP, DBMS_JAVA, CREATE OR REPLACE AND RESOLVE JAVA SOURCE, CHR( concatenation, or heavy quote/comment sequences — in request parameters. Forward WAF/IIS/Apache logs to Sentinel and alert on these strings in URI/query fields.
# Verify-and-harden script for Windows Oracle hosts
# Run elevated on the database server. Read-only checks first, then remediation notes.
$ErrorActionPreference = 'Continue'
$report = "C:\Windows\Temp\oracle_khunt_check_$(Get-Date -Format yyyyMMdd_HHmmss).txt"
"=== Oracle service account context ===" | Out-File $report
Get-CimInstance Win32_Service -Filter "Name LIKE '%OracleService%' OR Name LIKE '%Oracle%TNS%'" |
Select-Object Name, StartName, State | Format-Table -AutoSize | Out-File $report -Append
# RED FLAG: StartName = LocalSystem. Migrate the service to a low-privilege
# virtual account / gMSA to break the SYSTEM-inheritance path.
"=== Recent child processes of oracle.exe (last 24h from Security log) ===" | Out-File $report -Append
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4688; StartTime=(Get-Date).AddDays(-1)} -ErrorAction SilentlyContinue |
Where-Object { $_.Message -match 'oracle\.exe' -and $_.Message -match 'cmd\.exe|powershell|wscript|cscript|mshta' } |
Select-Object TimeCreated, Message | Format-List | Out-File $report -Append
"=== Sysmon process ancestry (if Sysmon installed) ===" | Out-File $report -Append
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational'; Id=1; StartTime=(Get-Date).AddDays(-7)} -ErrorAction SilentlyContinue |
Where-Object { $_.Message -match 'ParentImage:.*oracle\.exe' } |
Select-Object TimeCreated, Message | Format-List | Out-File $report -Append
"=== Oracle Unified Audit policies (requires sqlplus credentials) ===" | Out-File $report -Append
$sql = @"
SET PAGESIZE 200 LINESIZE 200
SELECT owner, object_name, object_type, created FROM dba_objects
WHERE object_type IN ('JAVA SOURCE','JAVA CLASS') AND created > SYSDATE - 30;
SELECT grantee, privilege FROM dba_tab_privs WHERE table_name = 'DBMS_JAVA';
SELECT grantee FROM dba_sys_privs WHERE privilege IN ('CREATE ANY PROCEDURE','DBA');
EXIT
"@
$sql | Out-File C:\Windows\Temp\khunt_audit.sql -Encoding ascii
"SQL script written to C:\Windows\Temp\khunt_audit.sql - run via: sqlplus / as sysdba @khunt_audit.sql" | Out-File $report -Append
Write-Output "Report written to $report. Review for: SYSTEM service account, oracle.exe shell children, unexpected JAVA objects, broad DBMS_JAVA grants."
Remediation
Prioritized, in order of impact:
1. Crush the privilege path (same day). Audit every database account used by a web application. Revoke CREATE PROCEDURE, CREATE JAVA SOURCE, execute on DBMS_JAVA, and any DDL rights from application runtime accounts. Web apps need SELECT/INSERT/UPDATE/DELETE on their schema and nothing else. This single step makes khunt inert — there is no compilation path without these grants.
2. Degrade the Oracle service account. If the Windows Oracle service runs as LocalSystem, migrate it to a dedicated low-privilege domain account, virtual account, or gMSA per Oracle's hardening guidance. Even if Java stored procedure execution occurs, command execution then lands in a constrained context rather than SYSTEM.
3. Fix the injection flaw and the SDLC gap. Identify the injectable parameter (pull WAF and application logs for the affected endpoint), remediate with parameterized queries/prepared statements, and conduct a full application security review. Engage your pen-testing team to validate no other injection points exist — attackers rarely find the only one.
4. Disable or fence Oracle JVM where unused. If no business function requires in-database Java, revoke EXECUTE on DBMS_JAVA from PUBLIC and consider removing the JVM option entirely. Where it is required, restrict dbms_java.grant_permission() grants and audit all Java object DDL.
5. Enable and forward Oracle Unified Auditing. Audit CREATE JAVA SOURCE, CREATE JAVA CLASS, CREATE PROCEDURE, and DBMS_JAVA execution. Ship audit trails off-box to the SIEM in near-real-time — an attacker with DBA access will purge local UNIFIED_AUDIT_TRAIL data given time.
6. Deploy the detections above and baseline legitimate DBMS_SCHEDULER external jobs before tuning the oracle.exe child-process rule. Add web-log alerting for Oracle-specific SQLi tokens (DBMS_JAVA, RESOLVE JAVA SOURCE, UTL_HTTP, UTL_FILE).
7. Hunt retroactively. Run the VQL and the DBA_OBJECTS query across every Oracle host. Java objects with creation timestamps outside change windows, objects in application schemas the developers don't recognize, or grant changes you can't account for are IR triggers, not tickets.
8. If compromise is confirmed: treat the database host as fully compromised. Rotate all credentials stored in or transiting the database, isolate the host, image it for forensics, and review TNS listener logs and DBA_HIST_ACTIVE_SESS_HISTORY for the origin application server — the web tier likely needs parallel investigation.
Executive Takeaways for Leadership
- This intrusion converted a web vulnerability into full host compromise using only Oracle-native features. Database privilege hygiene — not a missing patch — was the enabling failure.
- The toolkit leaves no file-based malware, which means prevention and database-layer auditing are the primary controls; EDR alone will not save you.
- Ask your team two questions this week: What privileges do our application database accounts hold? and Would we see
oracle.exespawn a shell? If either answer is unknown, that's your gap.
Related Resources
Security Arsenal Managed SOC Services AlertMonitor Platform Book a SOC Assessment soc-mdr Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.