2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SECCON CTF for Begginer 2026 WriteUp

2
Last updated at Posted at 2026-06-14

概要

久しぶりの投稿&CTF自体がかなり久し振りです。

本記事は、2026/6/13 (土) 14:00 JST から 2026/6/14 (日) 14:00 JST で実施されたctf4b2026のwriteUpです。
回答できた問題を中心に記載していきます。
※体調不良と別件があり、前回ほど時間は取れていませんが、解けた範囲で書いていきます。

結果

今回も1マンチームで参加し、
最終結果は、326/630 th、1100 point でした。
時間割けなかった割には去年より点数高いですね・・・(去年も同じこと言ってますね)

※今回からAIの使用について、強制的に登録が必要になっていました。が、なかなか仰々しい名前ですね・・・AIが主体か人間が主体かの2択しかありませんでしたので・・・・

score.beginners.seccon.jp_team - コピー.png
score.beginners.seccon.jp_challenges.png

環境

Windows + Kalilinux
プログラムはすべてPython3
その他、各種ツール

Welcome

ようこそ。
前回と同じです。
問題文にフラグが提示されてます。

Web

portfolio

はじめて作ったポートフォリオサイトを公開しました。 http://portfolio.beginners.seccon.games:33455

配布されたコードには、admin画面にアクセスした際に無条件に403にされるルーティングしか設定されていない。
flag.txtのパスは既知の情報であるため、直接flag.txtにアクセスすればよい。

bookshelf

書籍レビューサイトを公開しました。 
http://bookshelf.beginners.seccon.games:33456

\app\books\[id]\page.tsxのソース内に、それぞれのidの画面に渡すデータが設定されている。
その中に、id=2の際のデータにフラグが設定されていることが確認できる。
あとはサイトの構成上、/2のレスポンスを確認すればフラグが確認できる。

page.tsx
前略
const books: Book[] = [
  {
    id: "1",
    title: "The Little Web",
    author: "Alice",
    description: "A gentle introduction to web applications.",
    rating: 4,
  },
  {
    id: "2",
    title: "Flight Book",
    author: "Bob",
    description: "Notes about modern React rendering.",
    rating: 5,
    internalNote: process.env.FLAG ?? "ctf4b{dummy_flag}",
  },
  {
    id: "3",
    title: "HTTP Field Guide",
    author: "Carol",
    description: "A small book about requests and responses.",
    rating: 3,
  },
];
後略

スクリーンショット 2026-06-13 204543.png

Crypt

twins

RSAの公開鍵を2つ作ってみました!
chall.py
import os
from math import gcd
from pathlib import Path

from Crypto.Util.number import bytes_to_long, getPrime, long_to_bytes

FLAG = os.getenv("FLAG", "ctf4b{dummy_flag}").encode()
m = bytes_to_long(FLAG)

p = getPrime(512)
q1 = getPrime(512)
q2 = getPrime(512)
n1 = p * q1
n2 = p * q2
e = 65537
c = pow(m, e, n1)

assert m < n1
assert gcd(n1, n2) == p
assert gcd(n1, n2) != 1

phi = (p - 1) * (q1 - 1)
d = pow(e, -1, phi)
assert long_to_bytes(pow(c, d, n1)) == FLAG

output = "\n".join([
    f"n1 = {n1}",
    f"n2 = {n2}",
    f"e = {e}",
    f"c = {c}",
])

Path(__file__).with_name("output.txt").write_text(output + "\n")
print(output)
output.txt(配布ファイル)
n1 = 113880125198864950563107027313262858562579845169040599843244908620910863016550189657973462371771316792957786246501938664222083662393621306146341461444713328361747021647851967048322504706224619037767570006428934894715790606442824792889611101483284328574709759135027127435315296666269676354975141117473271303321
n2 = 105276345432465274963720722422774590917691220487589268040722899198110433602948101271470062639646432750400949217388976818212349789839198599553407451456746354799769561549120245004545841153155597677559555183979871182443047548869983267425969009743794827412550143572792952463128292049048381620452468992949469524739
e = 65537
c = 523724402186281757672504163102213938199531542190538176894240854156187650675308897872801979844253859168041096691538816812473265236344118603761747753962742078327527050567766258109597769320400583993445607364727303667121730062147288257549149953588914416172323461076634838540811797057063184864794352115558365151

