picoCTF 2017 writeup

# はじめに
2017.3.31 - 4.14の期間で、初心者向けCTFで有名(?)なpico ctfにチャレンジしてみたので、そのwriteup。基本的には自分のメモ用。

かなりCTFビギナーなので、LEVEL1を全部解くのを目標にしてたけど、ダメだった。(仕事が忙しかったと、言い訳だけしとくw)

# Tutorial 

### Tutorial 1

問題文:
How can you figure out Robin Morris's middle name? Thankfully you have a list you can check!

hint: Please don't search by hand!


"contractors.txt"というファイルを渡される。
中身は名簿になっているので、"Robin Morris"さんを"Robin"や"Moris"で検索して、ミドルネーム付きのフルネームをflagとしてsubmitする。

flag: Robin Almay Morris

### Tutorial 2

問題文:
Robin handed me this the other day. Maybe it will help me find the answer?

HINTS: 
There are a number of solvers on the internet that can help!

"message.txt"が渡される。
このファイルに、ROT13がどうのこうのって書いてあるので、ROT13で復号するだけ。
私は以前にCeaser暗号を全パターン(26パターン)を復号(これを復号と読んでいいのか微妙だが、、)するスクリプトをPythonで書いてたので、それを流用した。

```py:caesar.py
#!/usr/bin/env python
# coding: utf-8
import string

def encoder(crypt_str, shift):
    crypt_list = list(crypt_str)
    plain_str = ""
    num = int(shift)
    for ch in crypt_list:
        ch = ord(ch)
        if ord('a') <= ch and ch <= ord('z'):
            ch = ch + num
            if ch > ord('z'):
                ch -= 26
        if ord('A') <= ch and ch <= ord('Z'):
            ch = ch + num
            if ch > ord('Z'):
                ch -= 26
        a = chr(ch)
        plain_str += a
        
    print (plain_str)

crypt_str = raw_input("Crypto text: ")
#shift = raw_input("Shift?: ")
print "!----- decode -----!"
for shift in range(26):
    encoder(crypt_str, shift)
```

これを使って復号し、flagをゲット。

flag: Inflatable Sloth Monster


### Tutorial 3

問題文:
Robin handed me some color codes the other day. They don't look like anything to me though. Can you help me find her favorite shade of red?

