< ALL NOTES

Mapping an organisation's exposure without touching it

5 min read

Building the external attack surface of a bank or a telecom operator from public sources — and the four bugs that turn that map into fiction, including one that credits a stranger's leaked secrets to your client.

OSINTexposure mappingUEMOAattack surfacemethod

Before auditing anything, you have to know what exists. A regional bank, a telecom operator, a mobile-money issuer: each has more exposed surface than it has inventory of. Subsidiaries on their own hosting, a web agency that left three years ago and left a live subdomain behind, a staging environment reachable from the internet, a supplier hosting the customer portal on its own ASN.

Exposure mapping is rebuilding that inventory from the outside, from public sources, without sending a single request to a system the organisation has not authorised anyone to touch.

It is the work that comes before the audit — and it is also where you can be wrong most quietly, because a false map looks exactly like a true one.

Passive first, and the line is sharp

A passive source is one that does not speak to the target:

  • domain registries and WHOIS/RDAP data;
  • certificate transparency logs — every issued certificate is published there,

which reveals subdomains nobody announced;

  • public DNS and historical records;
  • declared address ranges and ASNs;
  • app stores, public code repositories, job postings (which name the technology stack

with remarkable generosity);

  • breach aggregators, to establish the existence of a compromise.

An active source speaks to the target: forced resolution, port scanning, HTTP requests, vulnerability probes. That changes the legal and ethical nature of the work.

The rule I apply: no active check without a written mandate explicitly covering the asset. Not "the client agreed", not "it is non-intrusive": a signed document naming the domains. And the mandate stops where it stops — a subdomain discovered along the way is not covered because it resembles the others.

On leaks the line is stricter still: you establish that data is circulating; you do not retrieve it, store it, or use it. An identified secret is reported by prefix and length, never in the clear.

Trap 1: deriving the organisation from a chunk of domain name

This one cost me the most, because it produces a report that is plausible and wrong.

Querying a leaked-secrets aggregator needs a key: the organisation name. The temptation is to take the first label of the domain:

organisation = domain.split(".")[0]      # NO

On example-bank.bf it works. On a subdomain shaped like a.example.io it returns a — the name of an organisation that exists, belongs to somebody else, and whose exposed secrets then get attributed to your client in the report.

A report that accuses one organisation of another's leaks is not an imprecision. It is a fault.

The fix: derive the organisation from the registrable label — the domain as sold under its public suffix, example.io and not a — and, where doubt remains, do not guess. An empty field is an honest result.

Trap 2: distribution domains are not yours

When scope is fed from mobile app URLs, hosts like apps.apple.com or play.google.com come along mechanically.

They enter the map, then the checks, then the report. But those are Apple's and Google's servers. Scanning them means testing a third party's infrastructure without authorisation — and reporting it as "client exposure" is a false finding on top.

Same family: github.com picked up from a repository link, a shared CDN, a URL shortener. The guard is an explicit list of distribution hosts excluded by construction, and a distinction, in the data model, between a host the organisation controls and a host where the organisation publishes.

Trap 3: a wildcard pattern is not a hostname

Published scopes contain wildcards: *.example.com. A naive parser takes the string as-is and files it among the hosts.

Forms like -api-*.example.com, or an entry beginning with a dot, are not hosts: they do not resolve, they cannot be scanned, and letting them through produces report rows that correspond to nothing. A wildcard is a membership rule, not an asset. Either expand it into real hosts through certificate transparency, or keep it as a rule — never confuse it with a target.

Trap 4: a silent tool is not a green light

The most dangerous, and the most ordinary.

A scanner launched without its rule set exits cleanly, status zero, zero findings. The report then says "no detections". The client reads "nothing to report". Nobody checked anything.

It is the same structure as in the APK audit: "nothing found" covers two opposite realities. Hence, here too, three states:

StateMeaning
CHECKED — CLEANthe tool ran with its rules and found nothing
CHECKED — FINDINGthe tool ran, here is what it found
NOT PERFORMEDthe tool did not run, or not correctly — said out loud

The practical consequence: the number of loaded rules has to be a field in the report, and None must never render as 0. Those are two different things, and conflating them is precisely the bug.

What the map establishes, and what it does not

A well-made passive map gives, with good confidence:

  • the inventory of live domains and subdomains, including the ones the organisation

has forgotten;

  • exposed technologies and their advertised versions;
  • address ranges and hosting providers, hence third-party dependencies;
  • published mobile applications and their declared publishers;
  • the existence of compromised credentials in circulation.

It does not say whether a vulnerability is exploitable, whether a service is genuinely reachable from the internet, or what happens behind a login page. All of that requires active work, and therefore a mandate.

A map is not a verdict. It is what lets you decide where to look, and decide it from facts rather than from the org chart.

OP_CENTER
STATUS: ENCRYPTED
SYS_BOOT.exeDOSSIER.exeREGISTRY.exeNOTES.logSERVICES.exeFORMATIONS.dirCV_DATA.dirSECURE_CONNECT