« SE5 IdO sécurité des objets 2025/2026 b3 » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
Ligne 351 : Ligne 351 :


==== Première tentative ====
==== Première tentative ====
Avec la capture de paquets sur wireshark la première tentative est de repérer les trames de commandes et d'après l'image au dessus j'ai fais ce script python pour pouvoir essayer de controler le drone en faisant une soustraction pour le Cheksum<syntaxhighlight lang="c">
À partir des captures Wireshark (voir Figure ci-dessus), j'ai isolé les trames UDP envoyées sur le port 7099. J'ai identifié la structure du paquet (Header <code>03 66</code>, Footer <code>99</code>) et les octets correspondant aux axes du joystick
 
Pour le script de contrôle j'ai tenté de reproduire une commande de décollage :
 
J'ai supposé un calcul par soustraction par rapport à la valeur neutre.<syntaxhighlight lang="c">
# SOCK_DGRAM = Protocole UDP
# SOCK_DGRAM = Protocole UDP
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Ligne 388 : Ligne 392 :
         client.sendto(cmd_stop, (IP_DRONE, PORT))
         client.sendto(cmd_stop, (IP_DRONE, PORT))
         time.sleep(0.05)
         time.sleep(0.05)
</syntaxhighlight>
</syntaxhighlight>Cette tentative n'a pas permis de faire décoller le drone. Cela nous a indiqué deux choses :
 
* le drône réagit bien aux envois de données
 
* le calcul du Checksum était incorrect (le drone rejetait les paquets)
* le décollage nécessite peut-être un bouton pour pouvoir decoller
 
==== Deuxième tentative ====

Version du 13 janvier 2026 à 16:55

Création de la machine virtuelle

xen-create-image --hostname=SE5-handrian --dhcp --bridge=bridgeStudents --dir=/usr/local/xen --size=10GB --dist=daedalus --memory=1024M

Configuration VM

# This file describes the network interfaces available on your system

# and how to activate them. For more information, see interfaces(5).

# The loopback network interface

auto lo

iface lo inet loopback

# The primary network interface

auto eth0

iface eth0 inet static

       address 172.26.145.111

       netmask 255.255.255.0

       gateway 172.26.145.251

       dns-nameservers 172.26.145.251


#VLAN411

auto eth1

iface eth1 inet static

       address 172.16.11.0

       netmask 255.255.255.0

Capbreton

#  Networking

#

dhcp        = 'dhcp'

vif         = [ 'mac=00:16:3E:1A:68:1E,bridge=bridgeStudents' ,

       'mac=00:16:3E:1A:68:1F,bridge=g3_handrian']

#

Configuration

auto Trunk.411

iface Trunk.411 inet manual

       vlan-raw-device Trunk

       up ip link set $IFACE up

       down ip link set $IFACE down

auto g3_handrian

iface g3_handrian inet manual

   bridge_ports Trunk.411

   up ip link set $IFACE up

   down ip link set $IFACE down

Sécurisation WiFi par WPA2-PSK

dot11 ssid SE5-handrian
  vlan 411
  authentication open
  authentication key-management wpa
  wpa-psk ascii 0 " "
  mbssid guest-mode
exit
interface Dot11Radio1
  encryption vlan 411 mode ciphers aes-ccm
  ssid SE5-handrian
  mbssid
  no shutdown
exit

interface Dot11Radio1.411
  encapsulation dot1Q 411
  bridge-group 11
exit

interface GigabitEthernet0.411
  encapsulation dot1Q 411
  bridge-group 11
exit

Pour vérifier : ap# sh dot11 bssid

ap#sh dot11 bssid                                                               
Interface      BSSID         Guest  SSID                                        
Dot11Radio1   04da.d2d1.4bf0  Yes  SE5-azongo                                   
Dot11Radio1   04da.d2d1.4bf1  Yes  SE5-crhanim                                  
Dot11Radio1   04da.d2d1.4bf2  Yes  SE5-handrian

Installer isc-dhcp-server dans la VM  : /etc/dhcp/dhcpd.conf

subnet 172.16.11.0 netmask 255.255.255.0 {
  range 172.16.11.100 172.16.11.200;
  option routers 172.16.11.1;
  #option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
  option domain-name-servers 172.16.11.1;
}

dans /etc/default/isc-dhcp-server : INTERFACESv4="eth1"

