Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Proxy code
/**
@file proxy.cpp
@brief Top level proxy implementation file
*/
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <pthread.h>
#include <string.h>
#include "hex.h"
void* client_thread(void* arg);
std::string encodePacket(byte* packet, int length);
std::string crackUsername(const std::string& plaintext1, const std::string& plaintext2, const std::string& ciphertext1,
const std::string& ciphertext2);
std::string crackPlaintext(const std::string& plaintext1, const std::string& plaintext2, const std::string& ciphertext1,
const std::string& ciphertext2);
bool verifyXOR(const std::string& plaintext1, const std::string& plaintext2,
const std::string& ciphertext1, const std::string& ciphertext2);
std::string XORHexStrings(std::string i1, std::string i2);
std::string encodeString(std::string input);
std::string decodeString(std::string input);
unsigned int stringToHex(std::string input);
std::string hexToString(unsigned int input);
unsigned short g_bankport;
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: proxy listen-port bank-connect-port\n");
return -1;
}
unsigned short ourport = atoi(argv[1]);
g_bankport = atoi(argv[2]);
//socket setup
int lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(!lsock)
{
printf("fail to create socket\n");
return -1;
}
//listening address
sockaddr_in addr_l;
memset(&addr_l,0,sizeof(addr_l));
addr_l.sin_family = AF_INET;
addr_l.sin_port = htons(ourport);
unsigned char* ipaddr = reinterpret_cast<unsigned char*>(&addr_l.sin_addr);
ipaddr[0] = 127;
ipaddr[1] = 0;
ipaddr[2] = 0;
ipaddr[3] = 1;
if(0 != bind(lsock, reinterpret_cast<sockaddr*>(&addr_l), sizeof(addr_l)))
{
printf("failed to bind socket\n");
return -1;
}
if(0 != listen(lsock, SOMAXCONN))
{
printf("failed to listen on socket\n");
return -1;
}
//loop forever accepting new connections
while(1)
{
sockaddr_in unused;
socklen_t size = sizeof(unused);
int csock = accept(lsock, reinterpret_cast<sockaddr*>(&unused), &size);
if(csock < 0) //bad client, skip it
continue;
pthread_t thread;
pthread_create(&thread, NULL, client_thread, (void*)csock);
}
}
void* client_thread(void* arg)
{
unsigned int atmTime = time(NULL)+1;
int csock = (int)arg;
printf("[proxy] client ID #%d connected\n", csock);
//create a new socket and connect to the bank
int bsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(!bsock)
{
printf("fail to create socket\n");
return NULL;
}
sockaddr_in addr_b;
addr_b.sin_family = AF_INET;
addr_b.sin_port = htons(g_bankport);
unsigned char* ipaddr = reinterpret_cast<unsigned char*>(&addr_b.sin_addr);
ipaddr[0] = 127;
ipaddr[1] = 0;
ipaddr[2] = 0;
ipaddr[3] = 1;
ipaddr[3] = 1;
if(0 != connect(bsock, reinterpret_cast<sockaddr*>(&addr_b), sizeof(addr_b)))
{
printf("fail to connect to bank\n");
return NULL;
}
unsigned int bankTime = time(NULL);
//input loop
int length;
char packet[1024];
std::string atmNonce, bankNonce;
srand(time(NULL) + 1);
std::vector<unsigned int> atmNonces, bankNonces;
for(unsigned int i = 0; i < 500; ++i)
{
atmNonces.push_back(rand());
}
srand(time(NULL));
for(unsigned int i = 0; i < 500; ++i)
{
bankNonces.push_back(rand());
}
//Setup two variables for breaking plaintext
std::string plaintext1 = encodeString("login alice 794582936 7945829364991124672345 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
std::string ciphertext1 = "A392119691E370432D8446750E631A2840D7822565BF35EBE731FDC5C82625486F551A8BDC818FE1773487F72AEFC92C4962170CA2FE4638AC851025AB4D6FC464D6C4D8668B1090485A1C63D25ED49A00BCF93D633EE38CFBACA2DE22811AEDC287573AF6C8D2195C690E94DFAD1AC6D4FB6CCA0B0DE382D1306D9655A8754F917A1C2A80C3A753328E0AC26AA1808E32FEAA064C1D4DC8F60ACD1B1898B4A3";
unsigned int loopCount = 0;
while(csock)
{
//atmTime = time(NULL)+1;
//bankTime = time(NULL);
std::string encodedPacket;
std::string plaintext2 = "";
//read the packet from the ATM
if(sizeof(int) != recv(csock, &length, sizeof(int), 0))
break;
if(length >= 1024)
{
printf("packet too long\n");
break;
}
if(length != recv(csock, packet, length, 0))
{
printf("[proxy] fail to read packet\n");
break;
}
//TODO: tamper with packet going from ATM to bank
encodedPacket = encodePacket((byte*)packet,160);
printf("[aTb] %s\n", encodedPacket.c_str());
if(encodedPacket.substr(0,12) == "A392119691E3" ||
encodedPacket.substr(0,18) == "BB8F17918CA5745D64" ||
encodedPacket.substr(0,14) == "A39211908AB731")
{
std::string username = crackUsername(plaintext1,plaintext2,ciphertext1,encodedPacket);
if(username.size() > 0)
{
printf("[cracked username] %s\n", username.c_str());
}
}
plaintext2 = crackPlaintext(plaintext1,plaintext2,ciphertext1,encodedPacket);
if(plaintext2.size() > 0)
{
printf("[aTb plaintext] %s\n", decodeString(plaintext2).c_str());
}
//Time to guess the ATM's nonce
printf("[atm nonce] %u\n", atmNonces[loopCount]);
//forward packet to bank
if(sizeof(int) != send(bsock, &length, sizeof(int), 0))
{
printf("[proxy] fail to send packet length 2\n");
break;
}
if(length != send(bsock, (void*)packet, length, 0))
{
printf("[proxy] fail to send packet\n");
break;
}
// atmTime = time(NULL)+1;
// bankTime = time(NULL);
if(sizeof(int) != recv(csock, &length, sizeof(int), 0))
break;
if(length >= 1024)
{
printf("packet too long\n");
break;
}
if(length != recv(csock, packet, length, 0))
{
printf("[proxy] fail to read packet\n");
break;
}
//TODO: tamper with packet going from ATM to bank
encodedPacket = encodePacket((byte*)packet,32);
printf("[aTb hash] %s\n", encodedPacket.c_str());
//forward packet to bank
if(sizeof(int) != send(bsock, &length, sizeof(int), 0))
{
printf("[proxy] fail to send packet length 2\n");
break;
}
if(length != send(bsock, (void*)packet, length, 0))
{
printf("[proxy] fail to send packet\n");
break;
}
// atmTime = time(NULL)+1;
// bankTime = time(NULL);
//get response packet from bank
if(sizeof(int) != recv(bsock, &length, sizeof(int), 0))
{
printf("[proxy] fail to read packet length 3\n");
break;
}
if(length >= 1024)
{
printf("packet too long\n");
break;
}
if(length != recv(bsock, packet, length, 0))
{
printf("[proxy] fail to read packet\n");
break;
}
//Guess the bank's nonce
printf("[bank nonce] %u\n", bankNonces[loopCount]);
//TODO: tamper with packet going from bank to ATM
encodedPacket = encodePacket((byte*)packet, 160);
printf("[bTa] %s\n", encodedPacket.c_str());
plaintext2 = "";
plaintext2 = crackPlaintext(plaintext1,plaintext2,ciphertext1,encodedPacket);
if(plaintext2.size() > 0)
{
printf("[bTa plaintext] %s\n", decodeString(plaintext2).c_str());
}
//forward packet to ATM
if(sizeof(int) != send(csock, &length, sizeof(int), 0))
{
printf("[proxy] fail to send packet length 1\n");
break;
}
if(length != send(csock, (void*)packet, length, 0))
{
printf("[proxy] fail to send packet\n");
break;
}
// atmTime = time(NULL)+1;
// bankTime = time(NULL);
if(sizeof(int) != recv(bsock, &length, sizeof(int), 0))
{
printf("[proxy] fail to read packet length 3\n");
break;
}
if(length >= 1024)
{
printf("packet too long\n");
break;
}
if(length != recv(bsock, packet, length, 0))
{
printf("[proxy] fail to read packet\n");
break;
}
//TODO: tamper with packet going from bank to ATM
encodedPacket = encodePacket((byte*)packet,32);
printf("[bTa hash] %s\n", encodedPacket.c_str());
//forward packet to ATM
if(sizeof(int) != send(csock, &length, sizeof(int), 0))
{
printf("[proxy] fail to send packet length 1\n");
break;
}
if(length != send(csock, (void*)packet, length, 0))
{
printf("[proxy] fail to send packet\n");
break;
}
printf("---------------------------\n");
++loopCount;
if(loopCount == bankNonces.size() || loopCount == atmNonces.size())
{
break;
}
}
printf("[proxy] client ID #%d disconnected\n", csock);
close(bsock);
close(csock);
return NULL;
}
std::string encodePacket(byte* packet, int length)
{
//return std::string("");
std::string encodedPacket;
CryptoPP::StringSource(packet, length, true,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(encodedPacket)
) // HexEncoder
);
return encodedPacket;
}
std::string encodeString(std::string input)
{
//return std::string("");
std::string output;
CryptoPP::StringSource(input, true,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(output)
) // HexEncoder
);
return output;
}
std::string decodeString(std::string input)
{
//return std::string("");
std::string output;
CryptoPP::StringSource(input, true,
new CryptoPP::HexDecoder(
new CryptoPP::StringSink(output)
) // HexEncoder
);
return output;
}
unsigned int stringToHex(std::string input)
{
unsigned int x;
std::stringstream ss;
ss << std::hex << input;
ss >> x;
return x;
}
std::string hexToString(unsigned int input)
{
std::stringstream stream;
stream << std::hex << input;
std::string result( stream.str() );
return result;
}
std::string XORHexStrings(std::string i1, std::string i2)
{
unsigned int e1 = stringToHex(i1);
unsigned int e2 = stringToHex(i2);
return hexToString(e1^e2);
}
bool verifyXOR(const std::string& plaintext1, const std::string& plaintext2,
const std::string& ciphertext1, const std::string& ciphertext2)
{
if(plaintext1.size() < 16 || plaintext2.size() < 16 || ciphertext1.size() < 16 || ciphertext2.size() < 16)
{
return false;
}
for(unsigned int i = 0; i < 16; ++i)
{
std::string plainXOR, cipherXOR;
cipherXOR = XORHexStrings(ciphertext1.substr(i*2,2), ciphertext2.substr(i*2,2));
plainXOR = XORHexStrings(plaintext1.substr(i*2,2), plaintext2.substr(i*2,2));
if(plainXOR != cipherXOR)
{
return false;
}
}
return true;
}
std::string crackPlaintext(const std::string& plaintext1, const std::string& plaintext2, const std::string& ciphertext1,
const std::string& ciphertext2)
{
std::string result("");
if(plaintext1.size() < 16 || ciphertext1.size() < 16 || ciphertext2.size() < 16)
{
return "";
}
if(plaintext2.size() >= 16)
{
return plaintext2;
}
for(unsigned int i = 0; i < 16; ++i)
{
std::string plainXOR, cipherXOR, discoverdPlain;
cipherXOR = XORHexStrings(ciphertext1.substr(i*2,2), ciphertext2.substr(i*2,2));
if(plaintext2.size() >= i*2+2)
{
discoverdPlain = plaintext2.substr(i*2,2);
} else {
discoverdPlain = XORHexStrings(plaintext1.substr(i*2,2), cipherXOR);
}
plainXOR = XORHexStrings(plaintext1.substr(i*2,2), discoverdPlain);
if(plainXOR != cipherXOR)
{
return "";
}
result += discoverdPlain;
}
return result;
}
std::string crackUsername(const std::string& plaintext1, const std::string& plaintext2, const std::string& ciphertext1,
const std::string& ciphertext2)
{
if(!(ciphertext2.substr(0,12) == "A392119691E3" ||
ciphertext2.substr(0,18) == "BB8F17918CA5745D64" ||
ciphertext2.substr(0,14) == "A39211908AB731"))
{
return "";
}
std::string crackedPlain = crackPlaintext(plaintext1,plaintext2,ciphertext1,ciphertext2);
if(crackedPlain.size() != 32)
{
return "";
}
if(ciphertext2.substr(0,12) == "A392119691E3")
{
crackedPlain = decodeString(crackedPlain.substr(12));
}
else if(ciphertext2.substr(0,18) == "BB8F17918CA5745D64")
{
crackedPlain = decodeString(crackedPlain.substr(18));
unsigned int i = 0;
for(; i < crackedPlain.size(); ++i)
{
if(crackedPlain[i] == ' ')
{
break;
}
}
crackedPlain = crackedPlain.substr(i+1);
}
else if(ciphertext2.substr(0,14) == "A39211908AB731")
{
crackedPlain = decodeString(crackedPlain.substr(14));
} else {
return "";
}
unsigned int i = 0;
for(; i < crackedPlain.size(); ++i)
{
if(crackedPlain[i] == ' ')
{
i -= 1;
break;
}
}
return crackedPlain.substr(0,i+1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.