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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2018-6789 — CVE-2018-6789 用エクスプロイト。Exim の base64 デコード処理におけるヒープバッファオーバーフローを悪用し、チャンクオーバーラップと ACL 文字列操作を介してリモートコード実行を達成します。 | Kitploit
ツール/GitHubGitHub/beraphin/cve-2018-6789
脆弱性分析エクスプロイトCTF学習と教育バイナリエクスプロイトラボと実践
GitHubberaphin/cve-2018-6789

CVE-2018-6789

CVE-2018-6789 用エクスプロイト。Exim の base64 デコード処理におけるヒープバッファオーバーフローを悪用し、チャンクオーバーラップと ACL 文字列操作を介してリモートコード実行を達成します。

リポジトリを見る
31136年前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2018-6789

環境構築

依存関係をインストールする

apt-get install gcc net-tools vim gdb python wget git make procps libpcre3-dev libdb-dev libxt-dev libxaw7-dev

旧バージョンのeximをダウンロードする

wget ftp://mirror.easyname.at/exim-ftp/exim/exim4/old/exim-4.89.tar.gz
tar -xvzf ./exim-4.89.tar.gz
cd ./exim-4.89
cp src/EDITME Local/Makefile
cp exim_monitor/EDITME Local/eximon.conf

次にLocal/Makefileを修正する デバッグしやすいように、各フォルダが現在のディレクトリを指すようにする

BIN_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/bin
CONFIGURE_FILE=/home/zzx/EVA/cve-2018-6789/exim-4.89/configure
SPOOL_DIRECTORY=/home/zzx/EVA/cve-2018-6789/exim-4.89/exim
EXIM_USER=zzx
AUTH_PLAINTEXT=yes
AUTH_CRAM_MD5=yes
AUTH_TLS=yes

これによりデバッグが容易になる そしてコンパイルしてインストールする

make install

./configureを修正し、以下の内容で直接上書きする

acl_smtp_mail=acl_check_mail
acl_smtp_data=acl_check_data
begin acl
acl_check_mail:
  .ifdef CHECK_MAIL_HELO_ISSUED
  deny
    message = no HELO given before MAIL command
    condition = ${if def:sender_helo_name {no}{yes}}
  .endif

  accept

acl_check_data:
  accept

begin authenticators
fixed_cram:
  driver = cram_md5
  public_name = CRAM-MD5
  server_secret = ${if eq{$auth1}{ph10}{secret}fail}
  server_set_id = $auth1

実行

./bin/exim -bd -d-receive

脆弱性分析

まずbase64.cにあるパッチを分析する: 1 ここでresultはbase64デコード結果を格納するバッファであり、store_get関数によって取得される パッチ適用前のsize計算に問題があることが分かる。sizeが4n〜4n+3の範囲にある場合、計算されたsizeの長さは等しくなるが、b64decodeは4の倍数でない引数をデコードする際に1〜2バイト多くデコードしてしまう

例えば、以下のように直接送信すると

auth_md5('Hf'*42)

size=0x40
結果のメモリ配置:

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 00  │....│....│....│....│
+0040 0x711da0  20 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

もう一度試す

auth_md5('Hf'*42+'HfH')

size=0x40

pwndbg> hexdump 0x711d60 0x50
+0000 0x711d60  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0010 0x711d70  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  │....│....│....│....│
+0020 0x711d80  df 1d f1 df  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  │....│....│....│....│
+0030 0x711d90  1d f1 df 1d  f1 df 1d f1  df 1d f1 df  1d f1 df 1d  │....│....│....│....│
+0040 0x711da0  f1 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │.aaa│aaaa│aaaa│aaaa│

2バイト溢れ出た

Eximのメモリ管理機構

eximはパフォーマンス向上のため、既存のヒープ管理機構の上に独自のメモリ管理機構を実装している。これはコードとglibcの間にある中間バッファに相当し、mallocとfreeの回数を減らすことを目的としている 2 eximでは、個々のヒープチャンクはstoreblockと呼ばれ、使用時にそこから適切なサイズのバッファを分割して使用する。storeblockを使い切った場合は、再度mallocでstoreblockを取得する。 各storeblockの構造は単純な単方向リストである:

/* Structure describing the beginning of each big block. */
typedef struct storeblock {
  struct storeblock *next;
  size_t length;
} storeblock;

プログラムがヒープを使用する際に主に使用するAPIはstore.cにある:

store_get
store_release
store_extend
store_reset

store_getはバッファを取得するために使用され、その主要なコードは以下の通り:

128 void *
129 store_get_3(int size, const char *filename, int linenumber)
....
145   int length = (size <= STORE_BLOCK_SIZE)? STORE_BLOCK_SIZE : size;
...
161   /* If there was no free block, get a new one */