n1,n2,e,cがすでに明示されています。
またコードより、n1n2の最大公約数がpであることが明示されています。
すなわち、

gcd(n1, n2) = gcd(p*q1, p*q2) = p * gcd(q1, q2) = p

よって、p=gcd(n1, n2)となります。
さらにpが求まれば、定義からq1=n1//pにてq1が求まります。
ここまで求まれば、phi=(p-1)*(q1-1)も計算でき、さらに秘密鍵d=pow(e, -1, phi)、フラグm = pow(c, d, n1)も逆順で計算できます。

decode.py
#諸事情でCrypt使ってないですが、
#from Crypto.Util.number import inverse, long_to_bytes
#使った方が楽です

from math import gcd

n1 = 113880125198864950563107027313262858562579845169040599843244908620910863016550189657973462371771316792957786246501938664222083662393621306146341461444713328361747021647851967048322504706224619037767570006428934894715790606442824792889611101483284328574709759135027127435315296666269676354975141117473271303321
n2 = 105276345432465274963720722422774590917691220487589268040722899198110433602948101271470062639646432750400949217388976818212349789839198599553407451456746354799769561549120245004545841153155597677559555183979871182443047548869983267425969009743794827412550143572792952463128292049048381620452468992949469524739
e = 65537
c = 523724402186281757672504163102213938199531542190538176894240854156187650675308897872801979844253859168041096691538816812473265236344118603761747753962742078327527050567766258109597769320400583993445607364727303667121730062147288257549149953588914416172323461076634838540811797057063184864794352115558365151

