Our Blog

Avoiding detection via DHCP options

Reading time ~5 min

When conducting a red team exercise, we want to blend in as much as possible with the existing systems on the target network. For most large networks, that means looking like a Windows machine when you request a DHCP address.

In a lot of cases, though, the machine that we connect to the target network is not going to be running Windows, but more likely, a variant of Linux. By default, Linux DHCP requests don’t look the same as Windows DHCP requests. One way of visualising this would be to take packet captures from Wireshark, copying DHCP requests into a text file and comparing them using Meld.

Windows 10 on the left, Linux (default Kali dhclient) on the right

Differences in DHCP request options can be enough to give you away if anyone is watching DHCP log files for anomalies. In particular, please change your hostname from “kali”!

I wanted to see what it would take to make this Linux DHCP request as close to the Windows 10 request as possible. To do this, I modified the /etc/dhcp/dhclient.conf file on my Kali VM.

I started by adjusting the order of options in the request stanza, as well as adding a few missing options, to get to this:

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option vendor-specific-information-43 code 43 = string;
option ms-classless-static-routes code 249 = array of unsigned integer 8;
option WPAD code 252 = string;

request subnet-mask, routers, domain-name-servers, 
	domain-name, router-discovery, static-routes, 
	vendor-specific-information-43, dhcp6.name-servers,
	dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers, 
	netbios-name-servers, netbios-node-type, netbios-scope,
	domain-search, rfc3442-classless-static-routes,
	ms-classless-static-routes, WPAD;

The option keywords at the beginning provides definitions for non-standard DHCP options that otherwise could not be requested in the request stanza. The rfc3442-classless-static-routes option was already present in the configuration file, but I had to add options 43, 249 and 252, which are requested by Windows 10.

That got me to an identical Option 55 Parameter Request List stanza as observed in the following meld comparison:

That left me needing Option 61 Client Identifier, Option 32 Host Name, Option 81 Client Fully Qualified Domain Name, and Option 60 Vendor class Identifier. Of these, Option 60 is probably the most important, as it indicates the Operating System making the request, and is most likely going to stand out in any system logs!

Googling for things like "dhclient" "client fully qualified domain name", etc led me to the answers for each of those options, resulting in the following final configuration file:

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option vendor-specific-information-43 code 43 = string;
option ms-classless-static-routes code 249 = array of unsigned integer 8;
option WPAD code 252 = string;

send host-name = "ROGAN-REPORTING";
send fqdn.fqdn = "ROGAN-REPORTING";

send dhcp-client-identifier = hardware;
send vendor-class-identifier "MSFT 5.0";

request subnet-mask, routers, domain-name-servers, domain-name,
router-discovery, static-routes, vendor-specific-information-43,
dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn,
dhcp6.sntp-servers, netbios-name-servers, netbios-node-type,
netbios-scope, domain-search, rfc3442-classless-static-routes,
ms-classless-static-routes, WPAD;

Obviously, you will probably want to snoop on the network for a while to see what the machine naming standards look like, so that you can update the hostname and fqdn.fqdn lines appropriately.

One other thing that I wanted to avoid was to send any IP addresses from previous DHCP requests on different networks. I managed this with the following command line:

dhclient -d -lf /dev/null

-d was used during debugging to keep the dhclient in the foreground, simplifying the debug cycle. And man dhclient informed me that -lf specified the path to the “lease file”, where dhclient would store any previously issued leases. By setting this to /dev/null, I ensured that no leases would be recorded, and none could be read.

At the end of the day, since I was comparing against a Windows request with that same hostname, I got:

Comparison of Windows (left) and Linux (right) DHCP requests.

And if you manually edit it to account for differences in option order, we get:

End result after manual re-ordering of stanzas. Only the sequence, MAC and IP addresses differ, as one would expect!

The only semantic differences (ignoring the order of the options in the packet) are the DHCP sequence number, MAC address, and IP address. Clearly the MAC address is something to watch out for, as many systems look up the OUI that issued the MAC address, and present that in the report or log files. An unusual OUI will also stand out, and could give you away. One way to avoid that is to run tcpdump for a while to see what OUI other DHCP clients are using, and then use macchanger to generate a random MAC address in the same OUI.

So, it is still possible to distinguish between the two by observing the order of the various options. I’d be pretty surprised to get caught just because of that, though! Other than that, you should now be able to fly below the radar of any but the most paranoid of network administrators – at least as far as getting an IP address goes!