好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

SECCON for Beginners CTF 2019 write-up

Beginners CTF 2019 が 2019/5/25 ~ 5/26 で開催されていたので参加しました!
相変わらず点数の低い問題しか解いていませんが、備忘録も兼ねてwrite-up書いておきます。あとで復習記事も書いておきたい。

f:id:kusuwada:20190526153713p:plain

今回は8問解いて897pt, 114位 (1問以上解いた666チーム中) でした。内訳はこんな感じ。

f:id:kusuwada:20190526163332p:plain

f:id:kusuwada:20190526154031p:plain

解いた時間が細切れなのは、育児タスクの合間にちょこちょこやったから…。こうやってみるとわかりやすい。

f:id:kusuwada:20190526154018p:plain

CTFを始めて身についた知識を使いました!!!と大きな声で言えるものが殆どないのが残念。Cryptoあたりもう1問くらい解きたかったなぁ。

順序は適当。手を付けた順です。

ちなみに去年のBeginners参加write-up。

kusuwada.hatenablog.com

warmup4問 + Misc1問だったので、少しは進歩した様子。

[Misc] [warmup] Welcome

SECCON Beginners CTFのIRCチャンネルで会いましょう。

IRC: freenode.net #seccon-beginners-ctf

IRCに入ると、チャネルの説明にflagが。

f:id:kusuwada:20190526154828p:plain

[Reversing] [warmup] Seccompare

https://score.beginners.seccon.jp/files/seccompare_44d43f6a4d247e65c712d7379157d6a9.tar.gz

サイトにアクセスしてファイルをDLします。
こんなファイルが出現しました。

$ file seccompare
seccompare: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 

実行してみます。

$ ./seccompare 
usage: ./seccompare flag

ということで、引数が一つ必要なようです。

# ./seccompare flag
wrong

こんな感じ。違ったら違うと言ってくれるようです。
radare2で解析してみようとmain関数を見たら、flagが書いてありました。

