ツール開発:Extract-PSImage(はじめてのGitHub)
勉強も兼ねて、初めてGitHub上にツールをリリースしました。
Extract-PSImage https://github.com/imurasheen/Extract-PSImage
Invoke-PSImage(https://github.com/peewpw/Invoke-PSImage)によってスクリプトが埋め込まれてしまった画像からスクリプトを抽出するためのツールです。
■Invoke-PSImageとは
Invoke-PSImageは2017年末にリリースされ、すぐに平昌オリンピックへの攻撃に利用されたことで有名になったツールです。
参考:https://ascii.jp/elem/000/001/615/1615152/
日本国内では、その後もしばしば攻撃に利用されているのを見かけます。
Invoke-PSImageは、画像にスクリプトを埋め込む際に、そのスクリプトを抽出するための専用の命令列=ワンライナーを生成します。
巧妙にデータが埋め込まれているため元々気づきにくいのですが、ワンライナーが特定できないとスクリプトを抽出できない、という点でも解析の難易度が高い攻撃です。
■Invoke-PSImageの処理を解析
今回は、Invoke-PSImageのスクリプト埋め込み処理を解析することで逆に抽出ができるのではないかと考え、挑戦してみました。
Invoke-PSImage.ps1の動きをトレース
(1)まずスクリプトをロード
(2)埋め込み対象の画像をimgオブジェクトにロードし、幅と
(3)メモリ上のキャンバスにビットマップデータを描画
(4)RGBデータを抽出
$bytes = [Math]::Abs($bmpData.Stride) * $img.Height
Absは絶対値。bmpData.Strideはストライド幅
ストライド幅:参考 http://neareal.com/470/
幅が512pxのデータだとすると、1画素がBGRAで構成され
(5)埋め込みたいペイロードの内容が画像サイズにフィットする
(6)ペイロードを埋めない場所に埋め込むランダムストリングを
(7)ループ処理でRGB配列にペイロードを埋め込み
(8)(7)で生成したデータをビットマップのキャンバスに戻す
(9)Png形式でファイルを保存
(10)ワンライナーのパラメータ生成
$rows = [math]::Ceiling($payload.Lengt
→$width = $img.Size.Width Ceilingは小数点以下切り上げ
$array = ($rows*$width)
$lrows = ($rows-1)
$lwidth = ($width-1)
$lpayload = ($payload.Length-1)
payload.L
よって、payload.Lengthを以下のいずれかで決定すればso
①画像に埋め込み可能な最大値
②最大値までインクリメントしながら発見できる箇所を探す
Invoke-PSImageのつくりからして①で行けるはず。
■Extract-PSImageの使用法
作成は基本的にInvoke-PSImageのコードをいじることで行いました。
詳細はリポジトリを参照してください。
https://github.com/imurasheen/Extract-PSImage
簡単な使用法だけ。
PS> Import-Module .\Extract-Invoke-PSImage.ps1
PS> Extract-Invoke-PSImage -Image [PNG画像へのパス] -Out [抽出したスクリプトの出力先のファイルパス]
[Oneliner to extract embedded payload]
ペイロードを抽出するワンライナー(実行は行わないような内容)
[First 50 characters of extracted payload]
抽出したペイロードの最初の50文字
Extract-PSImageは、対象となる画像に埋め込むことができる最大長のスクリプト文字列の抽出を試みます。そのため、結果には以下の制約が付きます。
(1)埋め込まれたスクリプトが、埋め込み可能な最大長よりも短い場合、抽出したスクリプトの後ろにランダムな文字列がくっついて出力されます。
(2)スクリプトが埋め込まれていない画像に対してExtract-PSImageにより解析を行った場合も、実行はエラーとなりません。ただし、出力された結果はすべて無意味なランダム文字列となります。
抽出に成功した際の例は以下の通り。
■GitHubへの投稿方法
ファイルのアップロードなどは直感的に分かったんですが、Readmeの書き方に少し苦戦しました。以下を参照しました。
https://deeeet.com/writing/2014/07/31/readme/
https://gist.github.com/wate/7072365
■まとめ
・十分な試験を行って作成したツールではありませんので、ロジックの読み間違えなどでバグや問題点があるかもしれません。使ってみた方がいらっしゃればご意見いただきたいです。
・初めてのGitHubへのツールのリリースでしたので、良い経験になったと思います。
・検知等に活用する方法について検討していきたいです。
■追記:ライセンス表記
当初はリポジトリにライセンス表記を入れてなかったのですが、
・ライセンス表記を入れていないと、
⇒表記しないとデフォルトの著作権が適用され、編集、
・Invoke-
設定方法は以下を参照しました。
h
①リポジトリのトップで[Create new file]をクリック
※一度登録に成功した後に画面キャプチャしたので、画面中に"MIT"のタブが表示されています。登録に成功するとこのように表示されますよ笑
②"LICENSE"というファイル名称を入力し、[Choose a license template]をクリック
③ライセンステンプレートの選択画面が表示される。「MIT License」を選択する
④MIT Licenseの内容が表示される。ライセンス表記中に記載される"Year" および"Full name"の内容を設定し、[Review and submit]を選択
⑤作成されたライセンスファイルの内容が表示される。問題なければ、このファイルをコミットすれば作業完了