n00bz CTF 2024 Writeup

WriteUp 1个月前 admin
130 0 0

8/3 から開催されていた n00bz CTF 2024 に 0nePadding で参加して最終順位 28 位でした。
我使用 0nePadding 参加了 8 月 3 日举行的 n00bz CTF 2024,并获得了第 28 名。

n00bz CTF 2024 Writeup

超優秀なチームメンバーのおかげでほぼ全完できました(惜しかった!
感谢超级才华横溢的团队成员,我们几乎能够完成所有事情(真遗憾!

n00bz CTF 2024 Writeup

今回は解いた問題数が多いのでざっくり Writeup を書きます。
这次解决了很多问题,所以我就写一篇快速的文章。

もくじ 目录

Vacation(Rev) 假期(修订版)

My friend told me they were going on vacation, but they sent me this weird PowerShell script instead of a postcard! Author: 0xBlue
我的朋友告诉我他们要去度假,但他们给我发了这个奇怪的 PowerShell 脚本而不是明信片!作者:0xBlue

問題バイナリとして以下のスクリプトと暗号文が与えられます。
以下脚本和密文作为问题二进制文件给出。

$bytes = [System.Text.Encoding]::ASCII.GetBytes((cat .\flag.txt))
[System.Collections.Generic.List[byte]]$newBytes = @()
$bytes.ForEach({
    $newBytes.Add($_ -bxor 3)
    })
$newString =  [System.Text.Encoding]::ASCII.GetString($newBytes)
echo $newString | Out-File -Encoding ascii .\output.txt
m33ayxeqln\sbqjp\twk\{lq~

コードを見てわかる通り 3 で XOR すると復号できます。
从代码中可以看出,可以通过与3进行异或来解密。

n00bz CTF 2024 Writeup

Brain(Rev) 大脑(修订版)

Help! A hacker said that this “language” has a flag but I can’t find it! Author: NoobMaster
帮助!一位黑客说这种“语言”有一个标志,但我找不到它!添加一名作者

問題バイナリとして以下の BrainFuck コードが与えられます。
以下 BrainFuck 代码作为问题二进制文件给出。

>+++++++++++[<++++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++[<+++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<+++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++[<++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<++++++>-]<[-]>+++++++[<++++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<[-]>+++++++++++[<+++>-]<[-]>+++++++++++++++++++++++++[<+++++>-]<[-]

例によって以下のスクリプトで C コードに置き換えます。
像往常一样,替换下面脚本中的 C 代码。

参考:bftoc/bftoc.py at master · paulkaefer/bftoc · GitHub
参考: bftoc/bftoc.py at master · paulkaefer/bftoc · GitHub

結果は以下のようになりました。 结果如下。

/* This is a translation of bf.txt, generated by bftoc.py (by Paul Kaefer)
 * It was generated on Saturday, August 03, 2024 at 03:20AM
 */

#include <stdio.h>

void main(void)
{
    int size = 1000;
    int tape[size];
    int i = 0;

    /* Clearing the tape (array) */
    for (i=0; i<size; i++)
        tape[i] = 0;

    int ptr = 0;

    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 10;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 8;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 8;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 14;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 7;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 61;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 2;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 41;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 3;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 7;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 7;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 19;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 5;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 9;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 13;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 4;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 10;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 19;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 5;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 9;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 8;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 10;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 10;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 17;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 3;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 19;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 5;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 7;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 7;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 10;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 19;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 5;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 14;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 7;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 19;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 13;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 4;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 7;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 7;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 10;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 17;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 7;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 6;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 9;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 107;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 1;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 11;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 3;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
    ptr += 1;
    tape[ptr] += 25;
    while (tape[ptr] != 0)
    {
        ptr -= 1;
        tape[ptr] += 5;
        ptr += 1;
        tape[ptr] -= 1;
    }
    ptr -= 1;
    while (tape[ptr] != 0)
    {
        tape[ptr] -= 1;
    }
}

このコードは、主に以下のパートで成り立っています。
这段代码主要由以下几部分组成。

ptr += 1;
tape[ptr] += 11;
while (tape[ptr] != 0)
{
    ptr -= 1;
    tape[ptr] += 10;
    ptr += 1;
    tape[ptr] -= 1;
}

これは Flag の各文字の検証を行っています。 这是验证 Flag 的每个字符。

なので以下の Solver で Flag を取得しました。
所以我使用以下解算器来获取标志。

case = """tape[ptr] += 11
tape[ptr] += 10
tape[ptr] += 8
tape[ptr] += 6
tape[ptr] += 8
tape[ptr] += 6
tape[ptr] += 14
tape[ptr] += 7
tape[ptr] += 61
tape[ptr] += 2
tape[ptr] += 41
tape[ptr] += 3
tape[ptr] += 7
tape[ptr] += 7
tape[ptr] += 19
tape[ptr] += 5
tape[ptr] += 11
tape[ptr] += 9
tape[ptr] += 13
tape[ptr] += 4
tape[ptr] += 11
tape[ptr] += 10
tape[ptr] += 19
tape[ptr] += 5
tape[ptr] += 11
tape[ptr] += 9
tape[ptr] += 8
tape[ptr] += 6
tape[ptr] += 10
tape[ptr] += 10
tape[ptr] += 17
tape[ptr] += 3
tape[ptr] += 19
tape[ptr] += 5
tape[ptr] += 7
tape[ptr] += 7
tape[ptr] += 11
tape[ptr] += 10
tape[ptr] += 19
tape[ptr] += 5
tape[ptr] += 14
tape[ptr] += 7
tape[ptr] += 19
tape[ptr] += 6
tape[ptr] += 13
tape[ptr] += 4
tape[ptr] += 7
tape[ptr] += 7
tape[ptr] += 11
tape[ptr] += 10
tape[ptr] += 17
tape[ptr] += 6
tape[ptr] += 7
tape[ptr] += 6
tape[ptr] += 11
tape[ptr] += 9
tape[ptr] += 107
tape[ptr] += 1
tape[ptr] += 11
tape[ptr] += 3
tape[ptr] += 25
tape[ptr] += 5"""

flag = ""
arr = case.splitlines()
for i,a in enumerate(arr):
    w = int(a.split(" ")[-1])
    if i % 2 == 0:
        count = w
    else:
        flag += chr(count*w)

# n00bz{1_c4n_c0d3_1n_br41nf*ck!}

FlagChecker(Rev) 旗帜检查器(修订版)

Why did the macros hide its knowledge? Because it didn’t want anyone to “excel”! Note: char21 is the SAME as char22 Note 2: The correct flag has ALL LOWERCASE, NUMBERS, n00bz{] AND UNDERSCORES (There’s two underscores in the entire flag) Author: NoobMaster
为什么宏要隐藏它的知识?因为它不想让任何人“出类拔萃”!注意:char 21 与 char 22 相同注2:正确的标志包含所有小写字母、数字、n00bz{] 和下划线(整个标志中有两个下划线)作者:NoobMaster

問題バイナリとして与えられた FlagChecker.xlsm から olevba でスクリプトを抽出します。
使用 olevba 从作为问题二进制文件给出的FlagChecker.xlsm中提取脚本。

olevba FlagChecker.xlsm > out.txt

抽出したスクリプトは以下の通りでした。 提取的脚本如下。

Sub FlagChecker()

    Dim chars(1 To 24) As String
    guess = InputBox("Enter the flag:")
    If Len(guess) <> 24 Then
        MsgBox "Nope"
    End If
    char_1 = Mid(guess, 1, 1)
    char_2 = Mid(guess, 2, 1)
    char_3 = Mid(guess, 3, 1)
    char_4 = Mid(guess, 4, 1)
    char_5 = Mid(guess, 5, 1)
    char_6 = Mid(guess, 6, 1)
    char_7 = Mid(guess, 7, 1)
    char_8 = Mid(guess, 8, 1)
    char_9 = Mid(guess, 9, 1)
    char_10 = Mid(guess, 10, 1)
    char_11 = Mid(guess, 11, 1)
    char_12 = Mid(guess, 12, 1)
    char_13 = Mid(guess, 13, 1)
    char_14 = Mid(guess, 14, 1)
    char_15 = Mid(guess, 15, 1)
    char_16 = Mid(guess, 16, 1)
    char_17 = Mid(guess, 17, 1)
    char_18 = Mid(guess, 18, 1)
    char_19 = Mid(guess, 19, 1)
    char_20 = Mid(guess, 20, 1)
    char_21 = Mid(guess, 21, 1)
    char_22 = Mid(guess, 22, 1)
    char_23 = Mid(guess, 23, 1)
    char_24 = Mid(guess, 24, 1)
    If Asc(char_1) Xor Asc(char_8) = 22 Then
        If Asc(char_10) + Asc(char_24) = 176 Then
            If Asc(char_9) - Asc(char_22) = -9 Then
                If Asc(char_22) Xor Asc(char_6) = 23 Then
                    If (Asc(char_12) / 5) ^ (Asc(char_3) / 12) = 130321 Then
                        If char_22 = char_11 Then
                            If Asc(char_15) * Asc(char_8) = 14040 Then
                                If Asc(char_12) Xor (Asc(char_17) - 5) = 5 Then
                                    If Asc(char_18) = Asc(char_23) Then
                                        If Asc(char_13) Xor Asc(char_14) Xor Asc(char_2) = 121 Then
                                            If Asc(char_14) Xor Asc(char_24) = 77 Then
                                                If 1365 = Asc(char_22) Xor 1337 Then
                                                    If Asc(char_10) = Asc(char_7) Then
                                                        If Asc(char_23) + Asc(char_8) = 235 Then
                                                            If Asc(char_16) = Asc(char_17) + 19 Then
                                                                If Asc(char_19) = 107 Then
                                                                    If Asc(char_20) + 501 = (Asc(char_1) * 5) Then
                                                                        If Asc(char_21) = Asc(char_22) Then
                                                                            MsgBox "you got the flag!"
                                                                        End If
                                                                    End If
                                                                End If
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        End If
    End If
End Sub

24 文字の Flag 文字列から各文字を取り出し、様々な検証を行っているようです。
看起来每个字符都是从24个字符的Flag字符串中提取出来的,并进行各种验证。

これを Z3Py で書き起こすと以下のようになりました。
当我使用 Z3Py 转录它时,它变成如下。

from z3 import *
flag = [BitVec(f"flag[{i}]", 64) for i in range(25)]
s = Solver()

for i in range(25):
    s.add(And(
        (flag[i] >= 0x21),
        (flag[i] <= 0x7e)
    ))

s.add(flag[1] == ord("n"))
s.add(flag[2] == ord("0"))
s.add(flag[3] == ord("0"))
s.add(flag[4] == ord("b"))
s.add(flag[5] == ord("z"))
s.add(flag[6] == ord("{"))
s.add(flag[24] == ord("}"))

s.add(flag[1] ^ flag[8] == 22)
s.add(flag[10] + flag[24] == 176)
s.add(flag[9] - flag[22] == -9)
s.add(flag[22] ^ flag[6] == 23)
s.add(flag[22] == flag[11])
# s.add(UDiv(flag[12],5) ** 4 == 130321)
s.add(flag[12] == 95)
s.add(flag[15] * flag[8] == 14040)
s.add(flag[12] ^ (flag[17] - 5) == 5)
s.add(flag[18] == flag[23])
s.add(flag[13] ^ flag[14] ^ flag[2] == 121)
s.add(flag[14] ^ flag[24] == 77)
s.add(flag[22] ^ 1337 == 1365)
s.add(flag[10] == flag[7])
s.add(flag[23] + flag[8] == 235)
s.add(flag[16] == flag[17] + 19)
s.add(flag[19] == 107)
s.add(flag[20] + 501 == flag[1] * 5)
s.add(flag[21]  == flag[22])

while s.check() == sat:
    m = s.model()
    for i in range(1,25):
        c = flag[i]
        print(chr(m[c].as_long()),end="")
    print("")

# n00bz{3xc3l_y0ur_sk1lls}

VBA で ^ が XOR じゃなくて累乗を意味するということに気づかず少しハマりました。
我对 VBA 有点上瘾,但没有意识到^意味着幂,而不是 XOR。

Plane(Forensic) 飞机(法医)

So many plane-related challenges! Why not another one? The flag is the latitude, longitude of the place this picture is taken from, rounded upto two decimal places. Example: n00bz{55.51,-20.27} Author: NoobMaster
这么多与飞机相关的挑战!为什么不换一个呢?标志是这张图片拍摄地点的纬度、经度,四舍五入到小数点后两位。示例:n00bz{55.51,-20.27} 作者:NoobMaster

exif に座標が埋まってました。 坐标存储在 exif 中。

n00bz CTF 2024 Writeup

Flag は以下。 旗帜在下面。

n00bz{13.37,-13.37}

Wave(Forensic) 波(法医)

The Wave is not audible, perhaps corrupted? Note: Wrap the flag in n00bz{}. There are no spaces in the flag and it is all lowercase. Author: NoobMaster
Wave 听不到,也许已损坏?注意:将标志包裹在 n00bz{} 中。标志中没有空格,并且全部为小写。添加一名作者

破損した WAV ファイルが与えられます。 您收到一个损坏的 WAV 文件。

マジックナンバーなどが 0 に置き換えられてるようです。
似乎幻数等都被替换为0。

n00bz CTF 2024 Writeup

適当に取得したサンプルの WAV ファイルは以下の通りでした。
随机获得的样本WAV文件如下。

n00bz CTF 2024 Writeup

これを参考に破損した WAV ファイルを修復します。
将此作为修复损坏的 WAV 文件的参考。

n00bz CTF 2024 Writeup

修復した WAV ファイルを再生するとモールス信号でしたので、以下のサイトで解読しました。
当我播放修复后的WAV文件时,它是莫尔斯电码,所以我使用下面的网站对其进行解码。

n00bz CTF 2024 Writeup

参考:Morse Code Adaptive Audio Decoder | Morse Code World
参考:莫尔斯电码自适应音频解码器 |摩尔斯电码世界

正しい Flag は以下でした。 正确的标志如下。

n00bz{beepbopmorsecode}

Vinegar(Crypto) 醋(加密)

Can you decode this message? Note: Wrap the decrypted text in n00bz{}
你能解码这条消息吗?注意:将解密后的文本包裹在 n00bz{} 中

以下のテキストが与えられます。 您将获得以下文本:

Encrypted flag: nmivrxbiaatjvvbcjsf
Key: secretkey

問題名の通りヴィジュネル暗号(Vigenere cipher)でしたので、以下のサイトで解析しました。
正如问题的名称所暗示的,这是一个维吉尼亚密码,所以我在以下站点对其进行了分析。

n00bz CTF 2024 Writeup

正しい Flag は以下でした。 正确的标志如下。

n00bz{vigenerecipherisfun}

Vinegar 2(Crypto) 醋2(加密)

Never limit yourself to only alphabets! Author: NoobMaster
永远不要将自己局限于字母!添加一名作者

問題バイナリとして以下の Solver が与えられます。
以下求解器作为问题二进制文件给出。

今回も換字式暗号のようですが、変換テーブルが独自に実装されているようです。
这次好像是替换密码,不过转换表好像是独立实现的。

alphanumerical = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}_?'
matrix = []
for i in alphanumerical:
	matrix.append([i])

idx=0
for i in alphanumerical:
	matrix[idx][0] = (alphanumerical[idx:len(alphanumerical)]+alphanumerical[0:idx])
	idx += 1

flag=open('../src/flag.txt').read().strip()
key='5up3r_s3cr3t_k3y_f0r_1337h4x0rs_r1gh7?'
assert len(key)==len(flag)
flag_arr = []
key_arr = []
enc_arr=[]
for y in flag:
	for i in range(len(alphanumerical)):
		if matrix[i][0][0]==y:
			flag_arr.append(i)

for y in key:
	for i in range(len(alphanumerical)):
		if matrix[i][0][0]==y:
			key_arr.append(i)

for i in range(len(flag)):
	enc_arr.append(matrix[flag_arr[i]][0][key_arr[i]])
encrypted=''.join(enc_arr)
f = open('enc.txt','w')
f.write(encrypted) # *fa4Q(}$ryHGswGPYhOC{C{1)&_vOpHpc2r0({

そこで、これを復号する以下の Solver を作成しました。
因此,我创建了以下解算器来解密它。

alphanumerical = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}_?'
matrix = []
for i in alphanumerical:
	matrix.append([i])

idx=0
for i in alphanumerical:
	matrix[idx][0] = (alphanumerical[idx:len(alphanumerical)]+alphanumerical[0:idx])
	idx += 1
	
flag=r"*fa4Q(}$ryHGswGPYhOC{C{1)&_vOpHpc2r0({"
key='5up3r_s3cr3t_k3y_f0r_1337h4x0rs_r1gh7?'
assert len(key)==len(flag)

flag_arr = []
key_arr = []
resolve_arr = []
for y in key:
	for i in range(len(alphanumerical)):
		if matrix[i][0][0]==y:
			key_arr.append(i)

for i,f in enumerate(flag):
	for j,arr in enumerate(matrix):
		if arr[0][key_arr[i]] == f:
			resolve_arr.append(j)
			break

for n in resolve_arr:
	print(alphanumerical[n],end="")
print("")

# n00bz{4lph4num3r1c4l_1s_n0t_4_pr0bl3m}

RSA(Crypto) RSA(加密)

The cryptography category is incomplete without RSA. So here is a simple RSA challenge. Have fun! Author: noob_abhinav
如果没有 RSA,密码学类别就不完整。这是一个简单的 RSA 挑战。玩得开心!添加一名作者

問題バイナリとして以下が与えられます。 给出了以下问题二进制文件:

e = 3
n = 135112325288715136727832177735512070625083219670480717841817583343851445454356579794543601926517886432778754079508684454122465776544049537510760149616899986522216930847357907483054348419798542025184280105958211364798924985051999921354369017984140216806642244876998054533895072842602131552047667500910960834243
c = 13037717184940851534440408074902031173938827302834506159512256813794613267487160058287930781080450199371859916605839773796744179698270340378901298046506802163106509143441799583051647999737073025726173300915916758770511497524353491642840238968166849681827669150543335788616727518429916536945395813

e が 3 であり、c が n より小さいため、c の 3 乗根をとることにしました。
由于 e 为 3 并且 c 小于 n,因此我们决定取 c 的立方根。

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

e = 3
n = 135112325288715136727832177735512070625083219670480717841817583343851445454356579794543601926517886432778754079508684454122465776544049537510760149616899986522216930847357907483054348419798542025184280105958211364798924985051999921354369017984140216806642244876998054533895072842602131552047667500910960834243
c = 13037717184940851534440408074902031173938827302834506159512256813794613267487160058287930781080450199371859916605839773796744179698270340378901298046506802163106509143441799583051647999737073025726173300915916758770511497524353491642840238968166849681827669150543335788616727518429916536945395813
assert c < n

a,b=gmpy2.iroot(c,e)
print(long_to_bytes(a))

# n00bz{crypt0_1s_1nc0mpl3t3_w1th0ut_rs4!!}

上記の Solver で Flag を取得できます。
您可以使用上面的 Solver 获得 Flag。

Random(Crypto) 随机(加密)

I hid my password behind an impressive sorting machine. The machine is very luck based, or is it?!?!?!? Author: Connor Chang
我把密码藏在一台令人印象深刻的分类机后面。该机器非常靠运气,或者是吗?!?!?!?作者:康纳·张

問題バイナリとして以下のスクリプトが与えられます。
以下脚本作为问题二进制文件给出。

リモートサーバーではこのコードをコンパイルしたプログラムが稼働しているようです。
看来由该代码编译的程序正在远程服务器上运行。

#include<chrono>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#include<fstream>
#include<thread>
#include<map>
using namespace std;

bool amazingcustomsortingalgorithm(string s) {
    int n = s.size();
    for (int i = 0; i < 69; i++) {
        cout << s << endl;
        bool good = true;
        for (int i = 0; i < n - 1; i++)
            good &= s[i] <= s[i + 1];
        
        if (good)
            return true;

        random_shuffle(s.begin(), s.end());

        this_thread::sleep_for(chrono::milliseconds(500));
    }

    return false;
}

int main() {
    string s;
    getline(cin, s);

    map<char, int> counts;
    for (char c : s) {
        if (counts[c]) {
            cout << "no repeating letters allowed passed this machine" << endl;
            return 1;
        }
        counts[c]++;
    }

    if (s.size() < 10) {
        cout << "this machine will only process worthy strings" << endl;
        return 1;
    }

    if (s.size() == 69) {
        cout << "a very worthy string" << endl;
        cout << "i'll give you a clue'" << endl;
        cout << "just because something says it's random mean it actually is" << endl;
        return 69;
    }

    random_shuffle(s.begin(), s.end());
    
    if (amazingcustomsortingalgorithm(s)) {
        ifstream fin("flag.txt");
        string flag;
        fin >> flag;
        cout << flag << endl;
    }
    else {
        cout << "UNWORTHY USER DETECTED" << endl;
    }
}

amazingcustomsortingalgorithm 関数では、入力した文字列を random_shuffle 関数でシャッフルし、ソートされた文字列が生成されれば Flag を取得できます。
Amazingcustomsortingalgorithm 函数用random_shuffle函数对输入字符串进行打乱,如果生成了排序后的字符串,就可以获得 Flag。

何度か操作を行うと、random_shuffle 関数によるシャッフルのパターンが固定化されていることに気づきます。
执行多次操作后,您会注意到random_shuffle函数创建的随机播放模式变得固定。

そこで、ABCDEFGHIJK をシャッフルした文字列と対応する位置の文字を手動で置き換え、1 回目のシャッフル結果が ABCDEFGHIJK となる文字列を用意しました。
于是,我手动将对应位置的字符替换为ABCDEFGHIJK打乱后的字符串,并准备了第一次打乱结果为ABCDEFGHIJK的字符串。

n00bz CTF 2024 Writeup

これを入力すると Flag を取得できます。 输入这个,就可以得到Flag。

n00bz CTF 2024 Writeup

Tail(OSINT) 尾巴(开源情报)

Here’s a picture of a plane’s tail. Can you find the airline’s hub (the airport where they mostly operate from). Use the three letter airport IATA code and wrap it in n00bz{}. Example: n00bz{SFO}
这是飞机尾部的照片。您能找到航空公司的枢纽(主要运营的机场)吗?使用三个字母的机场 IATA 代码并将其包装在 n00bz{} 中。示例:n00bz{SFO}

以下の画像が与えられます。 您将看到下图。

n00bz CTF 2024 Writeup

airplain blue flower などで検索するとこの模様の飛行機が見つかります。
如果您搜索airplain blue flower ,您会找到具有此图案的飞机。

n00bz CTF 2024 Writeup

正しい Flag は n00bz{PPT} でした。
正确的标志是n00bz{PPT} 。

The Gang(OSINT) 该团伙(开源情报)

John Doe has been suspected of creating a gang. The members of team n00bzUnit3d also seem associated with it. Can you find out if John Doe has recently joined the team? You might find what you are looking for 😉 P.S.: The team website might help
无名氏被怀疑创建了一个团伙。 n00bzUnit3d 团队的成员似乎也与此有联系。您能查出 John Doe 最近是否加入了该团队吗?您可能会找到您想要的东西;)PS:团队网站可能会有所帮助

n00bzUnit3d のチームサイトから以下のユーザページを見つけます。
从 n00bzUnit3d 的团队站点找到以下用户页面。

参考:Authors

n00bz CTF 2024 Writeup

The Gang 2(OSINT) 《黑帮 2》(开源情报)

You may have gotten your first flag, but it’s just the beginning! John Doe, as overconfident as he is, has left you with a riddle. Maybe it hides some secrets? Continue where you left off last time. Flag will already by wrapped in n00bz{} Author: NoobMaster
您可能已经获得了第一面旗帜,但这仅仅是开始!无名氏尽管过于自信,却给你留下了一个谜语。也许它隐藏着一些秘密?从上次中断的地方继续。标志已被包裹在 n00bz{} 作者:NoobMaster

以下の文を縦読みすると、ユーザ名が JOHN HACKER DOE であることがわかります。
如果你垂直阅读下面的句子,你会看到用户名是JOHN HACKER DOE 。

n00bz CTF 2024 Writeup

これを X で探すと、Flag が見つかりました。
我在X中搜索了这个并找到了Flag。

n00bz CTF 2024 Writeup

Flag は n00bz{5t0p_ch4s1ng_m3_4f2d1a7d} です。
标记はn00bz{5t0p_ch4s1ng_m3_4f2d1a7d}です。

The Gang 3(OSINT) 《黑帮 3》(开源情报)

Can you find out where the OG meetup point is? The flag is in the format n00bz{lat,long} with upto 3 decimal places, rounded. Continue where you left off… Note: Wikipedia can be wrong sometimes 😉 Author: NoobMaster
你能找到 OG 集合点在哪里吗?该标志的格式为 n00bz{lat,long},最多 3 位小数,四舍五入。从上次停下的地方继续……注意:维基百科有时可能是错误的;)作者:NoobMaster

ツイートを詳しく読むと、AES 暗号文と復号のためのヒントが与えられます。
仔细查看该推文,您将获得 AES 密文和解密提示。

n00bz CTF 2024 Writeup

過去の n00bzCTF の John Doe の関連問題を探すと、AES の復号に必要な情報が見つかります。
您可以通过查找过去的 n00bzCTF John Doe 问题来找到解密 AES 所需的信息。

参考:n00bzCTF2023-OfficalWriteups/OSINT/John Doe Strikes Again at master · n00bzUnit3d/n00bzCTF2023-OfficalWriteups
参考: n00bzCTF2023-OfficalWriteups/OSINT/John Doe 再次出击大师 · n00bzUnit3d/n00bzCTF2023-OfficalWriteups

参考:n00bzCTF-OfficialWriteups/osint/john_doe at main · n00bzUnit3d/n00bzCTF-OfficialWriteups
参考: n00bzCTF-OfficialWriteups/osint/john_doe at main · n00bzUnit3d/n00bzCTF-OfficialWriteups

これを復号すると Discord サーバの URL がでてきました。
当我解密它时,我得到了 Discord 服务器的 URL。

n00bz CTF 2024 Writeup

このサーバに参加すると、インドの Bengaluru 周辺の 110 フィートの銅像で合流する予定であることがわかります。
如果您加入此服务器,您会发现我们计划在印度班加罗尔周围的一座 110 英尺高的青铜雕像见面。

この銅像の人物は空港の名前の由来にもなっているらしいです。
看来这座铜像里的人也是机场名字的由来。

n00bz CTF 2024 Writeup

これは、以下の銅像でした。 这就是下面的雕像。

参考:Nadaprabhu Kempegowda Statue – Google Maps
参考: Nadaprabhu Kempegowda 雕像 – 谷歌地图

この銅像の座標が正しい Flag n00bz{13.199,77.682} になります。
该雕像的坐标是正确的 Flag n00bz{13.199,77.682} 。

The Gang 4(OSINT) 《黑帮 4》(开源情报)

Can you find more information about his flight? Time to close John Doe’s case one and for all! Author: NoobMaster Note: Flag format: n00bz{DateOfFlight(DD/MM/YYYY)FlightNumberIATAairportCodeOfDepartureIATAairportCodeofArrivalACTUALtimeOfDepartureACTUALtimeOfArrivalGateofDepartureAirplaneModel} Example: n00bz{26/06/2024AA1337DFWSFO13:3715:5132AAirbusA319-400} Please use the above format to format your flag.
您能找到有关他的航班的更多信息吗?是时候彻底了结无名氏的一案了!作者:NoobMaster 注意:标志格式:n00bz{DateOfFlight(DD/MM/YYYY) FlightNumber IATAairportCodeOfDeparture IATAairportCodeofArrival ACTUALtimeOfDeparture ACTUALtimeOfArrival GateofDeparture AirplaneModel} 示例:n00bz{26/06/2024 AA1337 DFW SFO 13:37 15:51 32A Airbus A319-400} 请使用上述格式来格式化您的标志。

Discord サーバ内の会話から、John Doe が乗った飛行機に関する情報を収集します。
从 Discord 服务器中的对话收集有关 John Doe 飞机的信息。

n00bz CTF 2024 Writeup

n00bz CTF 2024 Writeup

これらの情報から以下のサイトにたどり着くことができます。
此信息将引导您访问以下网站。

参考:AI506 (AIC506) Air India Flight Tracking and History 03-Aug-2024 (DEL / VIDP-BLR / VOBL) – FlightAware
参考: AI506 (AIC506) 印度航空 航班跟踪和历史记录 2024 年 8 月 3 日 (DEL / VIDP-BLR / VOBL) – FlightAware

正しい Flag は n00bz{03/08/2024_AI506_DEL_BLR_10:03_12:44_30_AirbusA350-900} でした。
正确的标志是n00bz{03/08/2024_AI506_DEL_BLR_10:03_12:44_30_AirbusA350-900} 。

Pastebin(OSINT) Pastebin(OSINT)

Just go to my pastebin which was created long time back. Username: abhinav654321
只要去我很久以前创建的pastebin就可以了。用户名: abhinav654321

与えられたユーザ名で Pastebin を検索します。
使用给定的用户名搜索 Pastebin。

n00bz CTF 2024 Writeup

参考:Nothing here – Pastebin.com
参考:这里什么都没有 – Pastebin.com

この投稿の過去のコンテンツを Wayback Machine で探すと Flag を特定できます。
您可以通过在 Wayback Machine 中搜索本文过去的内容来找到 Flag。

n00bz CTF 2024 Writeup

参考:n00bz{l0ngt1m3ag0m34nsw4yb4ck} – Pastebin.com
参考: n00bz{l0ng t1m3 ag0 m34ns w4yb4ck} – Pastebin.com

PastebinX(OSINT)

All I need is the User ID said the boss. Help the poor employee to find the id. Flag format – n00bz{1d}. If id is “hhjkh876897” then flag will be n00bz{1dhhjkh876897}
老板说我只需要用户ID。帮助可怜的员工找到身份证。标志格式 – n00bz{1d }。如果 id 为“hhjkh876897”,则标志将为 n00bz{1d hhjkh876897}

Pastebin の投稿から、@Abhinav78082932 という X アカウントの ID?を特定する問題であると予想できます。
从 Pastebin 帖子中,X 帐户@Abhinav78082932的 ID 是什么?可以预见,这是一个难以识别的问题。

しかし、ここで完全にハマりました。 但在这里我完全被迷住了。

最終的にチームメンバーが Twitter アカウントの内部 ID?のようなものが存在することに気づき、正しい Flag を特定できました。
最后,团队成员是 Twitter 帐户的内部 ID 吗?我意识到类似的事情,并且能够识别正确的 Flag 。

参考:Twitter ID Finder and Converter (100% Working ✅)
参考: Twitter ID 查找器和转换器(100% 工作 ✅)

Passwordless(Web) 无密码(网页)

Tired of storing passwords? No worries! This super secure website is passwordless! Author: NoobMaster
厌倦了存储密码?不用担心!这个超级安全的网站是无密码的!添加一名作者

問題バイナリとして以下のコードが与えられます。 以下代码作为问题二进制文件给出。

#!/usr/bin/env python3
from flask import Flask, request, redirect, render_template, render_template_string
import subprocess
import urllib
import uuid
global leet

app = Flask(__name__)
flag = open('/flag.txt').read()
leet=uuid.UUID('13371337-1337-1337-1337-133713371337')

@app.route('/',methods=['GET','POST'])
def main():
    global username
    if request.method == 'GET':
        return render_template('index.html')
    elif request.method == 'POST':
        username = request.values['username']
        if username == 'admin123':
            return 'Stop trying to act like you are the admin!'
        uid = uuid.uuid5(leet,username) # super secure!
        return redirect(f'/{uid}')

@app.route('/<uid>')
def user_page(uid):
    if uid != str(uuid.uuid5(leet,'admin123')):
        return f'Welcome! No flag for you :('
    else:
        return flag

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=1337)

ユーザ名 admin123 の UUID を URL に含む場合に Flag が返されるため、手動で生成した UUID を URL に付与して直接アクセスしました。
URL中包含用户名admin123的UUID时会返回flag,所以我将手动生成的UUID添加到URL中并直接访问。

n00bz CTF 2024 Writeup

n00bz CTF 2024 Writeup

Addition(Misc) 加法(杂项)

My little brother is learning math, can you show him how to do some addition problems? Author: Connor Chang
我的弟弟正在学数学,你能教他如何做一些加法题吗?作者:康纳·张

なんか足し算の計算をするらしいです。 它似乎在进行某种加法计算。

import time
import random

questions = int(input("how many questions do you want to answer? "))

for i in range(questions):
    a = random.randint(0, 10)
    b = random.randint(0, 10)

    yourans = int(input("what is " + str(a) + ' + ' + str(b) + ' = '))

    print("calculating")

    totaltime = pow(2, i)

    print('.')
    time.sleep(totaltime / 3)
    print('.')
    time.sleep(totaltime / 3)
    print('.')
    time.sleep(totaltime / 3)

    if yourans != a + b:
        print("You made my little brother cry 😭")
        exit(69)

f = open('/flag.txt', 'r')
flag = f.read()
print(flag[:questions])

totaltime = pow(2, i) で Sleep させられる時間が膨大過ぎるので、正攻法では解けません。
totaltime = pow(2, i)睡眠所需的时间量太大,因此无法使用简单的方法解决。

最終的に print(flag[:questions]) で Flag を表示できればいいため、単に -1 を入力して Flag を取得しました。
最后,我只需要能够使用print(flag[:questions])显示标志,所以我只需输入 -1 即可获取标志。

from pwn import *

# Set context
# context.log_level = "debug"
target = remote("24.199.110.35", 42189, ssl=False)

# Exploit
q = -1
target.recvuntil(b"how many questions do you want to answer? ")
target.sendline(str(q))
print(target.recvline())

# Finish exploit
target.interactive()
target.clean()

n00bz CTF 2024 Writeup

Subtraction(Misc) 减法(杂项)

My little brother is learning math, can you show him how to do some subtraction problems? Author: Connor Chang
我弟弟正在学数学,你能教他怎么做一些减法题吗?作者:康纳·张

今度は引き算らしいです。 这次好像是减法。

696969 個のランダムに生成された偶数の配列を任意の整数 c から引いた結果の絶対値をとる操作を最大 20 回繰り返した結果、配列内のすべての値を同じ値にすることができれば Flag を取得できます。
696969 如果通过重复从任意整数 c 中减去随机生成的偶数数组并取结果的绝对值的操作最多 20 次,可以使数组中的所有值都相同,则设置旗子就可以拿到了。

import random

n = 696969

a = []
for i in range(n):
    a.append(random.randint(0, n))
    a[i] -= a[i] % 2

print(' '.join(list(map(str, a))))

for turns in range(20):
    c = int(input())
    for i in range(n):
        a[i] = abs(c - a[i])

    if len(set(a)) == 1:
        print(open('/flag.txt', 'r').read())
        break

少し悩んだ末に、最終的に配列内の要素の最大値を 1 に近づけていく操作ができればよいことに気づきました。
想了一会儿,我终于意识到我可以做一个运算,使数组中元素的最大值更接近1。

そこで、以下の Solver で最大値と最小値の平均をとる操作を繰り返していくことで Flag を取得できました。
因此,通过使用下面的Solver重复计算最大和最小值的平均操作,我能够获得Flag。

from pwn import *

# context.log_level = "debug"
# target = process(TARGET_PATH)
target = remote("challs.n00bzunit3d.xyz", 10274, ssl=False)

r = target.recvline().decode()
arr = []
for n in r.split(" "):
    arr.append(int(n))

# Exploit
n = len(arr)
for turns in range(20):
    min_a = min(arr)
    max_a = max(arr)
    c = (min_a + max_a) // 2
    for i in range(n):
        arr[i] = abs(c - arr[i])
    target.sendline(str(c).encode())
    if len(set(arr)) == 1:
        print("found")
        break

print(target.recvline())

# Finish exploit
target.interactive()
target.clean()

n00bz CTF 2024 Writeup

Think Outside the Box(Pwn)
跳出框框思考(Pwn)

You cannot beat my Tic-Tac-Toe bot! If you do, you get a flag! Author: NoobMaster
你无法击败我的井字棋机器人!如果你这样做了,你就会得到一面旗帜!添加一名作者

○× ゲームの後攻でゲームに勝利すると Flag を得られます。
○× 如果您以第二名赢得比赛,您将获得一面旗帜。

しかし、普通にプレイしても後攻だと引き分けにしかできません。
不过,就算发挥正常,如果退居第二,也只能以平局告终。

また、入力をとる箇所も 1 箇所しかないため、Attack Surface が一切ありません。
此外,由于只有一个地方可以接受输入,因此根本不存在攻击面。

最終的に、チームメンバーが -1 を入力すると board_limit_0x3 s> y && board_limit_0x3 s> x の検証をバイパスするとともに、Bot の操作をバグらせることができることに気づきました。
最终,我们意识到团队成员可以输入 -1 来绕过board_limit_0x3 s> y && board_limit_0x3 s> x验证并导致机器人的操作出现错误。

int32_t main(int32_t argc, char** argv, char** envp)
{
    void* fsbase
    int64_t rax = *(fsbase + 0x28)
    int32_t board_limit_0x3 = 3
    int16_t board
    __builtin_strncpy(dest: &board, src: "____X____", n: 9)
    puts(str: "Welcome to Tic-Tac-Toe! In order…")
    printBoard(&board)
    int32_t N
    int32_t M
    move(&board, board_limit_0x3, stage_count: 1, &N, &M, 0, 1)
    printBoard(&board)
    int32_t K
    int32_t L
    move(&board, board_limit_0x3, stage_count: 2, &K, &L, N, M)
    printBoard(&board)
    int32_t var_30
    int32_t var_2c
    move(&board, board_limit_0x3, stage_count: 3, &var_30, &var_2c, K, L)
    printBoard(&board)
    void var_28
    void var_24
    move(&board, board_limit_0x3, stage_count: 4, &var_28, &var_24, var_30, var_2c)
    
    if (rax == *(fsbase + 0x28))
        return rax.d - (*(fsbase + 0x28)).d
    
    __stack_chk_fail()
    noreturn
}
        

int64_t move(char* board, int32_t board_limit_0x3, int32_t stage_count, int32_t* arg4, int32_t* arg5, int32_t arg6, int32_t arg7)
{
    void* fsbase
    int64_t rax = *(fsbase + 0x28)
    printf(format: "Move: ")
    int32_t y  // カンマ区切りでy,x
    int32_t x
    __isoc99_scanf(format: "%d,%d", &y, &x)
    
    if (board_limit_0x3 s> y && board_limit_0x3 s> x && board[sx.q(y) * 3 + sx.q(x)] != 'X' && board[sx.q(y) * 3 + sx.q(x)] != 'O')
        board[sx.q(y) * 3 + sx.q(x)] = 0x4f
        int32_t is_win
        is_win.b = checkWin(board, board_limit_0x3) != 0
        
        if (is_win.b != 0)
            printBoard(board)
            printf(format: "You won! Flag: ")
            void buf
            fgets(&buf, n: 0x26, fp: fopen(filename: "flag.txt", mode: &data_3080))
            printf(format: &data_308b, &buf)
            exit(status: 0)
            noreturn
        
        printBoard(board)
        
        if (stage_count == 1)
            puts(str: "Bot turn!")
            int32_t var_68
            int32_t var_64
            firstmove(board, y, x, &var_68, &var_64)
            *arg4 = var_68
            *arg5 = var_64
        
        if (stage_count == 2)
            puts(str: "Bot turn!")
            int32_t var_60
            int32_t var_5c
            secondmove(board, y, x, &var_60, &var_5c, arg6, arg7, board_limit_0x3)
            *arg4 = var_60
            *arg5 = var_5c
        
        if (stage_count == 3)
            puts(str: "Bot turn!")
            uint64_t board_limit_0x3_1 = zx.q(board_limit_0x3)
            uint64_t var_b8_2 = zx.q(arg7)
            void var_58
            void var_54
            thirdmove(board, y, x, &var_58, &var_54, arg6)
        
        if (stage_count == 4)
            puts(str: "Bot turn!")
            uint64_t board_limit_0x3_2 = zx.q(board_limit_0x3)
            uint64_t var_b8_3 = zx.q(arg7)
            fourthmove(board, y)
        
        if (rax == *(fsbase + 0x28))
            return rax - *(fsbase + 0x28)
        
        __stack_chk_fail()
        noreturn
    
    puts(str: "Invalid move!")
    exit(status: 0)
    noreturn
}

○× ゲームのテーブルは線形の文字列で管理されているため、-1 を入力に使用することで Bot の動きを止めつつ複数のマスを埋めることでゲームに勝利し、Flag を取得しました。
True/False 游戏表是由线性字符串管理的,因此通过使用 -1 作为输入,我们停止机器人的移动并填充多个方块以赢得游戏并获得 Flag。

n00bz CTF 2024 Writeup

まとめ 概括

たくさんの問題を解いた。 我解决了很多问题。

全体的に難易度は易しめでサクサク解けたので楽しかったです。
总的来说,难度很简单,我很快就能解决,所以很有趣。

原文始发于0nePadding:n00bz CTF 2024 Writeup

版权声明:admin 发表于 2024年8月6日 上午9:19。
转载请注明:n00bz CTF 2024 Writeup | CTF导航

相关文章