Autor Beitrag
mczero
Hält's aus hier
Beiträge: 1

Windows, von Zeit zu Zeit mal Linux Mint
Delphi 7, Lazarus
BeitragVerfasst: Fr 20.08.10 11:14 
Hallo!

Ich bin neu hier und möchte mich kurz vorstellen bevor ich zum Thema komme..
Ich bin nun seit ca. 2 Monaten dabei, mir Delphi anzueignen, da ich es beruflich einsetzen werde. Zurzeit bin ich noch weit davon entfernt, ein echter Delphi-Profi zu sein, aber ich denke ich bin auf einem guten Weg. Zuvor hatte ich Kontakt mit C, PHP und JAVA. Allerdings stehe ich erst am Anfang meiner Laufbahn, und so habe ich in keiner der Programmiersprachen jahrelange Erfahrung. Darum verzeit mir bitte allzu dumme Fragen, ich verspreche die Suche zuvor zu nutzen bevor Fragen auftauchen, die vllt. jemand anderes zuvor schon beantwortet hat!


Nun zum Thema:
Sicherheit ist ja ein großes Thema. Schaut man sich an, welche Patches jeden Monat durch Microsoft ins Betriebssystem einfließt, wird einem klar, wie oft Sicherheitslücken in Form von Pufferüberläufen ausgenutzt werden.

Ich denke ich habe eine ungefähre vorstellung, was das ausnutzen eines Pufferüberlaufs bedeutet: z.B. ist dort eine Variable deklariert, die einen gewissen Rahmen hat, z.b. ein ShortInt, und jemand schafft es, einen größeren Wert in eine Komponente oder ein Programm einzuschleusen, als es ein ShortInt zulässt. Somit wird der "überstehende" Bereich in einen Speicherbereich geschrieben, der eigentlich gar nicht für die Variable vorgesehen war. Wenn der überstehende Bereich nun aus Assemblercode besteht und man es schafft, den Zeiger auf diesen Bereich zu verbiegen, dann wird der Code ausgeführt.


Ich selbst habe aber kein einziges Beispiel in Form eines Delphi-Codes. Nicht einmal eine vage Vorstellung, wie sowas Codemäßig aussieht. Ich würde einfach gerne einmal ein Beispiel sehen, ein ganz simples, und möchte mich selbst ein wenig auf "guten Programmierstil" sensibilisieren, sofern das bei Pufferüberläufen möglich ist.
Das heißt: einmal ein Beispiel wo eine Lücke vorhanden ist, und ein Gegenbeispiel, wo diese Lücke geschlossen wurde.

Hat jemand vielleicht ein solches Beispiel? Ich bin gespannt.


Ansonsten wünsche ich euch allen ein schönes Wochenende!

Gruß,
Tim

Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.
Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Fr 20.08.2010 um 14:25
Moderiert von user profile iconNarses: Titel erweitert.
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 20.08.10 11:34 
Hallo und :welcome: in der Entwickler-Ecke,

Zuweisungen an ShortInt und andere einfache Typen sind kein Problem. Da kommt es dann zu einem Integerüberlauf, aber es wird kein falscher Speicher überschrieben. Das kann zwar auch doofe Auswirkungen haben, aber dürfte nicht direkt zu solchem Schweinkram führen.

Gefährlicher sind Operationen mit Arrays oder Strings, bei denen die Länge variieren kann. Ein Beispiel wäre sowas:

Du willst ein binäres Dateiformat einlesen. An einer Stelle steht ein Integer in der Datei, der die Länge des nachfolgenden Strings angibt. Laut Spezifikation des Formats darf die Länge nur 100 Zeichen sein, daher machst du sowas:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var i: integer;
    s: String[100];
// ...
fs := TFileStream.Create('c:\meinedatei.abc', fmOpenread);
fs.read(i, SizeOf(i));  // den Integer-Wert auslesen
fs.read(s[1], i);       // i Zeichen aus der Datei in den String lesen


Wenn du eine manipulierte Datei bekommst, in der der Wert für i größer ist als 100, wird dann zuviel gelesen, und dabei Speicher überschrieben. Besser wäre dann sowas:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var i: integer;
    s: String;
// ...
fs := TFileStream.Create('c:\meinedatei.abc', fmOpenread);
fs.read(i, SizeOf(i));  // den Integer-Wert auslesen
SetLength(s, i);        // den String auf die passende Länge setzen
fs.read(s[1], i);       // i Zeichen aus der Datei in den String lesen


In der Regel stürzt das Programm bei sowas einfach ab. Wie sich das genau ausnutzen lässt, um beliebigen Code auszuführen, weiß ich nicht.

_________________
We are, we were and will not be.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 20.08.10 12:17 
Zum Ausführen von beliebigen Code bedarf es ein wenig der Kenntnis der Speicherverwaltung von Programmen. Grundlegend gibt es da 3 Arten von Speicherbereichen:
1. Programmcode (read-only, executable)
2. Heap (read-write)
3. Stack (read-write)

