---
title: "The Service Was Observed. The Application Was Still Unknown."
description: "Passive internet data can reveal a live service without proving its current owner, hostname, virtual host, application, or business purpose. A defensible external pentest turns that observation into a bounded application model before testing for vulnerabilities."
date: 2026-09-10
author: Sevban Dönmez (@jankesec)
canonical: https://jankesec.com/posts/service-observation-application-mapping/
---

## Service observation in 60 seconds

A passive internet platform reports that `203.0.113.42:8443` spoke TLS yesterday. The certificate
contained a familiar domain. The response resembled an application server. That is valuable
intelligence—but it is not yet an application, an asset, a vulnerability, or permission to test.

The observation answers a narrow question:

> From one external vantage, at one recorded time, this address and port returned evidence
> consistent with this protocol and these response properties.

It does not automatically answer:

- who controls the address now;
- which hostname the service expects;
- whether the certificate name was active, default, stale, or shared;
- which virtual host or tenant produced the response;
- whether the endpoint is an edge, proxy, origin, appliance, API, or ordinary website;
- what identity and business workflow exist behind it;
- whether the observed endpoint is included in the current Rules of Engagement.

A modern external pentest therefore uses passive service data to reduce uncertainty before active
work. It does not replace uncertainty with tool output. The workflow is:

> preserve the observation → attribute the endpoint → recover the expected name and protocol
> context → confirm scope → perform the smallest current verification → map the application.

Only then does vulnerability testing have a meaningful target.

## A service record is a measurement, not a noun

The phrase “an HTTPS service exists” hides the fields that determine whether the statement remains
useful. A defensible observation record needs at least:

| Field                | Question it preserves                                      |
| -------------------- | ---------------------------------------------------------- |
| `observed_at`        | When did the service produce this evidence?                |
| `vantage`            | From which scanner or network perspective was it observed? |
| `ip` / `port`        | Which transport endpoint answered?                         |
| `transport`          | TCP, UDP, QUIC, or another transport?                      |
| `service_name`       | Which protocol did the scanner identify?                   |
| `service_confidence` | Was it proved by a handshake or guessed from the port?     |
| `banner_or_response` | Which smallest response supports the classification?       |
| `tls_names`          | Which names appeared in the observed certificate?          |
| `redirect_target`    | Did the service point toward a hostname or application?    |
| `source_record`      | Can another analyst retrieve the original observation?     |
| `scope_state`        | Is current interaction approved, excluded, or undecided?   |

