diff --git a/GlobalVars.cpp b/GlobalVars.cpp index 960d9d7..53653d6 100644 --- a/GlobalVars.cpp +++ b/GlobalVars.cpp @@ -9,7 +9,9 @@ std::string DADDR{ "" }; //IPv4 of device we will be impersonating std::string DGWAY{ "" }; //IPv4 of gateway device (Optional) bool istcp = false; bool both = false; -uint16_t gwlistenerport = 5351; //Default port -uint16_t internalport = 1025; -uint16_t externalport = 1025; -uint32_t mappinglifetime = 7200; //Recommended to be 2 hrs (https://datatracker.ietf.org/doc/html/rfc6886) \ No newline at end of file +uint_fast8_t progmode=0; +uint_fast16_t gwlistenerport = 5351; //Default port +extern uint_fast16_t internalport = 1025; +uint_fast16_t externalport = 1025; +uint_fast32_t mappinglifetime = 7200; //Recommended to be 2 hrs (https://datatracker.ietf.org/doc/html/rfc6886) +std::vector SentPackets; \ No newline at end of file diff --git a/GlobalVars.hpp b/GlobalVars.hpp index 8071737..dfe5baa 100644 --- a/GlobalVars.hpp +++ b/GlobalVars.hpp @@ -4,29 +4,32 @@ #include #include #include +#include extern bool istcp; extern bool both; -extern struct WinDev; -extern std::vector DEVS; + extern std::string SMAC; //Our MAC (Optional, might be reqired to determine output interface if target is in a different subnet) extern std::string DMAC; //MAC of device we will be impersonating (Optional) extern std::string GWMAC; //Gateway MAC (Optional) extern std::string DADDR; //IPv4 of device we will be impersonating extern std::string DGWAY; //IPv4 of gateway device (Optional) -extern uint16_t gwlistenerport; //Port that NAT-PMP-capable gateway listening to -extern uint16_t internalport; -extern uint16_t externalport; -extern uint32_t mappinglifetime; //Recommended to be 2 hrs (https://datatracker.ietf.org/doc/html/rfc6886) +extern uint_fast8_t progmode ; +extern uint_fast16_t gwlistenerport; //Port that NAT-PMP-capable gateway listening to +extern uint_fast16_t internalport; +extern uint_fast16_t externalport; +extern uint_fast32_t mappinglifetime; //Recommended to be 2 hrs (https://datatracker.ietf.org/doc/html/rfc6886) +extern std::vector SentPackets; extern struct WinDev { std::string ipaddr{ "" }; //IPv4 address of an interface as as tring std::string gwayip{ "" }; //DGWAY as a string - std::vector macaddrvec; //MAC address of an interface - std::uint32_t bitaddr{ 0 }; //IPv4 address as a 32bit unsigned integer - std::uint32_t bitmask{ 0 }; //Net mask as a 32bit unsigned integer - std::uint32_t wildcardmask{ 0 }; //bit-flip version of bitmask - std::uint32_t netaddress{ 0 }; //IPv4 address of a network (e.g. 192.168.1.0) - std::uint32_t broadcastaddress{ 0 }; //IPv4 broadcast address of that network (e.g. 192.168.1.255) + std::vector macaddrvec; //MAC address of an interface + std::uint_fast32_t bitaddr{ 0 }; //IPv4 address as a 32bit unsigned integer + std::uint_fast32_t bitmask{ 0 }; //Net mask as a 32bit unsigned integer + std::uint_fast32_t wildcardmask{ 0 }; //bit-flip version of bitmask + std::uint_fast32_t netaddress{ 0 }; //IPv4 address of a network (e.g. 192.168.1.0) + std::uint_fast32_t broadcastaddress{ 0 }; //IPv4 broadcast address of that network (e.g. 192.168.1.255) unsigned long interfaceindex{ 0 }; //So we can check if interface already added and update it accordingly. Index is the same as the one you get with "netsh interface ipv4 show interfaces" command. }; +extern std::vector DEVS; #endif \ No newline at end of file diff --git a/LaunchOptionsHandling.cpp b/LaunchOptionsHandling.cpp index 336851b..ac45bd9 100644 --- a/LaunchOptionsHandling.cpp +++ b/LaunchOptionsHandling.cpp @@ -3,7 +3,7 @@ #define usagetext "Usage: " << std::endl \ << "-help - Shows this message." << std::endl \ << "-DA xxx.xxx.xxx.xxx - IPv4 of host we will be impersonating (REQUIRED)" << std::endl \ -<< "-PH xxxxx - Port on the host, who we are impersonating (REQUIRED)" << std::endl \ +<< "-PH xxxxx - Port on the host, who we are impersonating (REQUIRED in creating mode)" << std::endl \ << "-PO xxxxx - Port on the GateWay (Optional, defaults to specified host port)" << std::endl \ << "-T xxxxxxxxx - Time of the binding in seconds: 0 for infinite, the max value is 2^32. (Optional, defaults to 7200)" << std::endl \ << "-TCP - Specifiy to create TCP mapping instead of UDP (Optional)" << std::endl \ @@ -12,18 +12,29 @@ << "-GW xxx.xxx.xxx.xxx - IPv4 of the NAT-PMP Gateway (Optional, defaults to IPv4 address of the gateway on the interface)" << std::endl \ << "-DM xx:xx:xx:xx:xx:xx - Destination (target's) MAC address (Optional, but host must be reachable with NetBios)" << std::endl \ << "-GM xx:xx:xx:xx:xx:xx - MAC address of Gateway in the broadcast domain, that is the next hop (Optional, but gateway must be reachable with NetBios)" << std::endl \ -<< "-SM xx:xx:xx:xx:xx:xx - MAC address of output interface (Optional, if host in the same subnet as the target)" << std::endl; +<< "-SM xx:xx:xx:xx:xx:xx - MAC address of output interface (Optional, if host in the same subnet as the target)" << std::endl << std::endl \ +<< "[Modes] (Optional)" << std::endl \ +<< "-A (Default) - Single Mapping creating mode" << std::endl \ +<< "-H - Hold mode" << std::endl \ +<< "-R - Single mapping removal mode" << std::endl \ +<< "-RALL - All mappings removal mode" << std::endl \ +<< "If no mode argument is provided, mapping creation mode (-A) will be used instead" << std::endl; + + +#define mutexclmodes "Error: Arguments ""-A"", ""-H"", ""-R"" and ""-RALL"" are mutually exclusive. You should only use one of them." << std::endl; + std::vector launcharguments; + int LaunchOptionsProcessing(int localargc, char* localargv[]) { - if (21 < localargc) // 8*2 + TCP + 1 + 1 + if (22 < localargc) // 8*2 + TCP + 1 + 1 { throw std::runtime_error("too many input parameters!"); } - if (5 > localargc) // (PH + DA)*2 + 1 + if (4 > localargc) // (DA)*2 + RALL + 1 { std::cerr << std::endl << "Error: Not enough arguments!" << std::endl; std::cerr << usagetext; @@ -44,7 +55,7 @@ int LaunchOptionsProcessing(int localargc, char* localargv[]) if (true == has_option(launcharguments, "-PH")) //Host port argument handling { std::string HostPortString = get_option(launcharguments, "-PH"); - uint16_t retloc = portcheck(HostPortString, "host"); + uint_fast16_t retloc = portcheck(HostPortString, "host"); if (0 != retloc) { internalport = retloc; @@ -56,8 +67,11 @@ int LaunchOptionsProcessing(int localargc, char* localargv[]) } else { - std::cerr << std::endl << "Error: Missing port argument. Please specify host's port with \"-PH\"." << std::endl; - return EXIT_FAILURE; + if (false == has_option(launcharguments, "-RALL")) + { + std::cerr << std::endl << "Error: Missing port argument. Please specify host's port with \"-PH\"." << std::endl; + return EXIT_FAILURE; + } } std::cout << "Host port is " << internalport << ". "; @@ -85,10 +99,62 @@ int LaunchOptionsProcessing(int localargc, char* localargv[]) std::cout << "Target's address is " << DADDR << "; " << std::endl; + if (true == has_option(launcharguments, "-H")) + { + if (0 == progmode) + { + progmode = 1; //Hold mode + } + else + { + std::cerr << mutexclmodes; + return EXIT_FAILURE; + } + } + + + if (true == has_option(launcharguments, "-R")) + { + if (0 == progmode) + { + progmode = 2; //Remove-specific-mapping mode + } + else + { + std::cerr << mutexclmodes; + return EXIT_FAILURE; + } + } + + + if (true == has_option(launcharguments, "-RALL")) + { + if (0 == progmode) + { + progmode = 3; //Mode that removes all mappings associated with host + } + else + { + std::cerr << mutexclmodes; + return EXIT_FAILURE; + } + } + + + if (true == has_option(launcharguments, "-A")) + { + if (0 != progmode) + { + std::cerr << mutexclmodes; + return EXIT_FAILURE; + } + } + + if (true == has_option(launcharguments, "-PO")) //Gateway binding port argument handling { std::string ExternalPortString = get_option(launcharguments, "-PO"); - uint16_t retloc = portcheck(ExternalPortString, "gateway"); + uint_fast16_t retloc = portcheck(ExternalPortString, "gateway"); if (0 != retloc) { externalport = retloc; @@ -106,17 +172,18 @@ int LaunchOptionsProcessing(int localargc, char* localargv[]) std::cout << "Gateway port for binding is " << externalport << ";" << std::endl; - istcp = has_option(launcharguments, "-TCP"); // TCP/UDP argument handling both = has_option(launcharguments, "-BOTH"); // TCP/UDP argument handling - if (istcp == true == both) + + if ((true ==istcp) and (true== both)) { std::cerr << std::endl << "Error: -TCP and -BOTH are mutually exclusive. You should only specify one."; return EXIT_FAILURE; } + if (true == has_option(launcharguments, "-DM")) //Destination MAC argument handling { mac_testerproto("-DM", DMAC); diff --git a/NetFormating.cpp b/NetFormating.cpp index 11f8b39..b2ad589 100644 --- a/NetFormating.cpp +++ b/NetFormating.cpp @@ -17,8 +17,19 @@ std::vector split(std::string s, const char delimiter) return res; } +std::vector payloadtovec(pcpp::PayloadLayer payload) +{ + std::vector retval; + uint8_t* addr = payload.getPayload(); + for (unsigned int i = 0; i < payload.getPayloadLen(); i++) + { + retval.push_back( *(addr + i) ); + } + return retval; +} + -void PrintIPV4(const char* msg, uint32_t input) //Not an endianness independent code +void PrintIPV4(const char* msg, uint_fast32_t input) //Not an endianness independent code { unsigned int d = input & 0xFF; unsigned int c = (input >> 8) & 0xFF; @@ -27,9 +38,9 @@ void PrintIPV4(const char* msg, uint32_t input) //Not an endianness independent std::cout << msg << std::dec << a << "." << b << "." << c << "." << d << std::endl; } -int MakeMeIpv4(uint32_t input, unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d) +int MakeMeIpv4(uint_fast32_t input, unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d) { - uint8_t* bytes = reinterpret_cast(&input); + uint_fast8_t* bytes = reinterpret_cast(&input); d = static_cast (bytes[0]); c = static_cast (bytes[1]); b = static_cast (bytes[2]); @@ -37,9 +48,9 @@ int MakeMeIpv4(uint32_t input, unsigned int& a, unsigned int& b, unsigned int& c return 0; } -void PrintIPV42(const char* msg, uint32_t input) +void PrintIPV42(const char* msg, uint_fast32_t input) { - uint8_t* bytes = reinterpret_cast(&input); + uint_fast8_t* bytes = reinterpret_cast(&input); unsigned int d = static_cast (bytes[0]); unsigned int c = static_cast (bytes[1]); unsigned int b = static_cast (bytes[2]); @@ -47,9 +58,9 @@ void PrintIPV42(const char* msg, uint32_t input) std::cout << msg << std::dec << a << "." << b << "." << c << "." << d << std::endl; } -void PrintIPV43(const char* msg, uint32_t input) +void PrintIPV43(const char* msg, uint_fast32_t input) { - uint8_t* cde = (uint8_t*)(&(input)); + uint_fast8_t* cde = (uint_fast8_t*)(&(input)); unsigned int d = *cde; unsigned int c = *(cde + 1); unsigned int b = *(cde + 2); @@ -57,10 +68,10 @@ void PrintIPV43(const char* msg, uint32_t input) std::cout << msg << std::dec << a << "." << b << "." << c << "." << d << std::endl; } -uint32_t SchizoConverter(std::string inputstring) +uint_fast32_t SchizoConverter(std::string inputstring) { std::vector v = split(inputstring, '.'); - uint32_t retval = 0; + uint_fast32_t retval = 0; for (int l = 0; l < v.size(); l++) { retval = (retval << 8) | std::stoi(v[l]); @@ -68,7 +79,7 @@ uint32_t SchizoConverter(std::string inputstring) return retval; } -std::string VecToString(std::vector inputvec) +std::string VecToString(std::vector inputvec) { std::string retval; for (int i = 0; i < inputvec.size(); i++) @@ -80,7 +91,7 @@ std::string VecToString(std::vector inputvec) return retval; } -std::string VecToStringWithDelimiters(std::vector inputvec, const char delimiter) +std::string VecToStringWithDelimiters(std::vector inputvec, const char delimiter) { std::string retval; for (int i = 0; i < (inputvec.size() - 1); i++) @@ -106,7 +117,7 @@ std::string VecToStringWithDelimiters(std::vector inputvec, const return retval; } -std::string MacVecToStringWithDelimiters(std::vector inputvec, const char delimiter) +std::string MacVecToStringWithDelimiters(std::vector inputvec, const char delimiter) { std::string retval; for (int i = 0; i < (inputvec.size() - 1); i++) @@ -118,7 +129,7 @@ std::string MacVecToStringWithDelimiters(std::vector inputvec, const c return retval; } -void PrintMacFromVec(const std::vector inputvec) +void PrintMacFromVec(const std::vector inputvec) { unsigned int k = (inputvec.size() - 1); for (unsigned int i = 0; i < k; i++) @@ -128,7 +139,7 @@ void PrintMacFromVec(const std::vector inputvec) std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)inputvec.at(k) << std::endl; } -uint16_t portcheck(const std::string inputstring, const char* whos) +uint_fast16_t portcheck(const std::string inputstring, const char* whos) { int64_t portinput; if (!inputstring.empty()) @@ -148,7 +159,7 @@ uint16_t portcheck(const std::string inputstring, const char* whos) } if (!((portinput > 0) && (portinput < 65536))) { - std::cerr << "Wrong " << whos << " port number!" << std::endl; + std::cerr << "Invalid " << whos << " port number!" << std::endl; return 0; } return portinput; @@ -162,9 +173,9 @@ uint16_t portcheck(const std::string inputstring, const char* whos) } } -char DetermineDelimiter(std::string inputstring, uint8_t expectedblocksize) +char DetermineDelimiter(std::string inputstring, uint_fast8_t expectedblocksize) { - uint8_t incr = expectedblocksize + 1; + uint_fast8_t incr = expectedblocksize + 1; unsigned int a = inputstring.size() / incr; //Delimiters count unsigned int b = (inputstring.size() + 1) / incr; //Blocks count diff --git a/NetFormating.hpp b/NetFormating.hpp index b404a10..7942a5f 100644 --- a/NetFormating.hpp +++ b/NetFormating.hpp @@ -6,24 +6,26 @@ #include #include #include +#include -char DetermineDelimiter(std::string inputstring, uint8_t expectedblocksize); -int MakeMeIpv4(uint32_t input, unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d); -uint16_t portcheck(const std::string inputstring, const char* whos); -uint32_t SchizoConverter(std::string inputstring); +char DetermineDelimiter(std::string inputstring, uint_fast8_t expectedblocksize); +int MakeMeIpv4(uint_fast32_t input, unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d); +uint_fast16_t portcheck(const std::string inputstring, const char* whos); +uint_fast32_t SchizoConverter(std::string inputstring); -void PrintIPV4(const char* msg, uint32_t input); -void PrintIPV4(const char* msg, uint32_t input); //Not an endianness independent code -void PrintIPV42(const char* msg, uint32_t input); -void PrintIPV43(const char* msg, uint32_t input); -void PrintMacFromVec(const std::vector inputvec); +void PrintIPV4(const char* msg, uint_fast32_t input); +void PrintIPV4(const char* msg, uint_fast32_t input); //Not an endianness independent code +void PrintIPV42(const char* msg, uint_fast32_t input); +void PrintIPV43(const char* msg, uint_fast32_t input); +void PrintMacFromVec(const std::vector inputvec); std::vector split(std::string s, const char delimiter); +std::vector payloadtovec(pcpp::PayloadLayer payload); -std::string MacVecToStringWithDelimiters(std::vector inputvec, const char delimiter); -std::string VecToString(std::vector inputvec); +std::string MacVecToStringWithDelimiters(std::vector inputvec, const char delimiter); +std::string VecToString(std::vector inputvec); std::string VecToStringWithDelimiters(std::vector inputvec, const char delimiter); -std::string VecToStringWithDelimiters(std::vector inputvec, const char delimiter); +std::string VecToStringWithDelimiters(std::vector inputvec, const char delimiter); const static auto MVTSWD = MacVecToStringWithDelimiters; \ No newline at end of file diff --git a/NetFunctions.cpp b/NetFunctions.cpp index 241e08c..0b394d0 100644 --- a/NetFunctions.cpp +++ b/NetFunctions.cpp @@ -1,7 +1,7 @@ #include "NetFunctions.hpp" #define VERBOSE -uint8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, WinDev Out, bool lstcp, uint16_t lsinternalport, uint16_t lsexternalport, std::string lsDGWAY, uint16_t lsGWlistenport, uint32_t mappingtime) +uint_fast8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, WinDev Out, bool lstcp, uint_fast16_t lsinternalport, uint_fast16_t lsexternalport, std::string lsDGWAY, uint_fast16_t lsGWlistenport, uint_fast32_t mappingtime) { /* 0 1 2 3 @@ -16,22 +16,22 @@ uint8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, (https://datatracker.ietf.org/doc/html/rfc6886) */ - uint8_t* lsbuffer = (uint8_t*)calloc(12, sizeof(uint8_t)); //4 bytes * 3 rows = 12 + uint_fast8_t* lsbuffer = (uint_fast8_t*)calloc(12, sizeof(uint_fast8_t)); //4 bytes * 3 rows = 12 if (lsbuffer) { lsbuffer[0] = 0; //Version - uint8_t mappingopcode = 1; + uint_fast8_t mappingopcode = 1; if (lstcp) mappingopcode = 2; - lsbuffer[1] = (uint8_t(mappingopcode)); //1 for UDP and 2 for TCP. + lsbuffer[1] = (uint_fast8_t(mappingopcode)); //1 for UDP and 2 for TCP. //2nd and 3rd bytes are reserved - uint8_t* ptr16t8 = (uint8_t*)(&(lsinternalport)); //Internal (host) port + uint_fast8_t* ptr16t8 = (uint_fast8_t*)(&(lsinternalport)); //Internal (host) port lsbuffer[4] = *(ptr16t8 + 1); //BE,MSB lsbuffer[5] = *ptr16t8; //LSB - ptr16t8 = (uint8_t*)(&(lsexternalport)); //External (GW) port + ptr16t8 = (uint_fast8_t*)(&(lsexternalport)); //External (GW) port lsbuffer[6] = *(ptr16t8 + 1); //BE,MSB lsbuffer[7] = *ptr16t8; //LSB @@ -68,11 +68,13 @@ uint8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(testv4); if (nullptr == dev) { - std::cout << "Couldn't find interface by provided IP address or name" << std::endl; + std::cerr << "Couldn't find interface by provided IP address or name" << std::endl; + return 201; } if (!dev->open()) { - std::cout << "!Couldn't open the device." << std::endl; + std::cerr << "Couldn't open the device." << std::endl; + return 202; } else { @@ -86,15 +88,35 @@ uint8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, std::cout << "UDP" << std::endl; } int sentCount = dev->sendPacket(&newPacket); + + + if (1 == progmode) //Caching mappings is only needed in Hold mode + { + bool alreadyexists = false; + for (unsigned int sp = 0; sp < SentPackets.size(); sp++) + { + if (0 == ComparePayloads(*(SentPackets.at(sp).getLayerOfType()), newPayload)) + { + alreadyexists = true; + SentPackets.at(sp) = newPacket; + } + } + if (false == alreadyexists) + { + SentPackets.push_back(newPacket); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(250)); //250ms delay to assure correct processing in series of requests + } free(lsbuffer); return 0; } - std::cout << "Host address didn't pass validation check. Aborting..." << std::endl; + std::cerr << "Host address didn't pass the validation check. Aborting..." << std::endl; return 322; } - std::cout << "Wasn't able to allocate memory. Aborting..." << std::endl; + std::cerr << "Wasn't able to allocate memory. Aborting..." << std::endl; return 323; } @@ -123,20 +145,20 @@ void getDevices() // Contains pointer to current adapter info PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo; do { - std::vector hwaddr; + std::vector hwaddr; if ('0' != pAdapterInfo->IpAddressList.IpAddress.String[0]) { for (unsigned int i = 0; i < pAdapterInfo->AddressLength; i++) { - hwaddr.push_back((uint8_t)pAdapterInfo->Address[i]); + hwaddr.push_back((uint_fast8_t)pAdapterInfo->Address[i]); } unsigned long localinterfaceindex = pAdapterInfo->Index; - uint32_t bitmask = SchizoConverter(pAdapterInfo->IpAddressList.IpMask.String); - uint32_t bitipaddr = SchizoConverter(pAdapterInfo->IpAddressList.IpAddress.String); - uint32_t netaddr = bitipaddr & bitmask; //Calculate network address - uint32_t wildcardmask = ~bitmask; - uint32_t broadcastaddr = netaddr | wildcardmask; //Calculate network broadcast address + uint_fast32_t bitmask = SchizoConverter(pAdapterInfo->IpAddressList.IpMask.String); + uint_fast32_t bitipaddr = SchizoConverter(pAdapterInfo->IpAddressList.IpAddress.String); + uint_fast32_t netaddr = bitipaddr & bitmask; //Calculate network address + uint_fast32_t wildcardmask = ~bitmask; + uint_fast32_t broadcastaddr = netaddr | wildcardmask; //Calculate network broadcast address bool interfaceexists = false; for (int l = 0; l < DEVS.size(); l++) @@ -160,7 +182,7 @@ void getDevices() free(AdapterInfo); } -void sendarp(const WinDev localstruct, const std::string destinationv4, std::vector & inputvec) //[IN] WinDev, [IN] std::string IPV4, [OUT] std::vector uint8_t +void sendarp(const WinDev localstruct, const std::string destinationv4, std::vector & inputvec) //[IN] WinDev, [IN] std::string IPV4, [OUT] std::vector uint_fast8_t { IPAddr SourceADR = inet_addr(localstruct.ipaddr.c_str()); IPAddr DestIp = inet_addr(destinationv4.c_str()); @@ -177,10 +199,10 @@ void sendarp(const WinDev localstruct, const std::string destinationv4, std::vec unsigned int id = ((int)addrlen - 1); for (unsigned int i = 0; i < id; i++) { - inputvec.push_back((uint8_t)bPhysAddr[i]); + inputvec.push_back((uint_fast8_t)bPhysAddr[i]); std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)bPhysAddr[i] << ":"; } - inputvec.push_back((uint8_t)bPhysAddr[id]); + inputvec.push_back((uint_fast8_t)bPhysAddr[id]); std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)bPhysAddr[id] << std::endl; } else @@ -219,7 +241,7 @@ void sendarp(const WinDev localstruct, const std::string destinationv4, std::vec WinDev FindAppropriateDevice(const std::vector inputvec, const std::string DestIp) { - uint32_t reformatedDestIP = SchizoConverter(DestIp); + uint_fast32_t reformatedDestIP = SchizoConverter(DestIp); for (int i = 0; i < inputvec.size(); i++) { if ((inputvec[i].bitmask & reformatedDestIP) == inputvec[i].netaddress) @@ -247,4 +269,106 @@ WinDev FindAppropriateDeviceByMac(const std::vector inputvec, const std } std::cerr << "Wasn't able to find an output device with matching Source MAC. Check if passed MAC is all lowercase, and if there is any typo" << std::endl; return { "", "", {NULL},0,0,0,0,0 }; //We probably should use default GW if interface wasn't found +} + + + +uint_fast8_t ComparePayloads(pcpp::PayloadLayer payload1, pcpp::PayloadLayer payload2) //0 = equal, 1 = not equal, 2 = len(p1)>len(p2), 3 = len(p1) vec1 = payloadtovec(payload1); + std::vector vec2 = payloadtovec(payload2); + bool vecequality = true; + for (unsigned int i = 0; i < len1; i++) + { + if (vec1.at(i) != vec2.at(i)) + { + vecequality = false; + break; + } + } + if (true == vecequality) + { + return 0; + } + return 1; + } + else + { + if (len1 > len2) + { + return 2; + } + return 3; + } +} + +uint_fast8_t DestroySingleMapping(std::string dsDMAC, std::string dsGWMAC, std::string dsDADDR, WinDev dsOut, bool tcp, uint_fast16_t dsinternalport, std::string dsDGWAY, uint_fast16_t dsGWlistenport) +{ + //A client requests explicit deletion of a mapping by sending a message to the NAT gateway requesting the mapping, with the Requested Lifetime in Seconds set to zero. + //The Suggested External Port MUST be set to zero by the client on sending, and MUST be ignored by the gateway on reception. + return sendspoof(dsDMAC, dsGWMAC, dsDADDR, dsOut, tcp, dsinternalport, (uint_fast16_t) 0, dsDGWAY, dsGWlistenport, (uint_fast32_t)0); +} + +uint_fast8_t DestroyAllMappings(std::string dsDMAC, std::string dsGWMAC, std::string dsDADDR, WinDev dsOut, bool tcp, std::string dsDGWAY, uint_fast16_t dsGWlistenport) +{ + //A client can request the explicit deletion of all its UDP or TCP mappings by sending the same deletion request to the NAT gateway with the external port, internal port, and lifetime set to zero. + return sendspoof(dsDMAC, dsGWMAC, dsDADDR, dsOut, tcp, (uint_fast16_t)0, (uint_fast16_t)0, dsDGWAY, dsGWlistenport, (uint_fast32_t)0); +} + + +uint_fast8_t RemoveCreatedMappings(std::vector &packetvector, std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, WinDev lsOut, std::string lsDGWAY, uint_fast16_t lsGWlistenport) +{ + pcpp::IPv4Address testv4(lsOut.ipaddr); + if (true == testv4.isValid()) + { + pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(testv4); + if (nullptr == dev) + { + std::cerr << "Couldn't find interface by provided IP address or name" << std::endl; + return 201; + } + if (!dev->open()) + { + std::cerr << "Couldn't open the device." << std::endl; + return 202; + } + else + { + for (int i = 0; i < packetvector.size(); i++) + { + uint8_t* pltest = packetvector.at(i).getLayerOfType()->getPayload(); + unsigned int z = SentPackets.at(i).getLastLayer()->getDataLen(); + // uint8_t* ar = new uint8_t[z]; + pltest[6] = 0; //ExPort MSB + pltest[7] = 0; //LSB + + pltest[8] = 0; //Lifetime MSB + pltest[9] = 0; + pltest[10] = 0; + pltest[11] = 0; //LSB + + packetvector.at(i).computeCalculateFields(); + dev->sendPacket(&packetvector.at(i)); + } + return 0; + } + } + std::cerr << "Host address didn't pass the validation check. Aborting..." << std::endl; + return 322; +} + +uint_fast8_t PrintPayloadFromPacket(pcpp::Packet packet) +{ + uint8_t* ppayload = packet.getLayerOfType()->getPayload(); + uint8_t dlen = packet.getLayerOfType()->getPayloadLen(); + std::cout << std::endl << "Payload print:"; + for (int i = 0; i < dlen; i++) + { + std::cout << std::hex << std::setfill('0') << std::setw(2) << (int)ppayload[i] << "-"; + } + return 0; } \ No newline at end of file diff --git a/NetFunctions.hpp b/NetFunctions.hpp index 2d7b9f5..49779f9 100644 --- a/NetFunctions.hpp +++ b/NetFunctions.hpp @@ -17,5 +17,10 @@ WinDev FindAppropriateDevice(const std::vector inputvec, const std::string DestIp); WinDev FindAppropriateDeviceByMac(const std::vector inputvec, const std::string SMAC); void getDevices(); -void sendarp(WinDev localstruct, std::string destinationv4, std::vector & inputvec); //[IN] WinDev, [IN] std::string IPV4, [OUT] std::vector uint8_t -uint8_t sendspoof(std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, WinDev Out, bool lstcp, uint16_t lsinternalport, uint16_t lsexternalport, std::string lsDGWAY, uint16_t lsGWlistenport, uint32_t mappingtime); +void sendarp(WinDev localstruct, std::string destinationv4, std::vector & inputvec); //[IN] WinDev, [IN] std::string IPV4, [OUT] std::vector uint_fast8_t +uint_fast8_t ComparePayloads(pcpp::PayloadLayer payload1, pcpp::PayloadLayer payload2); //0 = equal, 1 = not equal, 2 = len(p1)>len(p2), 3 = len(p1)& packetvector, std::string lsDMAC, std::string lsGWMAC, std::string lsDADDR, WinDev lsOut, std::string lsDGWAY, uint_fast16_t lsGWlistenport); //Removes all mappings created in the session diff --git a/README.md b/README.md index 8239e8e..06db553 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,15 @@ If you run the program behind NAT or from different subnet, the work depends on * -GP xxxxx - Port that NAT-PMP-capable gateway is listening on. (Optional, defaults to 5351); * -GW xxx.xxx.xxx.xxx - IPv4 of the NAT-PMP Gateway (Optional, defaults to IPv4 address of the gateway on the interface); * -DM xx:xx:xx:xx:xx:xx - Destination (target's) MAC address (Optional, but host must be reachable with NetBios); -* -GM xx:xx:xx:xx:xx:xx - MAC address of Gateway in the broadcast domain, that is the next hop (Optional, but gateway must be reachable with NetBios); +* -GM xx:xx:xx:xx:xx:xx - MAC address of Gateway in the broadcast domain, that is the next hop (Optional in single broadcast domain, but gateway must be reachable with NetBios); * -SM xx:xx:xx:xx:xx:xx - MAC address of output interface (Optional, if host is in the same subnet as the target); +## [Modes] (Optional) +* -A (Default) - Single Mapping creating mode +* -H - Hold mode (WORK IN PROGRESS); +* -R - Single mapping removal mode; +* -RALL - All mappings removal mode; +* If no mode argument is provided, mapping creation mode (-A) will be used instead; # Examples In most of the cases these will be enough: @@ -48,6 +54,16 @@ If, for some reason, the required data cannot be fetched, user must provide it m Providing additional data with launch arguments also increases speed of the programm, while also reducing network presence. +* Removing UDP: +`NAT-PMP-Spoofer.exe -R -DA 192.168.1.228 -PH 80` + +* Removing TCP+UDP: +`NAT-PMP-Spoofer.exe -R -DA 192.168.1.228 -PH 80 -BOTH` + +* Removing All NAT-PMP mappings, associated with host: +`NAT-PMP-Spoofer.exe -RALL -DA 192.168.1.228` + + # Q&A * Q: Can it create TCP mappings? @@ -58,9 +74,7 @@ Yes, that's the whole point of this project. * Q: How can I be sure that the mapping is really created? There is no feature for checking right now, but you can use UPnP Wizard (may not show mapping lifetime correctly) or you can check NAT-PMP leases on your GateWay (e.g. /tmp/upnp.leases) -* Q: How can I remove mapping? -There is no such feature right now, but you can still do it with UPnP Wizard or upnp.leases file. * Q: Windows Defender quarantines the program with "This program is dangerous and executes commands from an attacker"... You can check binary file with Virus Total (http://virustotal.com) or manually review the code and compile it. There is no RCE, and the only shadow thing in an entire project - is spoofing. @@ -74,7 +88,9 @@ Both UPNP and NAT-PMP aren't designed to work under such conditions. You can sti # Upcoming features - [ ] Viewing mappings; -- [ ] Removing mappings; +- [X] Removing mappings; +- [ ] Topology images for examples; - [ ] Endianness independent code for ARM-based Windows systems; +- [ ] Configuration via files; - [ ] Static builds; - [ ] CI/CD; \ No newline at end of file diff --git a/main.cpp b/main.cpp index 38e5ce6..ad7768c 100644 --- a/main.cpp +++ b/main.cpp @@ -24,7 +24,6 @@ WinDev OutputInterface; int main(int argc, char* argv[]) { - if (EXIT_FAILURE == LaunchOptionsProcessing(argc, argv) ) //Handling of launch arguments { return EXIT_FAILURE; @@ -60,21 +59,23 @@ int main(int argc, char* argv[]) } std::cout << "Output IPv4 is " << OutputInterface.ipaddr << std::endl; + if (DMAC.empty()) //If we don't pass destination MAC, we need to get it with ARP { SMAC = MacVecToStringWithDelimiters(OutputInterface.macaddrvec, ':'); - std::vector targetmac; + std::vector targetmac; std::cout << std::endl << "Destination MAC address not found, making an ARP request..." << std::endl; sendarp(OutputInterface, DADDR, targetmac); DMAC = MVTSWD(targetmac, ':'); } + if (DGWAY.empty()) { DGWAY = OutputInterface.gwayip; if (GWMAC.empty()) { - std::vector gwaymacvec; + std::vector gwaymacvec; std::cout << std::endl << "Gateway MAC address not found, making an ARP request..." << std::endl; sendarp(OutputInterface, DGWAY, gwaymacvec); if (!gwaymacvec.empty()) @@ -87,7 +88,7 @@ int main(int argc, char* argv[]) { if (GWMAC.empty()) { - std::vector gwaymacvec; + std::vector gwaymacvec; std::cout << std::endl << "Gateway MAC address not found, making an ARP request..." << std::endl; sendarp(OutputInterface, DGWAY, gwaymacvec); if (!gwaymacvec.empty()) @@ -97,32 +98,90 @@ int main(int argc, char* argv[]) } } + if (!GWMAC.empty()) { - if (1 == both) + + uint_fast8_t switchretval = 2; + switch (progmode) { - uint8_t pretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, false, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); - if (0 == pretval) + case 1: + //if (SetConsoleCtrlHandler(CtrlHandler, TRUE)) + //{ + // + //} + break; + case 2: { - std::cout << "Nat-PMP request sent for UDP" << std::endl; + if (true == both) + { + switchretval = DestroySingleMapping(DMAC, GWMAC, DADDR, OutputInterface, false, internalport, DGWAY, gwlistenerport); + if (0 == switchretval) + { + std::cout << "Sent Nat-PMP request for destroying UDP mapping" << std::endl; + } + istcp = true; + switchretval = DestroySingleMapping(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, DGWAY, gwlistenerport); + if (0 == switchretval) + { + std::cout << "Sent Nat-PMP request for destroying TCP mapping" << std::endl; + } + break; + } + else + { + switchretval = DestroySingleMapping(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, DGWAY, gwlistenerport); + if (0 == switchretval) + { + std::cout << "Sent Nat-PMP request for destroying mapping" << std::endl; + } + break; + } } - istcp = true; - pretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); - if (0 == pretval) + case 3: { - std::cout << "Nat-PMP request sent for TCP" << std::endl; + switchretval = DestroyAllMappings(DMAC, GWMAC, DADDR, OutputInterface, istcp, DGWAY, gwlistenerport); + if (0 == switchretval) + { + std::cout << "Sent Nat-PMP request for destroying all associated mappings" << std::endl; + } + break; + } + case 4: + //View mode + //for checking existing mappings + break; + default: + { + if (true == both) + { + switchretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, false, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); + if (0 == switchretval) + { + std::cout << "Nat-PMP request sent for UDP" << std::endl; + } + istcp = true; + switchretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); + if (0 == switchretval) + { + std::cout << "Nat-PMP request sent for TCP" << std::endl; + } + return 0; + } + else + { + switchretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); + if (0 == switchretval) + { + std::cout << "Nat-PMP request sent" << std::endl; + } + } + break; } - return 0; - } - - - uint8_t pretval = sendspoof(DMAC, GWMAC, DADDR, OutputInterface, istcp, internalport, externalport, DGWAY, gwlistenerport, mappinglifetime); - if (0 == pretval) - { - std::cout << "Nat-PMP request sent" << std::endl; } } + system("PAUSE"); return 0; }