News VP8-Videokodierung: Zero-Day-Schwachstelle betrifft weit mehr als nur Chrome

coffee4free

Redakteur
Teammitglied
Registriert
Okt. 2015
Beiträge
269
  • Gefällt mir
Reaktionen: BrollyLSSJ, Trent, iron_monkey und 4 andere
wie funktioniert das eigentlich technisch, mit diesen pufferüberläufen? als Laie verstehe ich das nur so: da liegen jetzt Daten, wo eigentlich keine oder andere Daten im Speicher sein sollten. blöd gelaufen, aber was macht das jetzt gefährlich? bloß weil irgendwo ne binary liegt - und sei sie auch noch so schädlich - heißt das ja noch lange nicht, dass sie auch ausgeführt wird, was ja irgendwie Voraussetzung ist, um schaden anzurichten. danke!
 
Easy, du schreibst ja keine Datei, sondern in den Arbeitsspeicher, dort liegen Daten UND Code. Machst du es richtig, trickst du das Programm dazu, etwas zu machen. Zum Beispiel an eine andere Stelle zu springen. Es reicht da halt oft, dass du eine Funktion des OS aufrufen kannst und ein Register auf die richtige Speicheradresse zeigt (exec, oder system z.B.).

BTT: Google und die Codequalität, wird Google das MS von 2000?
 
  • Gefällt mir
Reaktionen: mylight, hans_meiser und Mickey Cohen
Mickey Cohen schrieb:
wie funktioniert das eigentlich technisch, mit diesen pufferüberläufen?
Normalerweise liegen Daten und Code in unterschiedlichen Speicherbereichen, aber durchaus dicht bei einander. Bei einem Pufferüberlauf sind die Daten (z.B. eine Grafik die geladen wird) zu groß für den dafür vorgesehenen Speicherbereich und überschreiben den "dahinter" liegenden Speicher.
Wenn der überschriebene Speicherbereich nun gerade Code enthält, kann mit entsprechend präparierten Daten also fremder Code in den überschriebenen Bereich eingeschleust und dann anstelle des ursprünglichen Codes ausgeführt werden.

Manchmal wird so ein verwundbarer Speicherbereich nicht immer ausgeführt sondern nur unter gewissen Bedingungen (könnte sich z.B. um eine Druckfunktion handeln). In dem Beispiel müsste ein Angreifer außer dem Einschleusen das Codes also auch noch dafür sorgen, dass die Druckfunktion aktiviert wird. Es gibt inzwischen aber etliche Angriffstechniken, die das Ausführen von eingeschleustem Code auch unter erschwerten Bedingungen erzwingen.
 
  • Gefällt mir
Reaktionen: flo.murr, Mut4nt, up.whatever und 3 andere
Wenn ich richtig informiert bin, sind Bibliotheken in unixoiden Betriebssystemen in der Regel als shared library eingebunden. Das heißt, einmal diese shared library patchen und alle Programme die darauf zugreifen sind abgesichert.

Nur unter Windows, wo quasi jedes Programm seine eigene Suppe kocht und einmal eine shared library existiert, einmal die Bibliothek im Programmordner extern liegt und ein andermal sie in die binary integriert ist, ist die Fehlerbehebung so komplex und jedes Programm muss einzeln gepatcht werden.
 
  • Gefällt mir
Reaktionen: Snudl, SirSinclair, netzgestaltung und 3 andere
MarS81 schrieb:
Wenn ich richtig informiert bin, sind Bibliotheken in unixoiden Betriebssystemen in der Regel als shared library eingebunden. Das heißt, einmal diese shared library patchen und alle Programme die darauf zugreifen sind abgesichert.
Ja genau, ein weiterer riesen Vorteil von Linux :)
Es gibt aber auch Ausnahmen, Docker images enthalten alle librarys die für die Anwendung gebraucht werden, da muss dann das image gepatcht werden.


Für Arch gibt es schon die gepatchte libvpx:

https://gitlab.archlinux.org/archli...90298a52d11de6e7ca3855ced/CVE-2023-5217.patch
 
  • Gefällt mir
Reaktionen: masterw und iron_monkey
Da Sicherheitsproblem: Pufferüberlauf Fehler schon seit gefühlt Win95 bestehen. Frage ich mich wieso Programmierer ihre Programme so schlecht darauf Prüfen.
 
