I’ll try to disclose all details in the path until the flaw, the flaw itself and at last: my exploit ;).

So, before start posting a lot of dhclient’s source code here, I’ll try to explain the process within DHCP protocol:
1– The client (in our case dhclient process) sends a broadcast packet: DHCPDISCOVER
2– DHCP server answers with a DHCPOFFER packet offering an IP address, netmask, lease-time and other configs
3– So the client sends a DHCPREQUEST for that offered IP, notifying an acceptance for that configuration
4– DHCP server then sends a DHCPACK packet, meaning “configuration saved” and finishing the process.

A– The client now calculates, based on that lease-time previously provided by server, and schedule to send a new DHCPREQUEST packet (also known as Renewing Process) before lease’s expiration time, notifying the server that the client still holds this IP and avoiding the server to deliver it to another client.
B– Again DHCP server sends a DHCPACK packet to confirm.
If DHCP server configuration has changed between step 2 and B (e.g.: dns servers, new domain, router, whatever…), the server should attach these new options to DHCPACK packet.

If we pay attention in this process we realize a “gap” to consider: Until step 4 the client HAS NO IP address! It leaves us with 2 attacking vectors:
1) Break-in the first 4 steps and utilize a non-network shellcode;
2) Break-in between step 4 and B and to depend on client’s renew interval.
I was using an academic setup and had control of both (client and server machines), so decided to go with option 2 and manipulate server’s lease-time.

After all this intro we still need to understand the flaw, let’s take a look at DHCP’s internal structures:

First of all we can see two structs… One for header dhcp_hdr and another for options dhcp_opt (those configurations provided by server to client goes here). This is the setup I used on my exploit, based on RFC’s and the names can probably be different from those into isc-dhcp package. If you want to understand all fields, read RFCs 2131 and 2132.

You should notice some “details” into this exploit (we call it FixUps), the reason is that function script_write_params() still have some work to do after we messed up with its stack, so we need to make sure the function works correctly and reaches its return() instruction, there is where we steals the execution flow.