
マルウェアのトリアージとバイナリ解析のための構成可能なコマンドラインツールキット: 悪意のあるファイルやシェルコードからインジケータをデコード、復号、カービング、抽出します。
__ __ High Octane Triage Analysis __
|| _||______ __ __________ _____ ||
|| \||___ \__| ____/ ______/___ / ____\ ||
==||=====|| | __/ |/ \ /==| / __ \ __\===]|
'======|| | \ | | \_ _| \ ___/| | ||
||____ /__|___|__/ / | \____]| | ||
=========''====\/=========/ /==|__|=====|__|======'
\ /
\/
Binary Refinery™ は、圧縮や暗号化などのバイナリデータ変換を実装するPythonスクリプトのコレクションです。
私たちはこれを単に refinery と呼ぶことがよくありますが、これは対応するパッケージの名前でもあります。
スクリプトは、標準入力からのみ読み取り、標準出力に書き出すように設計されています。
主な理念は、すべてのスクリプトが 1つの ジョブを実行するユニットであるべきであり、
個々のユニットはコマンドライン上のパイプ演算子 | で パイプライン に組み合わせて、より複雑なタスクを実行できます。
このプロジェクトの主な焦点はマルウェアのトリアージであり、
コマンドライン上で CyberChef のようなものを実装する試みです。
Pythonの仮想環境を作成してください。Python 3.10以降が必要です。次のようにrefineryをインストールします:
python -m pip install -U pip
python -m pip install -U binary-refinery[extended]
ユニットの動作を確認するには -h を付けて実行し、docs を検索するか、binref コマンドを使用してユニットを見つけてください。
実際の動作を見たい場合は 最近のビデオ をご覧ください。
ただし、このREADMEの残りも読んでください。
リリーススケジュールはありませんが、リリースは非常に頻繁に行われるため、定期的に更新することをお勧めします。 バグ修正はGITの外部では文書化されませんが、その他の変更(つまり新機能)は changelog に文書化されます。 特に影響の大きいリリースの最新情報については、Mastodon で私をフォローしてください。
-h または --help スイッチを付けてユニットを実行したときに表示されるヘルプテキストが、その主要なドキュメントです。
自動生成されたドキュメント には、各ユニットのその出力のコンパイルが最上位レベルに含まれていますが、
ツールキットの3つの基本概念の仕様も含まれています:
フレーミング、マルチビン引数、メタ変数。
すべてのユニットの説明とヘルプテキストの全文検索も、提供されている binref コマンドを介してコマンドラインで利用できます。
リファレンスドキュメントは少し退屈になりがちであることを認識し、
一連の チュートリアル を作成する取り組みが進行中です。ぜひチェックすることをお勧めします。
さらに、追加リソース(サードパーティ製を含む)を以下にまとめています。
[!NOTE]
Refineryはまだアルファ版であり、インターフェースが変更されることがあります。 つまり、ユニットやパラメータが削除または名前変更される可能性があります。 そのため、古いビデオやブログ記事の特定のコマンドラインが機能しなくなることがあります。
2021/08] OALabs が、フィーチャービデオで ツールキットをデモする ことを快く許可してくれました。
このビデオでは、基本的に 最初のチュートリアル の内容を順に進めています。2021/11] Johannes Bader は、binary refineryを使ってマルスパムを分析する素晴らしい ブログ記事 を書きました。2024/03] Malware Analysis For Hedgehogs が refinery を使った XWormサンプルのアンパックに関するビデオ を作成しました。2024/11] CyberYeti が ストリームでrefineryを紹介 してくれました。2025/06] CyberYeti と 再びストリームに出演 しました。今回は少し生々しい内容です。
ここで見えるバグはすべて修正されました。😉ショーケースには、以下の例セクションのサンプルと チュートリアル も含まれています。
Binary Refinery は (c) 2019 Jesko Hüttenhain であり、3-Clause BSD License の下で公開されています。 このリポジトリには ライセンス全文のコピー も含まれています。 このライセンスでカバーされていないことを行いたい場合は、お気軽に著者に連絡してください。
refineryには少なくとも Python 3.10 が必要です。 専用の 仮想環境 にインストールすることをお勧めします: このパッケージは 多数の 依存関係を引き込む可能性があり、 グローバルなPythonにインストールするとバージョン競合が発生しやすくなります。 また、ツールキットは多数の新しいコマンドを導入するため、 一部のシステムではこれらの一部が衝突する可能性が高く、 それらを独自の仮想環境に保持することは、それを防ぐ1つの方法です。
すべてのrefineryコマンドを常にシェルで利用できるようにしたい場合(つまり、カスタム仮想環境に切り替える必要がないようにする場合)、
インストールに プレフィックス を選択するオプションもあります。
これは、インストールされるすべてのコマンドシムの前に付けられます。
たとえば、プレフィックスとして r. を選択すると、emit ユニットはコマンド r.emit としてインストールされます。
追加の利点として、r. と入力して Tab を2回押すと、利用可能なすべてのrefineryコマンドのリストを取得できます。
ただし、ドキュメントではプレフィックスは想定されておらず、ほとんどのシステムで衝突しないことはrefineryの開発目標です。
著者はプレフィックスを使用しておらず、このオプションを安全策として提供しています。
refineryをインストールおよび更新する最も簡単な方法は、pipを使用することです。 まず最新バージョンが実行されていることを確認してください:
python -m pip install -U pip
次に、refineryパッケージをインストールするだけです:
pip install -U binary-refinery
すべてのユニットにプレフィックスを選択する場合は、環境変数 REFINERY_PREFIX で指定できます。
たとえば、次のコマンドはLinuxでプレフィックス r. を付けて、現在のPython環境にrefineryをインストールします:
REFINERY_PREFIX=r. pip install -U binary-refinery
Windowsでは、次のコマンドを実行する必要があります:
set REFINERY_PREFIX=r.
pip install -U binary-refinery
特別なプレフィックス ! を指定すると、シェルコマンドはまったく作成されず、
binary refineryはライブラリとしてのみインストールされます。
現在のrefinery HEAD をインストールする場合は、上記のすべての手順を繰り返し、pipパッケージの代わりにこのリポジトリを指定できます。
たとえば、次のコマンドは最新のrefineryコミットをインストールします:
pip install -U git+git://github.com/binref/refinery.git
最後に、REMnux を使用している場合は、彼らの refinery docker container を使用できます。
ローカルのマルウェア解析 claude にbinary refineryの使い方を教えたい場合は、Binary Refinery Skill をチェックしてください。
以下は、さまざまなシェル環境が現在どの程度サポートされているかの概要です:
異なるシェルを使用していてフィードバックがあれば、お知らせください!
非常に状況依存的なユニットの中には、(場合によっては大きな)外部依存関係を持つものがあります。
たとえば、stego は画像解析ライブラリ Pillow を必要とするユニットです。
一部のライブラリは、初めてのユーザーのためにrefineryのインストール時間を妥当なレベルに保つため、デフォルトではインストールされません。
対応するユニットは、依存関係が欠落している場合に何をすべきかを教えてくれます:
$ emit config.png | stego RG
(13:37:00) failure in stego: dependency Pillow is missing; run pip install Pillow
その後、これらの欠落している依存関係を手動でインストールできます。 依存関係の欠落に悩まされたくなく、長時間のrefineryインストールが気にならない場合は、次のようにパッケージをインストールできます:
pip install -U binary-refinery[all]
これにより、必要な依存関係に加えて すべての 依存関係がインストールされます。 より正確には、次の追加カテゴリが利用可能です:
| 名前 | 含まれる依存関係 |
|---|---|
default | 合理的な依存関係の推奨セット(作者の選択) |
extended | 最もマイナーなものを除いた拡張セット |
all | すべてのrefineryユニットのすべての依存関係 |
これらは昇順でリストされています。つまり、extended は default がインストールするすべてのものをインストールします。
あるいは、このリポジトリをクローンし、update.sh(Linux)または update.ps1(Windows) スクリプトを使用して、refineryパッケージをローカルの仮想環境にインストールできます。 この方法でのインストールと更新のプロセスは、単にスクリプトを実行するだけです:
binary-refinery をアンインストールし、binary-refinery[all] をインストールします。すべてのドキュメントをローカルで生成することもできます。
そのためには、run-pdoc3.py スクリプトを実行してください。
これは、binary refineryがPythonパッケージとしてインストールされている環境から実行しない限り 失敗 します。
実行するには、run-pdoc3.py の最初のコマンドライン引数として仮想環境のパスを指定する必要があります。
これにより、スクリプトはその環境のインタープリタを使用して再実行されます。
run-pdoc3.py を実行すると確信がある場合は、
現在のデフォルトのPythonインタープリタでスクリプトを強制的に実行するコマンドラインスイッチがあります。
このスクリプトは pdoc3パッケージ をインストールし、それを使用して refinery パッケージのHTMLドキュメントを生成します。
ドキュメントは、このREADMEファイルのすぐ隣のサブディレクトリ html にあります。
チュートリアル はJupyterノートブックであり、仮想環境に Jupyterがインストールされている 場合は、そのまま実行できます。 Visual Studio CodeはJupyterを非常に快適にサポートしている ことに言及しておく価値があります。
emit と dump のユニットは特別な役割を果たします: 前者はデータの出力用であり、後者はデータをクリップボードまたはディスクにダンプするためのものです。 例として、次のパイプラインを考えてみましょう:
emit M7EwMzVzBkI3IwNTczM3cyMg2wQA | b64 | zl | hex
ここでは、文字列 M7EwMzVzBkI3IwNTczM3cyMg2wQA を出力し、
b64 を使用してbase64デコードし、
zl を使用して結果をzlib解凍し、
最後に解凍されたデータを hex でデコードします。
各ユニットはデフォルトで特定の変換の "デコード" 操作を実行しますが、一部のユニットは逆の操作も実装しています。
逆の操作を実装している場合、それは常にコマンドラインスイッチ -R または --reverse を指定することで行われます。
hex、zl、b64 はすべて逆の操作を提供するため、次のコマンドで上記のbase64文字列を生成できます:
emit "Hello World" | hex -R | zl -R | b64 -R
base64エンコードされたペイロードバッファを含むファイル packed.bin がある場合、次のパイプラインはそのペイロードを payload.bin に抽出します:
emit packed.bin | carve -l -t1 b64 | b64 | dump payload.bin
carve ユニットは、入力バッファからデータのブロックを切り出すために使用できます。
この場合、base64エンコードされたデータを探し、長さで並べ替え(-l)、最初のものを返します(-t1)。
つまり、packed.bin から最も大きなbase64らしいチャンクを切り出します。
その後、データはbase64デコードされ、ファイル payload.bin にダンプされます。
pack ユニットは、テキストバッファからすべての数値式を取得し、それらをバイナリ表現に変換します。 簡単な例は次のパイプラインです:
emit "0xBA 0xAD 0xC0 0xFF 0xEE" | pack | hex -R
これにより、文字列 BAADC0FFEE が出力されます。
BLOBから最も大きなbase64エンコードデータの断片を抽出してデコードします:
emit file.exe | carve -ds b64
バッファからZIPファイルを切り出し、そこからDLLを選び、その情報を表示します:
emit file.bin | carve-zip | xtzip file.dll | pemeta
PEファイルのセクションとそれに対応するSHA-256ハッシュを一覧表示します:
emit file.exe | vsect [| sha256 -t | pf {} {path} ]]
現在のディレクトリ内のすべてのファイルを再帰的に一覧表示し、それぞれのSHA-256ハッシュを表示します:
ef "**" [| sha256 -t | pf {} {path} ]]
現在のディレクトリ内で再帰的に列挙されたすべてのファイルからインジケータを抽出します:
ef "**" [| xtp -n6 ipv4 socket url email | dedup ]]
ネットワークバイトオーダーのハードコードされたIPアドレス 0xC0A80C2A を読み取り可能な形式に変換します:
emit 0xC0A80C2A | pack -EB4 | pack -R [| sep . ]
1バイトXORのブルートフォースを実行し、各反復でPEファイルのペイロードの抽出を試みます:
emit file.bin | rep 0x100 [| xor v:index | carve-pe -R | peek | dump {name} ]
RemCos C2サーバーを抽出します:
emit c0019718c4d4538452affb97c70d16b7af3e4816d059010c277c4e579075c944 \
| perc SETTINGS [| put keylen cut::1 | rc4 cut::keylen | xtp socket ]
AgentTeslaの設定を抽出します:
emit fb47a566911905d37bdb464a08ca66b9078f18f10411ce019e9d5ab747571b40 \
| dnfields [| aes x::32 --iv x::16 -T ]] \
| rex -M "((??email))\n(.*)\n(.*)\n:Zone" addr={1} pass={2} host={3}
悪意のあるXLSマクロドロッパーからPowerShellペイロードを抽出します:
emit 81a1fca7a1fb97fe021a1f2cf0bf9011dd2e72a5864aad674f8fea4ef009417b [ \
| xlxtr 9.5:11.5 15.15 12.5:14.5 [ \
| scope -n 3 | chop -t 5 [| sorted -a | snip 2: | sep ] \
| pack 10 | alu --dec -sN B-S ]] \
| dump payload.cmd
次のステージのドメインを取得します:
emit payload.cmd | cmdarg | ps1 | xtp -f domain
アンパックされたHawkEyeサンプルの設定を抽出します:
emit ee790d6f09c2292d457cbe92729937e06b3e21eb6b212bf2e32386ba7c2ff22c \
| put cfg perc[RCDATA]:c:: [\
| xtp guid | pbkdf2 48 rep[8]:h:00 | cca eat:cfg | aes -Q x::32 --iv x::16 ] \
| dnds
Warzone RAT:
emit 4537fab9de768a668ab4e72ae2cce3169b7af2dd36a1723ddab09c04d31d61a5 \
| vsect .bss | struct I{key:{}}{} [\
| rc4 eat:key | struct I{host:{}}{port:H} {host:u16}:{port} ]
シェルコードローダーからペイロードを抽出し、そのC2を切り出します:
emit 58ba30052d249805caae0107a0e2a5a3cb85f3000ba5479fafb7767e2a5a78f3 \
| rex yara:50607080.* [| struct LL{s:L}{} | xor -B2 rand[s]:msvc | xtp url ]
かつてこれが主流だった時代の悪意のあるVBAマクロを取得します:
emit ee103f8d64cd8fa884ff6a041db2f7aa403c502f54e26337c606044c2f205394 \
| vbamc
次に、悪意のあるダウンローダーペイロードを抽出します:
emit ee103f8d64cd8fa884ff6a041db2f7aa403c502f54e26337c606044c2f205394 \
| doctxt | repl drp:c: | carve -s b64 | rev | b64 | rev | ppjscript
悪意のあるPDFドキュメントからペイロードURLを抽出します:
emit 066aec7b106f669e587b10b3e3c6745f11f1c116f7728002f30c072bd42d6253 \
| xt JS | csd string | csd string | url | xtp url [| urlfix ]]
数式エディタのエクスプロイト文書からペイロードURLを抽出します:
emit e850f3849ea82980cf23844ad3caadf73856b2d5b0c4179847d82ce4016e80ee \
| officecrypt | xt oleObject | xt native | rex Y:E9[] | vstack -a=x32 -w=200 | xtp
data がCBCモードで256ビットAESを使用して暗号化されたファイルであると仮定します。
キーは、ソルト s4lty を使用するPBKDF2キー導出ルーチンを用いて、秘密のパスフレーズ swordfish から導出されました。
IVはバッファの先頭に最初の16バイトとしてプレフィックスされています。
これは次のパイプラインで復号化できます:
emit data | aes --mode cbc --iv cut::16 pbkdf2[32,s4lty]:swordfish
ここで、cut:0:16 と pbkdf2[32,s4lty]:swordfish はどちらも特別なハンドラを使用するマルチビン引数です。
この場合、cut:0:16 は入力データからスライス 0:16(つまり最初の16バイト)を抽出します。このマルチビンハンドラを適用した後、
入力データは最初の16バイトが削除され、引数 iv はこの正確な16バイトに設定されます。
最後の引数は32バイトの暗号化キーを指定します:
一方、ハンドラ pbkdf2[32,s4lty] は、コマンドラインでパラメータ 32 と s4lty をこの順序で指定し、このユニットでバイト文字列 swordfish を処理したかのように、refineryにpbkdf2ユニットのインスタンスを作成するように指示します。
簡単なテストとして、次のパイプラインはサンプルテキストを暗号化および復号化します:
emit "Once upon a time, at the foot of a great mountain ..." ^
| aes pbkdf2[32,s4lty]:swordfish --iv md5:X -R | ccp md5:X ^
| aes pbkdf2[32,s4lty]:swordfish --iv cut:0:16
| Shell | Platform | State | Comment |
|---|
| Bash | Posix | 🔵 良好 | 作者が時折使用。 |
| CMD | Windows | 🔵 良好 | 作者が広範囲に使用。 |
| PowerShell | Windows | 🟡 概ね良好 | PowerShellのバージョンが7.4以上であれば そのまま動作します。 |
| Zsh | Posix | 🟠 軽微な問題 | 議論 を受けて、修正 があります。 |
| Fish | Posix | 🟠 軽微な問題 | 問題 #55 と議論 #22 を参照してください。 |