Learning cyber security by playing and enjoying CTFs

Cyber Security関係の雑記帳です。表明されているお気持ちなどは全て個人的なものであり、筆者が所属もしくは関係する組織・団体の意向とは一切関係ありません。

TsukuCTF 2023 Writeup (by team N30Z30N)

1. はじめに

 2023/12/09(土)12:20 JST ~ 12/10(日)18:00 JST に開催された「TsukuCTF 2023」にチーム N30Z30N*1で参加しました。

ctftime.org

 結果は、22 問を解いて 6298 pts、51st でした。ソロ参加の CTF では大抵 Crypto(たまに Rev )中心にやっていて、チームプレイの場合*2 でもOSINT や Web は他のメンバーに任せているので、OSINT 問題を解くこと自体が久しぶりで楽しむことができました。

2. Writeup(Pickup)

 ここでは、解く過程に何がしかの "面白要素" があった 4 問をピックアップして紹介します。

2.1. new_cipher_scheme(crypto, 491pts, 31solves)

設問

以下のスクリプトと出力結果が与えられます。

「problem.py」

from Crypto.Util.number import *
from flag import flag


def magic2(a):
    sum = 0
    for i in range(a):
        sum += i * 2 + 1
    return sum


def magic(p, q, r):
    x = p + q
    for i in range(3):
        x = magic2(x)
    return x % r


m = bytes_to_long(flag.encode())
p = getPrime(512)
q = getPrime(512)
r = getPrime(1024)
n = p * q
e = 65537
c = pow(m, e, n)
s = magic(p, q, r)
print("r:", r)
print("n:", n)
print("e:", e)
print("c:", c)
print("s:", s)

「output.py」

r = 103223593878323616966427038558164830926502672938304332798494105455624811850665520007232855349275322661436610278579342219045141961390918581096853786570821153558254045159535424052709695034827346813080563034864500825268678590931984539859870234179994586959855078548304376995608256368401270715737193311910694875689
n = 90521376653923821958506872761083900256851127935359160710837379527192460953892753506429215845453212892652253605621731883413509776201057002264429057442656548984456115251090306646791059258375402999471135320210755348861434045380328105743420902906907790808856692202001235875364637226136825102255804354305482559609
e = 65537
c = 39668573485152693308506976557973651059962715190609831067529475947235507499262380684639847018675763554013384459402806860854682788726216001229367497152996318350435451964626471390994912819484930957099855090471916842543402636518804720798852670908465424119746453269056516567591615005540824659735238630769424838121
s = 47973982866708538282860872778400091099562248899259778360037347668440286307912908903978215839469425552581036546347166946878631770320447658019243172948791127890920650587484602734465156455346574205060576092006378013418405134156752490431761037178223087071698840062913540185985867322265081768252745826955229941850

検討

 「TsukuCTF だけど Crypto が出てる、しかも好物の RSA 問!」とばかりに、welcome 問を差し置いて早速に着手しました。

 magic2 が「平方」を行う関数であることが(実際に試してみてすぐ)分かったので、もうほぼ解けたようなものです。

 magic の中では p+q に対してmagic2 を 3度適用しているので、「(p+q)**8 mod r」が計算されるということになります。

 つまり、GF(r) の中で s の 8 乗根を計算すれば p + q (の候補が 8 つ)が判明し、(総当たりすれば)p,q を求め復号することができます。

解法

 検討したことをそのまま SageMath で実行するだけなのですが、8 乗根の計算をするところ(11行目)で止まってしまい泡を食いました。痛恨!

 急ぐあまり、予め立ち上げていた SageMath 9.3(Windows版)を使ったのが失敗の元。横着せず WSL に仕込んだ 10.2 を使っていればすんなり解けていたのでした。懺悔。

↓通すはずだったソルバ「solve.sage」

from Crypto.Util.number import  *
import gmpy2