162   if (!newblock)
163     {
164     pool_malloc += mlength;           /* Used in pools */
165     nonpool_malloc -= mlength;        /* Exclude from overall total */
166     newblock = store_malloc(mlength);
...

毎回申請されるstore_blockの最小長さはSTORE_BLOCK_SIZE、すなわち8192であることが分かる

したがって、8192サイズのstore_blockは、その構造ヘッダとヒープチャンクヘッダを加えると合計サイズは0x2020になる 3

eximがクライアントから送信されたコマンドを実行するたびに、コマンドの実行が成功するとstore_resetを呼び出して、不要なキャッシュや余分なstore_blockを解放する
ここで言う実行成功には、コマンドの形式が正しいことや、メールアドレスに不正な文字が含まれていないことなどが含まれる。そうでない場合はstore_resetは呼び出されない

悪用のアプローチ

この脆弱性は古典的なoff-by-oneである(実際には2バイト溢れ出ることができる)。しかし、溢れ出るバイト数が少ないため、ヒープチャンク上の重要な構造を直接上書きすることはできない。そこで、ptmallocのいくつかの特性を利用してこの脆弱性の影響を拡大し、より広範囲のoverflow、あるいはoverlapに変換する必要がある。
off-by-oneの脆弱性に対する古典的な悪用方法として、chunk enlarge -> chunk overlapがある。ヒープチャンクのsizeを大きく変更し、偽のヒープヘッダを偽造してglibcのsanity checkをバイパスすることで、ヒープチャンクの重なりを引き起こし、より広範囲の上書きを実現する。

ここでの主なプロセスは、chunk enlarge -> chunk overlap -> storeblock内のnextポインタの破壊、そしてstore_resetをトリガーして任意のヒープチャンクのfreeを引き起こすことである。再度このチャンクを申請できれば、その内容を変更できる(type confusion)。

mehは記事の中で、ACL文字列が存在するヒープチャンクの改変を推奨している。ACL文字列の処理にはコマンド実行機能が存在するためだ。 ACLの文字列は非常に多いが、ほとんどはNULLである(おそらく設定ファイルに関係している)。ここではacl_smtp_mail文字列を選択した。そのコマンド実行の構文は以下の通り

${run{command}}

おおよそのヒープレイアウトは以下の通り 4

最初のチャンクはbase64デコードで得られるチャンクで、off-by-oneに使用される。そのため、storeblockの末尾に位置する必要がある。便宜上、ここではbase64デコード結果を格納するために0x2020より大きいチャンクを直接申請する;
2番目のチャンクはsender_helo_nameで、次のチャンクを上書きするために使用される。sender_helo_nameはstoreblockに格納されるのではなく、直接mallocされる:

1832 static BOOL
1833 check_helo(uschar *s)
1834 {
...
1884 if (yield) sender_helo_name = string_copy_malloc(start);

したがって、サイズは任意でよい。 3番目のチャンクはbase64デコードで得られるチャンクで、主にヘッダの偽造と上書きに使用される。そのため、storeblockの先頭部分に位置する必要がある。便宜上、こちらも0x2020サイズを直接申請する。

Exploit

私のexpも、ネット上で公開されている他の人の分析に従って一歩ずつ作成したものである。大まかな方針は同じだが、ヒープのレイアウトが他の人とは少し異なるため、細かいパラメータもいくつか異なっている。

まず、サイズ0x6060のunsortedbinを生成する。以下のコマンドだけで実現できる

ehlo('a'*0x1000)

eximが"EHLO "+'a'*0x1000を受信すると、match.cのmatch_check_list関数で以下の3つの文字列が生成される

*name* in helo_lookup_domains? no (end of list)
sender_fullhost = (*name*) [127.0.0.1]
sender_rcvhost = [127.0.0.1] (helo=*name*)

ここでnameは'a'*0x1000である

nameの長さは0x1000なので、各文字列は1つのstoreblockを個別に占有する。これら3つの文字列は、連続した3つのstoreblockにそれぞれ配置される eximがehloコマンドを正常に完了すると、smtp_in.cのsmtp_setup_msgで前述の3つの文字列が解放され、0x6060サイズのヒープチャンクが得られる:

4369     cancel_cutthrough_connection(TRUE, US"sent EHLO response");
4370     smtp_reset(reset_point);
4371     toomany = FALSE;
4372     break;   /* HELO/EHLO */

このときのヒープレイアウトは以下の通り: 5

sender_helo_nameをヒープチャンクの中央に配置するために、元のsender_helo_nameを解放し、次に上部のヒープチャンクをプレースホルダで占有する必要がある。2番目のsender_helo_nameが配置されたら、上部のヒープチャンクを解放する。
ここではプレースホルダにunrecognizeコマンドを使用している。unrecognizeコマンドを受信することはコマンド実行の失敗に相当し、次のコマンド実行が成功した後で自動的に解放されるためである

ツールをダウンロード