Threat Research

LockFile ランサムウェアの攻撃手法: 断続的な暗号化と検出回避

本記事では LockFile を詳細に分析し、そのファイル暗号化手法の斬新さや、動作ベース、統計ベースのランサムウェア対策機能を回避する手法を明らかにしています。

2021 年 4 月に Microsoft Exchange サーバーに「ProxyShell」と呼ばれる脆弱性が発見されたことを受けて、2021 年 7 月に新たなランサムウェアファミリ「LockFile」が登場しました。LockFile ランサムウェアは、ProxyShell を悪用してパッチが適用されていないオンプレミスの Microsoft Exchange サーバーに侵入し、PetitPotam NTLM リレー攻撃を行うことでドメインの所有権を奪います。

本記事では LockFile ランサムウェアを詳細に分析し、LockFile のファイル暗号化手法の斬新さや、動作ベース、統計ベースのランサムウェア対策機能を回避する手法を明らかにしています。

本記事では、以下の主要な発見について詳しく分析しています。

  • LockFile ランサムウェアは、各ファイルのうち 16 バイトを暗号化します。ソフォスではこの手法を「断続的な暗号化」と読んでいますが、ソフォスの研究者がこの手法の使用を確認したのは今回が初めてです。断続的に暗号化されたドキュメントは暗号化される前のドキュメントと統計上非常に似ているため、一部のランサムウェア保護サービスによる検出を回避します。
  • LockFile ランサムウェアは WastedLocker ランサムウェアや Maze ランサムウェアと同様、ファイルの暗号化にメモリマップド I/O (インプット/アウトプット) を利用します。この技術により、ランサムウェアはキャッシュされたドキュメントをメモリ上で透過的に暗号化し、暗号化したドキュメントが OS によって書き込まれる際にディスク I/O を最小限にすることでセキュリティソフトによる検出を回避します。
  • LockFile ランサムウェアは、通信のためにコマンドアンドコントロール (C2) サーバーに接続する必要がないため、その活動を検知するシステムを掻い潜ることができます。
  • さらに、LockFile は暗号化されたドキュメントの名前を小文字に変更し、.lockfile というファイル拡張子を追加します。また、LockFile の HTA ランサムノート (身代金要求文書) は、LockBit 2.0 のものと非常によく似ています。

マルウェアの分析

本記事の分析は、bf315c9c064b887ee3276e1342d43637d8c0e067260946db45942f39b970d7ce という SHA-256 ハッシュを持つ LockFile のサンプルに基づいています。このファイルは VirusTotal にアップロードされています。

サンプルを Ghidra で読み込むと、3 つの関数と 3 つのセクションのみから構成されていることがわかります。

3 つの関数
3 つのセクション

LockFile ランサムウェアのバイナリは UPX によって二重に圧縮されており、エンドポイント保護ソフトによる静的解析を妨げるような形式になっています。また、セクション名が元の UPX0 および UPX1 からそれぞれ OPEN と CLSE に変更されています。

OPEN という名前の最初のセクションは 592 KB (0x94000) の大きさを持ちますが、ゼロが並んでいるだけで、データは含まれていません。

CLSE という名前の 2 番目のセクションは 286 KB (0x43000) で、上述の 3 つの関数はこのセクションの最後のページにあります。残りのデータはエンコードされたコードで、後でデコードされて OPEN セクションに置かれます。

1 つ目の関数である entry() 関数の動作は単純で、FUN_1400d71c0() 関数を呼び出すだけです。

Entry() 関数

FUN_1400d71c0() 関数は CLSE セクションのデータをデコードし、OPEN セクションに挿入します。また、必要な DLL や関数を解凍します。さらに、IMAGE_SCN_CNT_UNINITIALIZED_DATA の値を操作し、OPEN セクションに置かれたコードにジャンプします。

OPEN セクション

残りのコードは OPEN セクションで展開、つまり実行時に生成されるものなので、 WinDbg と .writemem を使用して以下のコマンドで OPEN セクションをディスクに書き込み、Ghidra でコードを静的に解析しました。

.writemem c:\[中略]\LockFile\sec_open.bin lockfileexe+1000 L94000

Ghidra にファイルを読み込んで解析すると、ランサムウェアが動作を開始するための主関数が見つかります。

C 言語のランタイムライブラリである主関数

上のスクリーンショットは CRT と呼ばれる C 言語のランタイムライブラリで、実際の主関数ではありません。しかし、調査の結果、以下の主関数が発見されました。

実際の主関数

WinDbg でのデバッグ時に参照できるよう、関数の名前を main_000861() に変更し、アドレスを手元に残しておきます。

