EUVD unter Rust nutzen

Bedingt durch die Kürzungen der US-Regierung, war es in den letzten Wochen durchaus denkbar, dass die CVE-Liste, mangels monetärer Mittel, ihre Arbeit hätte einstellen müssen. Das veranlasste die Agentur der Europäischen Union für Cybersicherheit (ENISA), ihre eigene Schwachstellen-Datenbank, die European Vulnerability Database (EUVD), früher vorzustellen. Neben der offiziellen Seite, wird auch eine API bereitgestellt.

Das Webinterface der EUVD

Mehrere spezialisierte Endpunkte stehen innerhalb der API zur Verfügung: /api/lastvulnerabilities, /api/exploitedvulnerabilities und /api/criticalvulnerabilities liefern jeweils bis zu acht aktuelle Einträge. Über /api/vulnerabilities lassen sich Schwachstellen detailliert nach Kriterien wie Score, EPSS-Wert, Veröffentlichungszeitraum, Hersteller oder Produktname filtern. Weitere Routen ermöglichen den Zugriff auf konkrete Einträge per ENISA-ID oder geben zugehörige Advisories aus.

Die erstellte OpenAPI-Spezifikation

Die Dokumentation der API ist allerdings eher rudimentär und nicht wirklich strukturiert gehalten, so werden z.B. die Response-Objekte nirgendwo definiert. Da ich die API in Rust nutzen wollte, führte dies zur Entwicklung des Crates euvd. Passend dazu habe ich eine OpenAPI-Spezifikation erstellt, welche die API möglichst vollumfänglich abbildet. Damit können auch Clients abseits von Rust für die EUVD-API erzeugt werden.

Der Content-Type ist text/plain

Die API selbst enthält noch einige Merkwürdigkeiten bzw. Inkonsistenzen. Dies fängt damit an, das JSON-Objekte zurückgegeben werden:

{
    "id": "cisco-sa-ata19x-multi-RDTEqRsy",
    "description": "Cisco ATA 190 Series Analog Telephone Adapter Firmware Vulnerabilities",
    "summary": "Multiple vulnerabilities in Cisco ATA 190 Series Analog Telephone Adapter firmware, both on-premises and multiplatform, could allow a remote attacker to delete or change the configuration, execute commands as the root user, conduct a cross-site scripting (XSS) attack against a user of the interface, view passwords, conduct a cross-site request forgery (CSRF) attack, or reboot the device.\r\n\r\nFor more information about these vulnerabilities, see the Details [\"#details\"] section of this advisory.\r\n\r\nCisco has released firmware updates that address these vulnerabilities. There are no workarounds that address these vulnerabilities. However, there is a mitigation that addresses some of these vulnerabilities for Cisco ATA 191 on-premises firmware only.\r\n\r\n",
    "datePublished": "Oct 16, 2024, 4:00:00 PM",
    ...
}

Der Content-Type seitens der API wird allerdings als text/plain;charset=UTF-8 definiert und entsprechend zurückgegeben. Dies führte unter anderem bei der Client-Generation zu Problemen, da der Text nicht standardmäßig in die bereitgestellten JSON-Objekte konvertiert wurde.

In den API-Objekten selbst wird mit Camel case gearbeitet, allerdings existieren aus Ausnahmen, wie die enisa_id, welche als Snake case geschrieben wird und die API an einigen Stellen etwas inkonsistent wirken lässt.

