feat: add royal-message-decryptor challenge
This commit is contained in:
parent
242f9b8636
commit
5991f63f5d
13
royal-message-decryptor/Dockerfile
Normal file
13
royal-message-decryptor/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM debian:bullseye
|
||||||
|
|
||||||
|
RUN apt update -y && apt install -y python3
|
||||||
|
|
||||||
|
RUN useradd -m ctf
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY spawner.py /app/spawner.py
|
||||||
|
COPY generator.py /app/generator.py
|
||||||
|
|
||||||
|
CMD ["python3", "spawner.py", "--host", "0.0.0.0", "--port", "3006", "python3", "./generator.py"]
|
||||||
|
|
||||||
|
EXPOSE 3006
|
23
royal-message-decryptor/README.md
Normal file
23
royal-message-decryptor/README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# royal-message-decryptor
|
||||||
|
## Text
|
||||||
|
Long ago, on a field of red,
|
||||||
|
Two great legions fought and bled.
|
||||||
|
The fate of the realm, the war’s cruel sting,
|
||||||
|
Now rests with you, the code-breaker’s king.
|
||||||
|
|
||||||
|
A scout bursts in with frantic cries,
|
||||||
|
A message clutched—your nation’s prize.
|
||||||
|
“Their plan is here, but locked away!
|
||||||
|
Decrypt it fast, there’s no delay!”
|
||||||
|
|
||||||
|
The symbols dance, the clock does too.
|
||||||
|
The kingdom’s fate depends on you.
|
||||||
|
|
||||||
|
## Author
|
||||||
|
Robbe De Greef
|
||||||
|
|
||||||
|
## Files
|
||||||
|
/
|
||||||
|
|
||||||
|
## How to Deploy
|
||||||
|
Deploy docker compose.
|
43
royal-message-decryptor/SOLUTION.md
Normal file
43
royal-message-decryptor/SOLUTION.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
## Difficulty
|
||||||
|
50/100 | MEDIUM
|
||||||
|
|
||||||
|
They need to figure out that the first part of the message is a
|
||||||
|
substitution alphabet, then decrypt the code, and then finally
|
||||||
|
figure out the flag is embedded in the last message they sent.
|
||||||
|
|
||||||
|
## Category
|
||||||
|
Crypto
|
||||||
|
|
||||||
|
## How To Solve
|
||||||
|
|
||||||
|
The first part of every message line was a substitution table,
|
||||||
|
the second part the message. Just substitute the message and the
|
||||||
|
last message will contain the flag.
|
||||||
|
|
||||||
|
```python3
|
||||||
|
from pwn import *
|
||||||
|
import string
|
||||||
|
|
||||||
|
p = remote("localhost", 3006)
|
||||||
|
p.recvline()
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
msg = p.recvline().decode()
|
||||||
|
p.recvuntil(b"> ")
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
alphabet = msg.split(" | ")[0]
|
||||||
|
message = msg.split(" | ")[1][:-1]
|
||||||
|
alphabet_map = dict(zip(alphabet, string.ascii_letters))
|
||||||
|
|
||||||
|
decoded = "".join([alphabet_map[c] if c in alphabet_map else c for c in message])
|
||||||
|
print(f"Sending back decoded: '{decoded}'")
|
||||||
|
p.sendline(decoded.encode())
|
||||||
|
|
||||||
|
p.recvline()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flag
|
||||||
|
IGCTF{Some-wicked-story-unfolded-here-great-work}
|
6
royal-message-decryptor/docker-compose.yaml
Normal file
6
royal-message-decryptor/docker-compose.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: '3.9'
|
||||||
|
services:
|
||||||
|
royal-message-decryptor:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- 3006:3006
|
82
royal-message-decryptor/generator.py
Normal file
82
royal-message-decryptor/generator.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
import signal
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
"Advance the knights from the east; let the banners be visible to all.",
|
||||||
|
"Charge the cavalry across the plains with speed—make the ground tremble beneath them.",
|
||||||
|
"Send a column of soldiers from the forest, shields raised, weapons at the ready.",
|
||||||
|
"Deploy scouts to the riverbank; observe their defenses without being seen.",
|
||||||
|
"Line the battlements with archers, and have the infantry gather at the forest's edge.",
|
||||||
|
"Send a detachment of riders to flank the hillside and strike their rear.",
|
||||||
|
"Move the siege engines forward; prepare them to target the castle walls.",
|
||||||
|
"March the battalion of spearmen down the valley road in perfect formation.",
|
||||||
|
"Halt the army at the mountain's base; wait for the reinforcements to arrive.",
|
||||||
|
"Under the cover of night, move the foot soldiers through the forest toward the west gate.",
|
||||||
|
"Break the cavalry formation, spread across the plains, and encircle them.",
|
||||||
|
"Cross the river with the infantry, shields up, and press toward their defenses.",
|
||||||
|
"Advance the siege towers slowly; let them loom over the field as a show of power.",
|
||||||
|
"Begin constructing palisades outside the village; block the main road leading to the castle.",
|
||||||
|
"Set up camp near the bridge; have the engineers secure the crossing by dusk.",
|
||||||
|
"Split the forces: one group toward the northern gate, the other to secure the southern ridge.",
|
||||||
|
"Raise the banners on the hill; archers prepare to volley, infantry ready behind them.",
|
||||||
|
"Withdraw the scouts after they encounter the patrol; signal the main force to advance.",
|
||||||
|
"Position the catapults under cover of darkness; infantry hold a defensive line until ready.",
|
||||||
|
"Send raiders to attack the supply convoy near the western pass—cut off their resources.",
|
||||||
|
"Begin scaling the cliffs with infantry to bypass the watchtower guarding the southern approach.",
|
||||||
|
"Set up camp on the plains just beyond the river; prepare for a dawn assault.",
|
||||||
|
"Advance the pikemen in a solid wall through the valley; have the archers provide cover from the ridges.",
|
||||||
|
"Reinforcements from the north, join the main army in the valley—prepare for a combined assault.",
|
||||||
|
"Divide the army into three columns: one toward the eastern gate, another through the southern forest, and a third to secure the ridge for a coordinated dawn attack.",
|
||||||
|
"Our smartest wizards have found the secret to eternal life, it is not 42, but rather IGCTF{Some-wicked-story-unfolded-here-great-work}.",
|
||||||
|
]
|
||||||
|
|
||||||
|
letters = [c for c in string.ascii_letters]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_substitution():
|
||||||
|
l = letters[:]
|
||||||
|
random.shuffle(l)
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def kill():
|
||||||
|
print(
|
||||||
|
"*You get violently decapitated while a crowd of desensitized dirty towns people watch the show with their family*"
|
||||||
|
)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_and_solve(msg):
|
||||||
|
sub = generate_substitution()
|
||||||
|
search_map = dict(zip(letters, sub))
|
||||||
|
new_msg = "".join([search_map[c] if c in search_map else c for c in msg])
|
||||||
|
|
||||||
|
print(f"{''.join(sub)} | {new_msg}")
|
||||||
|
inp = input("What does it say!!!> ")
|
||||||
|
if inp != msg:
|
||||||
|
print("YOU IDIOT! That was wrong. We lost troops because of you!")
|
||||||
|
kill()
|
||||||
|
|
||||||
|
print("Ok, it seemed to be right, the king is pleased")
|
||||||
|
|
||||||
|
def took_too_long(_, __):
|
||||||
|
print("YOU IDIOT! You took too long. We lost troops because of you!")
|
||||||
|
kill()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(
|
||||||
|
"Help! We intercepted messages from the enemy, if you do not decipher them quickly our royal highness will have you decapitated!"
|
||||||
|
)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGALRM, took_too_long)
|
||||||
|
signal.alarm(10)
|
||||||
|
|
||||||
|
for msg in messages:
|
||||||
|
generate_and_solve(msg)
|
||||||
|
|
||||||
|
print("You did great, no decapitations today!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
21
royal-message-decryptor/sol.py
Normal file
21
royal-message-decryptor/sol.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from pwn import *
|
||||||
|
import string
|
||||||
|
|
||||||
|
p = remote("localhost", 3006)
|
||||||
|
p.recvline()
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
msg = p.recvline().decode()
|
||||||
|
p.recvuntil(b"> ")
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
alphabet = msg.split(" | ")[0]
|
||||||
|
message = msg.split(" | ")[1][:-1]
|
||||||
|
alphabet_map = dict(zip(alphabet, string.ascii_letters))
|
||||||
|
|
||||||
|
decoded = "".join([alphabet_map[c] if c in alphabet_map else c for c in message])
|
||||||
|
print(f"Sending back decoded: '{decoded}'")
|
||||||
|
p.sendline(decoded.encode())
|
||||||
|
|
||||||
|
p.recvline()
|
47
royal-message-decryptor/spawner.py
Normal file
47
royal-message-decryptor/spawner.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import socket
|
||||||
|
from threading import Thread
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# How to use:
|
||||||
|
# Set the host and port above
|
||||||
|
# Invoke the spawner like this
|
||||||
|
# python3 spawner.py -h <host> -p <port> <your arguments to spawn here>
|
||||||
|
|
||||||
|
def on_new_client(conn, addr, cmd):
|
||||||
|
print(f"New connection with {addr}")
|
||||||
|
file = conn.makefile('w')
|
||||||
|
p = subprocess.Popen(cmd, stdout=file, stdin=file)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Spawn some processes over a socket")
|
||||||
|
parser.add_argument('--host', type=str, required=True, nargs=1, help='The host ip to listen on')
|
||||||
|
parser.add_argument('--port', type=int, required=True, nargs=1, help='The host port to listen on')
|
||||||
|
parser.add_argument('rest', nargs=argparse.REMAINDER)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
s = socket.socket()
|
||||||
|
host = args.host[0]
|
||||||
|
port = args.port[0]
|
||||||
|
cmd = args.rest
|
||||||
|
print(f"Command spawn each time: {cmd}")
|
||||||
|
|
||||||
|
s.bind((host, port))
|
||||||
|
s.listen(5)
|
||||||
|
|
||||||
|
print(f"Now listening for connections on {host}:{port}")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
conn, addr = s.accept()
|
||||||
|
t = Thread(target=on_new_client, args=(conn,addr, cmd))
|
||||||
|
t.run()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
s.close()
|
||||||
|
print("Goodbye")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user