Post

The InfoSecurity Challenge 2023

Writeup on The InfoSecurity Challenge 2023.

Level 1: Disk Archaeology

Unknown to the world, the sinister organization PALINDROME has been crafting a catastrophic malware that threatens to plunge civilization into chaos. Your mission, if you choose to accept it, is to infiltrate their secret digital lair, a disk image exfiltrated by our spies. This disk holds the key to unraveling their diabolical scheme and preventing the unleashing of a suspected destructive virus.

You will be provided with the following file:

  • md5(challenge.tar.xz) = 80ff51568943a39de4975648e688d6a3

Notes:

  • challenge.tar.xz decompresses into challenge.img
  • FLAG FORMAT is TISC{<some text you have to find>}
Downloadable File SHA256 checksum
challenge.tar.xz 49d54865399dac9d03158a057b643f3691cd23d430d869714aff5c9b34e01aa2

Downloaded challenge.tar.xz and performed some processing.

1
2
3
4
5
6
$ md5sum challenge.tar.xz
80ff51568943a39de4975648e688d6a3  challenge.tar.xz
$ tar -xvf challenge.tar.xz
challenge.img
$ md5sum challenge.img
8446ba456d81d8403a37e06fe7ebd8f8  challenge.img

Added challenge.img in FTK Imager as evidence item and saw that it was Linux filesystem.

image

Performed strings with grep to do a quick search, but was tricked with a fake flag.

1
2
$ strings challenge.img | grep -i "TISC"
TISC{w4s_th3r3_s0m3th1ng_l3ft_%s}

Guessed that %s may be referring to a string variable. Explored the directories in hope of finding some program or script, but was unsuccessful.

Moved on to perform file carving using PhotoRec to recover files from unallocated space.

1
$ sudo photorec challenge.img

Selected Disk challenge.img for media, P ext4 for Partition, [ext2/ext3] for filesystem type and Free to scan for file from ext2/ext3 unallocated space only.

Recovery completed and f1315992.elf was obtained.

1
2
$ md5sum f1315992.elf
fc344b7f694e727f06bc6dc0ed4ba402  f1315992.elf

Ran f1315992.elf and encountered error. The file is in the directory though.

1
2
$ ./f1315992.elf
-bash: ./f1315992.elf: No such file or directory

Checked further and realised the problem is lack of interpreter.

1
2
$ readelf -a f1315992.elf | grep -i "interpreter"
      [Requesting program interpreter: /lib/ld-musl-x86_64.so.1]

Found ld-musl-x86_64.so.1 in challenge.img and exported it.

image

Moved ld-musl-x86_64.so.1 to /lib of my VM and ran f1315992.elf again.

1
2
3
$ sudo mv ld-musl-x86_64.so.1 /lib
$ ./f1315992.elf
TISC{w4s_th3r3_s0m3th1ng_l3ft_ubrekeslydsqdpotohujsgpzqiojwzfq}

Flag: TISC{w4s_th3r3_s0m3th1ng_l3ft_ubrekeslydsqdpotohujsgpzqiojwzfq}

Level 2: XIPHEREHPIX’s Reckless Mistake

Our sources told us that one of PALINDROME’s lieutenants, XIPHEREHPIX, wrote a special computer program for certain members of PALINDROME. We have somehow managed to get a copy of the source code and the compiled binary. The intention of the program is unclear, but we think encrypted blob inside the program could contain a valuable secret.

Downloadable File SHA256 checksum
prog.c e06e901befa4cd1d9397a30d8e4418ac096539000057f92624e3d38d808a7ced
XIPHEREHPIX 5e9639909fbe874b3c15a3c86c35c1fe3007c203e369b95a19677e78e4ad8284

Interacted with the program.

1
2
3
4
5
6
$ ./XIPHEREHPIX
Hello PALINDROME member, please enter password:
The password should be at least 40 characters as per PALINDROME's security policy.
$ ./XIPHEREHPIX
Hello PALINDROME member, please enter password:
Failure!

Reviewed the source code provided and used ChatGPT to explain the various code functions.

