Skip to content

Commit

Permalink
Add replace tamper method.
Browse files Browse the repository at this point in the history
Explicitly use `std::mt19937` random engine
Make random engine within `TamperMethod::randRange` static
Add centralized hex parser to `TamperMethod`
  • Loading branch information
farlepet committed Oct 22, 2021
1 parent 0f50973 commit 5eb1b1c
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 14 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ Available methods and associated options:
- `off` - Offset at which to apply data
- Cannot be a range
- `data` - Hex data
- `replace` - Replace bytes within matching sequence
- `off` - Offset into sequence to start replacing
- Cannot be a range
- Can be negative
- `seq` - Hex sequence to search for
- `data` - Replacement data
- `multi` - Whether to allow multiple replacements
- NOTE: Previously matching sequence is currently skipped

Global options:
- `chance` - How likely the tamper method is to be used on a given packet
Expand Down
4 changes: 2 additions & 2 deletions inc/PacketHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class PacketHandler {
private:
std::vector<TamperMethod *> meths; /*!< List of configured tamper methods, in order they are to be applied */

std::random_device rand_rd;
std::default_random_engine rand_engine;
std::random_device rand_rd;
std::mt19937 rand_engine;

int handleTCPPacket(struct iphdr *_ip_head);
int handleUDPPacket(struct iphdr *_ip_head);
Expand Down
16 changes: 16 additions & 0 deletions inc/TamperMethod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ class TamperMethod {
*/
static int parseBool(std::string &_str, bool &_val);

/**
* @brief Parse hex string from configuration
*
* The format is byte-ordered groups of two hexadecimal characters:
* <byte0>[<byte1>[<byte2>[...]]]
*
* Where each of <byteX> is a sequence of two characters, e.g.:
* C0FFEE1234
*
* @param _str Configuration value string
* @param _val Output byte vector
*
* @return 0 on success, < 0 on failure
*/
static int parseHex(std::string &_str, std::vector<uint8_t> &_val);

/**
* @brief Generates a random non-negative number in the given range
*
Expand Down
4 changes: 2 additions & 2 deletions inc/TamperMethods/TamperMethodRand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class TamperMethodRand : public TamperMethod {
int size_min = 1; /*!< Minimum size of modified region */
int size_max = 1; /*!< Maximum size of modified region */

std::random_device rand_rd;
std::default_random_engine rand_engine;
std::random_device rand_rd;
std::mt19937 rand_engine;

public:
TamperMethodRand(std::map<std::string, std::string> &_opts);
Expand Down
24 changes: 24 additions & 0 deletions inc/TamperMethods/TamperMethodReplace.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef _TAMPER_METHOD_REPLACE_HPP_
#define _TAMPER_METHOD_REPLACE_HPP_

#include <vector>

#include "TamperMethod.hpp"

/**
* @brief Method used to tamper with packet data using search-and-replace with offset
*/
class TamperMethodReplace : public TamperMethod {
private:
int offset = 0; /*!< Offset into sequence in which to insert data */
bool multi = false; /*!< Whether to allow multiple replacements per packet */
std::vector<uint8_t> data; /*!< Data to insert */
std::vector<uint8_t> sequence; /*!< Sequence to search for */

public:
TamperMethodReplace(std::map<std::string, std::string> &_opts);

int tamper(size_t len, uint8_t *data);
};

#endif /* _TAMPER_METHOD_REPLACE_HPP_ */
2 changes: 1 addition & 1 deletion src/PacketHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ int PacketHandler::doTamper(size_t len, uint8_t *data) {
return 0;
}

std::uniform_real_distribution<double> rand_dist(0, 1);
std::uniform_real_distribution<double> rand_dist(0, 0.999);

for(TamperMethod *meth : this->meths) {
if(meth->getProbability() >= rand_dist(this->rand_engine)) {
Expand Down
24 changes: 21 additions & 3 deletions src/TamperMethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "TamperMethod.hpp"
#include "TamperMethods/TamperMethodRand.hpp"
#include "TamperMethods/TamperMethodFixed.hpp"
#include "TamperMethods/TamperMethodReplace.hpp"

TamperMethod::TamperMethod(std::map<std::string, std::string> &_opts) {
if(_opts.count("chance")) {
Expand Down Expand Up @@ -43,6 +44,8 @@ TamperMethod *TamperMethod::create(std::string &_str) {
return new TamperMethodRand(opts);
} else if(meth == "fixed") {
return new TamperMethodFixed(opts);
} else if(meth == "replace") {
return new TamperMethodReplace(opts);
} else {
throw std::runtime_error("Unhandled tamper method: " + meth);
}
Expand Down Expand Up @@ -85,7 +88,24 @@ int TamperMethod::parseBool(std::string &_str, bool &_val) {
return 0;
}

int TamperMethod::parseHex(std::string &_str, std::vector<uint8_t> &_val) {
if((_str.size() == 0) ||
(_str.size() & 1)) {
return -1;
}
for(size_t i = 0; i < _str.size(); i+=2) {
uint8_t byte = std::stoi(_str.substr(i,2), NULL, 16);
_val.push_back(byte);
}

return 0;
}


size_t TamperMethod::randRange(int _min, int _max, size_t _sz) {
static std::random_device rand_rd;
static std::mt19937 rand_engine(rand_rd());

if(_max == -1 || (size_t)_max > _sz) {
_max = _sz;
}
Expand All @@ -98,9 +118,7 @@ size_t TamperMethod::randRange(int _min, int _max, size_t _sz) {
}

/* TODO: This is likely highly ineffecient */
std::random_device rand_rd;
std::default_random_engine rand_engine(rand_rd());
std::uniform_int_distribution<size_t> rand_dist(_min, _max);

return rand_dist(rand_engine);
}
}
8 changes: 2 additions & 6 deletions src/TamperMethods/TamperMethodFixed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ TamperMethod(_opts) {
throw std::runtime_error("offset<0 for TamperMethodFixed!");
}

if(_opts["data"].size() & 1) {
throw std::runtime_error("Data length must be an even number of characters for TamperMethodFixed!");
}
for(size_t i = 0; i < _opts["data"].size(); i+=2) {
uint8_t byte = std::stoi(_opts["data"].substr(i,2), NULL, 16);
this->data.push_back(byte);
if(TamperMethod::parseHex(_opts["data"], this->data)) {
throw std::runtime_error("Error while parsing data for TamperMethodFixed!");
}
}

Expand Down
85 changes: 85 additions & 0 deletions src/TamperMethods/TamperMethodReplace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include <iostream>
#include <iomanip>

#include "TamperMethods/TamperMethodReplace.hpp"

TamperMethodReplace::TamperMethodReplace(std::map<std::string, std::string> &_opts) :
TamperMethod(_opts) {
if(!_opts.count("off")) {
throw std::runtime_error("Missing offset for TamperMethodReplace!");
}
if(!_opts.count("data")) {
throw std::runtime_error("Missing data for TamperMethodReplace!");
}
if(!_opts.count("seq")) {
throw std::runtime_error("Missing sequence for TamperMethodReplace!");
}

this->offset = std::stoi(_opts["off"]);

if(TamperMethod::parseHex(_opts["data"], this->data)) {
throw std::runtime_error("Error while parsing data for TamperMethodReplace!");
}
if(TamperMethod::parseHex(_opts["seq"], this->sequence)) {
throw std::runtime_error("Error while parsing sequence for TamperMethodReplace!");
}

if(_opts.count("multi") &&
TamperMethod::parseBool(_opts["multi"], this->multi)) {
throw std::runtime_error("Error while parsing multi for TamperMethodReplace!");
}
}

int TamperMethodReplace::tamper(size_t len, uint8_t *data) {
size_t search_sz = this->sequence.size();

for(size_t i = 0; i < (len - search_sz); i++) {
size_t j = 0;
for(; j < search_sz; j++) {
if(data[i+j] != this->sequence[j]) {
break;
}
}
if(j == search_sz) {
/* Sequence match */
size_t sz = this->data.size();
size_t off = i;
size_t idx = 0;

if(((ssize_t)off + this->offset) < 0) {
idx = (size_t)-((ssize_t)off + this->offset);
if(idx >= sz) {
/* Entire insertion is before the payload */
continue;
}
sz -= idx;
off = 0;
} else {
off += this->offset;
}

if(off >= len) {
break;
} else if((off + sz) > len) {
/* Insertion continues beyond end of payload */
sz = len - off;
}

std::cerr << " + TamperMethodReplace(off: " << off << ", sz: " << sz << "): ";
std::cerr << std::setw(2) << std::setfill('0') << std::hex;
for(size_t k = 0; k < sz; k++) {
data[off + k] = this->data[idx + k];
std::cerr << unsigned(data[off + k]);
}
std::cerr << std::endl << std::setw(0) << std::setfill(' ') << std::dec;

if(!this->multi) {
break;
}

i += (search_sz - 1);
}
}

return 0;
}
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ int main(int argc, char **argv) {

NFQueue nfqueue(_options.queueNumber, pHandler);
nfqueue.open();
std::cerr << "Starting NFQueue listener..." << std::endl;
nfqueue.run();
/* TODO: Run in a different thread, close on keyboard interrupt. */
nfqueue.close();
Expand Down

0 comments on commit 5eb1b1c

Please sign in to comment.