最初の部分は暗号ライブラリを初期化します。

暗号ライブラリの初期化

コードの中には、「これ以降暗号アルゴリズムを無効化」など、GitHub で自由に利用できる Crypto++ Library 内にも見られる文字列が使われており、LockFile ランサムウェアは暗号化にこのライブラリを活用していると考えられます。

その後、ミューテックスを作成し、ランサムウェアが同時に 2 回実行されるのを防ぎます。

ミューテックスの作成

重要なビジネスプロセスの終了

その後、文字列がデコードされ、161 行目のsystem() 関数で呼び出されるパラメータになります。

エンコードされた文字列。中身は終了させる重要なプロセスのリストです。

上述の通り、これらの文字列は 161 行目の system() 関数により呼び出されるパラメータです。この関数により、名前に vmwp を含む全てのプロセスが終了します。プロセスの終了には、Windows システムに含まれる WMI (Windows Management Interface) のコマンドラインツールである WMIC.EXE が活用されています。この操作は、仮想化ソフトウェアやデータベースに関連する他の重要プロセスに対しても繰り返されます。

プロセス コマンド
Hyper-V 仮想マシン wmic process where “name like ‘%vmwp%’” call terminate
Oracle VM Virtual Box Manager wmic process where “name like ‘%virtualbox%’” call terminate
Oracle VM Virtual Box サービス wmic process where “name like ‘%vbox%’” call terminate
Microsoft SQL Server (SharePoint、Exchangeでも使用) wmic process where “name like ‘%sqlservr%’” call terminate
MySQL データベース wmic process where “name like ‘%mysqld%’” call terminate
Oracle MTS Recovery Service wmic process where “name like ‘%omtsreco%’” call terminate
Oracle RDBMS Kernel wmic process where “name like ‘%oracle%’” call terminate
Oracle TNS Listener wmic process where “name like ‘%tnslsnr%’” call terminate
VMware 仮想マシン wmic process where “name like ‘%vmware%’” call terminate

 

WMI が活用されているので、ランサムウェア自身は重要なプロセスの強制終了とは直接は関係しません。これらのプロセスを終了することにより、関連するファイルやデータベースのロックが解除され、悪意のある暗号化が行えるようになります。

その後、692 行目の GetLogicalDriveString() 関数ですべてのドライブレター (ドライブに割り当てられた文字) を取得し、それぞれに対して同じ操作を繰り返し実行します。

それぞれのドライブに対して文字列を作成

ループ内では、GetDriveType() 関数によってドライブタイプを識別します。対象が内蔵ドライブの場合 (703 行目の「type three = DRIVE_FIXED」の部分)、関数 0x7f00 を開始アドレスとする新しいスレッドを生成します (705、706 行目)。

HTML アプリケーション形式のランサムノート

0x7f00 の関数は、まずドライブのルートに「LOCKFILE-README-[ホスト名]-[id].hta」のような名前の HTA ランサムノートを作成します。LockFile は、TXT 形式のメモをドロップする代わりに、ランサムノートを HTML アプリケーション (HTA) ファイルとしてフォーマットします。興味深いことに、LockFile が使用する HTA ランサムノートは、LockBit 2.0 ランサムウェアが使用するものと酷似しています。

LockFile のランサムノート

 

LockBit のランサムノート

 

LockFile のランサムノートは、被害者に特定の電子メールアドレス (contact@contipauper.com) に連絡するよう求めています。使用されているドメイン名「contipauper.com」は、競合するランサムウェアグループ「Conti」を揶揄したものだと思われます。このドメイン名は、2021 年 8 月 16 日に作られたものです。

ディレクトリの暗号化

さらにその後、6 行目で EncryptDir_00007820() 関数が呼び出されます。この関数の最初の部分には、あまり特徴はありません。

0x7f00 に位置する関数

しかし、続く部分は注目に値します。

63 行目の FindFirstFile() 関数および 129 行目の FindNextFile() 関数が使用され、param_1 で指定されているディレクトリで繰り返し処理が実行されます。

初めの部分 (66-91 行目) では、ファイル名に以下の文字列が含まれていないことを確認します。

  • “.lockfile”
  • “\Windows”
  • “LOCKFILE”
  • “NTUSER”

次に (92-102 行目)、攻撃対象から除外するファイルの種類を規定している 2 つのリストに合致する拡張子を持つドキュメントを飛ばします。

リスト 1:

.a3l .a3m .a4l .a4p .a5l .abk .abs .acp .ada .adb .add .adf .adi .adm .adp .adr .ads .af2 .afm .aif .aifc .aiff .aim .ais .akw .alaw .tlog .vsix .pch .json .nupkg .pdb .ipdb .alb .all .ams .anc .ani .ans .api .aps .arc .ari .arj .art .asa .asc .asd .ase .asf .xaml .aso .asp .ast .asv .asx .ico .rll .ado .jsonlz4 .cat .gds .atw .avb .avi .avr .avs .awd .awr .axx .bas .bdf .bgl .bif .biff .bks .bmi .bmk .book .box .bpl .bqy .brx .bs1 .bsc .bsp .btm .bud .bun .bw .bwv .byu .c0l .cal .cam .cap .cas .cat .cca .ccb .cch .ccm .cco .cct .cda .cdf .cdi .cdm .cdt .cdx .cel .cfb .cfg .cfm .cgi .cgm .chk .chp .chr .cht .cif .cil .cim .cin .ck1 .ck2 .ck3 .ck4 .ck5 .ck6 .class .cll .clp .cls .cmd .cmf .cmg .cmp .cmv .cmx .cnf .cnm .cnq .cnt .cob .cpd .cpi .cpl .cpo .cpr .cpx .crd .crp .csc .csp .css .ctl .cue .cur .cut .cwk .cws .cxt .d64 .dbc .dbx .dc5 .dcm .dcr .dcs .dct .dcu .dcx .ddf .ddif .def .defi .dem .der .dewf .dib .dic .dif .dig .dir .diz .dlg .dll .dls .dmd .dmf .dpl .dpr .drv .drw .dsf .dsg .dsm .dsp .dsq .dst .dsw .dta .dtf .dtm .dun .dwd .dwg .dxf .dxr .eda .edd .ede .edk .edq .eds .edv .efa .efe .efk .efq .efs .efv .emd .emf .eml .enc .enff .ephtml .eps .epsf .epx .eri .err .esps .eui .evy .ewl .exc .exe .f2r .f3r .f77 .f90 .far .fav .fax .fbk .fcd .fdb .fdf .fft .fif .fig .fits .fla .flc .flf .flt .fmb .fml .fmt .fnd .fng .fnk .fog .fon .for .fot .fp1 .fp3 .fpt .frt .frx .fsf .fsl .fsm .ftg .fts .fw2 .fw3 .fw4 .fxp .fzb .fzf .fzv .gal .gdb .gdm .ged .gen .getright .gfc .gfi .gfx .gho .gid .gif .gim .gix .gkh .gks .gna .gnt .gnx .gra .grd .grf .grp .gsm .gt2 .gtk .gwx .gwz .hcm .hcom .hcr .hdf .hed .hel .hex .hgl .hlp .hog .hpj .hpp .hqx .hst .htt .htx .hxm .ica .icb .icc .icl .icm .idb .idd .idf .idq .idx .iff .igf .iif .ima .imz .inc .inf .ini .ins .int .iso .isp .ist .isu .its .ivd .ivp .ivt .ivx .iwc .j62 .java .jbf .jmp .jn1 .jtf .k25 .kar .kdc .key .kfx .kiz .kkw .kmp .kqp .kr1 .krz .ksf .lab .ldb .ldl .leg .les .lft .lgo .lha .lib .lin .lis .lnk .log .llx .lpd .lrc .lsl .lsp .lst .lwlo .lwob .lwp .lwsc .lyr .lzh .lzs .m1v .m3d .m3u .mac .magic .mak .mam .man .map .maq .mar .mas .mat .maud .maz .mb1 .mbox .mbx .mcc .mcp .mcr .mcw .mda .mdb .mde .mdl .mdn .mdw .mdz .med .mer .met .mfg .mgf .mic .mid .mif .miff .mim .mli .mmf .mmg .mmm .mmp .mn2 .mnd .mng .mnt .mnu .mod .mov .mp2 .mpa .mpe .mpp .mpr .mri .msa .msdl .msg .msn .msp .mst .mtm .mul .mus .mus10 .mvb .nan .nap .ncb .ncd .ncf .ndo .nff .nft .nil .nist .nlb .nlm .nls .nlu .nod .ns2 .nsf .nso .nst .ntf .ntx .nwc .nws .o01 .obd .obj .obz .ocx .ods .off .ofn .oft .okt .olb .ole .oogl .opl .opo .opt .opx .or2 .or3 .ora .orc .org .oss .ost .otl .out .p10 .p3 .p65 .p7c .pab .pac .pak .pal .part .pas .pat .pbd .pbf .pbk .pbl .pbm .pbr .pcd .pce .pcl .pcm .pcp .pcs .pct .pcx .pdb .pdd .pdp .pdq .pds .pf .pfa .pfb .pfc .pfm .pgd .pgl .pgm .pgp .pict .pif .pin .pix .pjx .pkg .pkr .plg .pli .plm .pls .plt .pm5 .pm6 .pog .pol .pop .pot .pov .pp4 .ppa .ppf .ppm .ppp .pqi .prc .pre .prf .prj .prn .prp .prs .prt .prv .psb .psi .psm .psp .ptd .ptm .pwl .pwp .pwz .qad .qbw .qd3d .qdt .qfl .qic .qif .qlb .qry .qst .qti .qtp .qts .qtx .qxd .ram .ras .rbh .rcc .rdf .rdl .rec .reg .rep .res .rft .rgb .rmd .rmf .rmi .rom .rov .rpm .rpt .rrs .rsl .rsm .rtk .rtm .rts .rul .rvp .s3i .s3m .sam .sav .sbk .sbl .sc2 .sc3 .scc .scd .scf .sci .scn .scp .scr .sct01 .scv .sd2 .sdf .sdk .sdl .sdr .sds .sdt .sdv .sdw .sdx .sea .sep .ses .sf .sf2 .sfd .sfi .sfr .sfw .shw .sig .sit .siz .ska .skl .slb .sld .slk .sm3 .smp .snd .sndr .sndt .sou .spd .spl .sqc .sqr .ssd .ssf .st .stl .stm .str .sty .svx .swa .swf .swp .sys .syw .t2t .t64 .taz .tbk .tcl .tdb .tex .tga .tgz .tig .tlb .tle .tmp .toc .tol .tos .tpl .tpp .trk .trm .trn .ttf .tz .uwf .v8 .vap .vbp .vbw .vbx .vce .vcf .vct .vda .vi .viff .vir .viv .vqe .vqf .vrf .vrml .vsd .vsl .vsn .vst .vsw .vxd .wcm .wdb .wdg .web .wfb .wfd .wfm .wfn .xml .acc .adt .adts .avi .bat .bmp .cab .cpl .dll .exe .flv .gif .ini .iso .jpeg .jpg .m4a .mov .mp3 .mp4 .mpeg .msi .mui .php .png .sys .wmv .xml