Je nach dem, wo der Pufferüberlauf stattfindet, unterscheidet man zwischen Stack Overflows und Heap Overflows. Die Techniken, um diese auszunutzen variieren da immer ein wenig, laufen aber i.d.R. auf das Gleiche hinaus: Das Überschreiben von Rücksprungadressen.

@Gausi: Dein Code wäre nur mit extremen Heap Spraying exploitable ODER wenn Du SEHR VIELE kleine Objekte hättest. Daher nehm ich mal ein etwas anderes Beispiel.

Angenommen, du hast folgende Prozedur:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure ReadSomething(File:HFILE);
var
    I: Integer;
    Buffer: array[0..63of Char;
begin
    ReadFile(File, I, Sizeof(I));
    ReadFile(File, @Buffer[0], I);
end;


(Mal kurz bei Gausi geklaut, um sein Beispiel zu nem Stack Overflow umzubauen. Bewusst schlechter Code-Stil)

DProblem ist wie gesagt auch hier der Puffer fester Größe, der, wenn I als eine Zahl größer 64 gelesen wird, garantiert überläuft.

Nun ist die Anordnung auf dem Stack etwa folgende (Low --> High): I, Buffer, Stackframe, Return Address, Variablen, Stackframe, Return Address, ...

Wenn ich nun erraten kann, wo zu diesem Zeitpunkt der Stack Pointer ist (und damit weiß, wo Buffer anfängt), kann ich beliebigen Code in die Datei schreiben.

Nehmen wir also an, in der Datei stehen 2 KB von Duke Nukem Forever. Um diese zu starten müsste der Angreifer lediglich nach den 64 Bytes der Puffer-Länge 8 Bytes präparieren: den Stackframe (der kann ignoriert werden; kann aber auch zum Initialisieren des EBP-Registers verwendet werden) und der Start-Adresse für DNF. Statt nun zurück zum Programm zu springen findet die CPU als Rücksprung-Ziel den Start von DNF ... und zockt da erstmal ne Runde ;-)

Bei Heap Overflows würde man nicht die Rücksprung-Adressen manipulieren, sondern die Einsprung-Adressen zu Methoden. Diese liegen da z.B. als Teil der Objekt-Beschreibung im Speicher und werden durch einen Zeige auf die VMT (Virtual Method Table) einer Klasse referenziert. Überschreibt man diesen Zeiger, kann man effektiv ne eigene VMT bereitstellen und beim nächsten Aufruf einer Methode eines Objektes, wird diese neue VMT angesprungen. Das ist übrigens die Technik, die man bei PHP so gern verwendet ;-)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: Fr 20.08.10 17:36 
Hallo, ich würde eher schreiben
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var i: integer;
    s: String[100];
// ...
fs := TFileStream.Create('c:\meinedatei.abc', fmOpenread);
fs.read(i, SizeOf(i));  // den Integer-Wert auslesen
if i > 100 then i := 100;
fs.read(s[1], i);       // i Zeichen aus der Datei in den String lesen


und überhaupt einfach alles überprüfen, was von draussen kommt - Zahlen auf erlaubte Werte, aber auch Strings auf erlaubte Zeichen oder auf erlaubten Inhalt, das sind auch beliebte Angriffsmöglichkeiten, besonders in Kombination: bei Eingabe einer TCP/IP-Adresse könnte ein zu langer String eingegeben werden, der z.B. nach 192.168.178.001 noch eine Befehlssequenz enthält.

(Bei der Version mit setlength könnte man z.B. den string länger als den verfügbaren Speicher machen und so wenigstens das Programm abstürzen lassen, zumindest weiss ich nicht wieweit das zur Laufzeit abgesichert ist)

Gruss Reinhard
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Fr 20.08.10 18:32 
user profile iconReinhard Kern hat folgendes geschrieben Zum zitierten Posting springen:

(Bei der Version mit setlength könnte man z.B. den string länger als den verfügbaren Speicher machen und so wenigstens das Programm abstürzen lassen, zumindest weiss ich nicht wieweit das zur Laufzeit abgesichert ist)


Dann gibts ne OutOfMemory-Exception. Na und?
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 20.08.10 19:16 
user profile iconBoldar hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconReinhard Kern hat folgendes geschrieben Zum zitierten Posting springen:

(Bei der Version mit setlength könnte man z.B. den string länger als den verfügbaren Speicher machen und so wenigstens das Programm abstürzen lassen, zumindest weiss ich nicht wieweit das zur Laufzeit abgesichert ist)


Dann gibts ne OutOfMemory-Exception. Na und?

In C gäbt's da gar keine Exception, sondern nen Null-Pointer. Klingt erstmal Nutzlos, ist's aber nicht, wenn man weiß, dass die Null-Page unter manchen Umständen durchaus Writeable sein kann ;-) Gab's sgar schon recht witzige Bugs im Linux-Kernel deshalb ...

Und bzgl. Bei >100 einfach auf 100 reduzieren: Und damit bist du vollständig out-of-sync in dem Datenstrom und hättest auch einfach gleich ne Fehlermeldung schmeißen können.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.