1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-18 15:14:10 +01: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

405 lines
10 KiB
C++

//TFTP server in C++
#include <algorithm>
#include <string.h>
#include <time.h>
#include "TFTPserv.h"
const int bufferSize = 4096;
const int tftpServPort = 69;
const unsigned char OpRead = 1;
const unsigned char OpWrite = 2;
const unsigned char OpData = 3;
const unsigned char OpAck = 4;
const unsigned char OpError = 5;
const unsigned char OpOptAck = 6;
const unsigned char ErrFileNotFound = 1;
const unsigned char ErrAccessViolation = 2;
const unsigned char ErrDiskFull = 3;
const unsigned char ErrIllegalOperation = 4;
const unsigned char ErrUnknownTransferId = 5;
const unsigned char ErrFileExists = 6;
const unsigned char ErrNoSuchUser = 7;
const unsigned char ErrFailedOptNegotiation = 8;
// Creates the TFTP server, passing pointer to C caller
extern "C" void* createTFTPServer(){
return new TFTPserv();
}
// Destroys the given TFTP server
extern "C" void destroyTFTPServer(void * server){
delete (TFTPserv *)(server);
}
// Adds a file to the TFTP server, from C caller
extern "C" int addTFTPFile(void * server, char* filename, unsigned int filenamelen, char* file, unsigned int filelen){
string filenamestr(filename,filenamelen);
string filestr(file,filelen);
((TFTPserv*)server)->addFile(filenamestr,filestr);
return 0;
}
// Starts the TFTP server (in new thread)
extern "C" int startTFTPServer(void * server){
return ((TFTPserv*)server)->start();
}
// Stops the TFTP server
extern "C" int stopTFTPServer(void * server){
return ((TFTPserv*)server)->stop();
}
//constructor
TFTPserv::TFTPserv(): fileIndexes(), files(), transfers(){
index = 0;
thread = NULL;
shuttingDown = false;
smellySock = 0;
}
//htons except returns a binary string
string TFTPserv::htonstring(unsigned short input){
unsigned short output = htons(input);
string res((const char*)&output,2);
return res;
}
//adds a "file" based on name, contents
void TFTPserv::addFile(string filename, string data){
fileIndexes[filename] = index;
files[index] = data;
index++;
}
//checks whether a transfer needs to be marked for resend
void TFTPserv::checkRetransmission(map<string,unsigned int> & transfer){
unsigned int elapsed = clock() / CLOCKS_PER_SEC - transfer["lastSent"];
if ( elapsed <= transfer["timeout"] )
return;
if (transfer["retries"] >= 3){
transfers.erase(&transfer);
return;
}
transfer["lastSent"] = 0;
transfer["retries"] = transfer["retries"] + 1;
}
//Gets a request packet, figures out what to do, and does it
void TFTPserv::dispatchRequest(sockaddr_in &from, string buf)
{
unsigned short op = ntohs(*((unsigned short*)buf.c_str()));
size_t currentSpot = 2;
switch (op)
{
case OpRead:
{
currentSpot = buf.find('\x00',2);
if (currentSpot == string::npos)
{
return;
}
string fn(buf.substr(2,currentSpot - 2)); //get filename
if (fileIndexes.count(fn) == 0) //nonexistant file
{
return;
}
size_t newSpot = buf.find('\x00',currentSpot + 1);
if (newSpot == string::npos) //invalid packet format
{
return;
}
//string mode(buf.substr(currentSpot + 1, newSpot - currentSpot - 1)); //don't really need this
//New transfer!
map<string,unsigned int> *transfer = new map<string,unsigned int>();
(*transfer)["type"] = OpRead;
(*transfer)["fromIp"] = *((unsigned int *)&from.sin_addr);
(*transfer)["fromPort"] = from.sin_port;
(*transfer)["file"] = fileIndexes[fn];
(*transfer)["block"] = 1;
(*transfer)["blksize"] = 512;
(*transfer)["offset"] = 0;
(*transfer)["timeout"] = 3;
(*transfer)["lastSent"] = 0;
(*transfer)["retries"] = 0;
//process_options
processOptions((struct sockaddr *)&from, sizeof(sockaddr_in), buf, *transfer, (unsigned int)(newSpot + 1));
transfers.insert(transfer);
break;
}
case OpAck:
{
//Got an ack
unsigned short block = ntohs(*((unsigned short*)(buf.c_str() + 2)));
map<string,unsigned int> *transfer = NULL;
//Find transfer
for (set<map<string, unsigned int> *>::iterator it = transfers.begin(); it != transfers.end(); ++it)
{
if ((*(*it))["fromIp"] == *((unsigned int *)&from.sin_addr)
&& (*(*it))["fromPort"] == from.sin_port
&& (*(*it))["block"] == block)
{
transfer = *it;
}
}
if (transfer == NULL)
{
return;
}
(*transfer)["offset"] = (*transfer)["offset"] + (*transfer)["blksize"];
(*transfer)["block"] = (*transfer)["block"] + 1;
(*transfer)["lastSent"] = 0;
(*transfer)["retries"] = 0;
if ((*transfer)["offset"] <= files[(*transfer)["file"]].length())
{
return; //not complete
}
transfers.erase(transfer); // we're done!
delete transfer;
}
}
}
// Extracts an int option in ascii form; if in range saves it and appends an option ack to replyPacket
void TFTPserv::checkIntOption(const char * optName, int min, int max, string & opt, string & val, map<string, unsigned int> & transfer, string & replyPacket)
{
if (opt.compare(optName) != 0)
{
return;
}
//convert ascii to integer value
int intval = 0;
for (unsigned int i = 0; i < val.length(); i++)
{
if (val[i] >= '0' && val[i] <= '9')
{
intval = intval * 10 + val[i] - '0';
}
}
//Validate it
if (intval > max)
{
intval = max;
}
if (intval < min)
{
intval = min;
}
//Save it
transfer[optName] = intval;
//append ack
replyPacket.append(opt).append(1, (char)0).append(val).append(1, (char)0);
}
//Parses all options from received packet
void TFTPserv::processOptions(struct sockaddr * from, unsigned int fromlen, string buf, map<string, unsigned int> & transfer, unsigned int spot)
{
//Start with optack (two byte)
string data = htonstring(OpOptAck);
//Loop over options
size_t currentSpot = spot;
while (currentSpot < buf.length() - 4)
{
//Get option
size_t nextSpot = buf.find('\x00', currentSpot);
if (nextSpot == string::npos)
{
return;
}
string opt(buf.substr(currentSpot, nextSpot - currentSpot));
//Get value
currentSpot = nextSpot + 1;
nextSpot = buf.find('\x00', currentSpot);
if (nextSpot == string::npos)
{
return;
}
string val(buf.substr(currentSpot, nextSpot - currentSpot));
currentSpot = nextSpot + 1;
for (string::iterator it = opt.begin(); it < opt.end(); it++)
*it = tolower(*it);
checkIntOption("blksize", 8, 65464, opt, val, transfer, data);
checkIntOption("timeout", 1, 255, opt, val, transfer, data);
if (opt.compare("tsize") == 0)
{
//get length
size_t flen = files[transfer["file"]].length();
//convert to ascii
string strlen;
while (flen > 0)
{
strlen.insert(0, 1, (char)((flen % 10) + '0'));
flen = flen / 10;
}
data.append(opt).append(1, (char)0).append(strlen).append(1, (char)0);
}
}
//Send packet
sendto(smellySock, data.c_str(), (int)data.length(), 0, from, (int)fromlen);
}
// Asks server to stop
int TFTPserv::stop()
{
shuttingDown = true;
DWORD res = 0xffffffff;
if (thread != NULL)
{
res = WaitForSingleObject(thread, 5000);
}
thread = NULL;
return res;
}
// Method to pass to CreateThread
DWORD WINAPI runTFTPServer(void* server)
{
return ((TFTPserv*)server)->run();
}
// Starts server
int TFTPserv::start()
{
//get socket
smellySock = socket(AF_INET, SOCK_DGRAM, 0);
if (smellySock == INVALID_SOCKET)
{
return -1;
}
//Se up server socket address
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(tftpServPort);
server.sin_addr.s_addr = 0; //a.k.a. INADDR_ANY
// Bind address to socket
if (bind(smellySock, (struct sockaddr *)&server, sizeof(server)) != 0)
{
return GetLastError();
}
thread = CreateThread(NULL, 0, &runTFTPServer, this, 0, NULL);
if (thread != NULL)
{
return ERROR_SUCCESS;
}
return GetLastError();
}
//Internal run method that does all the hard work
int TFTPserv::run()
{
// Setup timeout
fd_set recvSet;
fd_set sendSet;
int n;
//Main packet-handling loop
shuttingDown = false;
while (shuttingDown == false){
FD_ZERO(&recvSet);
FD_SET(smellySock, &recvSet);
FD_ZERO(&sendSet);
//Do we need to check for sent items? Let's see
for (set<map<string, unsigned int> *>::iterator it = transfers.begin(); it != transfers.end(); ++it){
if ((*(*it))["lastSent"] != 0){
FD_SET(smellySock, &recvSet);
break;
}
}
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
n = select((int)(smellySock + 1), &recvSet, &sendSet, NULL, &tv);
if (n == -1)
{
break; //Error
}
//Get request
char receiveBuf[bufferSize];
struct sockaddr client;
int clientLength = sizeof(client);
int receiveSize = 0;
if (n != 0)
{
receiveSize = recvfrom(smellySock, receiveBuf, bufferSize, 0, &client, &clientLength);
}
if (receiveSize > 0)
{
string data(receiveBuf, receiveSize);
dispatchRequest(*((sockaddr_in *)&client), data);
}
//Now see if we need to transmit/retransmit another block
for (set<map<string, unsigned int> *>::iterator it = transfers.begin(); it != transfers.end(); ++it)
{
map<string, unsigned int> & transfer = *(*it);
if (transfer["type"] != OpRead)
{
continue;
}
if (transfer["lastSent"] != 0)
{
checkRetransmission(transfer);
}
else
{
string block = files[transfer["file"]].substr(transfer["offset"], transfer["blksize"]);
if (block.size() > 0)
{
string packet(htonstring(OpData));
packet.append(htonstring(transfer["block"]));
packet.append(block);
//Send packet
//first get address
sockaddr_in client;
memset((void*)&client, 0, sizeof(client));
client.sin_family = AF_INET;
*((unsigned int *)&client.sin_addr) = transfer["fromIp"];
client.sin_port = (unsigned short)transfer["fromPort"];
//whew. now send
sendto(smellySock, packet.c_str(), (int)packet.size(), 0, (sockaddr*)&client, (int)sizeof(sockaddr_in));
transfer["lastSent"] = clock() / CLOCKS_PER_SEC;
}
}
}
}
#ifdef WIN32
closesocket(smellySock);
#else
close(smellySock);
#endif
return 0;
}