|      |`-> 0x00400630      c645d063       mov byte [local_30h], 0x63  ; 'c' ; 99
|      |    0x00400634      c645d174       mov byte [local_2fh], 0x74  ; 't' ; 116
|      |    0x00400638      c645d266       mov byte [local_2eh], 0x66  ; 'f' ; 102
|      |    0x0040063c      c645d334       mov byte [local_2dh], 0x34  ; '4' ; 52
|      |    0x00400640      c645d462       mov byte [local_2ch], 0x62  ; 'b' ; 98
|      |    0x00400644      c645d57b       mov byte [local_2bh], 0x7b  ; '{' ; 123
|      |    0x00400648      c645d635       mov byte [local_2ah], 0x35  ; '5' ; 53
|      |    0x0040064c      c645d774       mov byte [local_29h], 0x74  ; 't' ; 116
|      |    0x00400650      c645d872       mov byte [local_28h], 0x72  ; 'r' ; 114
|      |    0x00400654      c645d931       mov byte [local_27h], 0x31  ; '1' ; 49
|      |    0x00400658      c645da6e       mov byte [local_26h], 0x6e  ; 'n' ; 110
|      |    0x0040065c      c645db67       mov byte [local_25h], 0x67  ; 'g' ; 103
|      |    0x00400660      c645dc73       mov byte [local_24h], 0x73  ; 's' ; 115
|      |    0x00400664      c645dd5f       mov byte [local_23h], 0x5f  ; '_' ; 95
|      |    0x00400668      c645de31       mov byte [local_22h], 0x31  ; '1' ; 49
|      |    0x0040066c      c645df73       mov byte [local_21h], 0x73  ; 's' ; 115
|      |    0x00400670      c645e05f       mov byte [local_20h], 0x5f  ; '_' ; 95
|      |    0x00400674      c645e16e       mov byte [local_1fh], 0x6e  ; 'n' ; 110
|      |    0x00400678      c645e230       mov byte [local_1eh], 0x30  ; '0' ; 48
|      |    0x0040067c      c645e374       mov byte [local_1dh], 0x74  ; 't' ; 116
|      |    0x00400680      c645e45f       mov byte [local_1ch], 0x5f  ; '_' ; 95
|      |    0x00400684      c645e565       mov byte [local_1bh], 0x65  ; 'e' ; 101
|      |    0x00400688      c645e66e       mov byte [local_1ah], 0x6e  ; 'n' ; 110
|      |    0x0040068c      c645e730       mov byte [local_19h], 0x30  ; '0' ; 48
|      |    0x00400690      c645e875       mov byte [local_18h], 0x75  ; 'u' ; 117
|      |    0x00400694      c645e967       mov byte [local_17h], 0x67  ; 'g' ; 103
|      |    0x00400698      c645ea68       mov byte [local_16h], 0x68  ; 'h' ; 104
|      |    0x0040069c      c645eb7d       mov byte [local_15h], 0x7d  ; '}' ; 125

flag: ctf4b{5tr1ngs_1s_n0t_en0ugh}

[Web] [warmup] Ramen

ラーメン https://ramen.quals.beginners.seccon.jp

こんなページが。

f:id:kusuwada:20190526154934p:plain

なんか入力フォームと SEARCH ボタンが有るので、すでにいるっぽい「せくこん太郎」を入れてSEARCHしてみる

f:id:kusuwada:20190526155049p:plain

HITしました。 つぎに、admin'-- などのSQL injection用クエリを投げてみます。

f:id:kusuwada:20190526155100p:plain

エラーページ現る。シングルクォーテーション'が入ってるともうだめっぽい。
今回はcookieも無いことから、検索機能・DB機能系の脆弱性を疑います。

ここで、検索欄に とだけ入れてみたところ、せくこん太郎・次郎・三郎の3人が表示されました。
…ということは前方一致でしょうか?ちなみに でも出てきました。前方どころじゃないようです。

ここで心当たりのある文字を総当たりで入力してみましたが、他に店員DBにはいないようでHitしません。
0-9,a-z,A-Z,あ-ん,ア-ンくらいを試してみたんですけどね・・・。
warmupだし、店員DBにFlag君がいて、一言にflagが書いてあることを期待していました。。。

ここで SQL injection の過去問をあさっていると下記の記事が。

CTF for ビギナーズ 2016 FINAL @東京 Writeup - Qiita

2016年のBeginnersのfinal問題です。
この手順に沿ってやってみたら出来ました。最初から SQL injection のクエリの組み立て方がわかっていたらいきなり最後のクエリを勘で組み立てて解けた気がします…。

まず、SQL injection が刺さっているかどうかの確認です。下記のように入れると全レコードがエラー無く出てきました。

' OR 1=1 -- 

今回も最後にスペースが必要でした。
次に、テーブルの列数を調べます。nullを増やしていくと2つでエラーでなかったので、テーブルは2列。

' union select null, null -- 

欲しいtable_namecolum_nameを2列に表示するようなクエリを組み立てます。

' union select table_name, column_name from information_schema.columns -- 

f:id:kusuwada:20190526155133p:plain

名前   一言
せくこん太郎  1970 年よりラーメン道一本。美味しいラメーンを作ることが生きがい。
せくこん次郎  せくこん太郎の弟。好きな食べものはコッペパン。
せくこん三郎  せくこん次郎の弟。食材本来の味を引き出すことに全力を注ぐ。
CHARACTER_SETS  CHARACTER_SET_NAME
CHARACTER_SETS  DEFAULT_COLLATE_NAME
CHARACTER_SETS  DESCRIPTION
(中略)
INNODB_FT_CONFIG    KEY
INNODB_FT_CONFIG    VALUE
flag    flag
members username
members profile

たくさん出てきました。flag flagがいます。テーブル・カラム名の特定は、勘でいった人のほうが多そう。
最後に、flagテーブルのflagカラムを抜き出して表示してもらいます。

' union select flag, null from flag -- 

f:id:kusuwada:20190526155156p:plain

取れました〜!!!٩(๑❛ᴗ❛๑)۶ ٩(๑❛ᴗ❛๑)۶ ٩(๑❛ᴗ❛๑)۶ 
今回もWeb問全然解けない、しかもwarmupすら解けないところだったので、終了間際に解けてめっちゃ嬉しかった!

[Web] katsudon

Rails 5.2.1で作られたサイトです。

https://katsudon.quals.beginners.seccon.jp

クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。

フラグは以下にあります。 https://katsudon.quals.beginners.seccon.jp/flag

# app/controllers/coupon_controller.rb
class CouponController < ApplicationController
def index
end

def show
  serial_code = params[:serial_code]
  @coupon_id = Rails.application.message_verifier(:coupon).verify(serial_code)
  end
end

なんか問題文にソースが書いてあります。

指定のurlに行くとこんなページ。topが店舗一覧画面のようです。

f:id:kusuwada:20190526155540p:plain

他、クーポンゲット = シリアルコードを入力するページがあります。

f:id:kusuwada:20190526155537p:plain

ためしに店舗一覧ページに合ったシリアルコードをクーポンゲットページに入力してみました。

f:id:kusuwada:20190526155535p:plain

ええー!
ちなみにどのクーポンも使えませんでした。

ここで問題文にあった、cupon_controller.rb を見てみます。
これが実装されていないので、まだクーポンが使えないとのこと。
ちなみに、flag用のシリアル番号は

BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a

のようです。(問題文のリンクより)
なので、未実装の cupon_controller の動作を理解して上記シリアル番号を解析、クーポンをゲットできればそこにflagがありそう。ありそう。

ここでもう一度、既に与えられているクーポンを確認します。

  • 令和飯店
    • ソースカツ丼の名店
    • シリアルコード: BAhJIhByZWl3YWhhbnRlbgY6BkVU--bc5614afcef948624ebc137432c2dcdc624111b6
  • 平成食堂
    • 持ち帰りが可能
    • シリアルコード: BAhJIhNoZWlzZWlzaG9rdWRvdQY6BkVU--f9aa81191fb073fb87bfa71b20c02bf3a30d1b10
  • レストラン昭和
    • デリバリー可能
    • シリアルコード: BAhJIhRyZXN0YXVyYW50c2hvd2EGOgZFVA==--a78497e11151cffc45af945a1a243138b6084140

何やらそれぞれ先頭が base64 encode されてるっぽいので、試しに -- の前を base64 decodeしてみます。

  • 令和飯店
    • I"reiwahanten:ET
  • 平成食堂
    • I"heiseishokudou:ET
  • レストラン昭和
    • I"restaurantshowa:ET
  • flag
    • I"%ctf4b{K33P_Y0UR_53CR37_K3Y_B453}:ET

なぁぁにぃぃぃぃっ!もうここでflagが出てきてしまった…!正攻法かわかりませんが、通ったので良し。ソースコード何も使わなかった…。

[Crypto] [warmup] So Tired

最強の暗号を作りました。 暗号よくわからないけどきっと大丈夫!

tarファイルが落とせたので解凍すると、encrypted.txtが出現。超長い。

$ file encrypted.txt 
encrypted.txt: ASCII text, with very long lines, with no line terminators

まずはこのなかにflagがないかを確認。

$ grep 'ctf4b{' encrypted.txt 

なし。
ぱっと見た感じ、base64のような文字列なので、base64 decodeしてみる。
更に、base64 decode結果を見たところ、バイナリファイルだったので書き出してみました。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import base64

with open('encrypted.txt') as f:
    data = f.read()

decoded = base64.b64decode(data)

with open('dat', 'wb') as f:
    f.write(decoded)

書き出したファイルを調べてみます。

$ file dat
dat: zlib compressed data

zlibでした。更にこのファイルをdecompressしてやると、今度はまたbase64っぽい文字列。
なるほど。これは base64 - zlib のルーっプッぽいぞ、ということで、汚いですが下記のコードを。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import base64
import zlib

with open('encrypted.txt') as f:
    data = f.read()

while True:
    decoded = base64.b64decode(data)
    with open('dat', 'wb') as f:
        f.write(decoded)

    data = zlib.decompress(decoded)
    with open('decompressed', 'wb') as f:
        f.write(data)

base64 decode か zlib decompress ができなくなったらエラーで止まるはずなので、止まったら成果物のファイルの中身を確認しようという作戦。
意図通り(?)エラーで止まったので、成果物ファイルの一つdecompressedの中身を見ると、flagがありました。

$ cat decompressed 
ctf4b{very_l0ng_l0ng_BASE64_3nc0ding}

[Crypto] Party

Let's 暗号パーティ

落としたtarファイルを解凍すると、pythonコードとテキストファイルが。

encrypt.py

from flag import FLAG
from Crypto.Util.number import bytes_to_long, getRandomInteger, getPrime


def f(x, coeff):
    y = 0
    for i in range(len(coeff)):
        y += coeff[i] * pow(x, i)
    return y


N = 512
M = 3
secret = bytes_to_long(FLAG)
assert(secret < 2**N)

coeff = [secret] + [getRandomInteger(N) for i in range(M-1)]
party = [getRandomInteger(N) for i in range(M)]

val = map(lambda x: f(x, coeff), party)
output = list(zip(party, val))
print(output)

encrypted

[(5100090496682565208825623434336918311864447624450952089752237720911276820495717484390023008022927770468262348522176083674815520433075299744011857887705787, 222638290427721156440609599834544835128160823091076225790070665084076715023297095195684276322931921148857141465170916344422315100980924624012693522150607074944043048564215929798729234427365374901697953272928546220688006218875942373216634654077464666167179276898397564097622636986101121187280281132230947805911792158826522348799847505076755936308255744454313483999276893076685632006604872057110505842966189961880510223366337320981324768295629831215770023881406933), (3084167692493508694370768656017593556897608397019882419874114526720613431299295063010916541874875224502547262257703456540809557381959085686435851695644473, 81417930808196073362113286771400172654343924897160732604367319504584434535742174505598230276807701733034198071146409460616109362911964089058325415946974601249986915787912876210507003930105868259455525880086344632637548921395439909280293255987594999511137797363950241518786018566983048842381134109258365351677883243296407495683472736151029476826049882308535335861496696382332499282956993259186298172080816198388461095039401628146034873832017491510944472269823075), (6308915880693983347537927034524726131444757600419531883747894372607630008404089949147423643207810234587371577335307857430456574490695233644960831655305379, 340685435384242111115333109687836854530859658515630412783515558593040637299676541210584027783029893125205091269452871160681117842281189602329407745329377925190556698633612278160369887385384944667644544397208574141409261779557109115742154052888418348808295172970976981851274238712282570481976858098814974211286989340942877781878912310809143844879640698027153722820609760752132963102408740130995110184113587954553302086618746425020532522148193032252721003579780125)]

初めて知ったんですけど、coeffって多項式係数の抽出に使われる関数らしい。これを踏まえてencrypt.pyを眺めてみると、ただの3連立方程式に落とせそう。

関数 f(x, coeff) が、

y = coeff[0] + coeff[1]*x + coeff[2]*x^2

なので、

val[i] = coeff[0] + coeff[1]*party[i] + coeff[2]*(party[i]**2)

※ただし i =0~2 となります。coeff[0] が求まれば、これがflagです。

numpyのlinalgscipyなど、色々python用のモジュールやスクリプトを使って楽して方程式を解いてもらう方法を試してみましたが、桁が大きすぎてそのまま使えるものが見つからず。
仕方ないので、下の数式を参考に、普通にcoeff[0]を計算する式の計算をゴリゴリ書きました。

Python (SymPy) で方程式・連立方程式を解く、数列を求める - pianofisica

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from Crypto.Util.number import long_to_bytes 

party = [5100090496682565208825623434336918311864447624450952089752237720911276820495717484390023008022927770468262348522176083674815520433075299744011857887705787, 3084167692493508694370768656017593556897608397019882419874114526720613431299295063010916541874875224502547262257703456540809557381959085686435851695644473, 6308915880693983347537927034524726131444757600419531883747894372607630008404089949147423643207810234587371577335307857430456574490695233644960831655305379]
val = [222638290427721156440609599834544835128160823091076225790070665084076715023297095195684276322931921148857141465170916344422315100980924624012693522150607074944043048564215929798729234427365374901697953272928546220688006218875942373216634654077464666167179276898397564097622636986101121187280281132230947805911792158826522348799847505076755936308255744454313483999276893076685632006604872057110505842966189961880510223366337320981324768295629831215770023881406933, 81417930808196073362113286771400172654343924897160732604367319504584434535742174505598230276807701733034198071146409460616109362911964089058325415946974601249986915787912876210507003930105868259455525880086344632637548921395439909280293255987594999511137797363950241518786018566983048842381134109258365351677883243296407495683472736151029476826049882308535335861496696382332499282956993259186298172080816198388461095039401628146034873832017491510944472269823075, 340685435384242111115333109687836854530859658515630412783515558593040637299676541210584027783029893125205091269452871160681117842281189602329407745329377925190556698633612278160369887385384944667644544397208574141409261779557109115742154052888418348808295172970976981851274238712282570481976858098814974211286989340942877781878912310809143844879640698027153722820609760752132963102408740130995110184113587954553302086618746425020532522148193032252721003579780125]

# val[i] = coeff[0] + coeff[1]*party[i] + coeff[2]*(party[i]**2)
# flag is coeff[0]

A = [[1, party[0], party[0]*party[0]], 
     [1, party[1], party[1]*party[1]],
     [1, party[2], party[2]*party[2]]]
b = val

# refer to follow page.
# https://pianofisica.hatenablog.com/entry/2019/04/04/233515#%EF%BC%93%E5%A4%89%E6%95%B0%E3%81%AE%E5%A0%B4%E5%90%88
d = A[0][1]*(A[2][2]*b[1]-A[1][2]*b[2]) + \
    A[0][2]*(A[1][1]*b[2]-A[2][1]*b[1]) + \
    b[0]*(A[1][2]*A[2][1]-A[1][1]*A[2][2])
n = A[0][0]*(A[1][2]*A[2][1]-A[1][1]*A[2][2]) + \
    A[0][1]*(A[1][0]*A[2][2]-A[1][2]*A[2][0]) + \
    A[0][2]*(A[1][1]*A[2][0]-A[1][0]*A[2][1])

ans = d//n
print(long_to_bytes(ans))

コードが汚すぎてワケワカメですが…。参考リンクの方を参照して下さいまし。
実行結果。

$ python solve.py 
b'ctf4b{just_d0ing_sh4mir}       '

[Misc] containers

Let's extract files from the container. https://score.beginners.seccon.jp/files/e35860e49ca3fa367e456207ebc9ff2f_containers

urlにアクセスすると、ファイルが貰えました。

$ file e35860e49ca3fa367e456207ebc9ff2f_containers 
e35860e49ca3fa367e456207ebc9ff2f_containers: data

stringコマンドで見てみると、下記のような気になる情報が書いてあります。(抜粋)

$ strings e35860e49ca3fa367e456207ebc9ff2f_containers 
CONTAINER.FILE0.
IHDR
sRGB
gAMA
pHYs
aIDATx^
ajlK-[
0TG~5
;-M\
IEND
FILE1.
IHDR
sRGB
gAMA
pHYs
(中略)
VALIDATOR.import hashlib
print('Valid flag.' if hashlib.sha1(input('Please your flag:').encode('utf-8')).hexdigest()=='3c90b7f38d3c200d8e6312fbea35668bec61d282' else 'wrong.'.ENDCONTAINER

画像っぽい文言が最初の方にあり、最後に急にソースっぽい文言が…?
とりあえず foremost かけてみると、沢山のpngイメージが出現。一文字ずつ書いてあり、ファイル名順に並べるとflagになっていました!

$ foremost -i e35860e49ca3fa367e456207ebc9ff2f_containers 
Processing: e35860e49ca3fa367e456207ebc9ff2f_containers
|*|

f:id:kusuwada:20190526160107p:plain

flag: ctf4b{e52df60c058746a66e4ac4f34db6fc81}

[Misc] Sliding puzzle

nc 133.242.50.201 24912

スライドパズルを解いてください。すべてのパズルを解き終わったとき FLAG が表示されます。

スライドパズルは以下のように表示されます。

----------------

| 0 | 2 | 3 |

| 6 | 7 | 1 |

| 8 | 4 | 5 |

----------------

0 はブランクで動かすことが可能です。操作方法は以下のとおりです。

0 : 上

1 : 右

2 : 下

3 : 左

最終的に以下の形になるように操作してください。

----------------

| 0 | 1 | 2 |

| 3 | 4 | 5 |

| 6 | 7 | 8 |

----------------

操作手順は以下の形式で送信してください。

1,3,2,0, ... ,2

なんだか競プロとかpaizaの問題っぽい。
スライドパズルを解くアルゴリズムの紹介はたくさんありましたが、時間勝負なので、できればpythonスクリプトが落ちていることを願ってgithubを漁ります。

運良く落ちてました!!

github.com

しかも 3×3 に特化したやつです。
動作環境がpython2なので、問題をとってきて配列にするところと、出力がグラフィカルな表示だったのをブランクを動かす手順に変えるところだけ、エイヤで書いて通しました。

#!/usr/bin/env python2
# -*- coding:utf-8 -*-
# This code uses bellow script
#   https://github.com/fabianokafor369/Sliding-puzzle-solver

from pwn import *

host = '133.242.50.201'
port = 24912

SHIFT_U = 0
SHIFT_R = 1
SHIFT_D = 2
SHIFT_L = 3

# ---- https://github.com/fabianokafor369/Sliding-puzzle-solver
# ---- start reference

class PuzzleNode:
   (略)

def place_heuristic(state):
   (略)

def Manhattan_heuristic(state):
   (略)

def myheuristic(state):
   (略)

#Creating list heuristics which is a pointer to both heuristics created
heuristics = [place_heuristic, Manhattan_heuristic, myheuristic]

def goalstate(state):
   (略)

def moves(inputs, n):
   (略)

def Astar(start, finish, heuristic):
   (略)


def solvePuzzle(n, state, heuristic, prnt):
   (略)

   #Prints the solutions if the prnt = True
   #Here I change code from https://github.com/fabianokafor369/Sliding-puzzle-solver
   if prnt == True:
       shift = []
       pre_blank_pos = {}
       blank_pos = {}
       for n in range(len(solutions[1:])):
           for i in range(len(solutions[n+1])):
               if solutions[n+1][i] == '0':
                   break
           blank_pos = calc_pos(i)
           if n != 0:
               shift.append(str(calc_shift(pre_blank_pos, blank_pos)))
           pre_blank_pos = blank_pos

   return ','.join(shift)
# ---- end reference

"""
BLANK_POS
  02 05 08
  13 16 19 
  24 27 30
"""
def calc_pos(pos):
    BLANK_POS = [[2, 5, 8], [13, 16, 19], [24, 27, 30]]
    for i in range(3):
        for j in range(3):
            if pos == BLANK_POS[i][j]:
                return [i, j]

def calc_shift(pre, curr):
    if curr[0] - pre[0] == 0:
        if curr[1] - pre[1] == 0:
            raise Exception
        if curr[1] - pre[1] == 1:
            return SHIFT_R
        if curr[1] - pre[1] == -1:
            return SHIFT_L
    elif curr[0] - pre[0] == 1:
        return SHIFT_D
    elif curr[0] - pre[0] == -1:
        return SHIFT_U

r = remote(host, port)
print(r.recvline().strip())

while True:
    p = r.recvuntil('\n\n')
    print p.strip()
    p = p.split('\n')
    puzzle = [[] for i in range(3)]
    for i in range(3):
        for j in range(3):
            puzzle[i].append(int(p[i].split('|')[j+1].strip()))
    print 'puzzle array: '
    print puzzle
    ans = solvePuzzle(3, puzzle, heuristics[2], True)
    print 'answer: ' + ans
    r.sendline(ans)
    print r.recvline().strip()

実行結果

(前略)
----------------
| 03 | 01 | 02 |
| 07 | 06 | 05 |
| 04 | 08 | 00 |
----------------
puzzle array: 
[[3, 1, 2], [7, 6, 5], [4, 8, 0]]
answer: 3,3,0,1,2,3,0,0
----------------
| 03 | 00 | 05 |
| 04 | 02 | 01 |
| 06 | 07 | 08 |
----------------
puzzle array: 
[[3, 0, 5], [4, 2, 1], [6, 7, 8]]
answer: 2,1,0,3,2,3,0
[+] Congratulations! ctf4b{fe6f512c15daf77a2f93b6a5771af2f723422c72}

どうやら100問あったみたいです!

感想

前回の感想

土日で耐久24時間って、用事があったり子守があったりで結局使える時間頑張っても6時間くらい。それでも今の実力だと十分だった気がするし、長くやりすぎても飽きそうなのでちょうどよかったかな。

同じこと書こうとしてたよ。危ない危ない。ただ今回はもっと時間欲しかったので、やっぱり少しは前進したかな。

Twitterでは愚痴ばっかりになってしまいましたが、子育て世代、特に育児メイン担当の週末CTFイベント参加は厳しいものがありますね。いっそ合宿とかで家にいないようにしてパートナーや他の方に育児を丸投げしないと育児イベントがちょこちょこ割り込むので、中々集中できる時間をまとまって確保するのが難しかったです。うまくやってる方いたらお話を聞きたい…!
まぁ今回はそれ以前に夫に急に仕事が入り、一日丸々子供と二人だったのですが( •̅_•̅ ) オンライン競技って理解してもらうのも難しいなぁと再認識。

ちなみに娘は競技が終了して1時間後に無事お昼寝をはじめました(๑′௰‵๑) なんだかんだ可愛いのです。