RADARCTF Writeup

この大会は2019/4/4 1:00(JST)~2019/4/5 1:00(JST)に開催されました。
今回もチームで参戦。結果は6752点で347チーム中11位でした。
自分で解けた問題をWriteupとして書いておきます。

Chars (Crypto 100)

大量のRの文字の中に斜めにBase64になりそうな文字が入っている。
取り出して、デコードする。

with open('flag.txt', 'r') as f:
    lines = f.readlines()

flag = ''
for i in range(len(lines)):
    flag += lines[i][i]

while True:
    if len(flag) % 8 == 0:
        break
    flag += '='

flag = flag.decode('base64')
print flag
radar{char_after_char_give_flag}

Random (Crypto, RE 400)

暗号の最後の数値から鍵を算出できる。それを使って復号する。

with open('flag.txt', 'r') as f:
    codes = map(int, f.read().split('.'))

key = int(chr(codes[-1] - 49))

flag = ''
for code in codes[:-1]:
    flag += chr(code + key)

print flag
radar{rand_is_not_good_idea_lol}

Unnatural (Crypto 50)

記号がたくさん入っているのを除くと、Base64になりそう。

with open('flag.txt', 'r') as f:
    enc = f.read()

b64_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

flag = ''
for i in range(len(enc)):
    if enc[i] in b64_chars:
        flag += enc[i]

while True:
    if len(flag) % 8 == 0:
        break
    flag += '='

flag = flag.decode('base64')
print flag
radar{unnatural_base64_bcz_bad_chars}

Logo (Misc 200)

TweakPNGで見ると、IHDRのチャンクがおかしいようだ。バイナリエディタで高さを高くすると、隠れていたところからフラグが現れた。
f:id:satou-y:20190410072036p:plain

radar{hidden_p4rt_looks_smart}

Ocean (Misc 200)

unknown.zipはパスワードがかかっているがわからないので、fcrackzipでクラックする。

$ fcrackzip -u -D -p dict/rockyou.txt unknown.zip 


PASSWORD FOUND!!!!: pw == loveyou
$ unzip -P loveyou unknown.zip 
Archive:  unknown.zip
  inflating: unknown

展開されたunknownは、KMLファイルだった。Google Mapにインポートすると、海上にフラグが浮かび上がった。
f:id:satou-y:20190410072211p:plain

RADAR{231337}

Scattered 1 (Programming 500)

1文字ずつの画像ファイルがたくさんあり、ファイル名に番号がついている。。base64になりそうなので、各文字の画像のmd5で判断し、プログラムする。その際、Iとlが区別付かないので調整する。

from hashlib import md5
import string

def get_hash(file):
    with open(file, 'rb') as f:
        data = f.read()
    return md5(data).hexdigest()

def replace_l(s, idx):
    return s[:idx] + 'l' + s[idx+1:]

id_list = [
    -1,  #A
    19,  #B
    18,  #C
    -1,  #D
    31,  #E
    51,  #F
    2,   #G
    114, #H
    27,  #I
    259, #J
    -1,  #K
    17,  #L
    499, #M
    59,  #N
    -1,  #O
    -1,  #P
    75,  #Q
    147, #R
    1,   #S
    378, #T
    23,  #U
    3,   #V
    10,  #W
    62,  #X
    9,   #Y
    25,  #Z
    13,  #a
    5,   #b
    185, #c
    11,  #d
    97,  #e
    -1,  #f
    8,   #g
    12,  #h
    56,  #i
    244, #j
    28,  #k
    -1,  #l
    94,  #m
    80,  #n
    496, #o
    87,  #p
    40,  #q
    364, #r
    4,   #s
    199, #t
    52,  #u
    36,  #v
    -1,  #w
    123, #x
    126, #y
    208, #z
    132, #0
    100, #1
    34,  #2
    22,  #3
    15,  #4
    20,  #5
    -1,  #6
    -1,  #7
    7,   #8
    35,  #9
]

chars = string.uppercase + string.lowercase + string.digits
char_hashes = {}
for i in range(len(id_list)):
    if id_list[i] != -1:
        file = 'Scattered/%d.jpg' % id_list[i]
        h = get_hash(file)
        char_hashes[h] = chars[i]

b64 = ''
for i in range(1, 577):
    file = 'Scattered/%d.jpg' % i
    h = get_hash(file)
    b64 += char_hashes[h]

b64 = replace_l(b64, 26)
b64 = replace_l(b64, 63)
b64 = replace_l(b64, 66)
b64 = replace_l(b64, 114)
b64 = replace_l(b64, 147)
b64 = replace_l(b64, 187)
b64 = replace_l(b64, 199)
b64 = replace_l(b64, 234)
b64 = replace_l(b64, 259)
b64 = replace_l(b64, 279)
b64 = replace_l(b64, 342)
b64 = replace_l(b64, 343)
b64 = replace_l(b64, 383)
b64 = replace_l(b64, 403)
b64 = replace_l(b64, 451)
b64 = replace_l(b64, 463)
b64 = replace_l(b64, 475)
b64 = replace_l(b64, 542)
b64 = replace_l(b64, 546)
b64 = replace_l(b64, 569)