Observed that initialise_key() may be vulnerable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void initialise_key(unsigned char *key, char *password, int password_length) {
    const char *seed = "PALINDROME IS THE BEST!";
    int i, j;
    int counter = 0;

    uint256_t *key256  = (uint256_t *)key;

    key256->a0 = 0;
    key256->a1 = 0;
    key256->a2 = 0;
    key256->a3 = 0;

    uint256_t arr[20] = { 0 };

    calculate_sha256((unsigned char *) arr, (unsigned char *) seed, strlen(seed));

    for (i = 1; i < 20; i++) {
        calculate_sha256((unsigned char *)(arr+i), (unsigned char *) (arr+i-1), 32);
    }

    for (i = 0; i < password_length; i++) {
        int ch = password[i];
        for (j = 0; j < 8; j++) {
            counter = counter % 20;

            if (ch & 0x1) {
                accumulate_xor(key256, arr+counter);
            }

            ch = ch >> 1;
            counter++;
        }
    }
}

Summarising the weakness found in initialise_key():

  • Regardless of the password length, only the first three printable and non-printable ASCII characters matters.
  • To be more specific, only the first 20 bits truly matters.
  • The 20 arr elements are being XORed with the key256 elements under certain conditions.
  • As XOR is an involutory function - i.e. its own inverse, there can only be two outcomes.
  • This restricts the number of possible outcomes resulting from performing multiple XOR operations with 20 arr elements to 2^20 = 1048576.
  • By testing all combinations of 24 bits in 3 character array form as password, decryption can be achieved via brute-force method within reasonable time.

Used ChatGPT to write a loop in C to generate all possible combinations of 24 bits and convert them into a 3 character array, then combine the loop with main().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char **argv) {
    char password[MAX_PASSWORD_SIZE + 1] = { 0 };
    int password_length;
    unsigned char key[32];
    password_length = 3;
    
    for (unsigned int i = 0; i < (1 << 24); i++) {
        // Convert the 24-bit value to a 3-character array
        char password[4]; // 3 characters + null terminator

        // Extract each 8-bit portion
        password[0] = (i >> 16) & 0xFF;
        password[1] = (i >> 8) & 0xFF;
        password[2] = i & 0xFF;
        password[3] = '\0'; // Null-terminate the string

        initialise_key(key, password, password_length);
        show_welcome_msg(key);
    }
}

Modified show_welcome_message() to print only if plaintext contains TISC and exit program.

1
2
3
4
    if (strstr(plaintext,"TISC") != NULL) {
        printf("Welcome PALINDROME member. Your secret message is %.*s\n", plaintext_length, plaintext);
        exit(1);
    }

Installed libssl-dev.

1
sudo apt-get install libssl-dev

Compiled the edited c code.

1
gcc -o prog prog.c -lssl -lcrypto

Ran prog.

1
2
./prog                           
Welcome PALINDROME member. Your secret message is TISC{K3ysP4ce_1s_t00_smol_d2g7d97agsd8yhr}

Flag: TISC{K3ysP4ce_1s_t00_smol_d2g7d97agsd8yhr}

Level 3: KPA

We’ve managed to grab an app from a suspicious device just before it got reset! The copying couldn’t finish so some of the last few bytes got corrupted… But not all is lost! We heard that the file shouldn’t have any comments in it! Help us uncover the secrets within this app!

Downloadable File SHA256 checksum
kpa.apk 5e93e5f6ed5f2c8b7286a6d7d03a73da2f75d8999c33be6a5e97bc425cacb497

Removed bytes from comment length of End of central directory record.

image

image

image

Decompiled apk using Decompiler.com and reviewed the contents. Found code related to flag at \sources\com\tisc\kappa\MainActivity.java.

1
2
> adb connect 192.168.188.131
> adb install kpa.apk

image

Setup Frida, a dynamic instrumentation toolkit to inject scripts.

1
2
3
4
> adb connect 192.168.188.131
> adb push frida-server /data/local/tmp/
> adb shell "chmod 755 /data/local/tmp/frida-server"
> adb shell "/data/local/tmp/frida-server &"

Checked processes.

image

Performed test on hooking functions using python script and observed the variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import frida, sys
jscode = """
Java.perform(() => {
let b = Java.use("j1.b");
b["e"].implementation = function () {
    console.log(`b.e is called`);
    let result = this["e"]();
    console.log(`b.e result=${result}`);
    return result;
};
});
"""
process = frida.get_usb_device().attach('KaPpA')
script = process.create_script(jscode)
print('[*] Running CTF')
script.load()
sys.stdin.read()