Idealerweise muss sich der Entwickler nicht darum kümmern, weil ihn Sprache/Kompiler/statische Codeanalyse davor bewahrt. Menschen machen Fehler.
 
wern001 schrieb:
Da Sicherheitsproblem: Pufferüberlauf Fehler schon seit gefühlt Win95 bestehen. Frage ich mich wieso Programmierer ihre Programme so schlecht darauf Prüfen.
Die bestehen seit Anbeginn der Programmierung. Darauf prüfen kann man nicht, weil man dazu wissen müsste, wie groß die Daten sind, die man von a nach b kopiert und das ist eben nicht immer der Fall. Darum gibt es eben bestimmte Bereiche im Executable-Format, die sicherstellen sollten, dass der Code eben nicht überschrieben wird. Eine von vielen verschiedenen Maßnahmen das Problem zu lösen.

Es gab seit dem natürlich Verbesserungen, z. B. die Einführung von Bibliotheken, so dass man nicht alles mittels Assembler selbst programmieren musste, sondern auf fertige Funktionen zurückgreifen konnte. Das gilt auch für höhere Programmiersprachen.

So wurde aus einem simplen strcpy (String Copy) eben strncpy: Bei der Kompilierung weiß der Compiler, wie lang die Strings sind und auch bei der Ausführung von Code konnte man die "bekannten", variablen Strings vorher deren Länge ermitteln und dann auch nur diese Länge kopieren. Vorher dachte man, dass das nicht nötig sei, weil z. B. in C(++) Strings mittels 0x00 terminiert wurden und das als Ende des "korrekten" Strings erachtet wurde. Dieser Mechanismus anhand der Länge ist aber offensichtlich nicht immer anwendbar, z. B. weil die Daten komprimiert sind und die finale Länge nicht bekannt ist (vermute ich mal). Wäre interessant zu wissen, ob besser abgesicherte Funktionen benutzt wurden oder ob da eben "vergessen" wurde, dass man diese benutzen kann oder ob sie gar absichtlich weggelassen wurden, da sie eben auch ein Stück langsamer sind als die "ungeschützten" Funktionen.

Früher wurde das übrigens auch für Kopierschutzmechanismen verwendet, siehe

Fun fact: Bei Spielen mit Texteingaben aus dem Handbuch konnte man sich das Terminierungsbyte zunutze machen: Wurde nichts eingegeben ist der String leer, also kann man in der Exe die einzugebenden Worte mit 0x00 überschreiben und dann wurde nichts mit nichts verglichen (strcmp) und man konnte noch den anzuzeigenden Text ändern (z. B. in "Press enter to continue") und schon war der Kopierschutz ausgehebelt. Funktioniert natürlich nur, wenn keine Prüfsummen das verhindern oder wenn der Text nicht "verschlüsselt" in der Binary war.
 
  • Gefällt mir
Reaktionen: >/cat/proc
Sowas fängt doch die Programmiersprache Rust komplett ab, oder nicht?
Manchmal muss man auch auf unsecure umschalten weil sonst nicht alles umsetzbar ist (redox os) aber explizieter gehts nicht.
Das sowas noch immer in C geschrieben wird liegt denk ich am Stolz einiger Entwicker
 
@###Zaunpfahl### Größtenteils fängt Rust so etwas ab. Aber Sicherheit kostet mitunter auch etwas, z.B. Performance. Alles an Prüfungen drumherum kostet. Und wenn der Kunde die Wahl hat, ein größeres langsameres oder ein kleineres schnelleres zu erhalten, ist der Reiz groß, das schnellere zu nehmen.

Es hat also mitunter gute Gründe, noch auf C zu setzen.

Dazu kommt natürlich auch, dass Entwickler evtl. schon vor 20 Jahren ihren Beruf ergriffen haben und sich seit 20 Jahren intensiv in C eingearbeitet haben. Wenn man nun die Wahl hat, schnell für wenig Geld ein C-Projekt umzusetzen oder viel Länger und mit weniger Personal das Ganze in Rust... ich mein ja nur.

