Anti-UPX Unpackingテクニック
Windows OSを狙うマルウェア(PEフォーマット)は、コードの分析を困難にするためのさまざまな難読化やパッキングが行われており、その種類は多岐にわたります。それに比べて、Linux OSを狙うマルウェア(ELFフォーマット)のパッキング手法は数が限られており、ほとんどの場合UPXやUPXベースのパッキング手法が用いられています。 今回は、Linux OSを狙うマルウェアによくみられる、upxコマンドでのアンパックを困難にするAnti-UPX Unpackingテクニックについて解説します。
Anti-UPX Unpackingテクニックを使用したマルウェア
Anti-UPX Unpackingテクニックを使用した最も有名なマルウェアは、IoT機器をターゲットに感染を広げているマルウェアMirai、およびそれらの亜種のマルウェアです。図1は、UPXパッキングされたバイナリとMiraiのヘッダーの比較です。通常のUPXパッキングではマジックナンバーとしてUPX!
が使用されています。それに対して、Miraiの場合は検体毎に使用されているマジックナンバーが異なっています。
UPXパッキングされたバイナリは、ヘッダーに以下のような情報が含まれます。通常l_magic
だけが改ざんされていますが、検体によっては、p_filesize
やp_blocksize
をゼロパディングしている検体も存在します。
struct l_info // 12-byte trailer in header for loader (offset 116) { uint32_t l_checksum; uint32_t l_magic; // magic number = "UPX!" uint16_t l_lsize; uint8_t l_version; uint8_t l_format; }; struct p_info // 12-byte packed program header follows stub loader { uint32_t p_progid; uint32_t p_filesize; uint32_t p_blocksize; };
Mirai以外にもAnti-UPX Unpackingテクニックを使用するマルウェアは多数存在します。このテクニックは古くから利用されており、過去には、2014年頃に確認されたBoSSaBotでも同じテクニックが使用されていました。また、最近ではコインマイナーやマルウェアSBIDIOTなどにも使われていたことを確認しています。さらには、攻撃グループLazarusも同様のテクニックを使用することを確認しています。図2は、攻撃グループLazarusが使用するマルウェアELF_VSingleの一部です。マジックナンバーが"MEMS"に変更されていることが分かります。
Anti-UPX Unpackingバイナリのアンパック
Anti-UPX Unpackingテクニックが使われたバイナリは、通常のupxコマンドではアンパックすることはできません。ただし、これらのバイナリをアンパックすることは簡単です。通常、このテクニックが使用されたバイナリは、マジックナンバーであるUPX!
が変更されているだけの場合が多いため、変更されているマジックナンバーをUPX!
に置換するだけで、upxコマンドを使ってアンパックすることが可能になります。図3は、Anti-UPX Unpackingテクニックが使用されている検体のマジックナンバーをUPX!
に変換して、upxコマンドを使ってアンパックする例です。
なお、以下のGitHubレポジトリにupxコマンドをForkして、Anti-UPX Unpackingテクニックが使用されたバイナリをアンパックできる変更を加えたものを作成しましたので、ご利用ください。なお、Anti-UPX Unpackingテクニックが使用されたバイナリのアンパックに特化した変更を行っているため、それ以外の目的で使用する場合は、正常に動作しない可能性がありますので、ご注意ください。
JPCERTCC/upx-mod - GitHub https://github.com/JPCERTCC/upx-mod/releases/tag/v4.00-beta
Anti-UPX Unpackingテクニックの検知
このAnti-UPX Unpackingテクニックの検知は、バイナリの目視でも可能ですが、目視の場合は見逃す可能性もあります。そのため、YARAを使用して自動で検知することをお勧めします。以下は、Anti-UPX Unpackingテクニックを検知するYARAルールです。なお、本ルールで通常のUPXパックされたバイナリは検知しません。
rule upx_antiunpack_elf32 { meta: description = "Anti-UPX Unpacking technique to magic renamed for ELF32" author = "JPCERT/CC Incident Response Group" condition: uint32(0) == 0x464C457F and uint8(4) == 1 and ( ( for any magic in (uint32(filesize - 0x24)) : (magic == uint32(uint16(0x2C) * uint16(0x2A) + uint16(0x28) + 4)) and not for any magic in (0x21585055, 0) : (magic == uint32(uint16(0x2C) * uint16(0x2A) + uint16(0x28) + 4)) ) or ( for any magic in (uint32(filesize - 0x24)) : (magic == uint32(uint16be(0x2C) * uint16be(0x2A) + uint16be(0x28) + 4)) and not for any magic in (0x21585055, 0) : (magic == uint32(uint16be(0x2C) * uint16be(0x2A) + uint16be(0x28) + 4)) ) ) } rule upx_antiunpack_elf64 { meta: description = "Anti-UPX Unpacking technique to magic renamed for ELF64" author = "JPCERT/CC Incident Response Group" condition: uint32(0) == 0x464C457F and uint8(4) == 2 and ( ( for any magic in (uint32(filesize - 0x24)) : (magic == uint32(uint16(0x36) * uint16(0x38) + uint16(0x34) + 4)) and not for any magic in (0x21585055, 0) : (magic == uint32(uint16(0x36) * uint16(0x38) + uint16(0x34) + 4)) ) or ( for any magic in (uint32(filesize - 0x24)) : (magic == uint32(uint16be(0x36) * uint16be(0x38) + uint16be(0x34) + 4)) and not for any magic in (0x21585055, 0) : (magic == uint32(uint16be(0x36) * uint16be(0x38) + uint16be(0x34) + 4)) ) ) }
おわりに
Anti-UPX Unpackingテクニックを使用する攻撃者は、多数存在します。このテクニックを使った検体のアンパックは、容易なのですが、気づけないとアンパックに無駄な時間を費やしてしまうことになります。パッキングされたELFバイナリを分析する際は、まずAnti-UPX Unpackingテクニックが使用されていないかを確認することをお勧めします。
インシデントレスポンスグループ 朝長 秀誠