Skip to content

Commit

Permalink
implement new challenge Leet Messenger
Browse files Browse the repository at this point in the history
  • Loading branch information
HappyStoic committed Nov 21, 2024
1 parent f028721 commit 5613f69
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 1 deletion.
12 changes: 12 additions & 0 deletions challenges/leet-messenger/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3-slim

RUN apt update && apt install -y gcc

RUN mkdir /opt/app
WORKDIR /opt/app

COPY main.c send.py /opt/app/

RUN gcc main.c -o binary && gzip binary

CMD ["python3", "send.py"]
72 changes: 72 additions & 0 deletions challenges/leet-messenger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Leet Messenger

This challenge has 2 phases.

In the first one, students are told someone is trying to speak with them. They should start capturing packets. They should
notice there is a lot of TCP SYN packets coming to a port 1337 (leet). But there is no listener. After starting a TCP listener on
port 1337, they will get a payload.

The payload has a custom protocol format. The format is

```
MAGIC_NUMBER (4 bytes) | VERSION (1 byte) | LEN_OF_MSG (8 bytes) | BASE_64_MSG_DATA | LEN_OF_DATA (8 bytes) | DATA
```

The base64 encoded message contains a first flag and also hint to keep digging.

The data section contains raw bytes which is a gz compressed ELF 64 bits executable file. Students should extract the
data, gunzip the file and reverse engineer the binary. By reversing the binary, students should find a correct input to the
binary which passes the implemented check. If they succeed, the binary prints that this is a correct input and that the input is
also a 2nd flag.

Voilá.

## How to solve
<details>
<summary>Click to reveal how to solve steps</summary>

TODO: write proper how to solve

1. start ncat listener and pipe the received data to a file
```bash
root@hackerlab:~# nc -lnvp 1337 > received.data
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::1337
Ncat: Listening on 0.0.0.0:1337
Ncat: Connection from 172.20.0.67.
Ncat: Connection from 172.20.0.67:49948.
```