リスト 2:

.acc .adt .adts .avi .bat .bmp .cab .cpl .dll .exe .flv .gif .ini .iso .jpeg .jpg .m4a .mov .mp3 .mp4 .mpeg .msi .mui .php

注: 興味深いことに、このランサムウェアは写真などの JPG 画像ファイルは攻撃しません。

ドキュメントのファイル拡張子がリストにない場合、コード内でファイル名とファイルパスを連結し (103 行目)、EncryptFile_00007360() を呼び出してドキュメントを暗号化します。

EncryptFile_00007360() 関数は、メモリマップド I/O を介してドキュメントを暗号化します。

メモリマップド I/O を介してドキュメントを暗号化

ドキュメントは 164 行目で開かれ、177 行目で CreateFileMapping() 関数がドキュメントをメモリにマッピングします。181 行目の lVar17 がメモリマップされたドキュメントを指しています。

このコードは、メモリ上のドキュメントの最後に復号用のバイナリラージオブジェクト (blob) を追加します。以下は、文字「a」(0x61) を 128 個並べたテストドキュメントの例です。

128 個の「a」(0x61) からなるテストドキュメントの例

復号用 blob が追加されると、メモリマップされたドキュメントは以下のようになります。

メモリマップされ、末尾に復号用 blob が追加されたテストドキュメント

さらに、271 行目の EncryptBuffer_0002cbf4() 関数によりドキュメントは 16 バイトずつ暗号化されます。

16 バイトずつの断続的な暗号化

EncryptBuffer_0002cbf4() 関数は引数 lVar15 の値を取得し、そのうち 16 バイトを暗号化します。lVar15 には 268 行目でメモリマップされたドキュメントを指す lVar7 が代入されています。

興味深いことに、上記の処理後 0x20 (32 バイト) が lVar15 に追加され、16 バイト分の暗号化がスキップされます。この手順により、暗号化が断続的に行われます。

一度目の暗号化後のメモリマップされたテストドキュメント
二度目の暗号化後のメモリマップされたテストドキュメント
全バイトに対して断続的な暗号化が行われた後のメモリマップされたテストドキュメント
元のドキュメントと LockFile により断続的に暗号化されたドキュメントを比較したアニメーション画像

LockFile ランサムウェアの特筆すべき点は、部分的な暗号化を実装していることではありません。たとえば、LockBit 2.0、DarkSide、BlackMatter などのランサムウェアも、暗号化を早く終わらせるために攻撃対象のドキュメントの一部だけを暗号化することが知られています。(これらのランサムウェアは、それぞれ最初の 4,096 バイト、512 KB、1 MB を暗号化します。)

