Who owns the address? Attributing an IP before reading its location in SOC triage
eHVB-IT · · SOC · alert triage · identity · threat intelligence · detection engineering
The location of an IP in a sign-in log often describes infrastructure, not a user. The triage rule we apply: decide who operates the address before reading its geography.
Summary
Identity alerts such as impossible travel, unfamiliar location or sign-in from a new country rest on one inference: the location attached to an IP address is where the user was. That inference is often wrong, and it fails in both directions. A corporate VPN, a security proxy or a mobile carrier puts a legitimate user in a city they have never visited, which produces false positives. An attacker relaying a stolen session through rented hosting near the victim looks local, which produces false negatives. This note describes the rule we apply in triage: before reading the geography of an address, decide who operates it. It gives the categories we use, the passive sources that answer the question, and a worked example built on documentation addresses that anyone can replay.
Where the location comes from
A sign-in log does not record where a person stood. It records the source address of the connection, and the location shown next to it comes from a geolocation database that maps address ranges to places. Those databases are estimates. Their providers publish accuracy radii, and the estimate is often the registered location of the network or the place where its traffic reaches the internet. Neither says where an individual user is.
For a home broadband line the estimate is usually close enough. For most of the infrastructure an enterprise user actually goes through, it describes the infrastructure.
Why geography misleads
Several ordinary situations move the apparent location away from the user:
- A full tunnel corporate VPN sends every connection out through the company's concentrator, so a user travelling abroad appears at head office, and a user at home appears wherever the concentrator is hosted.
- Cloud security proxies and zero trust access services send traffic out from the provider's nearest point of presence, which can be in another country.
- Mobile carriers route data through a small number of gateways, so a phone can appear hundreds of kilometres from where it is.
- A dual stack device can use an IPv4 address and an IPv6 address within minutes of each other, and the two may be geolocated differently. One laptop then appears to travel.
- User In Lyon laptop, home line
- Agent Security proxy captures traffic on the device
- Egress Point of presence the provider's, in Amsterdam
- IdP Identity provider sees the egress address
- Log Amsterdam the position of a machine
The reverse case is the one that costs most. Adversary in the middle phishing kits relay the victim's sign-in from the server that runs the kit, and that server is often rented hosting. An attacker who picks a provider with a data centre in the victim's country produces a sign-in whose location looks normal. A triage that only checks the country would close it.
The rule: attribute first
Every address in an alert gets an owner category before anyone reads its location. We use these categories:
| Category | Typical owner | What its location tells you |
|---|---|---|
| Internal | RFC 1918, loopback, link local | Nothing. Look at the device instead |
| Corporate egress | Your VPN concentrators, proxies, NAT gateways | The location of your own infrastructure |
| Security service egress | Your SSE or proxy provider's ranges | The provider's point of presence |
| Mobile carrier | Operator ASN | A gateway region at best |
| Residential or business ISP | Access provider ASN | Roughly where the user is, within the stated radius |
| Hosting or cloud | Data centre ASN | Where a server is. No user lives there |
| Anonymiser | Known Tor exit, commercial VPN | Nothing about the user. The choice to hide is the signal |
| Unknown | No clear match | Nothing yet. Say so |
Only the residential or business ISP category supports a geographic reading of the user. For every other category, the location field describes a machine or a network, and an analysis that treats it as a person's position is wrong whatever the verdict turns out to be.
A hosting or anonymiser category does not prove an attack either. Developers connect from cloud workstations and some users pay for a VPN. It moves the question from "where was the user" to "why would this user authenticate from a server", which is a better question and one the user or their manager can answer.
Passive sources that answer the question
Attribution can be done without touching the address itself:
- Your own inventory of egress ranges: VPN pools, proxy and NAT gateways, and the published ranges of the security services you subscribe to. This is the most useful source and the one most often missing.
- RDAP (the successor to WHOIS) for the registered holder of the range and its network name.
- The autonomous system number announcing the prefix, which tells a mobile operator from a hosting company faster than the holder's name does.
- Reverse DNS, when it exists, for naming conventions such as a carrier's gateway names or a cloud provider's instance names.
- Public lists of Tor exit nodes.
We do not scan, ping or connect to an address taken from an alert. That would be active probing of infrastructure we have no authorisation to touch, and an attacker who controls the server would see it.
A minimal first pass needs nothing beyond the Python standard library. It separates what you already know (internal space and your own egress) from what still needs an RDAP and ASN lookup:
import ipaddress
# Your own inventory. These ranges are placeholders from RFC 5737.
EGRESS = {
"corporate egress": ["198.51.100.0/28"],
"security service egress": ["203.0.113.64/26"],
}
INTERNAL = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "fc00::/7"]
def first_pass(ip: str) -> str:
addr = ipaddress.ip_address(ip)
for label, nets in EGRESS.items():
if any(addr in ipaddress.ip_network(n) for n in nets):
return label
if addr.is_loopback or addr.is_link_local or any(addr in ipaddress.ip_network(n) for n in INTERNAL):
return "internal"
return "external: attribute holder and ASN before reading the location"
if __name__ == "__main__":
assert first_pass("10.1.2.3") == "internal"
assert first_pass("198.51.100.5") == "corporate egress"
assert first_pass("203.0.113.70") == "security service egress"
assert first_pass("192.0.2.140").startswith("external")
assert first_pass("8.8.8.8").startswith("external")
print("ok")
Internal space is matched against an explicit list rather than is_private: Python's is_private also returns true for the RFC 5737 documentation ranges, and would label the external addresses of the worked example below as internal. The inventory check runs first for the same reason: a match in your own inventory should win over a generic rule.
Worked example
The addresses below come from the documentation ranges of RFC 5737 and stand for real ones. The scenario is synthetic and built to be replayed.
An identity platform raises an impossible travel alert for one user:
| Time | Source address | Location in the log |
|---|---|---|
| 09:02 | 198.51.100.23 | Lyon, France |
| 09:20 | 203.0.113.70 | Amsterdam, Netherlands |
Read by location, 18 minutes for more than 700 km is impossible and the alert looks strong. Attributed first, it reads differently. The second address falls in the egress range of the company's security proxy, whose point of presence for that region is in Amsterdam, and the first address belongs to a French residential ISP. The user opened a laptop at home on the ISP line, then the proxy agent connected and the following sign-in left from the provider. The verdict is a likely false positive, with medium confidence until the device and the session identifiers confirm that both sign-ins came from the same machine.
Now a second alert for another user, raised for an unfamiliar sign-in property, with a location that raises no concern:
| Time | Source address | Location in the log |
|---|---|---|
| 14:41 | 192.0.2.140 | Paris, France |
The user works in Paris, and a location check closes this one. Attribution finds that the range belongs to a hosting provider's data centre, and no inventory explains why this user would authenticate from a server. The verdict is open: the session needs to be checked for token reuse, the user asked whether they used a cloud workstation, and the sign-in compared with the user's usual device. The location in the log was accurate and had no bearing on the verdict.
Alert 1 · impossible travel
- 198.51.100.23 · Lyon
- 203.0.113.70 · Amsterdam
by location: impossible journey
attributed: residential ISP, then security proxy
likely false positive
Alert 2 · unfamiliar property
- 192.0.2.140 · Paris
by location: nothing unusual
attributed: hosting provider data centre
open, to investigate
Writing it down in the verdict
Attribution only helps if it appears in the report. We keep a short table of every address in the alert with its category, the source of the attribution and the time of the lookup, and we keep that table apart from the list of attacker indicators. A verdict that mentions a location without the owner category of the address is incomplete, and so is a verdict at less than high confidence that does not say what would raise it.
Limitations
- An egress inventory goes stale. Proxy providers add points of presence and VPN pools change. An address missing from the inventory falls back to RDAP and ASN, which is slower and less certain.
- ASN categories blur at the edges. Some operators sell both mobile access and hosting under one number, and residential proxy services route attacker traffic through real home lines, which would land in the one category we treat as geographically meaningful.
- Attribution says who operates an address. It does not say who used it. Device identity, session identifiers and the user's own account remain the evidence for that.
- Log retention bounds what can be checked. An earlier sign-in that the platform no longer keeps cannot serve as a baseline, and its absence proves nothing.
Checklist
- Keep an inventory of your egress ranges, including those of the security services you subscribe to.
- Give every address in an alert an owner category before reading its location.
- Read the location as the user's position only for residential and business ISP addresses.
- Treat a hosting or anonymiser source as a question to answer, even when the country is right.
- Attribute passively: inventory, RDAP, ASN, reverse DNS, public Tor lists. Never probe the address.
- Put the attribution table in the verdict, apart from attacker indicators.
eHVB-IT is a French cybersecurity consultancy working on SOC triage, application security and detection engineering. Contact: contact@ehvb-it.fr