2. decode the base64 encoded message to find 1st flag
```bash
root@hackerlab:~# strings received.data | head -n1 | base64 -d
Oh finally you hear me!!! This is your flag BSY{a!sk&fjlhý76S5F9OUILFNRQKJLRHIUFKHAS}. Now, you might be interested in the rest of the messagebase64: invalid input```
```

3. install binwalk, use it to extract the gzip and find the binary. Then use your favorite disassembler (gdb, ida, ghidra, ...) to find the implementation of the check and figure out a correct input (the 2nd flag)
```bash
root@hackerlab:~# binwalk -e received.data --run-as=root
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
213 0xD5 gzip compressed data, has original file name: "binary", from Unix, last modified: 2024-11-20 22:56:19
root@hackerlab:~# ls
_received.data.extracted received received.data
root@hackerlab:~# gzip _received.data.extracted/binary^C
root@hackerlab:~# file _received.data.extracted/binary
_received.data.extracted/binary: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7442f69752d03fa6c11be89b5427782a6879efd9, for GNU/Linux 3.2.0, not stripped
root@hackerlab:~# chmod +x ./_received.data.extracted/binary
root@hackerlab:~# ./_received.data.extracted/binary
Usage: ./_received.data.extracted/binary flag
root@hackerlab:~# ./_received.data.extracted/binary is_this_the_flag?
Incorrect flag. Try harder!
root@hackerlab:~# ./_received.data.extracted/binary iam-reverse-king
You found it! You can submit the flag, good job :)
```

</details>

## Testing

The script [auto-solve.sh](./auto-solve.sh) automatically verifies that the challenge can be solved.
56 changes: 56 additions & 0 deletions challenges/leet-messenger/auto-solve.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/bash

# try to get the payload with all required data
nc -lnvp 1337 > received.data 2> /dev/null

# search for the 1st flag
MATCH=`strings received.data | head -n1 | base64 -d 2> /dev/null | \
grep -o "BSY{a!sk&fjlhý76S5F9OUILFNRQKJLRHIUFKHAS}"`
if [[ "$MATCH" == "" ]]
then
echo "Error - did not find a 1st base64 encoded flag in the received data"
exit 1
fi

# submit the 1st flag
RES=`curl -s 'http://172.20.0.3/api/challenges/submit' \
-X POST \
-H 'Content-Type: application/json' \
--data-binary '{"challenge_id": "leet_messenger_id", "task_id": "task1", "flag" : "BSY{a!sk&fjlhý76S5F9OUILFNRQKJLRHIUFKHAS}"}'`

if [[ $RES != *"Congratulations"* ]]; then
echo "Failed to submit the 1st flag - $RES"
exit 2
fi


# if the machine is x86, run the binary with a correct input (2nd flag) to see if it outputs expected output.
# (first we have to extract the binary tho)
if [ "$(uname -m)" == "x86_64" ] || [ "$(uname -m)" == "i686" ]; then
binwalk -e received.data --run-as=root > /dev/null
chmod +x ./_received.data.extracted/binary
MATCH=`./_received.data.extracted/binary iam-reverse-king | grep -o "You found it! You can submit the flag, good job :)"`
if [[ "$MATCH" == "" ]]
then
echo "Error - inputting correct input to the binary did not print expected output"
exit 3
fi

RES=`curl -s 'http://172.20.0.3/api/challenges/submit' \
-X POST \
-H 'Content-Type: application/json' \
--data-binary '{"challenge_id": "leet_messenger_id", "task_id": "task2", "flag" : "iam-reverse-king"}'`
if [[ $RES != *"Congratulations"* ]]; then
echo "Failed to submit the 2st flag - $RES"
exit 4
fi

else
echo "Skipping check of 2nd flag because this is probably not x86 machine. so I cannot run the ELF x86 binary"
fi


echo "OK - tests passed"
exit 0


20 changes: 20 additions & 0 deletions challenges/leet-messenger/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: '3.3'

services:
challenge-leet-messenger:
container_name: scl-leet-messenger
stop_grace_period: 0s
build: .
networks:
playground-net:
ipv4_address: 172.20.0.67
healthcheck:
test: ["CMD", "python", "-c", "'import requests; response = requests.get(\"http://localhost/\"); assert response.status_code == 200'"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s

networks:
playground-net:
external: true
34 changes: 34 additions & 0 deletions challenges/leet-messenger/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <stdio.h>
#include <string.h>

const char bsy[] = "!cyberlab_rocks!";
const char just_an_array[16] = { 0x4d, 0x7, 0x19, 0x54, 0x1c, 0x1c, 0x1f, 0x9, 0x15, 0x31, 0x1c, 0x47, 0xd, 0x7, 0x22, 0x4b };

int check_flag(char *flag){
int str_len = strlen(flag);
for (int i=0; i<str_len; i++){
char temp = (just_an_array[i] - 5) ^ bsy[i];
if (temp != flag[i]){
return 0;
}
}
return 1;
}

int main(int argc, char **argv){
if (argc != 2){
printf("Usage: %s flag\n", argv[0]);
} else {
char *flag = argv[1];
if (strlen(flag) != 16){
printf("Incorrect flag. Try harder!\n");
} else {
int result = check_flag(flag);
if (result == 1){
printf("You found it! You can submit the flag, good job :)\n");
} else {
printf("Nope, that's not it!\n");
}
}
}
}
20 changes: 20 additions & 0 deletions challenges/leet-messenger/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Leet Messenger",
"id": "leet_messenger_id",
"difficulty": "hard",
"description": "",
"tasks": [
{
"id": "task1",
"name": "A message",
"description": "A leet coder is trying to tell you something, can you find it and make a sense of it?",
"flag": "BSY{a!sk&fjlhý76S5F9OUILFNRQKJLRHIUFKHAS}"
},
{
"id": "task2",
"name": "Reverse it",
"description": "After you find the 1st message, there might be a 2nd hidden message.",
"flag": "iam-reverse-king"
}
]
}
50 changes: 50 additions & 0 deletions challenges/leet-messenger/send.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import struct
import socket
import base64

from time import sleep


def craft_payload(message: str, data: bytes) -> bytes:
magic_number = 0x1A2B3C4D
version = 0x01

msg_encoded = base64.b64encode(message.encode())

payload = struct.pack('!I B', magic_number, version) # represents header
payload += struct.pack("Q", len(msg_encoded))
payload += msg_encoded
payload += struct.pack("Q", len(data))
payload += data
return payload


def send(payload: bytes):
dst_ip = "172.20.0.2"
dst_port = 1337

with socket.create_connection((dst_ip, dst_port)) as sock:
sock.sendall(payload)


def main():
first_flag = "BSY{a!sk&fjlhý76S5F9OUILFNRQKJLRHIUFKHAS}"
msg = f"Oh finally you hear me!!! This is your flag {first_flag}. Now, you might be interested in the rest of the message"
binary_file = "binary.gz"

with open(binary_file, "rb") as f:
file_data = f.read()

payload = craft_payload(msg, file_data)
while True:
try:
send(payload)
except ConnectionRefusedError:
pass
except Exception as e:
print(f"Unexpected exception while sending packets: {e}")

sleep(5)

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
| playground-net | `172.20.0.45` | Callenge [Jump Around](./../challenges/jump-around) |
| playground-net | `172.20.0.47` | Callenge [Jump Around](./../challenges/jump-around) |
| playground-net | `172.20.0.49` | Callenge [Jump Around](./../challenges/jump-around) |
| playground-net | `172.20.0.67` | Callenge [Leet Messenger](./../challenges/leet-messenger) |
| playground-net | `172.20.0.88` | [Class02](./../classes/class02) |
| playground-net | `172.20.0.90` | [Class03](./../classes/class03) |
| playground-net | `172.20.0.95` | [Class03](./../classes/class03) |
Expand Down
2 changes: 1 addition & 1 deletion hackerlab/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ COPY data /data
RUN apt update && \
apt install -y openssh-server curl vim nano nmap net-tools iputils-ping htop netcat-traditional dnsutils \
less tcpdump tmux wget iproute2 python3-pip git ncat rsyslog attr acl logcheck btop sshpass telnet python3-venv \
proxychains
proxychains binwalk

ENV TERM=xterm-256color
RUN echo "PS1='\e[92m\u\e[0m@\e[94m\h\e[0m:\e[35m\w\e[0m# '" >> /root/.bashrc
Expand Down

0 comments on commit 5613f69

Please sign in to comment.