LockFile の特徴は、最初の数ブロックを暗号化しないことです。その代わりに、LockFile はドキュメントを 16 バイトごとに暗号化します。この手法により、たとえばテキストファイルなどは部分的に読める状態が維持されることになります。

この手法には興味深い利点があります。断続的な暗号化は統計分析を欺き、いくつかの保護技術を混乱させます。

統計分析を欺くことでランサムウェア対策機能を回避

LockFile で採用されている断続的な暗号化方式は、一部のランサムウェア対策ソフトで使用されているカイ二乗 (chi^2) 検定のような分析手法を欺きます。

たとえば、ある暗号化されていない 481 KB のテキストファイルの chi^2 スコアが 3850061 だとします。このドキュメントが DarkSide ランサムウェアにより暗号化されると、ドキュメントの chi^2 スコアは 334 となり、ドキュメントが暗号化されていることが検知されます。しかし、同じドキュメントが LockFile ランサムウェアによって暗号化された場合、chi^2 スコアは 1789811 という高い値を保ちます。

以下のグラフ (バイト数/文字の分布) は、暗号化された同じテキストファイルを示したものです。

元のテキストファイル DarkSide によって暗号化されたテキストファイル LockFile によって暗号化されたテキストファイル

 

ご覧のように、LockFile によって暗号化されたテキストファイルは視覚的には元のドキュメントと非常によく似ていることがわかります。このような工夫は、暗号化を検出するために統計的分析を伴うスキャンを行うランサムウェア保護ソフトウェアに対しては効果を持ちます。

ランサムウェア攻撃に断続的な暗号化が使われたのは今回が初めてです。

暗号化されたドキュメントのディスクへの書き込み

暗号化後、ドキュメントが閉じられ (279-281 行目)、名前を変更した上でファイルが移動されます。

文字列「%s.lockfile」がデコードされ (284-298 行目)、300 行目の sprintf() 関数に渡されることでファイル名の末尾に「.lockfile」が追加されます。

301 行目では、元ファイルの名前が新しいものに変更されます。興味深いことに、変更されたファイル名はすべて小文字に統一されています。元のファイル名に大文字が含まれていた場合、復号の際に元のファイル名に戻すことはできません。

この攻撃は CreateFileMapping() 関数を利用しているため、メモリ上で暗号化されたドキュメントは、Windows システムプロセスである PID4 によってディスクに書き込まれます。この様子は、Sysinternals Process Monitor で確認できます。下図では、PID4 によるアクティビティを除外する Process Monitor のフィルタを無効化しています。

メモリマップド I/O を利用することでランサムウェアはキャッシュされたドキュメントに素早くアクセスし、Windows のシステムプロセスに書き込みを行わせることができます。システムプロセスに WriteFile 操作を実行させることで、暗号化された部分はランサムウェアではなく、OS 自身によって書き込まれます。

上記の例では、ランサムウェアがドキュメントを暗号化してから 6 秒後に OS からの書き込みが行われましたが、大規模なシステムではこの間隔が数分に及ぶこともあります。この仕組みによっても、動作ベースのランサムウェア対策ソフトによる検出を回避することができます。

メモリマップド I/O の使用は、ランサムウェアファミリとしてはあまり一般的ではありませんが、Maze ランサムウェアや、(あまりメジャーではない) WastedLocker ランサムウェアでは使用されていました。

ランサムウェアの自己消滅

マシン上のすべてのドキュメントを暗号化した後、ランサムウェアは以下のコマンドで自分自身を消去します。

cmd /c ping 127.0.0.1 -n 5 && del “C:\Users\Mark\Desktop\LockFile.exe” && exit

PING コマンドはローカルホスト (つまり攻撃対象のマシンそのもの) に 5 つの ICMP メッセージを送信します。これは単に、ランサムウェアのバイナリを削除するための DEL コマンドが実行される前に、ランサムウェアのプロセスを閉じるための 5 秒間の待機時間を確保するためのものです。

上記のコマンドが実行されることにより、インシデントの対応者やアンチウイルスソフトが検出、削除できるようなランサムウェアのバイナリは存在しなくなります。

注: 最近のほとんどのリモートで操作されるランサムウェアと同様に、LockFile ランサムウェアはインターネット上の C2 サーバーに接続する必要がありません。つまり、LockFile はインターネットに接続していないマシン上のデータも暗号化できます。

ソフォスは、本記事への貢献に対して、SophosLabs の研究者である Alex Vermaning と Gabor Szappanos の両名に謝意を表します。