I enjoy listening to the Darknet Diaries podcast by Jack Rhysider. In a recent episode a guest of the show was telling a story about how he managed to compromise a computer network while in prison for… You guessed it! Hacking. Anyway, the story of the hack isn’t what I wanted to discuss with you in this blog post. Instead, I wanted to talk about the hack itself, the vulnerability that it exploits, and how you can stop it with some simple scripting.
Setting The Stage
The hack involves the accessibility tools built into Windows. An attacker with physical access to your machine can abuse them at your Windows logon screen to do pretty much whatever they want. I know what you’re thinking, “But if the attacker already has physical access, why bother?” You have a point. Most attackers who have physical access to a machine will be able to gain control over that machine. This is true in almost every scenario. An attacker with physical access can almost always find some workaround to undermine your security. Whether they use a removable device, brute force attacks, or just plain-old-taking the cover off and making off with the disk drives… You’d be hard pressed to beat an attack when the attacker has your equipment and you don’t.
But there are circumstances where a potential attacker has physical access but still lacks the time, privacy, or tools to pull off an attack. Like in prison, where you have to be covert or guards will spot you. Or at work, where your co-workers might ask how you managed to get into the BIOS of a company computer, or at school where the librarian might ask why you’re taking her computers apart. These are all places where internal attacks become too risky and/or time-consuming to pull off. The Accessibility Tools hack is one where you need to enter the BIOS of the machine and reboot several times. That takes a while, and although the skill level of the attack is low, it’s still a very dangerous proposition to have an attacker with local admin access on your network. Lets setup a sandbox scenario…You’re a domain administrator named Bob with 50 machines on your network. Someone has pulled off an Accessibility Tools hack on a machine and has local admin rights whenever they want. They install a keylogger on the machine and forget about it until 3 days later you get a ticket to take a look at the machine because someone can’t get into their email. You log on remotely but nothing is broken. You sip your coffee and work up the nerve to go teach this person how to use their email. You make your way to the machine and, without thinking twice, blast your domain admin credentials into their machine in the process of helping them. Now the attacker has your domain admin credentials, and they don’t even need physical access anymore.
So, back to the attack. You start off with a USB thumb drive. Install your favorite flavor of Linux Live onto it so you can boot straight into a root shell. I like the Trinity Rescue Kit for this type of thing, because it comes with tons of tools like Windows password resetting, ClamScanning, and tons more.
Next, boot the target machine to the USB stick where you installed Linux. If you have it boot right into a shell, great! If not, get to a shell, and make it root! Next mount the local Windows filesystem somewhere and use cp or rm to get “/Windows/System32/Magnify.exe” out of the way. Then cp or mv “/Windows/System32/cmd.exe” to “/Windows/System32/Magnify.exe.” The commands you use depend on stealth/time constraints and how much the you care about putting things back later. You can also use any of the other accessibility tools to achieve the same attack.
Next reboot the machine and load the accessibility tool that you replaced with cmd.exe. You now have a SYSTEM command prompt. Because the file is owned by TrustedInstaller, it’s extremely difficult to modify this in a production domain environment with a standard user account, but if you can find a computer with USB ports enabled and an unprotected BIOS this should be relatively easy to pull off.
There are several prerequisites that need to be in-place for this attack to work.
- BIOS password disabled.
- USB ports enabled.
- Removable storage (CD/USB/floppy) set before primary OS boot device in BIOS.
- Accessibility Tools at logon screen enabled by Group Policy Management or Local Group Policy Editor.
If number 4 from the list above combines with number 1 or 3 then the conditions exist for Accessibility Tool exploits. So the easiest way out of this mess might just be to flip-the-switch on numbers 1 and 3 using built-in Windows functionality, or disable number 4 either on a standalone machine using the Local Group Policy Editor, or on a domain network using Group Policy Management.
Of course the easiest way isn’t always the best way. The Accessibility Tools do provide valuable features. I can’t tell you how many times the on-screen-keyboard has helped me fix laptops that took spills, or get around dead keyboard batteries, or diagnose machines with wonky drivers. Group Policy can control which machines get which policies, so it’s possible to be selective… but I’d rather just leave them on incase someone needs them. We can figure out a programmatic solution for this problem.
We need to develop a script for detecting this attack. As far as attacks go, this one is pretty noisy. Moving around Windows files in the System32 directory is the hacker equivilent of sticking your head out of the trenches. Since we know specifically which files are going to be affected we should be able to simply diff some hashes and check for file existence to be sure there was no tampering. Other possible metrics to use for tamper detection include filesize caching/diff’ing and date modified caching/diff’ing. By checking, caching, or simply hardcoding a predicted filesize or date modified we can compare the cache or hardcoded data with the current ecosystem. If things aren’t exactly the way we left them, we know someone’s tampered with the system.
oShell, oFSO, dangerousExes, exe, cmdHardCodedHash, cmdDynamicHash,
strComputerName, strUserName, strLogFilePath, strSafeDate, _
strSafeTime, strDateTime, strLogFileName, strEventInfo, objLogFile, cmdHashCache, objCmdHashCache, dangerHashCache, _
dangerHashData, mailFile, objDangerHashCache, oFile
Set oShell = WScript.CreateObject(“WScript.Shell”)
Set oFSO = CreateObject(“Scripting.FileSystemObject”)
dangerousExes = Array(“Magnify.exe”, “Narrator.exe”, “osk.exe”, “sapisvr.exe”, “control.exe”, “utilman.exe”)
cmdHardCodedHash = “db 06 c3 53 49 64 e3 fc 79 d2 76 31 44 ba 53 74 2d 7f a2 50 ca 33 6f 4a 0f e7 24 b7 5a af f3 86”
cmdDynamicHash = “”
strComputerName = oShell.ExpandEnvironmentStrings(“%COMPUTERNAME%”)
strUserName = oShell.ExpandEnvironmentStrings(“%USERNAME%”)
strLogFilePath = “\\server\Logs”
strSafeDate = DatePart(“yyyy”,Date) & Right(“0” & DatePart(“m”,Date), 2) & Right(“0” & DatePart(“d”,Date), 2)
strSafeTime = Right(“0” & Hour(Now), 2) & Right(“0” & Minute(Now), 2) & Right(“0” & Second(Now), 2)
strDateTime = strSafeDate & “-” & strSafeTime
strLogFileName = strLogFilePath & “\” & strComputerName & “-” & strDateTime & “-Accessibility_Defender.txt”
cmdHashCache = “C:\cmdHashCache.dat”
dangerHashCache = “C:\dangerHashCache.dat”
mailFile = “C:\Accessibility_Defender_Warning.mail”
‘A function to clear the previous dangerCache and create a new one.
If oFSO.FileExists(dangerHashCache) Then
If Not oFSO.FileExists(dangerHashCache) Then
‘A function to create the CMD Hash Cache file.
If oFSO.FileExists(“C:\Windows\System32\cmd.exe”) Then
oShell.run “cmd /c CertUtil -hashfile “”C:\Windows\System32\cmd.exe””
SHA256 | find /i /v “”SHA256″” | find /i /v “”certutil”” > ” &
cmdHashCache, 0, TRUE
‘A function to hash each of the hardcoded files and cache the value.
For Each exe In dangerousExes
If oFSO.FileExists(“C:\Windows\System32\” & exe) Then
oShell.run “cmd /c CertUtil -hashfile “”C:\Windows\System32\” & exe
& “”” SHA256 | find /i /v “”SHA256″” | find /i /v “”certutil””
>> ” & dangerHashCache, 0, TRUE
‘A function to read the CMD hash cache.
If oFSO.FileExists(cmdHashCache) Then
Set objCmdHashCache = oFSO.OpenTextFile(cmdHashCache)
cmdHashData = objCmdHashCache.ReadAll()
‘A function to read the Danger hash cache and compare it to the CMD hash cache and hardcoded CMD hash.
hashMatch = FALSE
If oFSO.FileExists(dangerHashCache) Then
Set objDangerHashCache = oFSO.OpenTextFile(dangerHashCache)
Do While Not objDangerHashCache.AtEndOfStream
dangerHashData = objDangerHashCache.ReadLine()
If dangerHashData = cmdHashData() Or dangerHashData = cmdHardCodedHash Then
hashMatch = TRUE
Obviously, like all good programmers, we’re going to want to log the results of our script. I like to keep a centralized log location for all my network wide scripts so that I can breeze through it every few hours to spot problems.
‘A function to create a log file.
If Not (strEventInfo = “”) Then
Set objLogFile = oFSO.CreateTextFile(strLogFileName, True)
Ok, so we have a good idea of how we can detect and keep track of these issues. But how can we stop it? The damage has already been done. We need an administrator to come investigate. A lot of old school Windows script blogs will tell you to use the deprecated Microsoft schemas for sending emails with Windows scripting languages, but I prefer Fake Sendmail For Windows by Byron Jones. It’s small, lightweight, and easy to use. Especially programmatically. I like to write my emails to a file and then execute sendmail on the file. That way there’s an intrinsic logging process built-in when the script leaves the sent mail message file behind. You will need to download this program and copy all of its files to your project folder.
If oFSO.FileExists(mailFile) Then
If Not oFSO.FileExists(mailFile) Then
Set oFile = oFSO.CreateTextFile(mailFile, True)
oFile.Write “To: IT@COMPANY.com” & vbNewLine & “From: server@COMPANY.com” & vbNewLine & _
“Subject: COMPANY Accessibility Defender Warning!!!” & vbNewLine & _
“This is an automatic email from the COMPANY Network to notify you
that a workstation was defended from Accessibility Tools exploitation.”
vbNewLine & vbNewLine & “Please log-in and verify that the equipment listed below is secure.” & vbNewLine & _
vbNewLine & “USER NAME: ” & strUserName & vbNewLine &
“WORKSTATION: ” & strComputerName & vbNewLine & _
“This check was generated by ” & strComputerName & ” and is
performed when Windows boots.” & vbNewLine & vbNewLine & _
End Function’A function for running SendMail.
oShell.run “cmd /c sendmail.exe ” & mailFile, 0, TRUE
Now we’ve detected an exploit in-progress and notified our IT department. We still have an attacker on a vulnerable machine staring down the sights of a loaded root shell with our machine on the receiving end. The only thing we can really do is log what’s happening to this machine and shut it down in the attackers face. He can always turn it back on, but it will just power off again once our script executes.
‘A function to kill the machine.
oShell.Run “cmd /c C:\windows\system32\shutdown.exe”, 0, false
Awesome! Now we’ve created all of the functionality we need and it’s all neatly organized into cohesive functions that we can call. It’s now time to write the bread-and-butter of our script. This is going to control the flow of our application and run all of the functions we made in the desired order. Note the conditional statement that executes if one of the Accessibility Tools has been compromised.
hashMatch()If hashMatch = TRUE Then
createLog(“The machine ” & strComputerName & ” just attempted to execute an Accessibility Tools exploitation!”)
The Victory Lap
Now our attacker is a deer in the headlights. He’s staring at a broken shutdown loop that he probably realizes he created, and IT is probably on the way. Typically when I write scripts that write data to the log directory I like to add the username that generated the log as well, but in this case that’s not possible because the script runs on machine startup, before a user has logged in.
And there you have it! We’ve just written our own heuristic tool for determining when someone is messing around on our network. You should still seek to password protect the BIOS’s in your organization and remove all the boot devices except for the primary OS drive. If possible, consider disabling unpopulated USB ports. If that’s impossible without creating mutiny, try to make a script of your own to detect when someone plugs in a USB device. I made one that sends me an email and writes a log whenever someone plugs in a storage device. It could easily be modified to reject certain devices, or quietly scan them in the background for large file changes or sensitive data your business doesn’t want exfiltrated. That’s a project for another day.
When you’re an administrator you’ve got the best team in the entire company on your side…. The equipment. Don’t work hard, work smart… And make your equipment work hard for you.