dans /etc/sysctl.conf : décommenter : net.ipv4.ip_forward=1

sysctl -p /etc/sysctl.conf : pour recharger configuration sysctl.

sysctl net.ipv4.ip_forward : pour vérifier

Interception de flux

Redirection par DNS

Modification du fichier /etc/bind/named.conf.local

//
// Do any local configuration here
//

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";

zone "wikipedia.org" {
        type master;
        file "/etc/bind/db.wikipedia.org";
};

Création de la zone db.wikipedia.org

$TTL    604800
@       IN      SOA     ns.wikipedia.org. admin.wikipedia.org. (
                             10         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      ns.wikipedia.org.
ns      IN      A       172.16.11.1
@       IN      A       172.16.11.1
www     IN      A       172.16.11.1

Redirection réseau

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 8080

iptables -t nat -L -n -v

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 REDIRECT   6    --  eth0   *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 redir ports 8080

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    5  1468 MASQUERADE  0    --  *      *       172.16.11.0/24       0.0.0.0/0

Serveur Apache sécurisé

Génération du certificat auto-signé Apache

openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout /etc/ssl/apache/apache-selfsigned.key \
  -out /etc/ssl/apache/apache-selfsigned.crt \
  -subj "/C=FR/ST=Nord/L=Lille/O=Polytech/CN=wikipedia.org"

Configuration Apache

<VirtualHost *:443>
    ServerName wikipedia.org

    DocumentRoot /var/www/html


    SSLEngine on
    SSLCertificateFile /etc/ssl/apache/apache-selfsigned.crt
    SSLCertificateKeyFile /etc/ssl/apache/apache-selfsigned.key

    ErrorLog ${APACHE_LOG_DIR}/site-error.log
    CustomLog ${APACHE_LOG_DIR}/site-access.log combined

</VirtualHost>

<VirtualHost *:80>
    ServerName wikipedia.org
    Redirect permanent / https://wikipedia.org/
</VirtualHost>

Pour activer

a2ensite site-se5.conf
service apache2 reload

Pour véridier l'écoute du port 443

# ss -tulpn | grep 443
tcp   LISTEN 0      128                *:443             *:*    users:(("apache2",pid=5394,fd=6),("apache2",pid=5393,fd=6),("apache2",pid=5390,fd=6))

Machine virtuelle android

Installation de la machine virtuelle Android

1ère tentative avec QEMU : Création disque

qemu-img create -f qcow2 android.qcow2 16G
Formatting 'android.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=17179869184 lazy_refcounts=off refcount_bits=16
Installation de l'android
qemu-system-x86_64 \
  -m 4096 \
  -smp 4 \
  -enable-kvm \
  -drive file=android.qcow2,format=qcow2 \
  -cdrom ~/Downloads/android-x86-9.0-r2.iso \
  -boot d \
  -net nic -net user

Pour lancer l'android :

qemu-system-x86_64   -m 4096   -smp 4   -enable-kvm   -drive file=android.qcow2,format=qcow2 -net nic -net user

2ème tentative avec Android Studio

Installation d’Android Studio

J'ai installé Android Studio à partir du site officiel de Google.

Après l’installation, les composants suivants ont été installés via le SDK Manager :

  • Android SDK Platform
  • Android SDK Platform-Tools
  • Android Emulator

L’installation du SDK s’est déroulée sans erreur particulière

Puis la création de l'AVD :

  • Modèle : Pixel 6 Pro
  • Version : API 31 Android 12
  • Architecture : x86_64

Mise en place du certificat

Première tentative avec les commandes suivantes :

adb root
adb shell avbctl disable-verification
adb reboot
adb wait-for-device root
adb remount
adb push 500e3c27.0 /system/etc/security/cacerts
adb shell chmod 664 /system/etc/security/cacerts/500e3c27.0
adb reboot

Problèmes rencontrés

Accès root et système en lecture seule

Même lorsque l’accès ADB était fonctionnel, l’accès root était souvent limité. Les partitions système étaient en lecture seule et les tentatives de remount (adb remount) ou de modification du système échouaient.

Résolutions

Démarrage de l'émulateur en Cold Boot avec la commande :

emulator -avd Pixel_6_Pro -writable-system -no-snapshot-load

Puis,

adb root
adb disable-verity
adb reboot
adb root
adb remount
adb push 500e3c27.0 /system/etc/security/cacerts/
adb shell chmod 664 /system/etc/security/cacerts/500e3c27.0
adb reboot

L'installation du certificat a été réalisée avec succès. Mais j'ai finalement laissé l'approche par machine virtuelle car le drone agit comme un point d'accès Wi-Fi donc privilégié l'analyse du trafic réel. J'ai utilisé mon téléphone pour envoyer les commandes de pilotage et l'ordinateur avec le Wipi et Wireshark pour intercepter et capturer les échanges de paquets entre le téléphone et le drone afin de repérer les octets de directions

Drone

Utilisation de la carte Wipi

airmon-ng start wlx40a5efd21166
airodump-ng -c 1 wlan0mon

40:07:76:C0:20:23  -39        4        0    0   1   65   OPN              WIFI_UFO_2320c0

iwconfig wlan0mon channel 1
wireshark

Ici, j'ai mis un filtre pour intercepter les paquets du drône :

wlan.addr == 40:07:76:C0:20:23 && wlan.fc.type == 2 && udp.port == 7099
  • ne garde que les donnée (Data)
  • ne garde que ce qui passe par commandes
Wireshark.png

Avec le filtre wlan.addr == 40:07:76:C0:20:23 && wlan.fc.type == 2 && udp.port == 7099 Il y a le flux unidirectionnel émis par le smartphone (192.168.1.100) vers le drone (192.168.1.1). Les paquets capturés d'une longueur de 9 octets correspondent aux instructions de vol envoyées.

Sur la trame sélectionnée (03 66 80 80 ba 80 00 3a 99) on peut identifier l'en-tête fixe (03 66), les axes au neutre (0x80), et la modification du 4 ème octet (0xC0) qui correspond l'instruction 'décoller'

Connexion Zabeth-Drone

Configuration wifi :

iface wlan1 inet static
  wireless-essid WIFI_UFO_2320c0
  address 192.168.1.101/24

Vérification : iwconfig

wlan1     IEEE 802.11  ESSID:"WIFI_UFO_2320c0"  
          Mode:Managed  Frequency:2.412 GHz  Access Point: 40:07:76:C0:20:23   
          Bit Rate=26 Mb/s   Tx-Power=22 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:on
          Link Quality=63/70  Signal level=-47 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:28   Missed beacon:0

ping 192.168.1.1

64 bytes from 192.168.1.1: icmp_seq=1 ttl=255 time=8.50 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=255 time=9.05 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=255 time=3.33 ms

Tentatives de control du drône

Première tentative

À partir des captures Wireshark (voir Figure ci-dessus), j'ai isolé les trames UDP envoyées sur le port 7099. J'ai identifié la structure du paquet (Header 03 66, Footer 99) et les octets correspondant aux axes du joystick

Pour le script de contrôle j'ai tenté de reproduire une commande de décollage :

J'ai supposé un calcul par soustraction par rapport à la valeur neutre.

# SOCK_DGRAM = Protocole UDP
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# STOP
# Tout est à 80 Checksum à 00
# Code : 03 66 80 80 80 80 00 00 99
cmd_stop = bytes.fromhex("036680808080000099")

# decoller
# 03 66 : Header
# 80    : Joystick Gauche
# C0    : Joystick Gauche
# 80    : Joystick Droit (Avancer)
# 80    : Joystick Droit
# 00    : Boutons
# 40    : Checksum (C0 - 80 = 40)
# 99    : Fin
cmd_decollage = bytes.fromhex("036680c08080004099")

# atterissage
cmd_baisse = bytes.fromhex("036680008080008099") # Coupe tout brutalement

try:
    print("\ndemarage")

    print("decollage")
    t_end = time.time() + 3
    while time.time() < t_end:
        client.sendto(cmd_decollage, (IP_DRONE, PORT))
        time.sleep(0.05) # 20fois/s

    # arret
    print("stop")
    for i in range(20):
        client.sendto(cmd_stop, (IP_DRONE, PORT))
        time.sleep(0.05)

Cette tentative n'a pas permis de faire décoller le drone. Cela nous a indiqué deux choses :

  • le drône réagit bien aux envois de données
  • le calcul du Checksum était incorrect (le drone rejetait les paquets)
  • le décollage nécessite peut-être un bouton pour pouvoir decoller

Deuxième tentative