May 22

DHCPpwn

It’s more than an alpha than beta but… This is an old piece of code I was working on a few years ago, but recently found time to start coding again. I know it’s a bit buggy (all of the buttons do not function yet and it tends to lock up bc of the loop on sending packets), but I still have lots of improvements to work on… I need to add my IPv4 Subnet calculator class (Should fix the lockup issues) and ARP class (Some DHCP servers like Fios modems send an arp request after DHCP). I also gotta add the function to hijack existing leases, but it’ll exhaust the DHCP pool on most servers(ie: linksys, cisco routers, etc)… I got it in a working state, so figured I’d post it for fun… It’ll be much improved soon!

BTW, if you test it on any type of DHCP server and don’t see addresses exhaust, let me know… I’ll get my hands on it and love to find out what else it’s doing!

DHCPwn1b

Jan 14

DHCP Message Class

Here is a class I wrote to generate a DHCP message.  It’s primary purpose is to send a DHCP message, which can be useful for finding DHCP servers on a network

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Globalization;
using System.Text.RegularExpressions;

namespace SigkillDHCP
{
public class DhcpMessage
{
private const UInt32 MagicNumber = 1666417251;
//http://search.cpan.org/~shadinger/Net-DHCP-0.66/lib/Net/DHCP/Packet.pm

//Declare Fields
private DhcpOp _op;
private DhcpHtype _htype;
private byte _hlen;
private byte _hops;
private int _xid;
private UInt16 _secs;
private UInt16 _flags = 128;
private string _ciaddr = "0.0.0.0";
private string _yiaddr = "0.0.0.0";
private string _siaddr = "0.0.0.0";
private string _giaddr = "0.0.0.0";
private string _chaddr;
private byte[] _sname = new byte[64];
private byte[] _file = new byte[128];
//OPTIONS
private byte[] _mcookie = new byte[4];
private Dictionary<dhcpoption, byte[]=""> _options = new Dictionary<dhcpoption, byte[]="">();

#region Constructors

public DhcpMessage()
{
//Default Constructor Zero Fields
}

public DhcpMessage(byte[] data)
{
//Initiate DHCP Instance Fields When Reading Packet From DHCP Server
int Offset = 0;
byte[] tempip = new byte[4];
//MessageBox.Show("Op:" + BitConverter.ToString(data, Offset, 1).Replace("-", ""));
this._op = (DhcpOp)data[Offset];
Offset++;

this._htype = (DhcpHtype)data[Offset];
Offset++;

this._hlen = data[Offset];
Offset++;

this._hops = data[Offset];
Offset++;

this._xid = BitConverter.ToInt32(data, Offset);
Offset += 4;

this._secs = BitConverter.ToUInt16(data, Offset); //Need to reverse Byte order???
Offset += 2;

this._flags = BitConverter.ToUInt16(data, Offset);
Offset += 2;

Array.Copy(data, Offset, tempip, 0, 4);
this._ciaddr = new IPAddress(tempip).ToString();
Offset += 4;

Array.Copy(data, Offset, tempip, 0, 4);
this._yiaddr = new IPAddress(tempip).ToString();
Offset += 4;

Array.Copy(data, Offset, tempip, 0, 4);
this._siaddr = new IPAddress(tempip).ToString();
Offset += 4;

Array.Copy(data, Offset, tempip, 0, 4);
this._giaddr = new IPAddress(tempip).ToString();
Offset += 4;

this._chaddr = BitConverter.ToString(data, Offset, 6);
Offset += 16;

Array.Copy(data, Offset, this._sname, 0, 64);
Offset += 64;

Array.Copy(data, Offset, this._file, 0, 128);
Offset += 128;

//Check for DHCP Magic Cookie
if (BitConverter.ToUInt32(data, Offset) == MagicNumber)
{
Offset += 4;
Boolean end = false;

//Loop Other DHCP Options
while (!end && Offset < data.Length)
{
DhcpOption Option = (DhcpOption)data[Offset];
Offset++;

int OptionLength;
switch (Option)
{
case DhcpOption.Pad:
continue;
case DhcpOption.End:
end = true;
continue;
default:
OptionLength = (int)data[Offset];
Offset++;
break;
}

byte[] OptionData = new byte[OptionLength];
Array.Copy(data, Offset, OptionData, 0, OptionLength);
Offset += OptionLength;
this._options.Add(Option, OptionData);
}

}
}
#endregion

#region Properties
public DhcpOp Op
{
get { return this._op; }
set { this._op = value; }
}

public DhcpHtype Htype
{
get { return this._htype; }
set { this._htype = value; }
}

public byte Hlen
{
get { return this._hlen; }
set { this._hlen = value; }
}

public byte Hops
{
get { return this._hops; }
set { this._hops = value; }
}

public int Xid
{
get { return this._xid; }
set { this._xid = value; }
}

public UInt16 Secs
{
get { return this._secs; }
set { this._secs = value; }
}

public UInt16 Flags
{
get { return this._flags; }
set { this._flags = value; }
}

public string Ciaddr
{
get { return this._ciaddr; }
set
{
if (ValidateIp(value) == false)
{
throw new Exception("Invalid IP Specified for Ciaddr");
}
this._ciaddr = value;
}
}

public string Yiaddr
{
get { return this._yiaddr; }
set
{
if (ValidateIp(value) == false)
{
throw new Exception("Invalid IP Specified for Yiaddr");
}
this._yiaddr = value;
}
}

public string Siaddr
{
get { return this._siaddr; }
set
{
if (ValidateIp(value) == false)
{
throw new Exception("Invalid IP Specified for Siaddr");
}
this._siaddr = value;
}
}

public string Giaddr
{
get { return this._giaddr; }
set
{
if (ValidateIp(value) == false)
{
throw new Exception("Invalid IP Specified for Giaddr");
}
this._giaddr = value;
}
}

public string Chaddr
{
get { return this._chaddr; }
set
{
if (ValidateMac(value) == false)
{
throw new Exception("Invalid MAC Specified for Chaddr");
}
this._chaddr = value.Replace(":", "").Replace("-", "").Replace(".", "");
}
}

public byte[] Sname
{
get { return this._sname; }
set { this._sname = value; }
}

public byte[] File
{
get { return this._file; }
set { this._file = value; }
}

#endregion

#region IP-Binary Conversions
public string IpToBitString(string Address)
{
//Convert IP String to Octets
byte[] IP = IPAddress.Parse(Address).GetAddressBytes();
string IPBits = "";

//Loop Octets and Convert to Binary
for (int i = 0; i < IP.Length; i++)
{
IPBits += PadBinary(Convert.ToString(IP[i], 2), 8);
}
return IPBits;
}

public string PadBinary(string Bits, int TotalBits)
{
//Pad Bit Strings to Ensure Proper Length
//ex: Decimal 4 converts to 100 as a Binary String
// But We Want to Pad it to 8 bits as 00000100
string PadBits = "";
if (Bits.Length < TotalBits)
{
for (int i = 0; i < (TotalBits - Bits.Length); i++)
{
PadBits += "0";
}
Bits = PadBits + Bits;
}
return Bits;
}

public string BitStringToIp(string Bits)
{
//Convert 32bit Binary to IP String
string IP = "";
if (Bits.Length == 32)
{
IP = BinaryStringToInt(Bits.Substring(0, 8)).ToString() + ".";
IP += BinaryStringToInt(Bits.Substring(8, 8)).ToString() + ".";
IP += BinaryStringToInt(Bits.Substring(16, 8)).ToString() + ".";
IP += BinaryStringToInt(Bits.Substring(24, 8)).ToString();
}
else
{
IP = "127.0.0.1";
}
return IP;
}

public int BinaryStringToInt(string Bits)
{
//Converts a Binary String to Integer Based on Most Significant Bit
//ex: Binary 00000100 and Binary 100 Converts to Integer 4
int Number = 0;
for (int i = 0, Exp = (Bits.Length - 1); i < Bits.Length; i++, Exp--)
{
if (Bits[i].ToString() == "1")
{
Number += (int)Math.Pow(2, Exp);
}
}
return Number;
}
#endregion

#region Subnet Calculations
public int GetNetworkPrefix(string Mask)
{
//Convert Subnet Mask to Bit String
Mask = IpToBitString(Mask);

//Get Network Prefix
int Prefix = 0;
for (int i = 0; i < Mask.Length; i++)
{
if (Mask[i].ToString() == "1")
{
Prefix++;
}
}
return Prefix;
}

public string GetSubnetNumber(string Address, string Mask)
{
//Convert IP and SubnetMask String to Octets
byte[] IP = IPAddress.Parse(Address).GetAddressBytes();
byte[] SM = IPAddress.Parse(Mask).GetAddressBytes();
string SubnetNumber = "";

//Loop Octets Then Bitwise Boolean AND the IP and Subnet Mask
for (int i = 0; i < IP.Length; i++)
{
if (i < (IP.Length - 1))
{
SubnetNumber += (IP[i] & SM[i]).ToString() + ".";
}
else
{
SubnetNumber += (IP[i] & SM[i]).ToString();
}
}
return SubnetNumber;
}

public string GetSubnetBroadcast(string Mask, string SubnetNumber)
{
//Get Prefix
int Prefix = GetNetworkPrefix(Mask);

//Copy Network/Subnet Bits of SubnetNumber Then Replace Host Bits with 1's
string SNBits = IpToBitString(SubnetNumber);
string Broadcast = "";
for (int i = 0; i < SNBits.Length; i++)
{
if (i < Prefix)
{
Broadcast += SNBits[i];
}
else
{
Broadcast += "1";
}
}

//Convert Broadcast From Binary to IP
Broadcast = BitStringToIp(Broadcast);

return Broadcast;
}

public string GetSubnetFirstAddress(string SubnetNumber)
{
//Convert Subnet Number String to Octets
byte[] IP = IPAddress.Parse(SubnetNumber).GetAddressBytes();
string FirstAddress = "";

//First Address Equals Subnet Number Plus 1 in the Last Octet
IP[IP.Length - 1] += 1;

//Loop Octets to Build IP
for (int i = 0; i < IP.Length; i++)
{
if (i < (IP.Length - 1))
{
FirstAddress += IP[i].ToString() + ".";
}
else
{
FirstAddress += IP[i].ToString();
}
}
return FirstAddress;
}

public string GetSubnetLastAddress(string Broadcast)
{
//Convert Broadcast String to Octets
byte[] IP = IPAddress.Parse(Broadcast).GetAddressBytes();
string LastAddress = "";

//Last Address Equals Broadcast Minus 1 in the Last Octet
IP[IP.Length - 1] -= 1;

//Loop Octets to Build IP
for (int i = 0; i < IP.Length; i++)
{
if (i < (IP.Length - 1))
{
LastAddress += IP[i].ToString() + ".";
}
else
{
LastAddress += IP[i].ToString();
}
}
return LastAddress;
}

public int GetNetworkBits(string Address)
{
//Convert IP String to Octets
byte[] IP = IPAddress.Parse(Address).GetAddressBytes();

//Determine Network Bits Based on IP Class
if ((IP[0] >= 1) && (IP[0] <= 126))
{
//Class A 8 Network Bits
return 8;
}
else if ((IP[0] >= 128) && (IP[0] <= 191))
{
//Class B 16 Network Bits
return 16;
}
else if ((IP[0] >= 192) && (IP[0] <= 223))
{
//Class C 24 Network Bits
return 24;
}
else
{
//Error Invalid
return 0;
}
}

public int GetHostBits(string Mask)
{
//Convert Subnet Mask to Binary
string SM = IpToBitString(Mask);
int HostBits = 0;

for (int i = 0; i < SM.Length; i++)
{
if (SM[i].ToString() == "0")
{
HostBits++;
}
}
return HostBits;
}

public int GetSubnetBits(int NetworkBits, int HostBits)
{

return (32 - (NetworkBits + HostBits));
}

public int GetMaxSubnets(int SubnetBits, bool ClassfulProtocol)
{
//Determine Number of Subnets
if (ClassfulProtocol == true)
{
//Use ((2^s)-2) When:
//Classful routing protocol, Rip Ver 1 or IGRP protocol used, or no ip subnet zero command is configured
//Subtract 2 because Subnet Zero and Broadcast Subnet are reserved
return ((int)Math.Pow(2, SubnetBits) - 2);
}
else
{
//Use 2^s When:
//Classless routing protocol, Rip Ver 2 EIGRP or OSPF protocol used, ip subnet zero is configured or omitted, VLSM used, no other clues
//Subnet Zero and Broadcast Subnet are not reserved and can be used
return (int)Math.Pow(2, SubnetBits);
}
}

public int GetMaxHosts(int HostBits)
{
//Use ((2^h) - 2) Subtract 2 for the Subnet Number and Broadcast Address
return ((int)Math.Pow(2, HostBits) - 2);
}
#endregion

#region Methods

public bool ValidateIp(string testip)
{
IPAddress ip;
bool valid = false;
if (string.IsNullOrEmpty(testip))
{
valid = false;
}
else
{
valid = IPAddress.TryParse(testip, out ip);
}
return valid;
}

public bool ValidateMac(string testmac)
{
testmac = testmac.Replace(":", "").Replace("-", "").Replace(".", "");
bool valid = false;
if (testmac.Length == 12)
{
Regex rx = new Regex("([0-9a-fA-F][0-9a-fA-F]){6}");
if (rx.IsMatch(testmac))
{
valid = true;
}
}
return valid;
}

public byte[] MacToByte(string mac)
{
byte[] macBytes = BitConverter.GetBytes(long.Parse(mac, NumberStyles.HexNumber));
byte[] macAddress = new byte[6];
if (BitConverter.IsLittleEndian)
{
Array.Reverse(macBytes);
for (int i = 0; i <= 5; i++)
{
macAddress[i] = macBytes[i + 2];
}
}
return macAddress;
}

public byte[] GetOption(DhcpOption option)
{
if (this._options.ContainsKey(option))
{
return this._options[option];
}
else
{
return null;
}
}

public void AddOption(DhcpOption option, params byte[] val)
{
byte[] data = new byte[1 + val.Length];
data[0] = (byte)val.Length;
val.CopyTo(data, 1);
this._options.Add(option, data);
}

public int SessionId()
{
return (int)DateTime.Now.Ticks;
}

public byte[] StringToByteArray(string str, EncodingType encodingType)
{
System.Text.Encoding encoding = null;
switch (encodingType)
{
case EncodingType.ASCII:
encoding = new System.Text.ASCIIEncoding();
break;
case EncodingType.Unicode:
encoding = new System.Text.UnicodeEncoding();
break;
case EncodingType.UTF7:
encoding = new System.Text.UTF7Encoding();
break;
case EncodingType.UTF8:
encoding = new System.Text.UTF8Encoding();
break;
}
return encoding.GetBytes(str);
}

public static string ByteArrayToString(byte[] bytes, EncodingType encodingType)
{
System.Text.Encoding encoding = null;
switch (encodingType)
{
case EncodingType.ASCII:
encoding = new System.Text.ASCIIEncoding();
break;
case EncodingType.Unicode:
encoding = new System.Text.UnicodeEncoding();
break;
case EncodingType.UTF7:
encoding = new System.Text.UTF7Encoding();
break;
case EncodingType.UTF8:
encoding = new System.Text.UTF8Encoding();
break;
}
return encoding.GetString(bytes);
}

public byte[] ClassToByteArray()
{
//Minimum DHCP Message Size + Magic Cookie + End
int DhcpMsgSize = 236 + 4 + 1;
foreach (KeyValuePair<dhcpoption, byte[]=""> pair in this._options)
{
DhcpMsgSize += 1 + pair.Value.Length;
}

byte[] data = new byte[DhcpMsgSize];
int Offset = 0;

data[Offset] = (byte)this._op;
Offset++;

data[Offset] = (byte)this._htype;
Offset++;

data[Offset] = this._hlen;
Offset++;

data[Offset] = this._hops;
Offset++;

BitConverter.GetBytes(this._xid).CopyTo(data, Offset);
Offset += 4;

BitConverter.GetBytes(this._secs).CopyTo(data, Offset); //Need to reverse Byte order???
Offset += 2;

BitConverter.GetBytes(this._flags).CopyTo(data, Offset);
Offset += 2;

IPAddress.Parse(this._ciaddr).GetAddressBytes().CopyTo(data, Offset);
Offset += 4;

IPAddress.Parse(this._yiaddr).GetAddressBytes().CopyTo(data, Offset);
Offset += 4;

IPAddress.Parse(this._siaddr).GetAddressBytes().CopyTo(data, Offset);
Offset += 4;

IPAddress.Parse(this._giaddr).GetAddressBytes().CopyTo(data, Offset);
Offset += 4;

MacToByte(this._chaddr).CopyTo(data, Offset);
Offset += 16;

this._sname.CopyTo(data, Offset);
Offset += 64;

this._file.CopyTo(data, Offset);
Offset += 128;

BitConverter.GetBytes(MagicNumber).CopyTo(data, Offset);
Offset += 4;

if (this._options.Count > 0)
{
foreach (DhcpOption option in this._options.Keys)
{
//Copy Option
data[Offset] = (byte)option;
Offset++;

//Copy Option Data
Array.Copy(this._options[option], 0, data, Offset, this._options[option].Length);
Offset += this._options[option].Length;
}
}
data[Offset] = (byte)DhcpOption.End;
return data;
}
#endregion

}
#region Packet Examples
//byte[] discoverMessage = {
// /* Opt */0x01,
// /* Htype */0x01,
// /* Hlen */0x06,
// /* Hops */0x00,
// /* XID */0x00, 0x00, 0x00, 0x01,
// /* Sec */0x00, 0x00,
// /* Flags */0x80, 0x00,
// /* Ciaddr */0x00, 0x00, 0x00, 0x00,
// /* Yiaddr */0x00, 0x00, 0x00, 0x00,
// /* Siaddr */0x00, 0x00, 0x00, 0x00,
// /* Giaddr */0x00, 0x00, 0x00, 0x00,
// /* Chaddr */0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
// /* Sname */0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// /* File */0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// /* DHCP OPTIONS */
// /* Mcookie */0x63, 0x82, 0x53, 0x63,
// /* ClientID */0x3d, 0x06, 0x00, 0x1f, 0x3b, 0x5b, 0xbd, 0xad,
// /* Hostname */0x0c, 0x05, 0x52, 0x6f, 0x67, 0x75, 0x65,
// /* DHCPDiscover */0x35, 0x01, 0x01,
// /* ParamReqList */0x37, 0x01, 0x03,
// /* EndOption */0xff
// };
#endregion

#region Enumerations
public enum DhcpOp : byte
{
//Number Operation Code - RFC1700
BootRequest = 0x01,
BootReply
}

public enum DhcpHtype : byte
{
//Number Hardware Type - RFC1700
Ethernet = 0x01,
ExperimentalEthernet,
AmateurRadio,
ProteonTokenRing,
Chaos,
Ieee802Networks,
Arcnet,
Hyperchannel,
Lanstar
}

public enum DhcpMsgType : byte
{
//DHCP Message Type - RFC2132, RFC4388
Discover = 0x01,
Offer,
Request,
Decline,
Ack,
Nak,
Release,
Inform,
ForceRenew,
LeaseQuery,
LeaseUnassigned,
LeaseUnknown,
LeaseActive
}

public enum DhcpOption : byte
{
//DHCP Options - RFC2132
Pad = 0x00,
SubnetMask = 0x01,
TimeOffset = 0x02,
Router = 0x03,
TimeServer = 0x04,
NameServer = 0x05,
DomainNameServer = 0x06,
Hostname = 0x0C,
DomainNameSuffix = 0x0F,
AddressRequest = 0x32,
AddressTime = 0x33,
DhcpMessageType = 0x35,
DhcpAddress = 0x36,
ParameterList = 0x37,
DhcpMessage = 0x38,
DhcpMaxMessageSize = 0x39,
ClassId = 0x3C,
ClientId = 0x3D,
AutoConfig = 0x74,
End = 0xFF
}

public enum EncodingType
{
ASCII,
Unicode,
UTF7,
UTF8
}

#endregion

}