[Censys documents](https://docs.censys.com/docs/internet-scanning) continuous service discovery,
automatic protocol detection, protocol-specific handshakes, and follow-up classification. It also
states that its internet scanning is for information gathering and does not attempt authenticated
entry. This makes the data an excellent source of externally observed service evidence.

The same documentation explains why the result still needs context. Services are found across
standard and non-standard ports; some remain `UNKNOWN`; HTTP observations may follow local
redirects; known services are refreshed on a cadence rather than continuously at every instant.
The record is a measurement produced by a scanner’s behavior and time window—not a live socket
held open for the pentester.

Preserve the raw facts before enriching them. If an analyst copies only `IP:port` into a target
list, the timestamp, protocol evidence, hostname clues, and uncertainty disappear. Later activity
then looks more authoritative than its source warrants.

## Keep five layers separate

An observed service becomes useful through successive attribution layers. Skipping a layer creates
the most common external-pentest false positives.

<figure class="diagram">
<svg viewBox="0 0 700 370" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Five nested evidence layers progress from a dated service observation through endpoint attribution, name and protocol context, application identity, and finally a business workflow with testable trust boundaries.">
<defs>
<marker id="soam-a" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L8,4 L0,8 z" class="dg-arrow" /></marker>
</defs>
<rect x="20" y="42" width="122" height="250" rx="10" class="dg-box" />
<text x="38" y="72" class="dg-label">observation</text>
<text x="38" y="98" class="dg-muted">IP · PORT</text>
<text x="38" y="120" class="dg-muted">TIME · VANTAGE</text>
<line x1="144" y1="166" x2="172" y2="166" class="dg-line" marker-end="url(#soam-a)" />
<rect x="176" y="60" width="112" height="214" rx="10" class="dg-box" />
<text x="194" y="90" class="dg-label">endpoint</text>
<text x="194" y="116" class="dg-muted">ROUTING</text>
<text x="194" y="138" class="dg-muted">HOSTING</text>
<line x1="290" y1="166" x2="318" y2="166" class="dg-line" marker-end="url(#soam-a)" />
<rect x="322" y="78" width="112" height="178" rx="10" class="dg-box" />
<text x="340" y="108" class="dg-label">name</text>
<text x="340" y="134" class="dg-muted">DNS · SNI</text>
<text x="340" y="156" class="dg-muted">HOST · TLS</text>
<line x1="436" y1="166" x2="464" y2="166" class="dg-line" marker-end="url(#soam-a)" />
<rect x="468" y="96" width="100" height="142" rx="10" class="dg-box-accent" />
<text x="486" y="126" class="dg-label">application</text>
<text x="486" y="152" class="dg-accent">ENTRY</text>
<text x="486" y="174" class="dg-muted">AUTH · API</text>
<line x1="570" y1="166" x2="598" y2="166" class="dg-line" marker-end="url(#soam-a)" />
<rect x="602" y="116" width="78" height="102" rx="10" class="dg-box-accent" />
<text x="616" y="146" class="dg-label">flow</text>
<text x="616" y="172" class="dg-accent">VALUE</text>
<text x="616" y="194" class="dg-muted">STATE</text>
<text x="20" y="328" class="dg-crit">ERROR</text><text x="78" y="328" class="dg-mono">treating the leftmost fact as if it proved the rightmost context</text>
<text x="20" y="354" class="dg-mono">EVERY ARROW REQUIRES NEW EVIDENCE</text>
</svg>
<figcaption>A passive record is the first layer of an application model. Each move toward business impact requires a different evidence class; none can be inferred solely from an open port.</figcaption>
</figure>

**Observation.** A scanner recorded a response on an address and port. The raw timestamp and
response belong here.

**Endpoint.** Routing, ASN, provider, address history, load balancer, CDN, NAT, and shared-hosting
context explain what the address represents. This layer can weaken attribution as easily as it
strengthens it.

**Name and protocol context.** DNS, SNI, HTTP `Host`, TLS certificate, redirect, application
protocol, and response variation identify the name the service expects. An IP response without the
correct name may show a default virtual host that no real user visits.

**Application.** Page families, API roots, authentication starts, static assets, headers, error
behavior, and visual identity distinguish one application boundary from another.

**Business flow.** Roles, objects, actions, state transitions, integrations, and data sensitivity
explain why the application matters and which security hypotheses deserve testing.

The port belongs only to the first two layers. Vulnerability impact belongs to the last two.

## Passive coverage changes the order of work

Broad active scanning often produces a large volume of technically correct but operationally weak
results: WAF responses, shared CDN edges, generic cloud addresses, honeypots, stale assets, and
duplicate services. Rate limits and defensive controls can also make repeated scans look
inconsistent, while high-volume verification consumes the engagement’s noise budget before the
important applications are understood.

Passive platforms invert that workflow. Search the attributed graph for recent services,
protocols, certificates, banners, and historical changes; then select the small set whose
relationship and potential business role justify current verification. The platform has already
performed the broad observation. The pentester’s job is to determine which observations are
relevant, current, attributable, authorized, and worth touching.

This is not “scan without scanning.” Internet measurement still involved packets; another party
sent them under its own published methodology. The distinction is about the engagement’s active
interaction with the customer target. Record the passive source and its collection behavior so the
client understands what evidence existed before the assessment contacted anything.

Freshness must remain visible. Censys says known services are continually evaluated and stale
records are rescanned according to its cadence, but an organisation can redeploy a cloud address,
rotate an origin, or remove a listener between observations. A record from yesterday may be ideal
triage evidence and still be wrong now.

Use three time states:

- `observed` — what the passive platform measured at its timestamp;
- `current-unverified` — no approved present check has confirmed or contradicted it;
- `current-verified` — a bounded engagement check confirmed the named behavior and recorded when.

Never overwrite `observed` with `current-verified`. Historical drift can explain exposure windows,
migrations, and why two analysts reached different conclusions.

## Recover the name before judging the web service

Modern hosting breaks the one-address-one-application assumption. OWASP’s
[attack-surface identification guidance](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/01-Information_Gathering/04-Attack_Surface_Identification)
explicitly calls out domains, virtual hosts, non-standard ports, certificates, and the fact that a
single IP can host multiple applications.

For HTTPS, the expected name can influence two separate stages. The TLS `server_name` extension
defined by [RFC 6066](https://www.rfc-editor.org/rfc/rfc6066.html) lets a client indicate the server
name during negotiation. After TLS, the HTTP target URI and `Host` information defined by
[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html) help the server select the intended resource
and virtual host. A check made only against `https://IP:port/` can therefore negotiate the wrong
certificate, reach a default site, or miss the application entirely.

Name recovery should combine independent clues:

- current forward DNS from attributed domains to the address;
- observed certificate SANs, validity, and collection time;
- current certificate behavior with the approved name as SNI;
- local redirects from the service to a canonical hostname;
- official application links and documentation;
- content, API, and identity relationships tied to the customer;
- customer confirmation when the technical signals are ambiguous.

Do not try every certificate name against every address. A multi-tenant certificate, shared edge,
or provider wildcard can create an enormous out-of-scope test matrix. Generate candidates from
attributed customer names, apply written scope, and verify only the exact combinations needed to
resolve the application boundary.

Wildcard DNS needs a negative control. If random hostnames resolve and return the same response,
the apparent discovery may be a catch-all rather than a real application. Compare response status,
certificate, title, body fingerprint, redirect, and server behavior across the attributed name, a
random label, and the bare address. The goal is to reject false names, not to enumerate hidden
tenants on shared infrastructure.

## Service detection is evidence with a confidence level

Port numbers are conventions, not protocol proof. An application can expose HTTPS on `8443`, SSH
on a high port, or a custom service on a port associated with something else. Passive data that
shows a completed protocol-specific exchange is stronger than a label derived only from the port.

[Nmap’s service and version detection documentation](https://nmap.org/book/man-version-detection.html)
describes how version detection interrogates an open service, matches responses against probes,
and can identify protocols on unexpected ports. It also exposes an important safety lesson: probes
have effects. Nmap excludes TCP 9100 by default from version detection because some printers may
print probe data. “Banner grab” is not automatically harmless.

Classify active verification intensity before execution:

| Level | Verification behavior                                     | Typical use                                           |
| ----- | --------------------------------------------------------- | ----------------------------------------------------- |
| `V0`  | No new target interaction                                 | Passive record and source preservation                |
| `V1`  | One transport connection or protocol-safe greeting        | Confirm listener and basic protocol                   |
| `V2`  | One named TLS/HTTP request with redirects bounded locally | Confirm hostname, virtual host, and current response  |
| `V3`  | Small approved protocol-specific handshake                | Confirm service family or security configuration      |
| `V4`  | Authenticated or stateful application journey             | Map roles, objects, APIs, and workflow with test data |

Each service type needs its own ceiling. An HTTP `GET /` is not equivalent to sending bytes to a
printer, mail relay, industrial protocol, database, or message broker. Use the platform’s existing
observation when a current probe adds little value or its effect is uncertain. The Rules of
Engagement should identify prohibited protocols, maximum requests, timeouts, source addresses, and
stop conditions.

## Turn HTTP response data into an application identity

A `200`, `401`, `403`, or `302` response is not an application classification. Status codes often
describe the edge policy rather than the origin. WAF block pages, generic reverse-proxy errors,
default server pages, and identity redirects can make unrelated applications look identical.

Use a small application fingerprint composed of explainable fields:

- final approved URL and redirect chain;
- status and content type;
- page title and a stable body fingerprint;
- certificate identity and current validity;
- response headers, cookies, and cache behavior;
- application-specific static assets or manifest;
- authentication start and callback destinations;
- linked API origins, WebSocket endpoints, and upload/download hosts;
- organisation-specific legal, product, or account context;
- screenshot with timestamp and viewport.

A screenshot is excellent triage evidence. It can separate a forgotten admin console from a
generic server page in seconds. It cannot prove ownership, authorization, technology version, or a
vulnerability. Logos and titles can be copied; visual similarity needs DNS, certificate, identity,
API, or customer evidence behind it.

After identifying an application, enumerate entry points before vulnerability classes. OWASP’s
[entry-point guidance](https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/01-Information_Gathering/06-Identify_Application_Entry_Points)
recommends recording requests, parameters, methods, authentication state, transport protection,
and multi-step behavior. Extend that record with role, object, state transition, trust boundary,
evidence reference, and data sensitivity.

The output is no longer “HTTPS on 8443.” It is:

> A customer-operated partner administration application, reached through this hostname and edge,
> using this identity flow, exposing these unauthenticated and authenticated entry points, and
> controlling these business objects under these roles.

That sentence can support a test plan. A port list cannot.

## Use a bounded admission pipeline

Every observation should either advance through explicit gates or stop with a reason.

<figure class="diagram">
<svg viewBox="0 0 700 360" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="A passive service observation passes through attribution, freshness and scope gates before narrow verification and application mapping, while stale, shared, excluded, or contradictory evidence routes to a stop register.">
<defs>
<marker id="soam-b" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L8,4 L0,8 z" class="dg-arrow" /></marker>
</defs>
<rect x="18" y="32" width="120" height="58" rx="8" class="dg-box" />
<text x="34" y="56" class="dg-label">observation</text><text x="34" y="76" class="dg-muted">SOURCE · TIME</text>
<line x1="140" y1="61" x2="170" y2="61" class="dg-line" marker-end="url(#soam-b)" />
<rect x="174" y="32" width="124" height="58" rx="8" class="dg-box" />
<text x="190" y="56" class="dg-label">attribute</text><text x="190" y="76" class="dg-muted">OWNER · HOST</text>
<line x1="300" y1="61" x2="330" y2="61" class="dg-line" marker-end="url(#soam-b)" />
<rect x="334" y="32" width="124" height="58" rx="8" class="dg-box" />
<text x="350" y="56" class="dg-label">scope gate</text><text x="350" y="76" class="dg-muted">NAME · METHOD</text>
<line x1="460" y1="61" x2="490" y2="61" class="dg-line" marker-end="url(#soam-b)" />
<rect x="494" y="32" width="188" height="58" rx="8" class="dg-box-accent" />
<text x="510" y="56" class="dg-label">narrow current verification</text><text x="510" y="76" class="dg-accent">EXPECTED RESPONSE</text>
<line x1="588" y1="92" x2="588" y2="130" class="dg-line" marker-end="url(#soam-b)" />
<rect x="494" y="134" width="188" height="58" rx="8" class="dg-box-accent" />
<text x="510" y="158" class="dg-label">application model</text><text x="510" y="178" class="dg-accent">ENTRY · AUTH · API · FLOW</text>
<line x1="492" y1="163" x2="462" y2="163" class="dg-line" marker-end="url(#soam-b)" />
<rect x="292" y="134" width="166" height="58" rx="8" class="dg-box-accent" />
<text x="308" y="158" class="dg-label">test hypotheses</text><text x="308" y="178" class="dg-accent">BOUNDARY · EFFECT</text>
<path d="M236 92 L236 244" class="dg-dashed" marker-end="url(#soam-b)" />
<path d="M396 92 C396 220, 350 244, 320 272" class="dg-dashed" marker-end="url(#soam-b)" />
<path d="M588 194 C588 246, 506 266, 464 272" class="dg-dashed" marker-end="url(#soam-b)" />
<rect x="146" y="248" width="320" height="62" rx="8" class="dg-box" />
<text x="166" y="274" class="dg-crit">STOP / REVIEW REGISTER</text>
<text x="166" y="296" class="dg-muted">STALE · SHARED · EXCLUDED · CONTRADICTED</text>
<text x="18" y="344" class="dg-mono">A CONFLICT LOWERS CONFIDENCE; IT DOES NOT JUSTIFY A LOUDER PROBE</text>
</svg>
<figcaption>Passive intelligence enters a target set only through attribution, scope, and current-verification gates. Contradictions are retained as evidence instead of being forced into a positive result.</figcaption>
</figure>

The pipeline protects against confirmation bias. If current DNS disagrees with the passive
certificate, or the approved hostname produces a generic provider page, the analyst should demote
the candidate and explain the conflict. Increasing scan intensity until something looks familiar
does not resolve attribution.

For each gate, store the decision and reason:

1. **Source gate:** is the original record retrievable, timestamped, and specific enough to use?
2. **Attribution gate:** which current and historical facts tie the endpoint to the customer?
3. **Shared-infrastructure gate:** could the signal belong to an edge, provider, or unrelated
   tenant?
4. **Scope gate:** which exact name, address, port, protocol, and action are approved?
5. **Freshness gate:** what smallest request can confirm the relevant current behavior?
6. **Application gate:** is there enough entry-point, identity, API, and workflow context to form a
   security hypothesis?

The rejected records still matter. A stale certificate may expose a retired brand. A moved service
may reveal unmanaged decommissioning. A shared edge may identify a supplier relationship. Those
are intelligence outcomes, not permission to test the old address or provider.

## A fictional service-to-application review

Assume a passive record observed TLS on `203.0.113.42:8443` eighteen hours ago. The certificate
contained `partners.meridian.example`, and the response redirected to `/login`.

1. The analyst stores the passive record, timestamp, certificate fingerprint, SAN, redirect, and
   scanner source. The candidate state is `observed`, not `live`.
2. Current RDAP and routing data show that the address belongs to a cloud provider. That supports
   hosting context, not Meridian ownership.
3. Current DNS for `partners.meridian.example` resolves to the observed address. The hostname is
   linked from Meridian’s official supplier documentation. Attribution becomes `probable`, but
   shared cloud hosting remains a constraint.
4. The customer confirms the partner portal and approves one named HTTPS request to that hostname
   on port 8443 from the assessment address. The cloud provider range, other names, and origin
   discovery remain excluded.
5. A `V2` request with the approved SNI and hostname returns the expected certificate, redirects
   locally, and renders a Meridian partner login. The bare IP returns a generic default site. The
   difference proves why the name context mattered.
6. The analyst records the login start, identity-provider redirect, callback, cookies, public
   JavaScript, API origin, unauthenticated recovery route, and role vocabulary visible to the two
   supplied test accounts.
7. Only now does the test plan contain hypotheses: tenant separation between suppliers, role
   conversion after SSO, object authorization in the partner API, and workflow enforcement around
   invoice approval. Each is tied to an approved account, object, endpoint, and expected effect.

The passive platform found the signal. Attribution made it a candidate. A narrow request made it
current. Application mapping made it testable.

## Evidence matrix

| Signal or result                                | What it supports                                           | What it cannot prove                                         | Required next step                                                   |
| ----------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------- |
| Passive IP and open-port observation            | A listener answered from a stated vantage and time         | Current reachability, ownership, protocol, or application    | Preserve source and compare current attribution                      |
| Protocol-specific passive handshake             | Response behavior matched a service classification         | Product version accuracy, safety, or customer control        | Record confidence and decide whether current proof is needed         |
| Certificate contains customer hostname          | Naming evidence existed at certificate or observation time | Deployment, exclusivity, current DNS, ownership, or scope    | Correlate DNS, official links, routing, and customer input           |
| Current DNS points hostname to observed address | A present name-to-address relationship                     | Which virtual host, tenant, origin, or business app responds | Obtain scope for the exact hostname and protocol context             |
| Bare IP shows a login or admin page             | The default virtual host exposes that content              | That real users reach it or that it belongs to the customer  | Recover approved hostname; reject shared/default responses           |
| Named TLS/HTTP request matches expected app     | Current behavior for one approved name and timestamp       | All paths, origins, roles, or vulnerability classes          | Build entry-point and trust-boundary model                           |
| Screenshot matches customer branding            | Useful visual correlation and triage evidence              | Ownership, technology version, authorization, or security    | Seek technical and customer corroboration                            |
| Service banner names a product and version      | A product hypothesis from disclosed response data          | Patch level, vulnerable configuration, or exploitability     | Verify safely, then test the actual control rather than CVE matching |
| Application entry-point map is complete enough  | Requests, roles, objects, and flows can support hypotheses | That any hypothesis is exploitable                           | Run bounded positive and negative tests                              |

## What the customer should receive

The final deliverable should preserve the transformation from observation to application.

**Observation ledger.** Raw service facts, source, timestamp, scanner behavior, response evidence,
and initial uncertainty.

**Attribution decisions.** DNS, certificate, routing, hosting, official-link, and customer evidence
with contradictions and confidence state.

**Verification plan and result.** Approved hostname, address, port, protocol context, request
budget, source address, expected response, observed response, timestamp, and stop condition.

**Application map.** Entry points, identity path, roles, objects, APIs, state transitions,
third-party dependencies, data classes, and evidence references.

**Rejection register.** Stale services, shared edges, default virtual hosts, unrelated tenants,
provider infrastructure, wildcard results, and unsupported version matches.

**Change signal.** What differs from the previous passive or engagement observation: new service,
moved address, certificate change, renamed application, new identity boundary, or retired route.

This structure gives defenders something a port list never can: the reason a service matters, the
application owner who can act, the exact control that should be tested, and the evidence needed to
retest it.

Passive discovery is valuable precisely because it lets the engagement be quieter and more
selective. Its purpose is not to declare vulnerabilities at a distance. It is to spend active
verification only where a current, attributable, authorized application boundary has emerged.

The next article follows the most common high-value boundary found in that model:
**the login page was public, but the identity boundary was somewhere else.**