Attackers turned an ordinary SQL injection bug into SYSTEM-level control of a Windows server by compiling their own malware inside the Oracle database itself. Huntress published the case on August 5, 2026, after investigating an intrusion its platform caught on July 27. The toolkit, which the attackers named khunt, consists of six Java objects and a set of khunt_* PL/SQL wrappers that live as schema objects in the database, so the operator gets command execution, credential theft and file access without ever dropping an executable on disk.
None of the individual pieces are new. Oracle has shipped an embedded JVM since the late 1990s, and running operating system commands through it has been a pentest party trick for at least two decades. What makes this worth reading is that Huntress says the technique is rarely documented actually being used in the wild, and the intrusion shows exactly how the gap between a web form and domain-level credentials closes when one database account is over-provisioned.
RelatedDuneSlide Turns a Cursor Prompt Into Full Code Execution
- Entry was an autocomplete search field in a public Java web app on Apache Tomcat that passed unvalidated input straight to Oracle over JDBC.
- The attackers used
CREATE JAVA SOURCEto compile khunt into the database, then called it through PL/SQL wrappers, which means no file was written to disk to get code execution. - KhuntCmd ran
cmd.exe /c whoamiand came back as SYSTEM, because the Oracle service on Windows runs with those rights by default. - Payoff was credential theft: the operators copied the SAM, SYSTEM and SECURITY registry hives to disk as
khunt*.hivfiles under the Oracle directory.
What actually happened on July 27?
Huntress did not find this by watching the database. Its detection fired on the Windows host, on a credential-theft rule that noticed reg.exe running with oracle.exe as its parent process. That is a strange parent for a registry export, and it was the thread that unravelled the rest. Working backwards through Apache access logs, the responders found the injectable endpoint: an autocomplete search feature in a public-facing Java application that fed whatever a visitor typed into an Oracle query over JDBC.
The account behind that JDBC connection could create Java sources. That is the entire pivot. Once the operators could issue CREATE JAVA SOURCE statements through the injection, they compiled six components into the schema and wrapped each one in PL/SQL so it could be invoked with a plain SQL call. KhuntCmd loaded cmd.exe and ran arbitrary commands. KhuntHash pulled usernames and password material out of Oracle's internal user table. KhuntFS and KhuntFS2 listed, read, searched and sized files. KhuntT was a ping, a way to confirm the install had taken. KhuntUnzip handled archives.
- Jul 27, 2026Huntress alerted on credential theft reg.exe spawned by oracle.exe on a Windows database server
- During the intrusionSAM, SYSTEM and SECURITY hives copied written as khuntSAM.hiv, khuntSYSTEM.hiv, khuntSECURITY.hiv, plus khunttasks.txt from tasklist /svc
- Aug 5, 2026Huntress publishes the analysis requests traced to 178.162.151[.]229
The registry hives are the tell that this was not smash and grab. SAM plus SYSTEM gives you local account hashes offline, SECURITY gives you cached domain material and service account secrets. Whoever ran this wanted credentials to move sideways with, not just the contents of one database.
Why does a database get you SYSTEM on Windows?
Oracle Database ships with a Java Virtual Machine inside it. That is a feature, not a bolt-on: stored procedures can be written in Java, and CREATE JAVA SOURCE stores the source as a schema object and compiles it in place. Oracle classifies those objects alongside procedures, so an account holding the CREATE PROCEDURE system privilege can author one. From there, a Java method calling Runtime.exec runs as whatever user the database process runs as.
On Windows, that user is very often SYSTEM. The database service is installed to run with local system rights so it can touch its own files, memory and services without argument, which is convenient right up until someone reaches the JVM through a web form. On Linux the same chain lands you as the oracle user instead, which is bad but survivable. The Windows default is what turns a SQL injection in a search box into full host ownership in one hop, with no exploit, no privilege escalation bug and no patch that would have stopped it.
How is this different from a normal webshell?
| Trait | khunt, inside Oracle | Classic Tomcat webshell | SQL Server xp_cmdshell |
|---|---|---|---|
| Where the code lives | Java objects in a database schema | A .jsp file in the web root | A built-in extended procedure |
| Touches disk to install | No | Yes, a file per shell | No, it ships with the product |
| Privileges inherited | The database service account, SYSTEM on Windows | The Tomcat service user | The SQL Server service account |
| How defenders find it | Query the data dictionary for JAVA objects | File integrity monitoring, antivirus | Check whether sp_configure enabled it |
| Survives a web app redeploy | Yes, it is in the database | No, the deploy wipes it | Yes |
| Off by default | No, if the account can create procedures | Not applicable | Yes, disabled since 2005 |
The comparison that matters is the last two rows. Microsoft learned this lesson in public: xp_cmdshell was the standard SQL Server escalation path until it was switched off by default, and now finding it enabled is itself an alert. Oracle's Java path has no equivalent switch, because it is not a single dangerous feature you can turn off. It is a legitimate capability that becomes dangerous the moment the wrong account holds a very ordinary privilege. And because the toolkit lives in the database rather than the application, the usual remediation reflex of redeploying the web app leaves the backdoor exactly where it was.
What should you check in your own Oracle estate today?
Three queries and one detection rule cover most of the exposure. Start by asking which accounts can author Java at all, since that privilege is what the whole chain rests on:
-- who can create procedure-class objects, including Java sources
SELECT grantee, privilege FROM dba_sys_privs
WHERE privilege IN ('CREATE PROCEDURE','CREATE ANY PROCEDURE');
-- who holds the Java roles
SELECT grantee, granted_role FROM dba_role_privs
WHERE granted_role IN ('JAVASYSPRIV','JAVAUSERPRIV');
Any account used by a public-facing web application should appear in neither result. If one does, that is the finding, whether or not anyone has abused it yet. Then look for objects that should not exist:
-- Java objects outside the Oracle-supplied schemas
SELECT owner, object_name, object_type, created
FROM dba_objects
WHERE object_type LIKE 'JAVA%'
AND owner NOT IN ('SYS','SYSTEM','XDB','MDSYS','ORDSYS','CTXSYS','WMSYS','OLAPSYS');
-- the specific toolkit
SELECT owner, object_name, object_type FROM dba_objects
WHERE UPPER(object_name) LIKE 'KHUNT%';
On the host side, the highest-value rule is the one that caught this: alert on reg.exe, cmd.exe, powershell.exe or tasklist.exe with oracle.exe as the parent process. A database engine has no business spawning a shell, so the false positive rate is close to zero and the signal is unambiguous. Add file paths matching khunt*.hiv and khunttasks.txt, and block the reported source address 178.162.151[.]229, though treat that IP as historical rather than a lasting control.
RelatedAtlassian Rovo AI Still Leaks Jira Data via Prompt Injection
The real fix is upstream of all of it, and Huntress says so plainly: parameterise the queries, validate the input, and cut the application's database account down to the reads and writes it genuinely needs. An account that serves an autocomplete box has no reason to be able to compile Java.
Who is actually exposed here?
Not everyone running Oracle. The exposure is specific: a database reachable, even indirectly, from a public application that concatenates user input into SQL, using an account provisioned by whoever built the app rather than by whoever runs the database. That combination is most common in long-lived internal line-of-business systems, the ones written years ago by a team that has since moved on, where the connection string got a generous grant early to make something work and nobody revisited it.
Vendor-supplied applications deserve a hard look too, since the deployment guide often specifies the privileges the app account needs and administrators grant them without argument. If that guide asks for CREATE PROCEDURE on an internet-facing system, the vendor is asking you to accept this exact chain.
- Whether khunt shows up again. A named, reusable toolkit with wrappers and a connectivity checker is built for repeat use, not for one job. A second sighting would tell us this is a crew's standard kit rather than an improvisation.
- Whether Oracle tightens the default. There is no
sp_configureequivalent to flip here. A supported way to deny an account the ability to author Java, without breaking legitimate Java stored procedures, would remove the pivot outright. - Windows service accounts. The SYSTEM default is doing the heavy lifting in this chain. Running the database under a dedicated low-privilege service account is unglamorous and would have contained this to the database.
Our take
The interesting part of this case is not the malware. Six Java classes that shell out, read files and dump hashes are unremarkable code, and any competent operator could write them in an afternoon. The interesting part is the choice of where to put them. By living inside the database, khunt sits in a place most security tooling does not inspect at all: endpoint agents watch processes and files, web application firewalls watch requests, and almost nobody is diffing the data dictionary for objects that appeared overnight.
That blind spot is structural, and it is the same shape as several other quiet corners of enterprise infrastructure, the ones where a system has a legitimate scripting or extension capability that nobody thinks of as a code execution surface. Databases have it. So do backup agents, monitoring platforms and CI runners. The lesson is not to fear Oracle's JVM. It is that any component allowed to compile and run code deserves the same privilege scrutiny you would give a shell, and that a decade-old injection bug is still perfectly capable of ending in domain credentials when the account behind it was never scoped.
- ResearchHuntress: khunt malware and SQL injection in Oracle the original investigation, IOCs and recommendations
- ReferenceOracle Java Developer's Guide how the embedded JVM and Java schema objects work
- ReferenceCREATE JAVA statement the privileges required to author a Java source object
- ReferenceGENZ TECH CVE Watchlist what we are currently tracking as actively exploited
Original analysis by GenZTech. Reported by BleepingComputer and The Hacker News.