HINTS
Once again, there are tools on the interwebz that can help! (There's a clear theme here, from the easiest pico problems, to the hardest ones in other CTFs, search engines are your friend!)

"codes.txt"というファイルが渡され、中に以下が記載されている。

```txt:codes.txt
These are a few of my favorite things!

7A3B00
6000C7
67C700
42FFFC
C70002
0003C7
007A78
```

16進数で記載されているよく分からない文字列はカラーコードになっている。
2桁ごとにそれぞれ、"red","green","blue"をさしている。

```:カラーコード
red  green  blue
----------------
7a   3b     00
60   00     c7
67   c7     00
42   ff     fc
c7   00     02
00   03     c7
00   7a     78
```

見やすくするとこんな感じになる。
この中で一番、赤に近いカラーコードをflagとしてsubmitする。

flag: C70002


# LEVEL 1


## WEB-EXPLOITATION

### What Is Web

問題文:
Someone told me that some guy came up with the "World Wide Web", using "HTML" and "stuff". Can you help me figure out what that is? Website.

HINTS:
How can you figure out how the webpage is actually built?
[sume guy](https://en.wikipedia.org/wiki/Tim_Berners-Lee)
[website](http://shell2017.picoctf.com:52334/)

とあるサイトのURLだけ渡される。
そこにアクセスすると、特に怪しい部分はないので、そのサイトのソースファイルを見てみる。

```html:index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<link rel="stylesheet" type="text/css" href="hacker.css">
</head>
<body>

HI MOM! LOOK WHAT I MADE!

<h1>I used some tags.</h1>
<p>More tags!</p>
<h3>I typed here.</h3>

This is my cat. He is nice.
<br><br>
<img src="./cat.jpg" alt="Cat" /img>

<button type="button" onclick="sayHI()"> Click me to say hello!</button>

<script src="script.js"></script>

</body>
</html>

<!-- Cool! Look at me! This is an HTML file. It describes what each page contains in a format your browser can understand. -->
<!-- The first part of the flag (there are 3 parts) is fab79c49d9e -->
<!-- What other types of files are there in a webpage? -->
```

上記html下部のコメントにflagは3つに分かれていることと、最初のflagが読み取れる。

となると、他にflagがありそうな怪しい部分は、CSSに使っている"hacker.css"と"script.js"、それともしかしたら、"cat.jpg"にもあるかもしれない。。。
とりあえずこの3つのどれかにhtmlと同じ感じで、flagがありそうなので、調べてみる。

結論をいうと、"cat.jpg"には何もなかった。
jheder?とstringsで何か情報がないか確認したけど、何もなし。

"hacker.css"を見てみると、ファイル上部のコメントに2つ目のflagが記載されている。
また、"script.js"も同様にファイル上部に3つ目のflagが記載されている。
これで後は、全部のflagを順番通りに繋げてsubmitするだけ。

flag: fab79c49d9e5ba511a0f2436308e33e85

## FORENSICS

### Digital Camouflage

問題文:
We need to gain access to some routers. Let's try and see if we can find the password in the captured network data: data.pcap.

HINTS
It looks like someone logged in with their password earlier. Where would log in data be located in a network capture?
If you think you found the flag, but it doesn't work, consider that the data may be encrypted.

"data.pcap"を渡されるので、それを解析してflagを手に入れる。
やっときたぜ、みんな大好きぃ Wireshark！

問題文をみると、routerにログインするためのパスワードがflagになっているっぽい。
routerにログインって時点で、ciscoルータとかにtelnetログインでもしてるのかと思いきや、全く違った。
httpでログインしていた。ciscoじゃねーのかい。

とりあえず、httpパケットでフィルターして、user/passwordを送っているパケットを見つけて終わり。
と、思いきや、passwordをそのままsubmitしても弾かれる。
問題文にpasswordは暗号化してるって記載があるので、復号する必要がある。

この辺りはあまり詳しくないので、user/passwordを送っているパケットをもっと詳しく見てみると、
content-typeに"x-www-form-urlencoded\r\n"となっている。
これを調べてみると、どうやらbase64urlとやらでencodeしているっぽい(以下抜粋)

> HTTPのPOSTメソッドでWebフォームの文字列を送信する場合に、文字列はエンコードして送信される。
その際の符号化方法はMIMEのContent-Typeがapplication/x-www-form-urlencodedで指定される。
この符号化方法はRFC1866のSection-8.2.1で定義されている。
この符号化方法をURLエンコードと言うことがある。
application/x-www-form-urlencodedでは、半角スペース（ASCIIコード 20）は「+」に変換される。
このため、バイナリデータをBase64経由で直接POSTすることはできず、下記の手順でBase64Urlに変換してPOSTする必要がある。
BASE64でテキスト化
"+"を"-"に置換
"/"を"_"に置換
POSTでデータを送信
"-"を"+"に置換
"_"を"/"に置換
BASE64でバイナリに戻す
また、複数のフォーム項目を送信する場合、各項目は「&」（アンパサンド）区切りで送信される。

つまり、単純にdecodeするスクリプトを書けばよさそう。
(書く程の内容じゃない気もするけど、普段あまりコードを書かないので、練習。)

```py:base64url-decoder.py
#coding:utf-8

import base64
import sys

before = sys.argv[1]
print "before: " + (before)

after = base64.urlsafe_b64decode(before)
print "after: " + after
```

これを実行して、decodeされたpasswordをflagとしてsubmit。

flag: hrKQSSLWvG

以下、参考サイト
http://yut.hatenablog.com/entry/20110825/1314228258
https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0


### Spesial Agent User

問題文:
We can get into the Administrator's computer with a browser exploit. But first, we need to figure out what browser they're using. Perhaps this information is located in a network packet capture we took: data.pcap. Enter the browser and version as "BrowserName BrowserVersion". NOTE: We're just looking for up to 3 levels of subversions for the browser version (ie. Version 1.2.3 for Version 1.2.3.4) and ignore any 0th subversions (ie. 1.2 for 1.2.0)

HINTS
Where can we find information on the browser in networking data? Maybe try reading up on user-agent strings.

"reading up on user-agent strings." http://www.useragentstring.com./


これもWiresahrk！
問題文からブラウザのバージョンがflagになってるっぽいので、
渡された"data.pcap"をhttpでフィルターして、GETメソッドを送っているパケットのUser-Agentを全部みる。(6個くらいしかない)
すると、殆んどがwgetなのに対して、1つだけChromeになってるのがあるので、それのバージョンをflagとしてsubmitする。

flag: 36.0.1985.67


## CRYPTOGRAPHY

今回、最も全然できなかった。
自分がどの分野が苦手かよくわかったので、今回のCTFはすごい今後のためになったと思う。

### keyz
問題文:
While webshells are nice, it'd be nice to be able to login directly. To do so, please add your own public key to ~/.ssh/authorized_keys, using the webshell. Make sure to copy it correctly! The key is in the ssh banner, displayed when you login remotely with ssh, to shell2017.picoctf.com

HINTS:
There are plenty of tutorials out there. This one covers key generation: https://confluence.atlassian.com/bitbucketserver/creating-ssh-keys-776639788.html
Then, use the web shell to copy/paste it, and use the appropriate tool to ssh to the server using your key

今回、初のよく分からないwebshellを使う問題。(別に使わなくてもできるけど。。。)

sshについてもっと勉強しなきゃ。。。
とりあえず、以下の手順でできた。

```bash:
$ cd ~/.ssh
$ ssh-keygen -t rsa -C shell2017.picoctf.com
$ cat id_rsa.pub > authorized_keys
$ ssh shell2017.picoctf.com                                       
Congratulations on setting up SSH key authentication!
Here is your flag: who_needs_pwords_anyways
$ 
```

要は、"shell2017.picoctf.com"に接続するためのRSAキーを作成するってだけ。なのかな？自分の理解が足りてない気がする。

flag: who_needs_pwords_anyways

## REVERSE ENGINEERING

### Hex2Raw

問題文:
This program requires some unprintable characters as input... But how do you print unprintable characters? CLI yourself to /problems/3ccd1ebb34d4cf595d1229d95aded6e8 and turn that Hex2Raw!

HINTS:
Google for easy techniques of getting raw output to command line. In this case, you should be looking for an easy solution.

hex2rawというelfを実行してflagを手に入れる問題。
hex2rawを動かすと"4991deeab0c6a24f0d364b51220e1911"という値が表示されるので、これをデコードすると同ディレクトリ内の"flag.txt"に記載されていると思われるflagを表示してくれる。

"4991deeab0c6a24f0d364b51220e1911"の値はASCIIコード(だったはず)なので、"4991deeab0c6a24f0d364b51220e1911"にあたる文字をキーボードで打ちたいけど、"91"とかの値をキーボードで打てないため、Pythonで無理やりデコードした値をhex2rawに渡してやる必要がある。

```bash:
$ ./hex2raw <<< `python -c "print '4991deeab0c6a24f0d364b51220e1911'.decode('hex')"`
```

こういうのをワンライナーと呼ぶのかな。
個人的には、coolに決めてやったぜ!って感じになってるw

flag: 3105ed66a9863242e30abd4acd3271ae


### Raw2Hex

問題文:
This program just prints a flag in raw form. All we need to do is convert the output to hex and we have it! CLI yourself to /problems/40b1e663252261e8203962486523629e and turn that Raw2Hex!

HINTS:
Google is always very helpful in these circumstances. In this case, you should be looking for an easy solution.


問題名から見るに、さっきの逆かな？

raw2hexを動かすとさっきとは逆で"The Flag is:"に続いて文字列が表示される(ただし、ASCIIコードがめちゃくちゃなので、文字化けする)
この文字化けしてる文字列のhex(16進数)がflagっぽいので、ASCIIコード->hex(16進数)へ変換する必要がある。

以下が、ASCIIコード->hex(16進数)へ変換するためのスクリプト

```py:hex-encode.py
#coding:utf-8

import sys

raw1 = sys.argv[1]
strings = raw1.encode("hex")
print strings

a = len(sys.argv)
if a != 2:
        strings1 = strings.decode("hex")
        print strings1
```

次に文字列を取得したいが、raw2hexをそのまま実行すると、"The flag is:"の文字列が邪魔なので、以下手順で除去する

```bash:
$ ./raw2hex > ~/raw2hex.txt
$ vi ~/raw2hex.txt # かっこわるいけど、手で邪魔な部分を削除するw
```

これで準備は整ったので、以下を実行し、flagをsubmitする。

```bash:
$ python hex-encode.py `cat ~/raw2hex.txt`
71c28db77578a80e38aae0d626d853a5
$ 
```

flag: 71c28db77578a80e38aae0d626d853a5


## BINARY EXPLOITATION

### Bash Loop

問題文:
We found a program that is hiding a flag but requires you to guess the number it is thinking of. Chances are Linux has an easy way to try all the numbers... Go to /problems/995871fcb203d3e223e9e4aaa65e4053 and try it out!

HINTS:
Either use SSH or use the Web Shell to get onto the shell server and navigate to the correct directory. Then do a quick Google search on 'bash loops'. You may need to use grep to filter out the responses as well!


"bashloop"とやらを実行すると、実行時の引数に0-4096の範囲で数字を指定しろって怒られ、適当な数字を指定すると、間違っているって言われる。
この動作から推測するに、0-4096の範囲の中に1つだけ正しい数字があって、それを指定した時だけflagが表示されそう。
どの数字が正しいか分からないので4097パターン全て試す必要がありそう。
これを手で動かすのは面倒なので、自動的にやりたい。

```bash:
$ for i in {0..4096}; do com="./bashloop"; eval $com $i; done;
```

Pythonでどうやるか思い当たらなかった(というより、面倒くさそうだったので、、、)bashを使ったけど、
初めてbashをまともに使った気がする。。。
ただ、webshellでやると、flagが画面から流れちゃうので、flagが出てきたタイミングで"ctrl+c"で中断する必要がある。
次はもっとcoolなやり方を目指そう。。。

flag: 5cabdea71dd5f428c8e080db5010a7d6


#### 2017.12.25 追記
以下でフラグだけを出力させることができる。
こうやればgrep使えたんだね。

```:bash
$ bash -c 'for i in {0..4096}; do com="./bashloop"; eval $com $i; done;' | grep flag
```


### Just No

問題文:
A program at /problems/f934d9ca116fb6e3e89cc85baaca028c has access to a flag but refuses to share it. Can you convince it otherwise?

HINTS:
Check out the difference between relative and absolute paths and see if you can figure out how to use them to solve this challenge. Could you possibly spoof another auth file it looks at instead...?

```c:justno.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char **argv){ 
  FILE* authf = fopen("../../problems/f934d9ca116fb6e3e89cc85baaca028c/aut
h","r"); //access auth file in ../../../problems/f934d9ca116fb6e3e89cc85ba
aca028c
  if(authf == NULL){
    printf("could not find auth file in ../../problems/f934d9ca116fb6e3e89
cc85baaca028c/\n");
    return 0;
  }
  char auth[8];
  fgets(auth,8,authf);
  fclose(authf);
  if(strcmp(auth,"no")!=0){
    FILE* flagf;
    flagf = fopen("/problems/f934d9ca116fb6e3e89cc85baaca028c/flag","r");
    char flag[64];
    fgets(flag,64,flagf);
    printf("Oh. Well the auth file doesn't say no anymore so... Here's the
 flag: %s",flag);
    fclose(flagf);
  }else{
    printf("auth file says no. So no. Just... no.\n");                    
  }                                                                       
  return 0;
```

相対パスと絶対パスの違いをちゃんと理解しているかを問われる問題。いい問題な気がする。
前提として、problems配下はjustnoのelfの実行権とjustno.cの読み込み権以外は基本的に許可されていない。
flagが記載されていると思われる"flag"ファイルを表示させるにはauthファイルに"no"が記載されていないことが条件になっているので、authファイルを編集したいが、書き込み権がない。

しかし、justno.cでauthファイルは**相対パス**で指定されているので、自分の権限のあるディレクトリ配下で同じディレクトリ構造を作り、"no"以外の文字列を記入した偽のauthファイルを作る。
そのディレクトリからjustnoを実行すれば、flagファイルの中身を出力してくれる。

```bash:
$ cd
$ mkdir aaa
$ cd aaa
$ mkdir bbb
$ cd bbb
$ mkdir problems
$ cd problems
$ mkdir f934d9ca116fb6e3e89cc85baaca028c
$ cd f934d9ca116fb6e3e89cc85baaca028c
$ echo "AAAAA" > auth
$ /problems/f934d9ca116fb6e3e89cc85baaca028c/justno
```

flag: 忘れちゃいました。。。


## MISC

### Internet Kitties

問題文:
I was told there was something at IP shell2017.picoctf.com with port 53382. How do I get there? Do I need a ship for the port?

HINTS:
Look at using the netcat (nc) command!
To figure out how to use it, you can run "man nc" or "nc -h" on the shell, or search for it on the interwebz


問題文で指定されている、"shell2017.picoctf.com"に53382ポート指定で接続してあげるだけ。
hintに記載されているように、netcatを使用。

```bash:
$ nc shell2017.picoctf.com 53382
```

flag:e7791aeada4dcc5dd89a0023f4f8bbce