Unpatched Internal Network Services
How Unpatched Internal Network Services works
An unpatched internal network service is a listening daemon running a build with a known, vendor-fixed vulnerability. On the internal estate that means SMB and RPC on every Windows host, RDP on jump boxes, the print spooler, SQL Server, PostgreSQL and MySQL back ends, and the application tier that grows in the dark - Jenkins, Confluence, GitLab, TeamCity and their kin. Each one advertises enough version detail, in a banner or an authenticated query, to place it on the vendor’s patch timeline.
The tester does not need an exploit to raise the finding: a version below the fixed-in build for a known CVE is the finding, and a safe check module confirms exposure without the destructive payload. What the attacker gains is code execution or a credential-bearing crash on a host already inside the trust boundary, then lateral movement. It survives review because these services are internal and assumed safe, patch reporting rolls up to a green percentage that hides the one CI server nobody agent-managed, and a banner that looks current can hide a distro back-port gap or, conversely, a back-ported fix a naive version match would flag wrongly.
Unpatched Internal Network Services in practice
Enumerate listening services across the segment
Start with a version-detecting sweep of the common internal service ports so every subsequent lookup has a concrete build string behind it.
# Version-detect the common internal service ports on the lab segment
nmap -sV -Pn -p 135,139,445,1433,3306,3389,5432,8080,8443 \
--version-intensity 5 -oA internal_svc_scan 10.10.20.0/24
# SMB dialect and signing detail on one host
nmap -Pn -p445 --script smb2-security-mode,smb-protocols host01.lab.internal
Pull build detail from Windows and Linux hosts
Banners are thin for SMB, RPC and the print spooler, so confirm the exact build. From an authorised session on a Windows target, read the OS build and last hotfix; for the app tier, read the version header.
# On an authorised Windows session: exact build and most recent hotfixes
Get-CimInstance Win32_OperatingSystem |
Select-Object Caption, Version, BuildNumber
Get-HotFix | Sort-Object InstalledOn -Descending |
Select-Object -First 5 HotFixID, InstalledOn
# App-tier version strings over HTTP(S), read-only
curl -skI https://jenkins.lab.internal:8443/login | grep -i "x-jenkins:"
curl -sk https://confluence.lab.internal/ | grep -oE 'Confluence [0-9.]+'
# Linux daemon banner (version string only, no distro back-port context)
nc -w3 db01.lab.internal 5432 </dev/null | head -c 120
Map the observed version to a fixed-in advisory
This is the step that turns a version string into a finding. Compare each observed build to the vendor’s fixed-in version, and flag the back-port ambiguity rather than guessing.
Observed Fixed-in (vendor advisory) Verdict
-------------------------- ----------------------------- -----------------
Jenkins 2.401.1 2.401.3 below -> finding
Confluence 7.13.0 7.13.20 / 7.19.x below -> finding
SQL Server 15.0.2000 current CU for the branch below -> finding
SMBv1 dialect enabled disable dialect entirely config -> finding
OpenSSH_8.2p1 (Ubuntu) distro back-ports the fix check pkg, not banner
Confirm exposure with a safe check, not the exploit
Prove exploitability with detection-only modules against the lab host. These report likely-vulnerable without sending the payload that would crash or compromise the service.
# Metasploit auxiliary scanner: detection only, no exploitation
msfconsole -q -x "use auxiliary/scanner/smb/smb_ms17_010; \
set RHOSTS 10.10.20.15; run; exit"
# nmap vuln-category scripts detect many CVEs without exploiting them
nmap -Pn -p445 --script smb-vuln-ms17-010 10.10.20.15
A “likely vulnerable” result plus the version-to-advisory map is the evidence. The destructive exploit is the real-world next action and is deliberately not run on a production estate.
How to fix and prevent Unpatched Internal Network Services
- Patch the reachable service tier on a defined cadence
- Prioritise services listening on user-reachable internal segments and those with a public proof of concept over raw CVSS.
- Reconcile the patch agent’s inventory against a network sweep
- The dangerous host is the one no agent reports on. Compare the update tool’s asset list to an nmap sweep of live service ports.
- Manage the application tier as software, not as a black box
- Jenkins, Confluence, GitLab and database engines need named owners and an update schedule; they rarely fall under OS patch tooling.
- Verify by version, accounting for distro back-ports
- On Linux, check the package build and changelog rather than the banner, so a back-ported fix is not misread as vulnerable and a real gap is not missed.
- Disable superseded protocols outright
- Remove SMBv1 and other legacy dialects rather than waiting for a patch; the fix is disablement, not update.
Last updated