seggewiss

Learning IT security in public — eJPT, CPTS, OSCP, and what actually happens along the way.

Reading a Netmask Without Guessing

Last week I was stuck in a pivoting exercise much longer than I want to admit, and the reason had nothing to do with pivoting. It was a netmask that I guessed instead of calculated.

The setup

The scenario is a standard one for this kind of lab: two internal machines and I can only reach one of them directly from my attack box. I get a foothold on the reachable one, and from there I need to route traffic to the second, hidden machine — pivoting through the first host like through a router.

The compromised host sees both networks. My attack box sees only the first one. So I add a route through my session on that host, pointing to whatever subnet the second machine is in, and everything after that — scans, exploits — goes through it automatically.

This “whatever subnet” is where it went wrong.

The mistake: guessing instead of reading

I ran ipconfig on the compromised host and got back an IP address and a subnet mask. I looked at the IP, assumed where the network boundary is, and routed like that. The route came up, some hosts answered, some did not, and I burned real time being convinced that pivoting itself is broken.

It was not. My subnet was wrong. I routed a slice of the network that did not contain the host I was looking for — smaller than the real subnet — so traffic for everything outside of my guessed range simply had nowhere to go.

The fix is not a pivoting technique. It is math that I skipped.

Netmask to CIDR, done properly

A subnet mask tells you per octet which bits are “network” and which are “host”. Convert the mask to CIDR notation and you get the real size of the network you are standing in:

NetmaskCIDRAddressesExample range
255.255.255.0/24256x.x.x.0x.x.x.255
255.255.240.0/204096x.x.0.0x.x.15.255
255.255.0.0/1665536x.x.0.0x.x.255.255

The row that got me is the /20 one, because it is not aligned to a clean octet boundary like /24 is. 255.255.240.0 means only the top four bits of the third octet are network bits. To find the real network address you AND the host’s own address with the mask. You do not round to the next nice looking number.

Example: a host with address 10.2.23.x and mask 255.255.240.0. 240 in binary is 11110000. 23 in binary is 00010111. AND them together and you get 00010000, decimal 16. So the network is not 10.2.23.0 (a guess based on the octet you can see), it is 10.2.16.0/20, which covers everything from 10.2.16.0 to 10.2.31.255. My guessed range was completely inside that block but did not cover all of it — exactly narrow enough that some traffic routes fine and other traffic dies silently.

The second trap: a target that was never “behind” anything

The machine I wanted to reach was in arp -a on the compromised host, but not as a separate entry in ipconfig. That difference matters: ARP only resolves inside the same broadcast domain. When a host only shows up via ARP, it is not hiding behind another hop at all — it is a direct neighbour in the same subnet as the box you are already standing on. After I had the /20 routed correctly, that “hidden” second machine was already reachable. No second pivot needed, just the first subnet done right.

What I would tell myself one week ago

Read the mask directly from the compromised host, do not derive it from the IP alone. Convert it to CIDR with the real AND operation, not with rounding in your head. And check arp -a before you assume a target needs a deeper route, maybe it is already a neighbour.

Nothing here is advanced. It is the kind of thing that is obvious afterwards and completely invisible while you are three failed scans deep and doubting a technique that worked the whole time.