Da aber Performance mitunter keine direkte Rolle spielt, z.B. weil für einen Anwendungszweck davon zu Genüge vorhanden ist oder einfach Sicherheit wichtiger ist als Performance, kann man sehr wohl auch die sicherere Variante vorziehen. Gerade im Falle interner Betriebssystemfunktionen oder z.B. Browser würde ich schon sagen, dass Sicherheit eine große Rolle spielt. Daher finde ich Projekte wie Redox OS sehr interessant. Mal sehen, ob das was ernstzunehmendes wird. :)
 
Mickey Cohen schrieb:
wie funktioniert das eigentlich technisch, mit diesen pufferüberläufen? als Laie verstehe ich das nur so: da liegen jetzt Daten, wo eigentlich keine oder andere Daten im Speicher sein sollten. blöd gelaufen, aber was macht das jetzt gefährlich? bloß weil irgendwo ne binary liegt - und sei sie auch noch so schädlich - heißt das ja noch lange nicht, dass sie auch ausgeführt wird, was ja irgendwie Voraussetzung ist, um schaden anzurichten. danke!
Beim jedem Funktionsaufruf speichert die CPU im Stack ab, wo sie im Code ist, um dann später dahin zurückzuspringen. Die Idee ist, die Adresse zu ändern, damit die CPU beim nächsten return zum eigenen Code springt. Stack buffer overflow is damit eigentlich schon erklärt.

Hier beim heap buffer overflow geht es genauso darum, den Stack zu manipulieren. Dafür werden die Eigenheiten von malloc und free ausgenutzt. malloc ist kein syscall sondern das Programm selbst verwaltet den Speicher. Wenn das Programm zum ersten Mal Speicher anfordert wird per syscall gleich ein größerer Block vom OS angefragt. Bei weiteren mallocs schaut das Programm, ob im Block noch Platz ist, um sich den syscall zu sparen. So ein Block ist dann im Grunde eine doubly linked list, also jedes Element hat pointer zu Vorgänger BK und Nachfolder FD. Die Metadaten liegen dann direkt vor dem Pointer, den man von malloc zurückbekommt. Der klassische heap buffer overflow nutzt das Verhalten von free aus. Angenommen wir haben drei Elemente A<->B<->C im Block und B soll gelöscht werden. Es sollen also A->FD und C->BK angepasst werden, damit sie nicht mehr auf B zeigen sondern direkt auf C bzw. A. Das Programm läuft erstmal zu B und schaut sich B->BK und B->FD an. FD ist der Nachfolger, sollte also C entsprechen. Nach dem Löschen von B soll C direkt auf A zeigen, d.h. free führt aus: B->FD->BK = B->BK. Der Angreifer hat volle Kontrolle über B inklusive B->FD und B->BK und setzt also vorher FD auf den richtigen Ort im Stack und BK auf den Start des eigenen Codes. free ist dann so freundlich, den Stack zu ändern. Danach ist es dasselbe wie beim stack buffer overflow. Beim nächsten return springt die CPU zum eigenen Code. Gibt mittlerweile natürlich Schutzmechanismen, aber die Grundidee hat sich nicht geändert.
 
  • Gefällt mir
Reaktionen: Snudl, pvcf, RedSlusher und 2 andere
dev/random schrieb:
Normalerweise liegen Daten und Code in unterschiedlichen Speicherbereichen, aber durchaus dicht bei einander. Bei einem Pufferüberlauf sind die Daten (z.B. eine Grafik die geladen wird) zu groß für den dafür vorgesehenen Speicherbereich und überschreiben den "dahinter" liegenden Speicher.
Code wird heute in der Regel nicht mehr überschrieben, der ist normalerweise auch gegen Überschreiben geschützt. Ebenso sind Datenbereiche dagegen geschützt als Code ausgeführt zu werden. Das Problem ist in der Regel der Stack, da liegen die lokalen Variablen zusammen mit den Return Adressen, außerdem oft auch noch Funktionspointer. Die lassen sich leicht mit Pufferüberläufen überschreiben. Man injiziert also nicht direkt Code, sondern ändert den Kontrollfluss des Programmes so, das der existierende Programmcode etwas anderes tut, als er normalerweise tun würde. Da alle Shared Libraries eines Prozesses im Adressraum verfügbar sind, ist man nicht auf den Code der Library mit der Verwundbarkeit beschränkt.
MarS81 schrieb:
Wenn ich richtig informiert bin, sind Bibliotheken in unixoiden Betriebssystemen in der Regel als shared library eingebunden. Das heißt, einmal diese shared library patchen und alle Programme die darauf zugreifen sind abgesichert.
Das ist oft so, aber es gibt auch viele Programme, die Bibliotheken statisch einbinden. Das gilt besonders für Software die nicht im Repo der Distribution ausgeliefert wird, sondern z.B. als deb/rpm „Datei“ verteilt wird. Also z.B. Chrome oder auch “kommerzielle“ Linux Software.
Dann gibt es ja zunehmend Package Manager wird Snap die eben „Self Contained“ Binaries mit allen Libraries enthalten. Und dann eben Docker Images, usw.