r = 103223593878323616966427038558164830926502672938304332798494105455624811850665520007232855349275322661436610278579342219045141961390918581096853786570821153558254045159535424052709695034827346813080563034864500825268678590931984539859870234179994586959855078548304376995608256368401270715737193311910694875689
n = 90521376653923821958506872761083900256851127935359160710837379527192460953892753506429215845453212892652253605621731883413509776201057002264429057442656548984456115251090306646791059258375402999471135320210755348861434045380328105743420902906907790808856692202001235875364637226136825102255804354305482559609
e = 65537
c = 39668573485152693308506976557973651059962715190609831067529475947235507499262380684639847018675763554013384459402806860854682788726216001229367497152996318350435451964626471390994912819484930957099855090471916842543402636518804720798852670908465424119746453269056516567591615005540824659735238630769424838121
s = 47973982866708538282860872778400091099562248899259778360037347668440286307912908903978215839469425552581036546347166946878631770320447658019243172948791127890920650587484602734465156455346574205060576092006378013418405134156752490431761037178223087071698840062913540185985867322265081768252745826955229941850

F = GF(r)
ts = F(s).nth_root(8, all=True)

for t in ts:
  D = int(t**2 - 4*n)
  sqrt_D = int(gmpy2.isqrt(D))
  p = int((t + sqrt_D)//2)
  q = int((t - sqrt_D)//2)
  if isPrime(p) and isPrime(q):
    phi = (p-1)*(q-1)
    d = inverse(e, phi)
    print(long_to_bytes(int(pow(c,d,n))))

↓実際に使ったソルバ「solve2.sage」*3

from Crypto.Util.number import  *
import gmpy2

r = 103223593878323616966427038558164830926502672938304332798494105455624811850665520007232855349275322661436610278579342219045141961390918581096853786570821153558254045159535424052709695034827346813080563034864500825268678590931984539859870234179994586959855078548304376995608256368401270715737193311910694875689
n = 90521376653923821958506872761083900256851127935359160710837379527192460953892753506429215845453212892652253605621731883413509776201057002264429057442656548984456115251090306646791059258375402999471135320210755348861434045380328105743420902906907790808856692202001235875364637226136825102255804354305482559609
e = 65537
c = 39668573485152693308506976557973651059962715190609831067529475947235507499262380684639847018675763554013384459402806860854682788726216001229367497152996318350435451964626471390994912819484930957099855090471916842543402636518804720798852670908465424119746453269056516567591615005540824659735238630769424838121
s = 47973982866708538282860872778400091099562248899259778360037347668440286307912908903978215839469425552581036546347166946878631770320447658019243172948791127890920650587484602734465156455346574205060576092006378013418405134156752490431761037178223087071698840062913540185985867322265081768252745826955229941850

F = GF(r)
t1 = F(s).sqrt()

t1s = [t1, -t1]
t2s = []
ts = []

for t in t1s:
  t2 = F(t).sqrt()
  t2s.append(t2)
  t2s.append(-t2)

for t in t2s:
  t3 = F(t).sqrt()
  ts.append(t3)
  ts.append(-t3)

for t in ts:
  D = int(t**2 - 4*n)
  sqrt_D = int(gmpy2.isqrt(D))
  p = int((t + sqrt_D)//2)
  q = int((t - sqrt_D)//2)
  if isPrime(p) and isPrime(q):
    phi = (p-1)*(q-1)
    d = inverse(e, phi)
    print(long_to_bytes(int(pow(c,d,n))))

フラグ

TsukuCTF23{Welcome_to_crypto!}

 ちなみに、3rd blood でした。welcome 問蹴ってこの有様です。当人はともかく、傍から見たら「面白い」ですよね…

2.2. title_screen(rev, 487pts, 38solves)

設問

 以下の 3 ファイルが与えられます。「プログラムで、起動時にタイトルに表示される文字」が答えとなります。

「character.bmp

「main.asm」

.setcpu        "6502"
.autoimport   on

PPU_ADDR1    =   $0001
PPU_ADDR2    =   $0002

PPU_STATUS   =   $2002

.segment "HEADER"
    .byte $4E, $45, $53, $1A
    .byte $02
    .byte $01
    .byte $01
    .byte $00
    .byte $00, $00, $00, $00
    .byte $00, $00, $00, $00

.segment "STARTUP"
.proc Reset
    sei
    ldx #$ff
    txs
    clc
    cld
    
    lda #$00
    sta $2000
    sta $2001
    sta $2005
    sta $2006
    
    lda $4015
    and #%11111110
    sta $4015

    lda PPU_STATUS
    lda #$00
    sta $2000
    sta $2001

    lda #$00
    ldx #$00

clear_memory:
    sta $0000, X
    sta $0100, X
    sta $0200, X
    sta $0300, X
    sta $0400, X
    sta $0500, X
    sta $0600, X
    sta $0700, X
    inx
    cpx #$00
    bne clear_memory

    lda #$20
    sta $2006
    lda #$00
    sta $2006
    lda #$00
    ldx #$00
    ldy #$04

clear_vram_loop:
    sta $2007
    inx
    bne clear_vram_loop
    dey
    bne clear_vram_loop

    lda  #$3F
    sta  $2006
    lda  #$00
    sta  $2006
    ldx  #$00
    ldy  #$10

setpal:
    lda  palettes, x
    sta  $2007
    inx
    dey
    bne  setpal
    
    lda  #$20
    sta  $2006
    lda  #$00
    sta  $2006

    ldy #0
    jsr set_row

    jmp mapping1

mapping1:
    ldy  #11
    ldx  #$00
    lda  #$8c
mapping1_y_loop:
    jsr set_row
    ldx #05
    jsr set_col
    ldx #$14
mapping1_x_loop:
    sta  $2007
    dex
    bne  mapping1_x_loop

    iny
    cpy #16
    bne mapping1_y_loop


mapping2:
    ldy  #13
    jsr set_row
    ldx #08
    jsr set_col
    ldx #00
    ldy #14
mapping2_x_loop:
    lda  data, x
    sta  $2007
    inx
    dey
    bne  mapping2_x_loop


screenend:
    lda  #$00
    sta  $2005
    sta  $2005

    lda  #$08
    sta  $2000
    lda  #$1e
    sta  $2001

loop:
    jmp  loop

set_row:
    pha

    tya
    lsr a
    lsr a
    lsr a
    clc
    adc #$20
    sta  PPU_ADDR1

    tya
    asl a
    asl a
    asl a
    asl a
    asl a
    sta  PPU_ADDR2

    lda  PPU_ADDR1
    sta  $2006
    lda  PPU_ADDR2
    sta  $2006

    pla
    rts

set_col:
    pha

    txa
    adc PPU_ADDR2
    sta  PPU_ADDR2

    lda  PPU_ADDR1
    sta  $2006
    lda  PPU_ADDR2
    sta  $2006

    pla
    rts

.endproc

palettes:
    .byte $01, $18, $39, $30
    .byte $0f, $06, $16, $26
    .byte $0f, $08, $18, $28
    .byte $0f, $0a, $1a, $2a

data:
    .byte $22, $a4, $39, $26, $39
    .byte $a4, $55, $79, $bb, $4c
    .byte $39, $c7, $a4, $d1, $8c

.segment "VECINFO"
    .word $0000
    .word Reset
    .word $0000

.segment "CHARS"
    .incbin "character.chr"

「main.cfg」

MEMORY {
    HEADER:       start = $0000, size = $0010, file = %O, fill = yes;
    ROMST:        start = $8000, size = $7ffa, type = ro, file = %O, fill = yes, define = yes;
    ROMINFO:      start = $fffa, size = $0006, type = ro, file = %O, fill = yes, define = yes;
    ROMCHR:       start = $0000, size = $2000, type = rw, define = yes;

}

SEGMENTS {
    HEADER:       load = HEADER,       type = ro;
    STARTUP:      load = ROMST,        type = ro,    define = yes;
    VECINFO:      load = ROMINFO,      type = ro,    define = yes;
    CHARS:        load = ROMCHR,       type = rw;
}

FEATURES {
    CONDES: segment = RODATA,
        type = constructor,
        label = __CONSTRUCTOR_TABLE__,
        count = __CONSTRUCTOR_COUNT__;
    CONDES: segment = RODATA,
        type = destructor,
        label = __DESTRUCTOR_TABLE__,
        count = __DESTRUCTOR_COUNT__;
}

検討

 まともに動かそうとすると大変そうなのですが、

data:
    .byte   $22, $a4, $39, $26, $39
    .byte   $a4, $55, $79, $bb, $4c
    .byte   $39, $c7, $a4, $d1, $8c

のあたり、何か匂います。ヒントで「キャラクターは8x8ピクセルを1ブロックとして並べられます。」とあることから、この値がブロックの位置を示すのではないか、と Guess します。*4

解法

 とりあえず、上の Guess を確かめるべく画像を順番に切り出して、名前を付けて保存するプログラムを作成してみます。*5

「solve.py」

import cv2
import numpy as np

img = cv2.imread('character.bmp')
H_MAX = 128
W_MAX = 128
CELL_SIZE = 8
cells = {}
cnt = 0

for _h in range(0, H_MAX, CELL_SIZE):
  for _w in range(0, W_MAX, CELL_SIZE):
    cells[cnt] = img[_h:_h+CELL_SIZE, _w:_w+CELL_SIZE]
    cnt += 1

ind = [0x22, 0xa4, 0x39, 0x26, 0x39, 0xa4, 0x55, 0x79, 0xbb, 0x4c, 0x39, 0xc7, 0xa4, 0xd1, 0x8c]

img_result = np.zeros((CELL_SIZE, CELL_SIZE * len(ind), 3))

for i in range(len(ind)):
  cv2.imwrite(str(i) + '.bmp', cells[ind[i]])

フラグ

TsukuCTF23{Tsukushi_Quest}

 まともに asm を読んでおらず、テキトーな Guess によって正解にたどり着いてしまったところが面白ポイントです。

2.3. build_error(misc, 476pts, 50solves)

設問

 Makefileと、main.o、one.o という 2 つの実行形式(ELF)ファイルが与えられます。

 ビルドして標準出力からフラグを入手せよ、とありますが、ビルドがそう簡単に成功するかどうか怪しい。。。

Makefile

.PHONY: all

all:main.o one.o
    $(CC) main.o one.o -no-pie
    

検討

 頑張ってビルドする方向ではなく、静的解析をすることにします。そっちの方が楽そうなので。

 とりあえず、IDA Free で疑似コードを生成してみます。

「main.txt」

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+4h] [rbp-2Ch]
  __int64 v5; // [rsp+8h] [rbp-28h]
  __int64 v6; // [rsp+10h] [rbp-20h]
  __int64 v7; // [rsp+18h] [rbp-18h]
  __int64 v8; // [rsp+20h] [rbp-10h]

  v5 = 12LL;
  v6 = 11LL;
  v7 = 75LL;
  one_init(argc, argv, envp);
  for ( i = 0; v6 > i; ++i )
  {
    if ( v5 > i )
      ++v7;
    if ( v7 < i )
      ++v6;
    ++v5;
  }
  v8 = v6 + v5 + v7;
  if ( v8 == b + a + c )
    printf("flag is %ld\n", v8);
  else
    puts("please retry");
  return 0;
}

「one.txt」

__int64 one_init()
{
  __int64 result; // rax
  int i; // [rsp+0h] [rbp-4h]

  a = 12LL;
  b = 11LL;
  c = 75LL;
  for ( i = 0; ; ++i )
  {
    result = b;
    if ( i >= (unsigned __int64)b )
      break;
    if ( i < (unsigned __int64)a )
      ++c;
    if ( c < (unsigned __int64)i )
      ++b;
    ++a;
  }
  return result;
}

 これを見ると、main.txt の「v8」の値を計算すれば良さそうです。

解法

 疑似コードをもとに、「v8」の値を計算してみました。

「solve.py」

v5 = 12;
v6 = 11;
v7 = 75;

for i in range(v6):
  if v5 > i :
    v7 +=1
  if v7 < i :
    v6 += 1
  v5 += 1

v8 = v6 + v5 + v7;

print(v8)
#120

フラグ

TsukuCTF23{120}

 「動的解析が苦手で、すぐ静的解析したがる」という "悪い癖" が珍しく功を奏した、という点が面白ポイントです。

2.4. TrainWindow(osint, 394pts, 104solves)

設問

「夏、騒音、車窓にて。フラグのフォーマットは、TsukuCTF23{緯度_経度}です。緯度経度は小数第五位を切り捨てとします。」

検討

 既視感のある車窓の風景です。*6

 海に浮かんで見える島は何となく「初島」っぽいです。しかし似たような風景はほかにもあるでしょう。ですので、断言はできません。

 そこで問題文に目を戻すと・・・騒音!?・・・昔乗った「踊り子号」*7の騒音!!そういうことか!!*8・・・これで確信しました。これは熱海の近く、島の角度的には熱海から先、伊東線に違いない!

 そう確信して、Youtubeの適当な車窓モノ(前面を撮影したいわゆる展望ビデオではなく、海側車窓を映したもの)を見ながらGoogle Mapと照らし合わせ、場所を推定することにしました。

解法

 Youtubeに上がっている、来宮-伊豆多賀間の車窓ビデオを見て場所を推定することにしました。

 踏切のタイミングやStreet Viewへの切り替えなどから場所を特定し、Google Map上でマウスをクリックします。その時のURLから緯度・経度の情報を収集できます。

https://www.google.com/maps/place/%E9%9D%99%E5%B2%A1%E7%9C%8C%E7%86%B1%E6%B5%B7%E5%B8%82/@35.0640595,139.0664555,63m/data=!3m1!1e3!4m6!3m5!1s0x6019bedfe3859a9d:0xc7ce80b39564208e!8m2!3d35.0963896!4d139.071784!16zL20vMDF3bGNt?entry=ttu

フラグ

TsukuCTF23{35.0640_139.0664}

 特徴的な建物ではなく、Youtubeの車窓ビデオから場所を特定したこと、そして伊東線と推測するに至る要因が「電車の騒音」だった、という点が面白ポイントです。

3. 簡易Writeup

 以下、ほぼ蛇足なのですが、解けた問題のうち pick up から漏れたものについて簡易 Writup*9 を残しておきます。

3.1. welcome(tsukushi)

 Discord からコピペ。大会によっては、welcome 問でも一捻りしてある場合があるので油断ならないが今回はセーフ。

TsukuCTF23{TsukuCTF_is_back_again_in_2023!}

3.2. basic(web)

 WiresharkTCPパケットを追跡。basic 認証のため送信されている base64文字列「YWRtaW46MjkyOWIwdTQ=」をデコードしてパスワード該当部分を答えれば OK。

TsukuCTF23{2929b0u4}

3.3. what_os(misc)

 ディストリビューションまで特定するのか粒度がわからなかったのでとりあえず「Linux」と解答したがで不正解。「unix」と解答して正解。

TsukuCTF23{unix}

3.4. content_sign(misc)

 ググってみると、アドビが推奨するコンテンツ認証機能を利用していることがわかる。以下のサイトで署名の状況を確認可能であるが、日時の「秒」が見えないので元画像の中をバイナリエディタで確認。

https://contentcredentials.org/verify

TsukuCTF23{TSUKU4_IS_H@CKER&2023-12-08T13:00:26+00:00}

3.5. airport(osint)

 Google Lensで検索をかけると「伊丹空港」の文字が散見されることから、設問の指示に従いIATAコード「ITM」を解答。

TsukuCTF23{ITM}

3.6. castle(osint)

 Google Lensで検索をかけると、ドンピシャでヒットし、太陽公園の白鳥城であることがわかる。

TsukuCTF23{34.886_134.630}

3.7. eruption(osint)

 画像内に日付情報が埋め込まれていたが、改ざんも考えられるので念のため過去のニュースを検索し確認した。

TsukuCTF23{2022/01/28}

3.8. location_for_what(osint)

 これもGoogle Lensで検索をかけると「言の葉の庭」が散見された。

TsukuCTF23{言の葉の庭}

3.9. green_bridge(osint)

 これもGoogle Lensでイイ感じに当該橋が写っている写真がヒットし、それらを掲載しているブログ等から名称等を確認し位置を特定した。

TsukuCTF23{36.956_139.880}

3.10. perfume(osint)

 これもGoogle Lensで検索、同一被写体を撮影した写真を発見して施設名(大分香りの博物館)を特定。

TsukuCTF23{33.311_131.488}

3.11. mab(osint)

 aguse で「mab.main.jp」を検索。

TsukuCTF23{lolipop.jp}

3.12. tsukushi_estate(osint)

 「合同会社つくし不動産」の Web サイトで貸事務所っぽい物件を検索。「伊勢SIビル」であると特定。同サイトに記載されている建築年月を解答。

TsukuCTF23{1983_03}

3.13. travel_with_tsukushi(osint)

 Google Lensで検索をし、機体から判明する航空会社名をヒントにググってみるとマレーシアのクアラルンプール空港が有力候補として出てきたので解答。

TsukuCTF23{KUL}

3.14. kiZOU(osint)

 写真の中の文字から、店舗は「au style 那覇」と分かる。件の像はパレット久茂地前のシーサー。

 シーサーを探求されている方による X(Twitter)の投稿から寄贈者が判明。

https://x.com/kintaro11111/status/1082234341361504256

TsukuCTF23{上原清善}

3.15. big_statue(osint)

 写真中に写っている文字「榴莲王 利陞」を手掛かりにググると同じ像の写真(ほぼ逆側から撮ったもの)などがヒットする。それらをヒントに像の位置を特定。

TsukuCTF23{1.3623_103.8872}

3.16. CtrlAltPrtSc(osint)

 最初は全く見当が付かなかったが、赤いアイコンとその右のドット配置から Youtube と推測。

TsukuCTF23{YouTube}

3.17. free_rider(osint)

 X(Twitter)の投稿から元動画の URL を把握。再 up されている動画があったので、そこから時間(秒数)を算出。

TsukuCTF23{https://www.youtube.com/watch?v=Dg_TKW3sS1U&t=176s}

3.18. flower_bed(osint)

 一部隠れたQRコードがあるがそれは一旦忘れ、読み取れる英文・和文から場所を特定(旧福岡県公会堂貴賓館)。「FUKUOKA」モニュメントの存在が浮上するので画像を検索すると、読み取り可能なQRコードを得られそこからURLを取得。

TsukuCTF23{http://www.fukuokaken-kihinkan.jp}

4. 解けなかった問題

 さらなる蛇足として、解けなかった問題について簡単に状況を記しておきます。もう少しで解けそうだったものから全然ワカランというものまで、状況は様々でした。

4.1. MEMOwow(web)

 問題セットを回収したが、見当が付かずパス。

4.2. EXECpy(web)

 問題セットを回収したが、面倒くさそうで見当も付かないなのでパス。

4.3. laser(osint)

 直感で「スカイツリー」と決めつけていたがハズレ。その後手掛かりを得られず。

4.4. 3636(osint)

 ドメインと電話番号から「とうみょう子ども園」と推測したが、肝心の看板が見つからなかった。無念。

4.5. Yuki(osint)

 直感で「日光」と決めつけていたが、その後手掛かりを得られず。

4.6. tsukushi_no_kuni(osint)

 「国造」が誰のことかわからずそのまま。

4.7. river(osint)

 newgin の看板から、同社の Web サイトから拠点を探し鹿児島にたどり着いたのは 19:40 過ぎ、競技終了後であった*10。残念。

4.8. broken_display(osint)

 L'OCCITANE のサインを頼りに検索するも発見に至らず。「西宮阪急」が浮上するも「西宮ガーデンズ」が出なかった。この問題で大分時間を溶かした。

4.9. stickers(osint)

 「なつかしの熱海プリン」の車から熱海近辺と推測するが、そこまで。

4.10. RegexCrossword(osint)

 面白そうと思ったが、面倒くさそうなのでパス。作った会社の電話番号なので別のアプローチがあったかも。

4.11. koi(osint)

 皿の模様を手掛かりに「食べログ」の写真を検索するも、発見に至らず。

4.12. grass_court(osint)

 枯れ木に掛かっている謎のキャラクターが気になるも、未着手のまま。

4.13. fiction(osint)

 ゲームの世界が題材となっており斬新だが、ゲーム世界が OSINT 対象かどうかについては異論もあるかと思う*11

4.14. hunter(osint)

 メアド(@より前)は総当たりで「qeinijo.iby8」と推定したが、その先の情報は得られず。

4.15. twin(osint)

 これも手つかず。タイトルからは「双子」を推測したがそれだけでは。。。

4.16. sunset(osint)

 場所の見当が付かなかったので勝手に「11/19 SecHack365第4回イベント」とかなりイイカゲンに推測、同日の日の入り日時を送るもハズレ。3回しかトライできないことにこの時初めて気づきショック!以降手つかずのまま。

4.17. udon_2023(osint)

 ただひたすらに、鳥天がおいしそうでした。うどんも麺のコシがあって良さげです。*12

5. 振り返り(反省会)

  • 😄Good:Crypto と Rev 全完*13
  • 😣Bad :CTF 経験もそこそこ長くなってきたのに Web ほぼ壊滅で、OSINT もあまり解けていない。
  • 😞反省:環境不備(古いツールは使用停止!)。

6. おわりに

 最後になりましたが、運営の皆様・対戦してくださった皆様、楽しい CTF をありがとうございました*14。SecHack365の枠組み有無にかかわらず、今回運営に携わられた方々には、次回の開催もぜひご検討いただけるとありがたいです。

*1:いつものとおりソロ参加です。

*2:ほとんどソロ参加なので、チームプレイ自体ごく稀ではありますが。

*3:実際に競技で使ったものを、汚いままですが掲載します。

*4:こういうやつを「Guess の勘繰り」と言います(言わない)。

*5:競技中、最初は縦横逆に計算してしまいすぐ修正ました。

*6:個人の感想です。

*7:国鉄時代に製造された185系電車。あれは確かにウルサイが、だがそれがいい

*8:作問者の意図なのかどうか、答え合わせをしてみたいところです。

*9:メモ程度のものです。

*10:しかも、経度が0.001ズレていた

*11:個人的にはどちらかというと否定的で、カテゴライズは「misc+osint」とでもしておけば良かった気がします。とは言え、架空世界を取り扱うというアイデア自体はとても面白いと思います。

*12:TsukuCTF23 参加者が近日中にこの店舗を訪問する可能性は極めて大きいと思われるため、誰かの Writeup を読んで場所・店名を特定の上、少し時間をおいてから訪問したいと思います。

*13:どちらも解きやすい問題 1 問ずつですが。

*14:SecHack365は自体は若年層向けのものですが、今回のような年齢性別不問で参加できるイベントの開催は素晴らしいことだと思います。