Flight
Flight
Overview
Flight is a hard-rated Windows machine. It starts with a website running two virtual hosts, one of which is vulnerable to LFI. We abuse the LFI to grab an NTLMv2 hash and crack it offline.
With the cleartext password in hand, we spray it across a list of valid usernames and find a password-reuse case that gives us another account. That account can write to a share, so we drop a file that forces other users to authenticate to us when they access it, letting us steal a second NTLMv2 hash. We crack that one too and use the credentials to write a PHP webshell onto the share that one of the virtual hosts is mounted on.
Having compromised the web service user, we move to the more privileged account from the second cracked hash and use it to write an ASPX webshell on a development web application that only listens on localhost.
This lands us a shell as the IIS application pool virtual account, which holds the SeImpersonatePrivilege which we abuse to escalate to NT AUTHORITY\SYSTEM.
Pwning
We start off with a nmap scan to identify the open ports
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
┌──(kali㉿kali)-[~/Desktop/OSCP/Prep/Flight]
└─$ cat 10.129.228.120.scan
# Nmap 7.99 scan initiated Mon Oct 5 14:15:54 2026 as: /usr/lib/nmap/nmap --privileged -vvv -p 53,80,88,135,139,389,445,464,593,636,3269,3268,5985,9389,49667,49673,49674,49699,49737 -4 -A -oN 10.129.228.120.scan -Pn 10.129.228.120
Nmap scan report for G0.flight.htb (10.129.228.120)
Host is up, received user-set (0.21s latency).
Scanned at 2026-10-05 14:15:59 WAT for 113s
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack ttl 127 Simple DNS Plus
80/tcp open http syn-ack ttl 127 Apache httpd 2.4.52 ((Win64) OpenSSL/1.1.1m PHP/8.1.1)
|_http-title: g0 Aviation
| http-methods:
| Supported Methods: POST OPTIONS HEAD GET TRACE
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.52 (Win64) OpenSSL/1.1.1m PHP/8.1.1
88/tcp open kerberos-sec syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2026-10-05 20:15:40Z)
135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 127 Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: flight.htb, Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack ttl 127
464/tcp open kpasswd5? syn-ack ttl 127
593/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack ttl 127
3268/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: flight.htb, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack ttl 127
5985/tcp open http syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf syn-ack ttl 127 .NET Message Framing
49667/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49673/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
49674/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49699/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49737/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
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|10 (97%)
OS CPE: cpe:/o:microsoft:windows_server_2019 cpe:/o:microsoft:windows_10
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
Aggressive OS guesses: Microsoft Windows Server 2019 (97%), Microsoft Windows 10 1903 - 22H2 (91%)
No exact OS matches for host (test conditions non-ideal).
TCP/IP fingerprint:
SCAN(V=7.99%E=4%D=10/5%OT=53%CT=%CU=%PV=Y%DS=2%DC=T%G=N%TM=6AC3A380%P=x86_64-pc-linux-gnu)
SEQ(SP=105%GCD=1%ISR=10B%TI=I%II=I%SS=S%TS=U)
SEQ(SP=105%GCD=1%ISR=10C%TI=I%II=I%SS=S%TS=U)
OPS(O1=M552NW8NNS%O2=M552NW8NNS%O3=M552NW8%O4=M552NW8NNS%O5=M552NW8NNS%O6=M552NNS)
WIN(W1=FFFF%W2=FFFF%W3=FFFF%W4=FFFF%W5=FFFF%W6=FF70)
ECN(R=Y%DF=Y%TG=80%W=FFFF%O=M552NW8NNS%CC=Y%Q=)
T1(R=Y%DF=Y%TG=80%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=N)
U1(R=N)
IE(R=Y%DFI=N%TG=80%CD=Z)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: Incremental
Service Info: Host: G0; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2026-10-05T20:16:40
|_ start_date: N/A
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled and required
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 50845/tcp): CLEAN (Timeout)
| Check 2 (port 32149/tcp): CLEAN (Timeout)
| Check 3 (port 21917/udp): CLEAN (Timeout)
| Check 4 (port 28337/udp): CLEAN (Timeout)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
|_clock-skew: 6h59m31s
TRACEROUTE (using port 139/tcp)
HOP RTT ADDRESS
1 209.55 ms 10.10.14.1
2 209.75 ms G0.flight.htb (10.129.228.120)
Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Oct 5 14:17:52 2026 -- 1 IP address (1 host up) scanned in 118.65 seconds
From the presence of:
- 53 (DNS)
- 88 (Kerberos)
we can tell this is an Active Directory domain controller.
NetExec (https://github.com/Pennyw0rth/NetExec) can be used to enumerate the host over SMB and pull its FQDN and domain name, which we then add to our local /etc/hosts file.
It’s also important to sync our local clock with the DC to avoid Kerberos clock-skew issues.
1
2
3
4
┌──(kali㉿kali)-[~/Desktop/OSCP/Prep/Flight]
└─$ sudo ntpdate flight.htb
2026-10-05 23:55:37.302022 (+0100) +678.814538 +/- 0.117473 flight.htb 10.129.101.114 s1 no-leap
CLOCK: time stepped by 678.814538
Starting with enumeration, our attack surface isn’t large since we don’t have any valid domain credentials yet, so we begin by authenticating to the services as an anonymous user.
With the SMB and LDAP services running, I tried to authenticate using null credentials.
That doesn’t work, so our focus shifts fully to the web application.
Accessing it shows that it’s an Airline Flight Planner.
The page is pretty much static and from the fingerprinting nmap did, we know that this is an Apache web server running PHP/8.1.1
I went ahead and fuzzed for files and directories but got nothing. Fuzzing for virtual hosts, however, gave me school.flight.htb.
After poking around the application, I noticed it loads pages through a file-inclusion parameter (e.g. ?view=), which immediately hints at a possible LFI.
Attempts to traverse shows it’s filtered and blocked.
Since I have no idea what filtering is in place, we can either try a few characters manually to see which ones get blocked, or fuzz the parameter with a payload list and see which entries succeed.
A useful observation from the fuzz output is that the filter doesn’t block any file read as long as the Windows path separator \ isn’t used… but that’s not much of a restriction, since forward slashes / work just as well on Windows for path traversal.
We could have also just read the source code index.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
ini_set('display_errors', 0);
error_reporting(E_ERROR | E_WARNING | E_PARSE);
if(isset($_GET['view'])){
$file=$_GET['view'];
if ((strpos(urldecode($_GET['view']),'..')!==false)||
(strpos(urldecode(strtolower($_GET['view'])),'filter')!==false)||
(strpos(urldecode($_GET['view']),'\\')!==false)||
(strpos(urldecode($_GET['view']),'htaccess')!==false)||
(strpos(urldecode($_GET['view']),'.shtml')!==false)
){
echo "<h1>Suspicious Activity Blocked!";
echo "<h3>Incident will be reported</h3>\r\n";
}else{
echo file_get_contents($_GET['view']);
}
}else{
echo file_get_contents("C:\\xampp\\htdocs\\school.flight.htb\\home.html");
}
?>
This confirms our assumption, as we now know the filter in place.
Since the function file_get_contents is used, this makes getting RCE tough because it only gives us limited file read primitive.
I read the php.ini file to see if the dangerous option allow_url_include is enabled but unfortunately it isn’t.
Click to expand the full php.ini
```text ┌──(kali㉿kali)-[~/Desktop/OSCP/Prep/Flight] └─$ grep -Ev '^\s*(;|$)' a.txt engine = On short_open_tag = Off precision = 14 output_buffering = 4096 zlib.output_compression = Off implicit_flush = Off unserialize_callback_func = serialize_precision = -1 disable_functions = disable_classes = zend.enable_gc = On zend.exception_ignore_args = Off zend.exception_string_param_max_len = 15 expose_php = On max_execution_time = 120 max_input_time = 60 memory_limit = 512M error_reporting = E_ALL display_errors = On display_startup_errors = On log_errors = On ignore_repeated_errors = Off ignore_repeated_source = Off report_memleaks = On variables_order = "GPCS" request_order = "GP" register_argc_argv = Off auto_globals_jit = On post_max_size = 40M auto_prepend_file = auto_append_file = default_mimetype = "text/html" default_charset = "UTF-8" include_path = \xampp\php\PEAR doc_root = user_dir = extension_dir = "\xampp\php\ext" enable_dl = Off file_uploads = On upload_tmp_dir = "\xampp\tmp" upload_max_filesize = 40M max_file_uploads = 20 allow_url_fopen = On allow_url_include = Off default_socket_timeout = 60 extension=bz2 extension=curl extension=fileinfo extension=gettext extension=mbstring extension=exif ; Must be after mbstring as it depends on it extension=mysqli extension=pdo_mysql extension=pdo_sqlite asp_tags=Off display_startup_errors=On track_errors=Off y2k_compliance=On allow_call_time_pass_reference=Off safe_mode=Off safe_mode_gid=Off safe_mode_allowed_env_vars=PHP_ safe_mode_protected_env_vars=LD_LIBRARY_PATH error_log="\xampp\php\logs\php_error_log" register_globals=Off register_long_arrays=Off magic_quotes_gpc=Off magic_quotes_runtime=Off magic_quotes_sybase=Off extension=php_openssl.dll extension=php_ftp.dll [CLI Server] cli_server.color = On [Date] [filter] [iconv] [imap] [intl] [sqlite3] [Pcre] [Pdo] pdo_mysql.default_socket="MySQL" [Pdo_mysql] pdo_mysql.default_socket= [Phar] [mail function] SMTP = localhost smtp_port = 25 mail.add_x_header = Off [ODBC] odbc.allow_persistent = On odbc.check_persistent = On odbc.max_persistent = -1 odbc.max_links = -1 odbc.defaultlrl = 4096 odbc.defaultbinmode = 1 [MySQLi] mysqli.max_persistent = -1 mysqli.allow_persistent = On mysqli.max_links = -1 mysqli.default_port = 3306 mysqli.default_socket = mysqli.default_host = mysqli.default_user = mysqli.default_pw = mysqli.reconnect = Off [mysqlnd] mysqlnd.collect_statistics = On mysqlnd.collect_memory_statistics = On [OCI8] [PostgreSQL] pgsql.allow_persistent = On pgsql.auto_reset_persistent = Off pgsql.max_persistent = -1 pgsql.max_links = -1 pgsql.ignore_notice = 0 pgsql.log_notice = 0 [bcmath] bcmath.scale = 0 [browscap] browscap = "\xampp\php\extras\browscap.ini" [Session] session.save_handler = files session.save_path = "\xampp\tmp" session.use_strict_mode = 0 session.use_cookies = 1 session.use_only_cookies = 1 session.name = PHPSESSID session.auto_start = 0 session.cookie_lifetime = 0 session.cookie_path = / session.cookie_domain = session.cookie_httponly = session.cookie_samesite = session.serialize_handler = php session.gc_probability = 1 session.gc_divisor = 1000 session.gc_maxlifetime = 1440 session.referer_check = session.cache_limiter = nocache session.cache_expire = 180 session.use_trans_sid = 0 session.sid_length = 26 session.trans_sid_tags = "a=href,area=href,frame=src,form=" session.sid_bits_per_character = 5 [Assertion] zend.assertions = 1 [COM] [mbstring] [gd] [exif] [Tidy] tidy.clean_output = Off [soap] soap.wsdl_cache_enabled=1 soap.wsdl_cache_dir="/tmp" soap.wsdl_cache_ttl=86400 soap.wsdl_cache_limit = 5 [sysvshm] [ldap] ldap.max_links = -1 [dba] [opcache] [curl] curl.cainfo = "\xampp\apache\bin\curl-ca-bundle.crt" [openssl] openssl.cafile = "\xampp\apache\bin\curl-ca-bundle.crt" [ffi] [Syslog] define_syslog_variables=Off [Session] define_syslog_variables=Off [Date] date.timezone=Europe/Berlin [MySQL] mysql.allow_local_infile=On mysql.allow_persistent=On mysql.cache_size=2000 mysql.max_persistent=-1 mysql.max_link=-1 mysql.default_port=3306 mysql.default_socket="MySQL" mysql.connect_timeout=3 mysql.trace_mode=Off [Sybase-CT] sybct.allow_persistent=On sybct.max_persistent=-1 sybct.max_links=-1 sybct.min_server_severity=10 sybct.min_client_severity=10 [MSSQL] mssql.allow_persistent=On mssql.max_persistent=-1 mssql.max_links=-1 mssql.min_error_severity=10 mssql.min_message_severity=10 mssql.compatability_mode=Off mssql.secure_connection=Off ``` I also read the virtual host configuration file to check for any vhosts I might have missed. It’s located at C:/xampp/apache/conf/extra/httpd-vhosts.conf
1
2
3
4
5
6
7
8
<VirtualHost *:80>
DocumentRoot "C:\xampp\htdocs\flight.htb"
ServerName flight.htb
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "C:\xampp\htdocs\school.flight.htb"
ServerName school.flight.htb
</VirtualHost>
1
svc_apache:S@Ss!K@*t13
1
c.bum:Tikkycoll_431012284
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
< Server: Microsoft-IIS/10.0
< X-Powered-By: ASP.NET
< Date: Mon, 05 Oct 2026 22:04:43 GMT
< Content-Length: 4848
<
* Connection #0 to host 127.0.0.1 left intact