flag = b64.decode('base64')
print flag

実行結果は以下の通り。

Hello again , you did a good job wow and because you did a good job and you can find your flag in the end of text , good luck and don't forget to take a rest and have a good night because you are good programmer and don't forget to submit the flag and yes yes I want to make the base64 very long because I want to create a lot of photos because the lazzy people finally this is your flag radar{programming_is_important_good_job_bro}
radar{programming_is_important_good_job_bro}

Puzzle (Web 250)

ソースを見ると、こう書いてある。

<!-- don't forget to remove /puzzle_code_file.zip -->

コードを入手する。

<html>
    <head>
        <title>Puzzle</title>
        <style>
            #main {
    height: 100vh;
}
        </style>
    </head>
    <body>
        <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<?php
$puzzle = $_SERVER['HTTP_USER_AGENT'];
if (is_numeric($puzzle)){
      if (strlen($puzzle) < 4){
          if ($puzzle > 10000){
                 echo ('<div class="d-flex justify-content-center align-items-center" id="main">
    <h1 class="mr-3 pr-3 align-top border-right inline-block align-content-center">Correct</h1>
    <div class="inline-block align-middle">
    	<h2 class="font-weight-normal lead" id="desc">radar{}</h2>
    </div>
</div>');
          } else {
                 echo ('<div class="d-flex justify-content-center align-items-center" id="main">
    <h1 class="mr-3 pr-3 align-top border-right inline-block align-content-center">Wrong</h1>
    <div class="inline-block align-middle">
    	<h2 class="font-weight-normal lead" id="desc">you solved 2 out 3</h2>
    </div>
</div>');
          }
      } else {
             echo ('<div class="d-flex justify-content-center align-items-center" id="main">
    <h1 class="mr-3 pr-3 align-top border-right inline-block align-content-center">Wrong</h1>
    <div class="inline-block align-middle">
    	<h2 class="font-weight-normal lead" id="desc">you solved 1 out 3</h2>
    </div>
</div>');
      }
} else {
    echo ('<div class="d-flex justify-content-center align-items-center" id="main">
    <h1 class="mr-3 pr-3 align-top border-right inline-block align-content-center">Wrong</h1>
    <div class="inline-block align-middle">
    	<h2 class="font-weight-normal lead" id="desc">you solved 0 out 3</h2>
    </div>
</div>');
}
?>

<!-- don't forget to remove /administrator_files.zip -->
    </body>
</html>

以下の条件を満たす必要あり。

・UserAgentは数字
・UserAgentは3桁以下
・UserAgenは10000より大きい

1e9にしたら、フラグが表示された。

radar{tricky_character_make_big_thing5}

Hawking (Misc 200)

$ steghide extract -sf SH.jpg 
Enter passphrase: ★hawkingを指定
wrote extracted data to "radar.txt".
$ cat radar.txt 
radar{h4wking_revealed_a_lot_of_secrets}
radar{h4wking_revealed_a_lot_of_secrets}

RadarEncrypt (Crypto, RE 300)

$ file RadarEncrypt.exe 
RadarEncrypt.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

ILSpyでデコンパイルする。

        :
		public object encode(string pattern, string plaintext)
		{
			checked
			{
				try
				{
					bool flag = Conversions.ToBoolean(Operators.NotObject(this.checkSame(pattern, plaintext)));
					if (flag)
					{
						Interaction.MsgBox("You should include all the your string characters in the pattern", MsgBoxStyle.OkOnly, null);
					}
					else
					{
						string text = plaintext;
						int arg_38_0 = 0;
						int num = plaintext.Length - 1;
						int num2 = arg_38_0;
						while (true)
						{
							int arg_79_0 = num2;
							int num3 = num;
							if (arg_79_0 > num3)
							{
								break;
							}
							text = Strings.Replace(text, Conversions.ToString(plaintext[num2]), Conversions.ToString(pattern.IndexOf(plaintext[num2])) + ":", 1, 1, CompareMethod.Binary);
							num2++;
						}
						this.TextBox3.Text = text;
					}
				}
				catch (Exception expr_8A)
				{
					ProjectData.SetProjectError(expr_8A);
					ProjectData.ClearProjectError();
				}
				object result;
				return result;
			}
		}
        :

暗号はpatternのインデックスを表していることを使って、復号する。

with open('flag.txt', 'r') as f:
    idxes = map(int, f.read().split(':')[:-1])

pattern = '{qwertyuiopas_dfghjklzxcvbnm}'

flag = ''
for idx in idxes:
    flag += pattern[idx]

print flag
radar{index_of_make_small_cryptor}

EasyZip (Misc 50)

$ zip2john EasyZip.zip > hash.txt
ver 2.0 efh 9901 EasyZip.zip/flag.txt PKZIP Encr: cmplen=56, decmplen=28, crc=94113DF
$ john --wordlist=dict/rockyou.txt hash.txt --rules
Using default input encoding: UTF-8
Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 128/128 AVX 4x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
saudi            (EasyZip.zip/flag.txt)
1g 0:00:02:07 DONE (2019-04-04 20:12) 0.007841g/s 1686p/s 1686c/s 1686C/s sexysis..pakala
Use the "--show" option to display all of the cracked passwords reliably
Session completed
$ john --show hash.txt 
EasyZip.zip/flag.txt:saudi:flag.txt:EasyZip.zip:EasyZip.zip

1 password hash cracked, 0 left

パスワードsaudiで解凍する。展開されたflag.txtにフラグが書いてある。

radar{easy_fl4g_in_e4sy_zip}

EasyCrypto (Crypto 50)

スペース区切りで2進数が並んでいる。末尾が必ず0になっているので、逆になっていると推測。デコードする。

with open('EasyCrypto.txt', 'r') as f:
    enc = f.read()

enc = enc[::-1].split(' ')

flag = ''
for e in enc:
    flag += chr(int(e, 2))

print flag
radar{ea5y_binaries_giv3_easy_fl4g}

EasyWeb (Web 50)

ソースを見ると、次のようなコメントが書いてある。

<!-- index.php?secretword= -->

secretwordにいろいろ文字列を指定することを試してみる。
http://blackfoxs.org/radar/easyweb/index.php?secretword=radarにアクセスすると、フラグが表示された。

radar{e4zy_w3b_true_m0ve_on}

RSA (Crypto 700)

nをfactordbで素因数分解する。

7576962585305391589 = 2045145391 * 3704852779

各行について復号すると、6桁の数字が並んでいる。2桁ずつ切って文字にしていくと、Base32になるので、デコードする。ASCIIコードがスペース区切りに並んでいるので、文字にしていく。

from Crypto.Util.number import inverse
import base64

with open('RSA.txt', 'r') as f:
    lines = f.readlines()

n = int(lines[0].strip().split('=')[1])
p = 2045145391
q = 3704852779
assert n == p * q

e = int(lines[2].strip().split('=')[1])

c_list = map(int, lines[4:])

phi = (p - 1) * (q - 1)
d = inverse(e, phi)

b32 = ''
for c in c_list:
    m = pow(c, d, n)
    s = str(m)
    for i in range(0, len(s), 2):
        b32 += chr(int(s[i:i+2]))

codes = base64.b32decode(b32)
codes = map(int, codes.split(' '))

flag = ''
for code in codes:
    flag += chr(code)

print flag
radar{factor1ng_c@n_cr@ck_rsa}

EasyReverse (RE 80)

$ file EasyReverse.exe 
EasyReverse.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

ILSpyで開く。

namespace WindowsApplication20
{

                 :

	public class Form1 : Form

                 :

		public object flag()
		{
			string text = "radar";
			string text2 = "{";
			string text3 = "}";
			string text4 = "_";
			string text5 = "flagino";
			string text6 = "flago";
			string text7 = string.Concat(new string[]
			{
				text,
				text2,
				text5,
				text4,
				text6,
				text4,
				text6,
				text3
			});
			return string.Concat(new string[]
			{
				text,
				text2,
				text5,
				text6,
				text3
			});
		}

text7がフラグだった。

radar{flagino_flago_flago}

Black (Misc 200)

Stegsolveで開き、Red plane 1を見ると、フラグが出てきた。
f:id:satou-y:20190410212225p:plain

radar{reverse_color_give_flag}

Unzip (Misc 250)

zipの先頭10バイトが2バイト単位で逆になっているので直してみるが、パスワードがかかっている。

$ zip2john flag_fix.zip > hash.txt
ver 2.0 efh 9901 flag_fix.zip/flag.txt PKZIP Encr: cmplen=62, decmplen=32, crc=985EE9BE
$ john --wordlist=dict/rockyou.txt hash.txt --rules
Using default input encoding: UTF-8
Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 128/128 AVX 4x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
root             (flag_fix.zip/flag.txt)
1g 0:00:01:43 DONE (2019-04-04 22:31) 0.009633g/s 7773p/s 7773c/s 7773C/s ruru12..room1234
Use the "--show" option to display all of the cracked passwords reliably
Session completed
$ john --show hash.txt
flag_fix.zip/flag.txt:root:flag.txt:flag_fix.zip:flag_fix.zip

1 password hash cracked, 0 left

パスワードrootで解凍する。展開されたflag.txtにフラグが書いてある。

radar{offest_is_v3ry_imp0rtantx}

その他

Rulesページにフラグがあった。(50pt)

radar{i_love_read_rules_because_im_good}

Giftのページにフラグがあった。(60pt)

radar{3njoy}

Hintsに書いてあったメールアドレス(radarctf@gmail.com)にメール送ったら、返信メールにフラグが書いてあった。(75pt)

radar{thanks_for_messaging_me}

Hintsなどのページにフラグが分断されて書いてあった。(1337pt)

radar{the_big_secret_is_you}