Observed b.e is called with result true.

image

Changed b.e to false and a.a is called.

image

Check back on the code.

image

Changed a.a to 20.

Prepared eventual python script to perform necessary changes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import frida, sys
jscode = """
Java.perform(() => {
let b = Java.use("j1.b");
b["e"].implementation = function () {
    console.log(`b.e is called`);
    let result = false;
    console.log(`b.e result=${result}`);
    return result;
};
let a = Java.use("j1.a");
a["a"].implementation = function (packageManager) {
    console.log(`a.a is called: packageManager=${packageManager}`);
    let result = 20;
    console.log(`a.a result=${result}`);
    return result;
};
let sw = Java.use("com.tisc.kappa.sw");
sw["css"].implementation = function () {
    console.log(`sw.css is called`);
    let result = this["css"]();
    console.log(`sw.css result=${result}`);
    return result;
};
});
"""
process = frida.get_usb_device().attach('KaPpA')
script = process.create_script(jscode)
print('[*] Running CTF')
script.load()
sys.stdin.read()

image

Submit ArBraCaDabra?KAPPACABANA! to retrieve flag.

image

Flag obtained.

image

Flag: TISC{C0ngr@tS!us0lv3dIT,KaPpA!}

Level 4: Really Unfair Battleships Game

After last year’s hit online RPG game Slay The Dragon, the cybercriminal organization PALINDROME has once again released another seemingly impossible game called Really Unfair Battleships Game (RUBG). This version of Battleships is played on a 16x16 grid, and you only have one life. Once again, we suspect that the game is being used as a recruitment campaign. So once again, you’re up!

Things are a little different this time. According to the intelligence we’ve gathered, just getting a VICTORY in the game is not enough.

PALINDROME would only be handing out flags to hackers who can get a FLAWLESS VICTORY.

You are tasked to beat the game and provide us with the flag (a string in the format TISC{xxx}) that would be displayed after getting a FLAWLESS VICTORY. Our success is critical to ensure the safety of Singapore’s cyberspace, as it would allow us to send more undercover operatives to infiltrate PALINDROME.

Godspeed!

You will be provided with the following:

1) Windows Client (.exe)

  • Client takes a while to launch, please wait a few seconds.
  • If Windows SmartScreen pops up, tell it to run the client anyway.
  • If exe does not run, make sure Windows Defender isn’t putting it on quarantine.

2) Linux Client (.AppImage)

  • Please install fuse before running, you can do sudo apt install -y fuse
  • Tested to work on Ubuntu 22.04 LTS
Downloadable File SHA256 checksum
rubg-1.0.0.AppImage 679dc457478e97bbc1a3adf247d9d3f4c1b178709ff29a3aa5a6820462842730
rubg_1.0.0.exe e599ba12bb11dbd2e7a2b0326f1c7cbb03f792fd278fdfd6ba4c7343b095500e

Interacted with the game.

image

Oh! After multiple DEFEAT, finally a hit!

image

And then on next click, GGWP…

image

Use 7-Zip File Manager to extract files from rubg_1.0.0.exe. A directory $PLUGINSDIR was extracted, containing app-64.7z and 3 DLL files.

Use 7-Zip File Manager to extract files from app-64.7z. In \app-64\resources found app.asar.

Use 7-Zip File Manager with Asar7z distribution package to extract files from app.asar. In \app\dist\assets found index-c08c228b.js, which is the source code for the game.

Reviewed index-c08c228b.js to understand game logic.

Install http-server by typing npm install -g http-server. Change into working directory. Start http server by issuing http-server -c-1.

image

Go to 127.0.0.1:8080 on Chrome Web Browser and press Ctr+Shift+I to open Developer tools.

image

Set Breakpoint, indicated by left blue tab. Watch t, n and r values.

image

Used ChatGPT to write a python script that take in t as decimal_numbers and produced the initial board configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
decimal_numbers = [
    0,
    2048,
    2048,
    0,
    0,
    960,
    14336,
    0,
    12288,
    0,
    0,
    124,
    0,
    0,
    0,
    0
]