DarkSoul schrieb:
Wäre interessant zu wissen, ob besser abgesicherte Funktionen benutzt wurden oder ob da eben "vergessen" wurde, dass man diese benutzen kann oder ob sie gar absichtlich weggelassen wurden, da sie eben auch ein Stück langsamer sind als die "ungeschützten" Funktionen.
Es gibt halt ein bisschen mehr auf der Welt als Strings und die Standard C Library bietet jenseits von Strings nicht viel an. Bei den genannten Libraries geht es ja um Basisbibliotheken die z.B. das WebP Datenformat überhaupt erst implementieren. Und die müssen dabei „Low-Level“ Operationen auf dynamischen Speicherstrukturen implementieren. Dabei kann auch ein geübter Entwickler schlicht Fehler machen und auch die Test-Coverage kann Lücken enthalten, die diese Fehler nicht entdecken.

###Zaunpfahl### schrieb:
Das sowas noch immer in C geschrieben wird liegt denk ich am Stolz einiger Entwicker
Naja, die Code Basis in C ist halt so extrem riesig, das alles in Rust neu zu schreiben würde Jahrzehnte dauern.

Softwareentwicklung funktioniert ja in der Regel so, das vielleicht 10-20% des Codes Eigenentwicklung sind, der Rest ist eingebundener Third-Party Code. Das ist auch gut so, denn wenn z.B. Jeder wieder seine eigene SSL Library bauen würde, wäre die Qualität mit Sicherheit schlechter.

Außerdem sorgt die Verwendung von Rust nicht automatisch für sicheren Code. Gerade wenn man Low-Level Blbiotheken implementiert, die z.B. direkt mit dem Speicherlayout von Datenstrukturen hantieren, kann man die gleichen Fehler wie in C machen.
Hier ist ein ganz guter Artikel dazu, warum man für „Real-World“ Anwendungen Unsafe Rust braucht und wie man damit umgeht.
https://rustmagazine.org/issue-3/understand-unsafe-rust/

Der Artikel bringt es ganz gut auf den Punkt:
Die „Welt“ ist unsicher, und unsafe Rust Code wird benutzt die Brücke zur unsicheren Welt zu bauen.
Und beim Bau dieser Brücken kann man Fehler machen.
 
Zuletzt bearbeitet:
metoer schrieb:
Es gibt aber auch Ausnahmen, Docker images enthalten alle librarys die für die Anwendung gebraucht werden, da muss dann das image gepatcht werden.
Nicht nur Docker, auch appimage, flatpak, snap und alles was mit Emulation zu tun hat...
Wenn sich Anwendungen nicht in die Distribution integrieren und eigene Umgebungen schaffen, gehen genau diese Vorteile wieder verloren.

Auf meinem aktuellen System finde ich zum Beispiel 4 libvpx aus arch Paketen (2 Versionen in je 64 und 32 bit), aber auch 6 weitere libvpx Bibliotheken in der Steam runtime (~/.local/share/Steam) und 2 weitere in der Lutris runtime (~/.local/share/lutris). Die können von arch nicht gepatcht werden. Und bis Steam und Lutris reagieren dauert es sicherlich deutlich länger.
 
  • Gefällt mir
Reaktionen: metoer, netzgestaltung und TomH22
TomH22 schrieb:
Bei den genannten Libraries geht es ja um Basisbibliotheken die z.B. das WebP Datenformat überhaupt erst implementieren. Und die müssen dabei „Low-Level“ Operationen auf dynamischen Speicherstrukturen implementieren. Dabei kann auch ein geübter Entwickler schlicht Fehler machen und auch die Test-Coverage kann Lücken enthalten, die diese Fehler nicht entdecken.
Ich hatte das auch nicht auf Strings beschränkt. ;) Auch Low-Level-Code wird nicht komplett neu geschrieben, da greift man genauso auf Bibliotheken/Sniplets/etc zurück, die dann fest eingebunden werden um es einfach auszudrücken. Eigentlich sollten solche Fehler bei Prüfungen mittlerweile auffallen, dachte ich.
 