def egcd(a, b):
    if b == 0:
        return a, 1, 0
    g, x1, y1 = egcd(b, a % b)
    return g, y1, x1 - (a // b) * y1

def inverse(a, m):
    g, x, _ = egcd(a, m)
    return x % m

def long_to_bytes(n):
    return n.to_bytes((n.bit_length() + 7) // 8, "big")


p = gcd(n1, n2)
q1 = n1 // p

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

m = pow(c, d, n1)

print(long_to_bytes(m))

reversing

baby-rev

Welcome to the world of Reversing! I hope you find it interesting :)
baby-rev.c
#include <stdio.h>

int main()
{
    const unsigned char xorFlag[] = {0xeb,0xfc,0xee,0xbc,0xea,0xf3,0xe4,0xb8,0xb8,0xe3,0xd7,0xe5,0xb8,0xe5,0xd7,0xe6,0xb8,0xd7,0xe0,0xbc,0xe6,0xec,0xfb,0xd7,0xe2,0xfd,0xfb,0xfc,0xd7,0xf0,0xb8,0xfa,0xa9,0xf5};
    const int xorKey = 0x88;
    const int len = 34;

    unsigned char inp[64] = {0};
    printf("INPUT > ");


    if (scanf("%63s", inp) != 1) {
        printf("Wrong:(\n");
        return -1;
    }

    int inputLen = 0;
    while (inp[inputLen] != '\0') inputLen++;
    if (inputLen != len) {
        printf("Wrong:(\n");
        return -1;
    }

    for (int i = 0; i < len; i++) {
        if ((inp[i] ^ xorKey) != xorFlag[i]) {
            printf("Wrong:(\n");
            return -1;
        }
    }

    printf("Correct:)\n");
    return 0;
}

暗号化処理内に、XOR元(xorFlag)とXORキー(xorFlag)がハードコートされているのでXORするのみでフラグが取れます。

decode
python3 -c 'data=[0xeb,0xfc,0xee,0xbc,0xea,0xf3,0xe4,0xb8,0xb8,0xe3,0xd7,0xe5,0xb8,0xe5,0xd7,0xe6,0xb8,0xd7,0xe0,0xbc,0xe6,0xec,0xfb,0xd7,0xe2,0xfd,0xfb,0xfc,0xd7,0xf0,0xb8,0xfa,0xa9,0xf5]; print(bytes(x^0x88 for x in data))'

1st-Memory-Errand

Your mother: Could you run a quick errand for me and look for the FLAG in Memory? It might be in a hard-to-find spot, but if you look for it, you'll find it, so please do me this favor.

配布ファイルをGhidra通したらキレイにデコンパイルできたので、とりあえずmain関数を確認。

デコンパイル結果(main)
int main(void)

{
  byte bVar3;
  int iVar4;
  long in_FS_OFFSET;
  size_t i;
  uchar flag [38];
  char dummy [64];
  byte bVar1;
  long lVar2;
  
  lVar2 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Mom: Go fetch the flag from memory!");
  puts("You: OK! Heading out...");
  for (i = 0; i < 0x25; i = i + 1) {
    bVar1 = enc[i];
    bVar3 = gen_key((int)i);
    flag[i] = bVar1 ^ bVar3;
  }
  flag[0x25] = '\0';
  puts("You: I\'m at the memory store now. Looking around...");
  if (flag[0] == 0xff) {
    puts((char *)flag);
  }
  printf("Mom: Did you find it? Type what you got: ");
  iVar4 = __isoc99_scanf(&DAT_004020ea,dummy);
  if (iVar4 == 1) {
    iVar4 = strcmp(dummy,(char *)flag);
    if (iVar4 == 0) {
      puts("Mom: Well done! That\'s my child :)");
    }
    else {
      puts("Mom: Hmm, that doesn\'t look right. Go check again!");
    }
  }
  if (lVar2 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

mainのコードを読むと
①変数flagにフラグとなる文字列を入れ、最終的に入力文字列と比較し、一致していれば成功している旨のメッセージを出力
②変数flagにはbVar1bVar3がXORされた結果が代入されている
bVar1にはencというグローバル変数が設定されている。
 (久しぶりにGhidra触ったので画面の見方にてこずりました。
  デコンパイル結果のencをダブルクリックすることで、画面中央のListingにenc内のデータが表示されています)
bVar3の値はgen_key((int)i)

gen_key((int)i)
uchar gen_key(int i)
{
  return ((char)(i << 3) - (char)i) + '!';
}

より、
(i << 3) - i = 8i - i = 7i

gen_key(i) = (char)(7i) + 0x21

スクリーンショット 2026-06-14 034619.png

以上①~④より、以下の復号化コードにてフラグを取得。

decode.py
enc = [0x42, 0x5c, 0x49, 0x02, 0x5f, 0x3f, 0x06, 0x2b,
       0x06, 0x06, 0x0e, 0x1c, 0x40, 0x08,
       0xdc, 0xb9, 0xe3, 0xea, 0xab, 0xc8,
       0xc9, 0xeb, 0xcc, 0xf6, 0xfc, 0x8f,
       0xe3, 0x81, 0xd0, 0x99, 0x90, 0x99,
       0x32, 0x3d, 0x3a, 0x37, 0x60]

flag = []
for i, c in enumerate(enc):
    key = (7 * i + 0x21) & 0xff
    flag.append(c ^ key)

print(bytes(flag))

Reversing-2050

Let’s give the next-generation programming language a try:) 実行を行う場合は

pip install qsharp
python Main.py
で行えます
Encrypt.qs
namespace QuantumCipher2050 {
    open Microsoft.Quantum.Intrinsic;

    function KeyBytes() : Int[] {
        return [0x51, 0x75, 0x61, 0x6E, 0x74, 0x75, 0x6D];
    }

    function CipherText() : Int[] {
        return [
            0x32, 0x01, 0x07, 0x5A, 0x16, 0x0E, 0x25, 0x34,
            0x19, 0x0D, 0x01, 0x2B, 0x24, 0x18, 0x30, 0x1B,
            0x15, 0x1B, 0x19, 0x2A, 0x3A, 0x3E, 0x07, 0x0D,
            0x0A, 0x55, 0x54, 0x4C, 0x2C
        ];
    }

    operation EncryptQuantum(dataByte : Int, keyByte : Int) : Int {
        use reg = Qubit[8];
        mutable result = 0;
        for i in 0..7 {
            if (dataByte >>> i) &&& 1 == 1 { X(reg[i]); }
            if (keyByte  >>> i) &&& 1 == 1 { X(reg[i]); }
        }
        for i in 0..7 {
            if M(reg[i]) == One { set result |||= (1 <<< i); }
        }
        ResetAll(reg);
        return result;
    }

    operation CheckFlag(input : Int[]) : Bool {
        let ct  = CipherText();
        let key = KeyBytes();
        let klen = Length(key);
        if Length(input) != Length(ct) {
            return false;
        }
        mutable ok = true;
        for i in 0..Length(input) - 1 {
            let kb = key[i % klen];
            let xored = EncryptQuantum(input[i], kb);
            if xored != ct[i] {
                set ok = false;
            }
        }
        return ok;
    }
}

暗号化処理の本体はEncrypt.qs内で実施されている。
しかしEncryptQuantumで仰々しいことしているように見えて、実質XOR演算をQ#でしているだけ。
(量子暗号化関係なし。見た目だけでした)
このメソッドの返り値がフラグ。
よって、問題文のコードに沿って、古典計算で復号してフラグを取得する。

decode.py
key = [0x51, 0x75, 0x61, 0x6E, 0x74, 0x75, 0x6D]

ct = [
0x32, 0x01, 0x07, 0x5A, 0x16, 0x0E, 0x25, 0x34,
0x19, 0x0D, 0x01, 0x2B, 0x24, 0x18, 0x30, 0x1B,
0x15, 0x1B, 0x19, 0x2A, 0x3A, 0x3E, 0x07, 0x0D,
0x0A, 0x55, 0x54, 0x4C, 0x2C
]

flag = []

for i in range(len(ct)):
    v = ct[i] ^ key[i % len(key)]
    flag.append(v)

print(flag)
print(bytes(flag))

Pwnable

login

まずは手始めにadminを目指しましょう

nc login.beginners.seccon.games 9080

単純にスタックオーバーフローの問題。
ソースコードより、

main.c
#include <stdio.h>

struct user {
    char username[0x10];
    int is_admin;
};

void win() {
    system("/bin/sh");
}

static void setup(void) {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
}

int main() {
    setup();

    struct user normal_user = {0};
    printf("Input username: ");
    fgets(normal_user.username, sizeof(struct user), stdin);
    normal_user.username[strcspn(normal_user.username, "\n")] = '\0';
    if (normal_user.is_admin) {
        printf("Welcome, admin %s!\n", normal_user.username);
        win();
    } else {
        printf("Welcome, %s!\n", normal_user.username);
    }
    return 0;
}

と記述されており、バッファオーバーフローしてwin関数を呼び出すだけ。

misc

omikuji

名前を入れておみくじを引きましょう。結果を全部当てられますか?

nc omikuji.beginners.seccon.games 33457
main.py
import os
import random
import sys

FLAG = os.getenv("FLAG", "ctf4b{dummy_flag}")
ROUNDS = 5
MAX_NAME_LENGTH = 64
MAX_GUESS_LENGTH = 16


def read_limited(prompt, max_length):
    sys.stdout.write(prompt)
    sys.stdout.flush()

    line = sys.stdin.readline(max_length + 2)
    if not line:
        sys.exit()

    value = line.rstrip("\r\n")
    if len(value) > max_length or (not line.endswith("\n") and len(line) > max_length):
        print("wrong")
        sys.exit()

    return value.strip()


print("=== Omikuji ===")
print("Tell me your name, and I will draw your fortune.")
name = read_limited("name > ", MAX_NAME_LENGTH)
random.seed(name)

print(f"Welcome, {name}!")
print(f"Guess the next {ROUNDS} omikuji numbers to get the flag.")

for i in range(ROUNDS):
    x = random.randint(1, 1000000)
    try:
        guess = int(read_limited(f"guess {i + 1} > ", MAX_GUESS_LENGTH))
    except ValueError:
        print("wrong")
        exit()

    if guess != x:
        print("wrong")
        exit()

print(f"Congratulations! Here is your flag: {FLAG}")

メインのコードの内容は、サーバー側で発生させたランダムな数値を5回連続で正解した場合にのみフラグ文字列を出力するというもの。なお発生した数値は入力側からは確認できない。
しかし、サーバー接続時にユーザー名を入力させ、その値をシードしとしてランダムな数値を発生させている。
ローカルで配布されたコードを実行してみると、入力した文字列が完全一致であれば、必ずまったく同じランダムな数値が発生、すなわちシード値によりランダムな値は完全に1対1で対応している。
この性質を利用し、ローカルで値を確認後、サーバーで同じ値を入力することでフラグを獲得可能。

※利用しているrandomは“疑似乱数”であり、seedが同じなら出力列は100%一致する。
※state遷移・出力関数も決定論的。

#main2.py は、配布されたコード内に、入力すべき値を標準出力させるようにデバグコード差し込んでいます。

└─# python3 main2.py
=== Omikuji ===
Tell me your name, and I will draw your fortune.
name > hoge
Welcome, hoge!
Guess the next 5 omikuji numbers to get the flag.
342042
guess 1 > 342042
246190
guess 2 > 246190
401986
guess 3 > 401986
352872
guess 4 > 352872
821335
guess 5 > 821335
Congratulations! Here is your flag: ctf4b{dummy_flag}
                                                                                                                                                            
# nc omikuji.beginners.seccon.games 33457 
=== Omikuji ===
Tell me your name, and I will draw your fortune.
name > hoge
Welcome, hoge!
Guess the next 5 omikuji numbers to get the flag.
guess 1 > 342042
guess 2 > 246190
guess 3 > 401986
guess 4 > 352872
guess 5 > 821335
Congratulations! Here is your flag: ctf4b{0m1kuj1_15_d373rm1n15t1c}

viewer

表示できるファイルを選んでください。

nc viewer.beginners.seccon.games 33458
main.py
import os
import sys
import unicodedata


FILES_DIR = "/app/files"
ALLOWED_FILES = {"readme.txt", "hello.txt", "flag.txt"}
MAX_FILENAME_LENGTH = 64
BANNER = r"""
__     ___                        
\ \   / (_) _____      _____ _ __ 
 \ \ / /| |/ _ \ \ /\ / / _ \ '__|
  \ V / | |  __/\ V  V /  __/ |   
   \_/  |_|\___| \_/\_/ \___|_|   
"""


def read_limited(prompt, max_length):
    sys.stdout.write(prompt)
    sys.stdout.flush()

    line = sys.stdin.readline(max_length + 2)
    if not line:
        sys.exit()

    value = line.rstrip("\r\n")
    if len(value) > max_length or (not line.endswith("\n") and len(line) > max_length):
        print("invalid path")
        sys.exit()

    return value.strip()


def resolve_path(filename):
    normalized = unicodedata.normalize("NFKC", filename)

    if normalized != os.path.basename(normalized):
        return None, "invalid path"
    if normalized not in ALLOWED_FILES:
        return None, "file not found"

    path = os.path.normpath(os.path.join(FILES_DIR, normalized))
    if os.path.commonpath([FILES_DIR, path]) != FILES_DIR:
        return None, "invalid path"

    return path, None


def main():
    print(BANNER)
    print("available files:")
    print("- readme.txt")
    print("- hello.txt")

    filename = read_limited("filename > ", MAX_FILENAME_LENGTH)

    if "flag" in filename:
        print("blocked")
        return

    path, error = resolve_path(filename)
    if error is not None:
        print(error)
        return

    try:
        with open(path, encoding="utf-8") as f:
            print(f.read(), end="")
    except (FileNotFoundError, IsADirectoryError):
        print("file not found")


if __name__ == "__main__":
    main()

問題文のコードを確認すると

  • 入力内容の確認にて、
    • 許可されている文字列以外はBAN
    • 許可されている文字列にflagが含まれているが、flag.txtは弾く
  • resolve_pathメソッド(ファイル名を元に存在性などを判定)にて正規化を正規形 KC (NFKC)で実施していることが確認できる。

上記より、
flagと似た文字列であり完全一致でない文字列、かつ、正規化後に同じ内容に解釈される文字列を入力すればよい。
今回は、全角文字で入力(メモ:windowsのF9キーですぐに全角化可能)、すなわち、
flag.txt
を入力することで、フラグを取得可能。

Homework

My teacher told me to do this assignment. I’d like to use AI to make it easier, but I have a feeling there’s something hidden here...

実施した解法

少々長かったので、手順をナンバリングします。

①初期調査

配布されているファイルはHomework.pdfのみであり、ファイル内に不審な点はなく、文章内に暗号や黒塗りや透かしも無さそう。

そのためまずは、フォレンジックやrevなどの解析系と同様に、初期調査として以下を実行。

file problem.pdf
pdfinfo problem.pdf
strings problem.pdf

今回はstringsで以下を発見

FLAG.txt
PK

②PKを見たらZIPを疑う

①の結果でPK文字列がヒットしていることを確認。
これは、ZIPの代表的なシグネチャである。

PK 03 04
PK 01 02
PK 05 06
PK0304 : Local File Header
PK0102 : Central Directory
PK0506 : End of Central Directory

③binwalkで確認

PKが見えたので、binwalkで解析・抽出できないか調査。

# binwalk Homework.pdf 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PDF document, version: "1.4"
734           0x2DE           Zlib compressed data, default compression
2890          0xB4A           Zip archive data, at least v2.0 to extract, compressed size: 37, uncompressed size: 35, name: FLAG.txt
3019          0xBCB           End of Zip archive, footer length: 22

結果として、ZIPらしきものを検出。
ただし結果を盲信しない。
実際、抽出しようとしてみたが、ファイル形式がおかしいか破損しているか、抽出できず。

# binwalk -e Homework.pdf

Extractor Exception: Binwalk extraction uses many third party utilities, which may not be secure. If you wish to have extraction utilities executed as the current user, use '--run-as=root' (binwalk itself must be run as root).
----------------------------------------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/binwalk/core/module.py", line 258, in __init__
    self.load()
    ~~~~~~~~~^^
  File "/usr/lib/python3/dist-packages/binwalk/modules/extractor.py", line 153, in load
    raise ModuleException("Binwalk extraction uses many third party utilities, which may not be secure. If you wish to have extraction utilities executed as the current user, use '--run-as=%s' (binwalk itself must be run as root)." % user_info.pw_name)
binwalk.core.exceptions.ModuleException: Binwalk extraction uses many third party utilities, which may not be secure. If you wish to have extraction utilities executed as the current user, use '--run-as=root' (binwalk itself must be run as root).
----------------------------------------------------------------------------------------------------

④PDF構造を確認

pdf-parser.py problem.pdfなどで、末尾にPDF Commentを発見。
実際に、ファイルstring内部の最後の辺りに、以下通りEOF以降に怪しいデータの存在を発見。

(中略)
startxref 2558

PDF Comment '%%EOF\n\n'

PDF Comment '%\x00\x00\x00#\x00\x00\x00\x08\x00\x00\x00FLAG.txtK.I3I\xaa\xf6\xcc\x8d\xb744I\x89\xaf4(\x8dO3(\xcdK\x89/\xc9\xc84\x8dO34\xb1\xac\xe5\x02\x00PK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xe9\x80\xca\\\x91\xcb\x845%\x00\x00\x00#\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00FLAG.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00\x00\x00K\x00\x00\x00\x00\x00'

⑤PKの位置を特定

ここまでで、配布されたPDFファイルにZIPが埋め込まれている可能性があると推測。
そこで、このZIPファイルを抽出するための調査を進める。
まずはPKの位置を特定する。

grep -abo "PK" problem.pdf

結果

2890:PK
2965:PK
3019:PK

⑥各PKの種類を確認

xxd problem.pdf

確認結果

2890 -> PK0304
2965 -> PK0102
3019 -> PK0506

⑦ZIP開始位置を確定

これまでの調査より、埋め込まれたIP構造は、

PK0304
↓
ファイルデータ
↓
PK0102
↓
PK0506

したがってZIP開始位置は2890と確定。

⑧ZIPを切り出す

ここまでの調査の結果を利用して、ddにて配布されたPDFファイルからZIPファイルを切り出す。

dd if=Homework.pdf of=extracted.zip bs=1 skip=2890

※通常は512バイト単位などで利用するコマンドだが、今回txt埋め込まれているような感じなので、細かい情報が落ちないように1バイト単位に指定

⑨切り出したファイルを確認

file extracted.zip

ZIPファイルとして認識されることを確認

⑩解凍

unzip extracted.zip

解凍後にFLAG.txtが展開され、そのファイル内にフラグが記載されていることを確認。

今後の課題

  • 体調管理と長時間イベントへのガチ目の対策。無理が効かなくなってきました。(去年と同じ)
  • 事前にスケジュールを調整する。
  • そもそも環境構築を当日に実施しない。
  • 睡眠時間や休憩時間をスケジュールする。(OSCPとかでも重要になると思います)
  • 初動でより早く動けるように対策を考える。
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?