# Convert to 16-bit binary representation and reverse the order of bits
binary_representations = [bin(num)[2:].zfill(16)[::-1] for num in decimal_numbers]

for i, binary in enumerate(binary_representations):
    print(f"Decimal: {decimal_numbers[i]:4}, Binary: {binary}")

Based on the initial board configuration, boxes marked with 1 are the position of enemy’s battleships.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Decimal:     0, Binary: 0000000000000000
Decimal:  2048, Binary: 0000000000010000
Decimal:  2048, Binary: 0000000000010000
Decimal:     0, Binary: 0000000000000000
Decimal:     0, Binary: 0000000000000000
Decimal:   960, Binary: 0000001111000000
Decimal: 14336, Binary: 0000000000011100
Decimal:     0, Binary: 0000000000000000
Decimal: 12288, Binary: 0000000000001100
Decimal:     0, Binary: 0000000000000000
Decimal:     0, Binary: 0000000000000000
Decimal:   124, Binary: 0011111000000000
Decimal:     0, Binary: 0000000000000000
Decimal:     0, Binary: 0000000000000000
Decimal:     0, Binary: 0000000000000000
Decimal:     0, Binary: 0000000000000000

Clicked on all the boxes indicated with 1 on the board configuration and achieved VICTORY.

image

Analysed index-c08c228b.js to determine FLAWLESS VICTORY condition. The boxes indicated with 1 need to be clicked in a certain order.

Used ChatGPT to add on code that will help to determine the order.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
decimal_numbers = [
    0,
    16384,
    16384,
    0,
    0,
    0,
    0,
    15360,
    0,
    124,
    0,
    0,
    0,
    14528,
    0,
    0
]

# Convert to 16-bit binary representation and reverse the order of bits
binary_representations = [bin(num)[2:].zfill(16)[::-1] for num in decimal_numbers]

for i, binary in enumerate(binary_representations):
    print(f"Decimal: {decimal_numbers[i]:4}, Binary: {binary}")

# Define the input values n and r (random large integers)
n = 14088954749275437540
r = 10806988793789711595
hex_n = hex(n)[2:]
hex_r = hex(r)[2:]
# print(hex_n)
# print(hex_r)

c_values = []
for i in range(len(binary_representations)):
    for j in range(len(binary)):
        if binary_representations[i][j] == '1':
            c1 = hex_n[15 - j]
            c2 = hex_r[i]
            c12 = c1 + c2
            c_values.append(c12)
# print(c_values)
sorted_c = sorted(c_values, key=lambda x: int(x, 16))
# print(sorted_c)

solution = []

for i in range(len(binary_representations)):
    solution_line = list(binary_representations[i])
    for j in range(len(binary)):
        if binary_representations[i][j] == '1':
            c1 = hex_n[15 - j]
            c2 = hex_r[i]
            c12 = c1 + c2
            solution_line[j] = str(chr(ord('A') + sorted_c.index(c12)))
    final_solution_line = ''.join(solution_line)
    solution.append(final_solution_line)

for line in solution:
    print(line)

The eventual python script was able to take in t, n and r values, then produced the following board configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0000000000000000
00000000000000D0
00000000000000E0
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000FBHK00
0000000000000000
00LINCO000000000
0000000000000000
0000000000000000
0000000000000000
000000PM000AGJ00
0000000000000000
0000000000000000

All the boxes are then clicked in ascending alphabetical order, starting from A to P.

image

Achieved FLAWLESS VICTORY and obtained flag.

image

Flag: TISC{t4rg3t5_4cqu1r3d_fl4wl355ly_64b35477ac}

Level 5: PALINDROME’s Invitation

Valuable intel suggests that PALINDROME has established a secret online chat room for their members to discuss on plans to invade Singapore’s cyber space. One of their junior developers accidentally left a repository public, but he was quick enough to remove all the commit history, only leaving some non-classified files behind. One might be able to just dig out some secrets of PALINDROME and get invited to their secret chat room…who knows?

Start here: https://github.com/palindrome-wow/PALINDROME-PORTAL