DarkSoul schrieb:
Auch Low-Level-Code wird nicht komplett neu geschrieben, da greift man genauso auf Bibliotheken/Sniplets/etc zurück, die dann fest eingebunden werden um es einfach auszudrücken.
Ich kann als erfahrener C-Programmierer mit dieser Aussage nichts anfangen. Kannst Du mal ein konkretes Beispiel nennen? Zu mal "Sniplets" was ganz anderes sind als "Bibliotheken".
Also wenn ich irgendein Binärformat (de)kodieren will, dann definiere ich mir eine Reihe von structs, die die Speicherlayout dieses Formats beschreiben, oft haben solche Formate auch Varianten, die ich z.B. mit einer union darstelle. Alternativ arbeite ich mit Pointer-Arithmetik und irgendwelchen Offsets. In der Praxis ist meist eine Mischung daraus. Was würdest Du anders machen?
DarkSoul schrieb:
Eigentlich sollten solche Fehler bei Prüfungen mittlerweile auffallen, dachte ich.
Welche Prüfungen? In Realität wird längst nicht jeder Code einem intensiven Review unterzogen, und selbst wenn es ein Review gibt, ist es nicht sicher, das es jeden Fehler findet.
Es gibt sehr Open Source Code der ursprünglich mal von einem Entwickler geschrieben wurde (QUEMU z.B. oder lwIP, der verbreitete Emebedded TCP/IP Stack). Wenn die Projekte größer werden, gibt es dann irgendein "Project Team", d.h. ein lockerer Verbund von Entwicklern die dazu beitragen. Je nach Projekt gibt es Geld von Stiftungen wie der Linux Foundation oder auch direkt von Firmen.
Aber das ist nicht immer konstant, sodass die Projekte nicht unbedingt durchgehend personell und finanziell gut ausgestattet sind.

Beispiel Heartbleed :
https://de.wikipedia.org/wiki/Heartbleed

Zitat aus dem Wikipedia Artikel:
Der Quellcode, der den Fehler aufweist, wurde am 31. Dezember 2011 von dem einzigen fest angestellten Mitarbeiter des OpenSSL-Teams aus dem Entwurfszweig in das OpenSSL-Git-Repository eingepflegt und erstmals am 14. März 2012 mit OpenSSL-Version 1.0.1 veröffentlicht. Der Code wurde zuvor von einem Studenten der Fachhochschule Münster und der Universität Duisburg-Essen im Rahmen der Vorarbeiten zu seiner Dissertation über das SCTP-Protokoll entwickelt und als Entwurf bei OpenSSL eingereicht

OpenSSL wird seitdem zwar besser überprüft, trotzdem gab es 2022 wieder eine Lücke:
https://www.heise.de/news/Jetzt-akt...durch-Luecke-in-OpenSSL-moeglich-7163675.html

Und ich habe nicht den Eindruck, dass die Probleme weniger werden, wenn ich die Menge an Security Hinweisen unseres Firmen CERT Teams so ansehe.
 
Wenn C oder eine andere Sprache solche Fehler erlauben zu programmieren läuft irgendwas falsch.
Und wenn dann die Hardware auch noch nen Bug hat bist wahrscheinlich eh der Gelackmeierte.

Ich denke bald ist es aber eh soweit dass man auch KIs hat um all das umgehen zu können.

Vielleicht sollte man sich auch anderen Architekturen als Von-Neumann öffnen.
 
Zuletzt bearbeitet:
wern001 schrieb:
Da Sicherheitsproblem: Pufferüberlauf Fehler schon seit gefühlt Win95 bestehen.
Das gibt's mindestens, seitdem es Multitasking-Betriebssysteme gibt. Also mindestens seit Unix (1969).


wern001 schrieb:
Frage ich mich wieso Programmierer ihre Programme so schlecht darauf Prüfen.
Weil das Problem alles andere als trivial ist. Was meinst du, warum man sich an neuen Konzepten/Sprachen wie Rust versucht?
 
Zurück
Oben