1723 - Pentesting PPTP
Basic Information
Point-to-Point Tunneling Protocol (PPTP) is an old VPN tunneling protocol used for remote access. It uses TCP port 1723 for the control channel and IP protocol 47 (GRE) to carry the PPP payload. The traffic inside the tunnel is commonly protected with MPPE, while authentication is frequently based on MS-CHAPv2.
From an offensive perspective, the interesting part is usually not the control connection itself but the fact that capturing a PPTP/MS-CHAPv2 handshake can enable offline password or NT-hash recovery. Also remember that a host can answer on TCP/1723 while the tunnel still fails because GRE (protocol 47) is filtered.
From an assessment perspective, exposed PPTP in 2026 is usually a legacy signal. Modern Microsoft guidance has started pushing it out of default deployments: new RRAS setups on Windows Server 2025 don’t accept PPTP by default, and MSCHAPv2-based WiFi/VPN connections are explicitly called out as being subject to NTLMv1-like attacks. If you still find PPTP enabled externally, it often means an old compatibility path was kept alive on purpose.[5][6]
Default Port:1723
Enumeration
nmap -Pn -sSV -p1723 <IP>
nmap -Pn -sV --script pptp-version -p1723 <IP>
nmap -Pn -sO --protocol 47 <IP>
nmap’s pptp-version NSE script can sometimes extract hostname, vendor, or firmware details from the PPTP control channel, which is useful for quickly spotting legacy routers/VPN concentrators.
If you only confirm tcp/1723 and miss GRE, you can easily get a false sense that the VPN is reachable. During troubleshooting or sniffing, capture both the control and encapsulated traffic:
sudo tcpdump -ni <iface> 'tcp port 1723 or gre' -w pptp-handshake.pcap
tshark -r pptp-handshake.pcap -Y 'pptp || gre || ppp || chap'
If you are capturing on the VPN endpoint itself instead of from a SPAN/mirror port or another on-path vantage point, keep in mind that local PPP capture can be incomplete. On Linux in particular, normal libpcap capture on the PPP interface may miss PPP control traffic; for local troubleshooting you may need to capture the GRE packets on the physical interface or use pppd record style logging to preserve the control exchange.
If you can influence the pppd invocation on a Linux client/server, the built-in recorder is often more reliable than sniffing pppX:
# Add to the pppd options / peer file
record /tmp/pptp.record
# Decode the recorded PPP conversation later
pppdump -p /tmp/pptp.record
Brute Force
Attack Notes
MS-CHAPv2 handshake capture
For PPTP, the relevant material is the PPP authentication exchange transported inside GRE. In MS-CHAPv2 the response depends on:
- The server AuthenticatorChallenge
- The client Peer-Challenge
- The username
- The NT-Response
That means a packet capture is often enough to move the attack offline. If you can sniff the initial connection, request the user to reconnect, or position yourself on-path, capture the handshake and extract the challenge/response data.
Useful quick filters:
tshark -r pptp-handshake.pcap -Y 'chap'
tshark -r pptp-handshake.pcap -Y 'ppp and chap'
Extract the exact MS-CHAPv2 fields with tshark
Wireshark’s CHAP dissector exposes enough data to script the extraction without relying only on chapcrack:
tshark -r pptp-handshake.pcap -Y 'chap.code == 1 || chap.code == 2' \
-T fields -e frame.number -e chap.code -e chap.identifier -e chap.value -e chap.name
chap.code == 1is the server Challenge packet;chap.valueis the 16-byte AuthenticatorChallenge.chap.code == 2is the client Response packet;chap.valueis laid out asPeerChallenge[16] | Reserved[8] | NT-Response[24] | Flags[1].chap.identifierhelps you match the correct Challenge and Response if the capture contains retries or multiple negotiations.chap.nameusually contains the username used in the exchange.
Example split of a response chap.value:
python3 - <<'PY'
resp = bytes.fromhex('<chap.value from CHAP Response>')
print('PeerChallenge =', resp[:16].hex())
print('Reserved =', resp[16:24].hex())
print('NT-Response =', resp[24:48].hex())
print('Flags =', f'{resp[48]:02x}')
PY
This is handy when you want to mass-process PCAPs, validate what chapcrack extracted, or feed the values into a custom hashcat/asleap conversion script.
Convert the handshake into a hashcat workload
For PPTP/MS-CHAPv2, the 24-byte NT-Response alone is not the full story. Per RFC 2759, the effective 8-byte challenge is derived from:[3]
- The server AuthenticatorChallenge
- The client Peer-Challenge
- The UserName
In practice, this means you need to preserve those fields during extraction if you want to move from a packet capture into a modern GPU workflow. A useful pattern is:
- Parse the capture with
chapcrackortshark - Extract the username, peer-challenge, authenticator challenge, and NT-Response
- Convert the result into a
hashcat-compatibleNetNTLMv1/ESSstyle line
Do not throw away the rest of the response blob too early: in the CHAP Response Value, the Peer-Challenge, reserved bytes, NT-Response, and flags all sit next to each other, and parsing mistakes there are a common reason for uncrackable conversions.
The exact hashcat representation commonly used for MS-CHAPv2 is:[4]
<user>::<domain_or_blank>:<peer_challenge>:<nt_response>:<authenticator_challenge>
Example attack:
hashcat -m 5500 -a 0 mschapv2.hashes /usr/share/wordlists/rockyou.txt
This is operationally useful when you want to keep everything local instead of sending a token to an external cracking service, or when you already have a tuned hashcat rules/masks workflow.
Parse and decrypt with chapcrack
chapcrack is still one of the cleanest ways to process a PPTP capture:[1]
chapcrack.py parse -i pptp-handshake.pcap
If you recover the underlying secret material, you can decrypt the PPTP packet capture:
chapcrack.py decrypt -i pptp-handshake.pcap -o pptp-decrypted.pcap -n <recovered_nt_hash_or_token>
This is especially useful when the goal is not only credential recovery but also session decryption and post-auth traffic analysis.
Crack challenge/response material
If you already extracted the challenge/response pair, asleap can still be used directly against PPTP/MS-CHAPv2 material:
asleap -C 58:16:d5:ac:4b:dc:e4:0f -R 50:ae:a3:0a:10:9e:28:f9:33:1b:44:b1:3d:9e:20:91:85:e8:2e:c3:c5:4c:00:23 -W /usr/share/wordlists/rockyou.txt
asleap also supports working from packet captures or precomputed lookup tables, but for PPTP assessments the most common workflow is:
- Capture the PPTP handshake
- Extract the challenge/response
- Run offline cracking with
asleap,chapcrack, or a custom workflow
Recent tradecraft also includes NT-hash-first workflows such as assless-chaps, which recover the NT hash from MS-CHAPv2/NTLMv1 challenge-response material using a prepared hash database. This can be faster than conventional password cracking if you maintain a good NT-hash corpus:[2]
./assless-chaps <challenge> <response> <hashes.db>
This matters because for PPTP the recovered NT hash is operationally valuable by itself: once obtained, it can be used to validate the crack, decrypt captures, and pivot into Windows-oriented reuse checks.
If you plan to use this at scale during assessments, the practical bottleneck is usually not the cracking step but maintaining a good NT-hash database. assless-chaps becomes especially useful when you can prebuild SQLite databases from breached NTLM corpora, HIBP-derived NT hashes, or aggressive in-house rule expansions generated with hashcat.[2]
Protocol weakness summary
- PPTP depends on a separate GRE data channel, so firewalls often expose
tcp/1723while silently breaking the tunnel. - MS-CHAPv2 security effectively collapses to recovering DES-derived material / NT-hash-equivalent secrets, making passive capture much more dangerous than with modern VPNs.
- Even if the password is not immediately recovered, the handshake can usually be stored and attacked offline later.
- In current enterprise environments, a reachable PPTP listener often indicates a deliberately preserved legacy path, not a default deployment, which makes it especially interesting for password-reuse and lateral-movement testing.