Thick clients store ample information on the device. In this part, we are going to investigate DVTA to see what, how, and where it stores data. We are also going to do some basic DLL hijacking. Our tools are procmon, PowerSploit, and dnSpy.
Previous parts are at:
In Part 4 we discovered the MSSQL credentials through dynamic analysis with dnSpy. The credentials are admin:p@ssw0rd
. This time we are going to see where they are stored and how.
Open up dnSpy and load the application. Search for the RegisterUser
method (if the search is not successful manually drag and drop DBAccess.dll
). Right-click on the RegisterUser
method and select Analyze
. Note we are not in the main application anymore but inside DBAccess.dll
. Under Used By
we can see btnReg_Click
.
Tracing RegisterUser
Inside btnReg_Click
the connection is being created:
Inside btnReg_Click
Double-clicking on openConnection
takes us to the method that establishes the connection.
openConnection method
The application is reading some information from ConfigurationManager.AppSettings
. This information comes from the AppSettings
tag in the configuration file. If the application is named myFancyApp.exe
then the configuration file is usually named myFancyApp.exe.config
.
I have written about configuration files before in context of proxying. More background material here:
Open the configuration file dvta-master\DVTA\DVTA\bin\Release\DVTA.exe.config
and look inside. It's an XML file with an appSettings
section:
<appSettings>
<add key="DBSERVER" value="127.0.0.1\SQLEXPRESS" />
<add key="DBNAME" value="DVTA" />
<add key="DBUSERNAME" value="sa" />
<add key="DBPASSWORD" value="CTsvjZ0jQghXYWbSRcPxpQ==" />
<add key="AESKEY" value="J8gLXc454o5tW2HEF7HahcXPufj9v8k8" />
<add key="IV" value="fq20T0gMnXa6g0l4" />
<add key="ClientSettingsProvider.ServiceUri" value="" />
</appSettings>
As you can guess, DBPASSWORD
is base64 encoded and encrypted. We can decrypt it with this program on Go playground: https://play.golang.org/p/7Vjw2Asr4Lo.
package main
import (
"fmt"
"crypto/aes"
"encoding/base64"
"crypto/cipher"
)
func main() {
dbPassword, err := base64.StdEncoding.DecodeString("CTsvjZ0jQghXYWbSRcPxpQ==")
if err != nil {
panic(err)
}
aesKey := []byte("J8gLXc454o5tW2HEF7HahcXPufj9v8k8")
iv := []byte("fq20T0gMnXa6g0l4")
cb, err := aes.NewCipher(aesKey)
if err != nil {
panic(err)
}
mode := cipher.NewCBCDecrypter(cb, iv)
dec := make([]byte, len(dbPassword))
mode.CryptBlocks(dec, dbPassword)
fmt.Printf("% x\n", dec)
fmt.Printf("%s", dec)
}
Result is (note the PKCS#7 padding):
70 40 73 73 77 30 72 64 08 08 08 08 08 08 08 08
p@ssw0rd
If we did not know the algorithm, we had to investigate in dnSpy. Click on decryptPassword
:
public string decryptPassword()
{
string s = ConfigurationManager.AppSettings["DBPASSWORD"].ToString();
string key = ConfigurationManager.AppSettings["AESKEY"].ToString();
string IV = ConfigurationManager.AppSettings["IV"].ToString();
byte[] encryptedBytes = Convert.FromBase64String(s);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = Encoding.ASCII.GetBytes(key);
aes.IV = Encoding.ASCII.GetBytes(IV);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
byte[] decryptedbytes = aes.CreateDecryptor(aes.Key, aes.IV).TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
this.decryptedDBPassword = Encoding.ASCII.GetString(decryptedbytes);
Console.WriteLine(this.decryptedDBPassword);
return this.decryptedDBPassword;
}
Which is similar to what we did. Note it's also printed to console.
What else is there? Applications usually store information in local files and the registry. We can use procmon to view their filesystem activity. Start procmon and then the application. In procmon, only keep the Process Name is dvta.exe
filter and remove our previous ones. Then use the menu buttons to only Show File System Activity
. It's beside the Network Activity
button that we used before.
Enabling Network Activity
procmon displays files accessed by the application:
Reading the config file
To reduce clutter, you can add filters and exclude paths.
Play with the application and sign-in with a few different users, Unfortunately it seems like the application does not store any information in local files. However, do not close procmon because we are going to do some DLL hijacking.
There are a lot of articles that explain it much better than me so I am going to do a short description and then link to resources. DLL hijacking happens when the application is looking for a DLL not via an absolute path. This means Windows will search for the DLL is specific paths starting with the root directory of the application. If it's not found in one, it will move on to the other. If attackers have write access to one of those paths (that is higher on the search hierarchy than where the actual DLL is), they can put a malicious DLL there and effectively take control of the application.
Some links from Microsoft:
You can find so many more with a search.
First, we need to figure out which DLLs are vulnerable to hijacking. I am going to show two ways.
To discover DLL hijacking entry points, we can use procmon. Add these filters:
Process Name contains DVTA
Result is NAME NOT FOUND
Path ends with dll
Procmon filters for DLL hijacking
A lot of results pop up:
NAME NOT FOUND results
The application is looking for these DLLs in the current directory (or other paths) and cannot find them. This means, Windows will search for these DLLs on the machine according to the search order.
PowerSploit also has utilities for identifying (and performing) DLL hijacking.
To install PowerSploit:
C:\Users\IEUser\Documents\WindowsPowerShell\Modules
where IEUser
is the current user.Set-ExecutionPolicy bypass
. This will disable all the warnings. You are running in a VM right?Import-Module PowerSploit
.Run the application and execute the following PowerShell command (we have auto-complete):
Find-ProcessDLLHijack DVTA-v3 | Format-List
I have patched the utility three times, so my executable is named DVTA-v3
. Replace it with your process name.
Hijackable DLLs according to PowerSploit
Without write access to somewhere high enough in the search path to replace the DLL, we cannot do anything. In our sample setup, this is not a problem because we most likely have admin on the machine. In the real world, be sure to check ACLs for write access.
There are also other paths, Find-PathDLLHijack
can identify them.
Paths with Write Access
Now we need to write it to the path identified in the previous section with Write-HijackDll
. I chose VERSION.dll
.
We can deploy with PowerSploit using Write-HijackDll
. It creates a bat file, runs the command in it and deletes itself. We can specify the bat file path with -BatPath
and the command with -Command
:
Write-HijackDll -BatPath b.bat -Command "copy NUL testfile.txt"
Deploying the DLL with Wire-HijackDll
We run the application and nothing happens. Why? Let's investigate with procmon.
Disable the NAME NOT FOUND
filter and add a new filter Path contains version.dll
.
Path contains version.dll filter
Which shows us that version.dll
was found in System32
. Our malicious DLL was not high enough on the DLL search order hierarchy.
version.dll found in System32
We need to deploy the DLL to the application directory. I also learned another lesson, either store the bat file in the same directory as the DLL or provide the full path when running Write-HijackDll
. This time I also changed the payload to pop calc.exe
.
Running Write-HijackDll again
And run the application again.
Calc executed
Registry hives are also popular places for storing information. Procmon allows us to monitor registry activity too. Run procmon and keep the Process Name contains dvta
filter. Disable all other filters from before. Enable registry activity with the Show Registry Activity
button. It is to the left of the file activity one.
Show registry activity button
Run the application and see the registry keys that are accessed.
Registry activity in procmon
But this is too much, we only want to see what registry keys are created or modified. Add a new filter Operation is RegSetValue
(you can also add RegCreateKey
). Login to the application and see the important events roll in.
Registry keys modified by the app
The application writes password and other information to the registry at HKCU\dvta
. These keys are also not erased when the user exits.
DVTA registry keys
That was it for part five. We learned how to look at client-side storage, trace registry activity, and did a bit of DLL hijacking. At this point I think I am done with this app. I might have missed some parts.
I hope this helped. Thanks for reading this and if you have any questions/feedback, you know where to find me.