Navigated to Actions and checked out Portal opening, then Latest attempt #2. When checking out the error associated with test_portal.yml, observed that the portal’s ip address and password are in plaintext.

image

Visited 18.143.127.62:45938 on web broswer and log in using :dIcH:..uU9gp1%3C@%3C3Q%22DBM5F%3C)64S%3C(01tF(Jj%25ATV@$Gl as password

image

A discord link was provided. Upon joining the discord channel, saw the following message.

image

Went back to the page, right click and View page source. Obtained some sort of token. Likely to be related to discord.

image

However, the token was not a Discord Token that replace credentials for login purpose.

Reviewing all information on hand, managed to find a hint. Using CyberChef with Magic Recipe on the password, it was suggested that URL Decode, From Base85 will produce PALINDROME has an AUTOMATED secretary.

Used ChatGPT to write a python script that uses the Discord API via the discord.py library to interact with Discord bot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import discord
from discord.ext import commands

intents = discord.Intents.default()
intents.typing = False
intents.presences = False

bot = commands.Bot(command_prefix='!', intents=intents)

@bot.command()
async def hello(ctx):
    await ctx.send('Hello, world!')

@bot.command()
async def ping(ctx):
    await ctx.send('Pong!')

@bot.event
async def on_ready():
    print(f'Logged in as {bot.user.name}')
    print('------')

    # Print the list of servers (guilds)
    print("Servers (Guilds):")
    for guild in bot.guilds:
        print(f"Server (Guild) Name: {guild.name} (ID: {guild.id})")
        
        # Enumerate permissions in each guild
        for channel in guild.channels:
            permissions = channel.permissions_for(guild.me)
            print(f"Channel: {channel.name} (ID: {channel.id})")
            print(f"Bot's Permissions: {permissions}")

bot.run('YOUR_BOT_TOKEN')

Received the following output in terminal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2023-10-01 13:21:35 WARNING  discord.ext.commands.bot Privileged message content intent is missing, commands may not work as expected.
2023-10-01 13:21:35 INFO     discord.client logging in using static token
2023-10-01 13:21:37 INFO     discord.gateway Shard ID None has connected to Gateway (Session ID: 1546b42da2a112f5c1d4baf2de45d569).
Logged in as PALINDROME's secretary 5
------
Servers (Guilds):
Server (Guild) Name: PALINDROME's secret chat room (ID: 1130166064710426674)
Channel: Text Channels (ID: 1130166064710426676)
Bot's Permissions: <Permissions value=422212465132672>

Channel: general (ID: 1130166064710426678)
Bot's Permissions: <Permissions value=422212465132672>

Channel: secrets (ID: 1132169821623165142)
Bot's Permissions: <Permissions value=422212466181248>

Channel: meeting-records (ID: 1132170180101947504)
Bot's Permissions: <Permissions value=422212465132672>

Channel: flag (ID: 1132170608013226084)
Bot's Permissions: <Permissions value=422212465066112>

Use ChatGPT to write a python script to understand Permissions value and convert it to authorised actions that the bot can take in the flag channel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Your permission value
permission_value = 422212465066112
# Convert the numeric value to a Permissions object
permissions = discord.Permissions(permission_value)
# Define a dictionary of permission flags and their meanings
permission_flags = {
    "create_instant_invite": "Create Instant Invite",
    "kick_members": "Kick Members",
    "ban_members": "Ban Members",
    "administrator": "Administrator",
    "manage_channels": "Manage Channels",
    "manage_guild": "Manage Guild",
    "add_reactions": "Add Reactions",
    "view_audit_log": "View Audit Log",
    "priority_speaker": "Priority Speaker",
    "stream": "Stream",
    "read_messages": "Read Messages",
    "send_messages": "Send Messages",
    "send_tts_messages": "Send TTS Messages",
    "manage_messages": "Manage Messages",
    "embed_links": "Embed Links",
    "attach_files": "Attach Files",
    "read_message_history": "Read Message History",
    "mention_everyone": "Mention Everyone",
    "external_emojis": "Use External Emojis",
    "view_guild_insights": "View Guild Insights",
    "connect": "Connect (Voice)",
    "speak": "Speak (Voice)",
    "mute_members": "Mute Members (Voice)",
    "deafen_members": "Deafen Members (Voice)",
    "move_members": "Move Members (Voice)",
    "use_voice_activation": "Use Voice Activation (Voice)",
    "change_nickname": "Change Nickname",
    "manage_nicknames": "Manage Nicknames",
    "manage_roles": "Manage Roles",
    "manage_webhooks": "Manage Webhooks",
    "manage_emojis": "Manage Emojis"
}
# Print granted permissions
print("Granted Permissions:")
for flag, description in permission_flags.items():
    if getattr(permissions, flag):
        print(f"{description}: Granted")
# Print denied permissions
print("\nDenied Permissions:")
for flag, description in permission_flags.items():
    if not getattr(permissions, flag):
        print(f"{description}: Denied")

Observed that the bot can only perform View Audit Log.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Granted Permissions:
View Audit Log: Granted

Denied Permissions:
Create Instant Invite: Denied
Kick Members: Denied
Ban Members: Denied
Administrator: Denied
Manage Channels: Denied
Manage Guild: Denied
Add Reactions: Denied
Priority Speaker: Denied
Stream: Denied
Read Messages: Denied
Send Messages: Denied
Send TTS Messages: Denied
Manage Messages: Denied
Embed Links: Denied
Attach Files: Denied
Read Message History: Denied
Mention Everyone: Denied
Use External Emojis: Denied
View Guild Insights: Denied
Connect (Voice): Denied
Speak (Voice): Denied
Mute Members (Voice): Denied
Deafen Members (Voice): Denied
Move Members (Voice): Denied
Use Voice Activation (Voice): Denied
Change Nickname: Denied
Manage Nicknames: Denied
Manage Roles: Denied
Manage Webhooks: Denied
Manage Emojis: Denied

Use ChatGPT to write a python script to fetch the Audit Log from flag channel using the Discord bot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import discord
from discord.ext import commands

intents = discord.Intents.default()

bot = commands.Bot(command_prefix='!', intents=intents)

@bot.event
async def on_ready():
    """Returns all audit logs for the PALINDROME's secret chat room server and flag channel on startup."""

    print(f'Logged in as {bot.user.name}')
    print('------')
    
    # Print the list of channels in each server (guild)
    print("Channels in Servers (Guilds):")
    for guild in bot.guilds:
        print(f"Server (Guild) Name: {guild.name} (ID: {guild.id})")
        print("Channels:")
        for channel in guild.channels:
            print(f"Channel Name: {channel.name} (ID: {channel.id})")

    target_channel_id = 1132170608013226084  # ID of the 'flag' channel

    # Find the target channel by ID
    target_channel = None
    for guild in bot.guilds:
        for channel in guild.channels:
            if channel.id == target_channel_id:
                target_channel = channel
                break
        if target_channel:
            break

    if target_channel:
        # Fetch the audit logs for the target channel
        async for entry in target_channel.guild.audit_logs(limit=None):
            print(f"{entry.user.name} did {entry.action.name} to {entry.target}")
    else:
        print("Channel 'flag' not found in any server (guild).")

    print()  # Add a blank line for readability         

# Start the bot.
bot.run('YOUR_BOT_TOKEN')

Observed in terminal output that several discord invite urls were created and deleted.

image

Tested all discord invite urls.

1
2
3
4
5
6
7
8
9
10
palindromewow did invite_delete to https://discord.gg/RBjatqsJ
palindromewow did invite_create to https://discord.gg/HQvTm5DSTs    <--- correct invite
palindromewow did invite_create to https://discord.gg/RBjatqsJ
palindromewow did invite_delete to https://discord.gg/pxbYNkbb
palindromewow did invite_create to https://discord.gg/pxbYNkbb
palindromewow did invite_delete to https://discord.gg/QB2VRCz3
palindromewow did invite_create to https://discord.gg/2cyZ6zpw7J
palindromewow did invite_create to https://discord.gg/QB2VRCz3
palindromewow did invite_delete to https://discord.gg/3kbjCcYZup
palindromewow did invite_delete to https://discord.gg/ReTcnwNzCZ

The correct invite allows one to view the content in flag channel.

image

Flag: TISC{H4ppY_B1rThD4y_4nY4!}

This post is licensed under CC BY 4.0 by the author.