"enisa_id": "EUVD-2024-45012\n",
"assigner": "mitre",
"epss": 0.05,
"enisaIdProduct": [
...

An anderen Punkten wird wieder die Schreibweise in Camel case genutzt, wie z.B. beim enisaIdProduct-Feld. Auch eine Versionierung ist nicht zu erkennen, was die Frage nach dem genauen Updateprocedere der API aufwirft.

In Bezug auf digitale Souveränität fällt zudem auf, dass die API bei Azure gehostet wird, wie ein whois zeigt:

% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

refer:        whois.arin.net

inetnum:      20.0.0.0 - 20.255.255.255
organisation: Administered by ARIN
status:       LEGACY

whois:        whois.arin.net

changed:      1994-10
source:       IANA

# whois.arin.net

NetRange:       20.33.0.0 - 20.128.255.255
CIDR:           20.64.0.0/10, 20.128.0.0/16, 20.40.0.0/13, 20.34.0.0/15, 20.36.0.0/14, 20.33.0.0/16, 20.48.0.0/12
NetName:        MSFT
NetHandle:      NET-20-33-0-0-1
Parent:         NET20 (NET-20-0-0-0-0)
NetType:        Direct Allocation
OriginAS:       
Organization:   Microsoft Corporation (MSFT)
RegDate:        2017-10-18
Updated:        2021-12-14
Ref:            https://rdap.arin.net/registry/ip/20.33.0.0

Dies lässt strategische Autonomie vermissen, wenn solche Dienste auf einer Infrastruktur betrieben werden, welche unter ausländischer Rechtshoheit steht.

Um die API bzw. den Client in Rust zu nutzen, muss im ersten Schritt das Crate ins eigene Projekt eingebunden werden:

cargo add euvd

Anschließend können die einzelnen Ressourcen aufgerufen werden:

use euvd::apis::configuration::Configuration;
use euvd::apis::default_api;

async fn get_last_vulnerabilities() {

    // Preparation
    let config = Configuration::default();
    let result = default_api::get_last_vulnerabilities(&config).await;

    // Print result if successful
    if let Ok(response) = &result {
        println!("Response received:");
        for vuln in response {
            println!("• ID: {:?}, Description: {:?}", vuln.id, vuln.description);
        }
    }

    // Asserts
    assert!(result.is_ok(), "API call failed: {:?}", result.err());
}

Weitere Beispiele zur Nutzung der API finden sich im Integrationstest. Der Client ist unter MIT- und Apache-Lizenz lizenziert und auf GitHub und crates.io zu finden.

Shelly Plug S mit HomeKit-Unterstützung nachrüsten

Der Shelly Plug S unterstützt, wie andere Shelly-Geräte, von sich aus kein HomeKit. Allerdings existiert eine alternative Firmware, über welche diese Unterstützung nachgerüstet werden kann.

Der Shelly Plug S

Zur Installation muss ermittelt werden, unter welcher IP-Adresse der Shelly Plug S erreichbar ist. Diese wird im Browser aufgerufen und anschließend sollte ein Update durchgeführt werden.

Die Firmware sollte auf die aktuelle Version geflasht werden

Ist dies geschehen, kann die Installation der alternativen Firmware durchgeführt werden. Dazu wird die IP-Adresse des Shelly Plug S mit einem neuen Parameter aufgerufen:

http://192.168.1.42/ota?url=http://rojer.me/files/shelly/shelly-homekit-ShellyPlugS.zip

Es wird anschließend ein JSON ausgegeben:

{„status“:“updating“,“has_update“:false,“new_version“:“20230913-113421/v1.14.0-gcb84623″,“old_version“:“20230913-113421/v1.14.0-gcb84623″,“beta_version“:“20231107-164219/v1.14.1-rc1-g0617c15″}

Nach etwa einer bis zwei Minuten ist das Firmware-Update komplett und eine neue Oberfläche erscheint, beim Aufruf der IP-Adresse im Browser.

Die neue Oberfläche

Mit der neuen Firmware kann der Shelly Plug S als HomeKit-Gerät eingebunden werden. Dazu muss der Setup-Button in der Weboberfläche aktiviert werden. Anschließend kann das Gerät über die Home-App unter iOS hinzugefügt werden. Es ist auch möglich, die Factory-Firmware wieder aufzuspielen, sodass der Shelly Plug S wieder wie gewöhnlich genutzt werden kann.

JSON mit Schlüsselwörtern unter Java deserialisieren

Mittels GSON von Google, können JSONs unter Java einfach in Objekte deserialisiert werden. Allerdings können bestimmte JSON-Objekte zu Problemen führen. So zum Beispiel folgende JSON-Datei:

{
   "default":"ABC",
   "value":"DEF"
}

Das entsprechende Java-Objekt könnte in diesem Fall wie folgt aussehen:

class Data {

  public String default;
  public String value;
}

Damit wäre GSON in der Lage die entsprechenden Felder aus dem JSON, den Felder in der Klasse zuzuordnen. Allerdings kann obige Klasse nicht kompiliert werden. Hintergrund hierfür ist das Feld default. Unter Java ist dies ein Schlüsselwort und kann somit nicht als Feldname genutzt werden. Unter Sprachen wie C# könnte hier mit einer Verbatim-Zeichenkette gearbeitet werden:

public String @default;

Allerdings bietet Java diese Möglichkeit nicht an, sodass sich hier anders beholfen werden muss. Die Lösung ist die Annotation SerializedName. Diese gibt den Namen des Schlüssels im JSON an, welcher in das entsprechende Feld deserialisiert werden soll:

class Data {

  @SerializedName("default")
  public String defaultValue;
  public String value;
}

Damit kann GSON die Serialisierung wieder vornehmen und das obige JSON kann in eine entsprechende Java-Struktur abgebildet werden.

Discord-Channels exportieren

Zum Export eines Discord-Channels war ich auf der Suche nach einer Möglichkeit den Text und eingebettete Medien zu exportieren. Fündig wurde ich beim DiscordChatExporter. Mithilfe dieses Werkzeuges können Channels als HTML-, Text-, CSV- oder JSON-Datei exportiert werden. Für Windows steht eine Version mit grafischer Oberfläche zur Verfügung. Nutzer welche den DiscordChatExporter unter Linux oder macOS betreiben möchten, können die Version für die Kommandozeile nutzen.

Der DiscordChatExporter unter Windows

Der Quelltext des Projektes ist auf GitHub zu finden. Dort sind die ebenfalls die aktuellen Releases zu finden. Lizenziert ist der DiscordChatExporter unter der GPL in Version 3 und damit freie Software.

JSON-Validator und Formatierer

Der JavaScript Object Notation, kurz JSON, sind viele Entwickler sicherlich schon einmal über den Weg gelaufen. Bei der Arbeit mit JSON-Daten tritt ab und an der Fall auf das Daten für einen Test validiert oder sinnvoll formatiert werden sollen.

Der JSON Formatter & Validator von Curious Concept

Im Web existieren unterschiedlichste JSON-Validatoren und Formatierer, allerdings mit eher schwankender Qualität. Einer der Validatoren, welcher heraussticht ist der JSON Formatter & Validator von Curious Concept. Er kann JSON-Daten nach den unterschiedlichsten Standards (RFC 8259, RFC 7159, RFC 4627 und ECMA-404) validieren und anhand unterschiedlichster Templates formatieren. Zu finden ist der Validator unter jsonformatter.curiousconcept.com.