-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2dda7f9
Showing
1,782 changed files
with
274,476 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[config] | ||
url = https://ctf.heroctf.fr/ | ||
access_token = ctfd_ba540261e30641d81c02719e44bce5550dc07402f36af6a4debcce10908534cc | ||
|
||
[challenges] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.avi filter=lfs diff=lfs merge=lfs -text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
name: Build check on Dockerfiles | ||
|
||
on: | ||
push: | ||
branches: | ||
- "main" | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout repo content | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
|
||
- name: Build Docker Images | ||
run: | | ||
find . -type f -name "*Dockerfile*" | while read -r dockerfile_path; do | ||
echo "==========[ $dockerfile_path ]==========" | ||
pushd "$(dirname "$dockerfile_path")" | ||
echo "Building image..." | ||
docker buildx build --platform linux/amd64 . &> /tmp/docker-build.log | ||
build_result=$? | ||
if [ $build_result -eq 0 ]; then | ||
echo "Build success!" | ||
else | ||
cat /tmp/docker-build.log | ||
rm /tmp/docker-build.log | ||
echo "Build failed!" | ||
fi | ||
popd | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: Syntax check on 'challenge.yml' files | ||
|
||
on: | ||
push: | ||
branches: | ||
- "main" | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout repo content | ||
uses: actions/checkout@v4 | ||
|
||
- name: Setup python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: "3.12" | ||
|
||
- name: Install dependencies | ||
run: python3 -m pip install PyYAML | ||
|
||
- name: Run the syntax checker | ||
run: python3 .github/yaml_chall_checker.py $GITHUB_WORKSPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import os | ||
import sys | ||
import yaml | ||
from yaml.loader import SafeLoader | ||
|
||
|
||
REQUIRED_ATTRIBUTES = ["name", "author", "category", "description", "value", "type", "flags", "tags", "state", "version"] | ||
OPTIONAL_ATTRIBUTES = ["image", "host", "hints", "files", "requirements", "extra"] | ||
REQUIRED_CATEGORIES = [ | ||
"Blockchain", | ||
"Crypto", | ||
"Forensics", | ||
"Forensic", | ||
"Misc", | ||
"OSINT", | ||
"Prog", | ||
"Pwn", | ||
"Reverse", | ||
"Sponsors", | ||
"Steganography", | ||
"System", | ||
"Web" | ||
] | ||
|
||
def find_challenge_files(directory: str) -> list[str]: | ||
"""Find all challenge.yml files in subdirectories""" | ||
challenge_files = [] | ||
for root, _, files in os.walk(directory): | ||
for file in files: | ||
if file == "challenge.yml": | ||
challenge_files.append(os.path.join(root, file)) | ||
return challenge_files | ||
|
||
def syntax_check(challenge_file: str) -> None: | ||
"""Validate the syntax, attributes, and types of a 'challenge.yml' file""" | ||
print(f"Checking syntax of '{challenge_file}'...") | ||
try: | ||
with open(os.path.join(challenge_file), "r") as f: | ||
yaml_data = yaml.load(f, Loader=SafeLoader) | ||
|
||
missing_attributes = [] | ||
for attribute in REQUIRED_ATTRIBUTES: | ||
if attribute not in yaml_data: | ||
missing_attributes.append(attribute) | ||
|
||
if missing_attributes: | ||
print(f"Missing required attributes: {', '.join(missing_attributes)}") | ||
|
||
for key, value in yaml_data.items(): | ||
if key not in REQUIRED_ATTRIBUTES + OPTIONAL_ATTRIBUTES: | ||
print(f"Unknown attribute '{key}'") | ||
|
||
match key: | ||
case "name": | ||
if not isinstance(value, str): | ||
print(f"Attribute '{key}' is not a string") | ||
case "author": | ||
if not isinstance(value, str): | ||
print(f"Attribute '{key}' is not a string") | ||
case "category": | ||
if value not in REQUIRED_CATEGORIES: | ||
print(f"Attribute '{key}' is not a valid category") | ||
case "description": | ||
if not isinstance(value, str): | ||
print(f"Attribute '{key}' is not a string") | ||
case "value": | ||
if not (isinstance(value, int) or value is None): | ||
print(f"Attribute '{key}' is not an integer or None") | ||
case "type": | ||
if value != "dynamic": | ||
print(f"Attribute '{key}' is not 'dynamic'") | ||
case "extra": | ||
if not isinstance(value, dict): | ||
print(f"Attribute '{key}' is not a dictionary") | ||
if "initial" not in value or "decay" not in value or "minimum" not in value: | ||
print(f"Attribute '{key}' is missing required sub-attributes") | ||
if not isinstance(value["initial"], int) or not isinstance(value["decay"], int) or not isinstance(value["minimum"], int): | ||
print(f"Attribute '{key}' sub-attributes are not integers") | ||
if value["initial"] != 500: | ||
print(f"Attribute '{key}' sub-attribute 'initial' is not 500") | ||
if value["decay"] != 100: | ||
print(f"Attribute '{key}' sub-attribute 'decay' is not 100") | ||
if value["minimum"] < 1 or value["minimum"] > 50: | ||
print(f"Attribute '{key}' sub-attribute 'minimum' is not between 1 and 50") | ||
case "image": | ||
if value is not None: | ||
print(f"Attribute '{key}' is not None") | ||
case "host": | ||
if value is not None: | ||
print(f"Attribute '{key}' is not None") | ||
case "flags": | ||
if not isinstance(value, list): | ||
print(f"Attribute '{key}' is not a list") | ||
case "tags": | ||
if not isinstance(value, list): | ||
print(f"Attribute '{key}' is not a list") | ||
case "files": | ||
if not (isinstance(value, list) or value is None): | ||
print(f"Attribute '{key}' is not a list or None") | ||
case "state": | ||
if value not in ["hidden", "visible"]: | ||
print(f"Attribute '{key}' is not 'hidden' or 'visible'") | ||
case "version": | ||
if not isinstance(value, str): | ||
print(f"Attribute '{key}' is not a string") | ||
case "requirements": | ||
if not isinstance(value, list): | ||
print(f"Attribute '{key}' is not a list") | ||
case "hints": | ||
if not isinstance(value, list): | ||
print(f"Attribute '{key}' is not a list") | ||
|
||
print("Syntax is valid") | ||
except yaml.YAMLError as exc: | ||
print(f"Syntax is invalid: {exc}") | ||
|
||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) != 2: | ||
print("Usage: python yaml_chall_checker.py <directory>") | ||
sys.exit(1) | ||
|
||
challenge_files = find_challenge_files(sys.argv[1]) | ||
for challenge_file in challenge_files: | ||
syntax_check(challenge_file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
__pycache__/ | ||
.env | ||
|
||
fullchain.pem | ||
privkey.pem |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
FROM python:3.11-alpine | ||
|
||
RUN apk --update add socat \ | ||
&& adduser -D --home /app user \ | ||
&& pip3 install gostcrypto | ||
|
||
COPY --chown=user . /app | ||
|
||
RUN chmod 755 /app/entry.sh /app/chall.py | ||
|
||
WORKDIR /app | ||
|
||
EXPOSE ${LISTEN_PORT} | ||
|
||
ENTRYPOINT ["/app/entry.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Halloween | ||
|
||
### Category | ||
|
||
Crypto | ||
|
||
### Description | ||
|
||
Boo! Do you believe in ghosts ? I sure don't.<br><br> | ||
Host : **nc crypto.heroctf.fr 9001**<br> | ||
Format : **Hero{flag}**<br> | ||
Author : **Alol** | ||
|
||
### Files | ||
|
||
- [halloween.zip](halloween.zip) | ||
|
||
### Write up | ||
|
||
The challenge prints the encrypted flag before repeatedly encrypting user-submitted data. On the surface this is not vulnerable code, the key and nonce are generated properly meaning that the keystream should be 2\*\*68 bytes long before the counter wraps around and the keystream repeats. We need to dig deeper. | ||
|
||
Looking into the source code we find this function that, supposedly, increments the counter. | ||
```py | ||
# https://github.com/drobotun/gostcrypto/blob/master/gostcrypto/gostcipher/gost_34_13_2015.py#L841C5-L841C8 | ||
def _inc_ctr(self, ctr: bytearray) -> bytearray: | ||
internal = 0 | ||
bit = bytearray(self.block_size) | ||
bit[self.block_size - 1] = 0x01 | ||
for i in range(self.block_size): | ||
internal = ctr[i] + bit[i] + (internal << 8) | ||
ctr[i] = internal & 0xff | ||
return ctr | ||
``` | ||
|
||
The screenshot below taken from one of the tickets I handled illustrates clearly what's wrong. | ||
|
||
<p align="center"> | ||
<img src="https://i.imgur.com/FfoNRKM.png"> | ||
</p> | ||
|
||
The counter isn't incremented properly, effectively downgrading it from a 64 bit integer to a 8 bit integer. This, in turn, means that the keystream is now only 4096 bytes long. We can perform a chosen plaintext attack to recover the full keystream and decrypt the flag. | ||
|
||
```py | ||
from pwn import * | ||
|
||
BS = 16 | ||
# io = process(["python3", "chall.py"]) | ||
io = remote("crypto.heroctf.fr", 9001) | ||
|
||
io.recvuntil(b"It's almost Halloween, time to get sp00") | ||
flag = bytes.fromhex(io.recvuntil(b"00ky")[:-4].decode()) | ||
io.recvline() | ||
|
||
io.sendline(b"00" * BS * 256) | ||
keystream = bytes.fromhex(io.recvlineS()) | ||
|
||
print(xor(flag, keystream[-(1 + len(flag) // BS) * BS :])[: len(flag)]) | ||
``` | ||
|
||
### Flag | ||
|
||
```Hero{5p00ky_5c4ry_fl4w3d_cryp70_1mpl3m3n74710ns_53nd_5h1v3r5_d0wn_y0ur_5p1n3}``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env python3 | ||
import gostcrypto | ||
import os | ||
|
||
with open("flag.txt", "rb") as f: | ||
flag = f.read() | ||
|
||
key, iv = os.urandom(32), os.urandom(8) | ||
cipher = gostcrypto.gostcipher.new( | ||
"kuznechik", key, gostcrypto.gostcipher.MODE_CTR, init_vect=iv | ||
) | ||
|
||
print(f"It's almost Halloween, time to get sp00{cipher.encrypt(flag).hex()}00ky 👻!") | ||
|
||
while True: | ||
print(cipher.encrypt(bytes.fromhex(input())).hex()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
name: Halloween | ||
author: Alol | ||
category: Crypto | ||
description: "Boo! Do you believe in ghosts ? I sure don't.<br><br> | ||
Host : **nc crypto.heroctf.fr 9001**<br> | ||
Format : **Hero{flag}**<br> | ||
Author : **Alol**" | ||
value: null | ||
type: dynamic | ||
extra: | ||
initial: 500 | ||
decay: 100 | ||
minimum: 50 | ||
|
||
image: null | ||
host: null | ||
|
||
flags: | ||
- { | ||
type: "static", | ||
content: "Hero{5p00ky_5c4ry_fl4w3d_cryp70_1mpl3m3n74710ns_53nd_5h1v3r5_d0wn_y0ur_5p1n3}", | ||
data: "case_insensitive", | ||
} | ||
|
||
tags: | ||
- hard | ||
|
||
files: | ||
- halloween.zip | ||
|
||
state: visible | ||
version: "0.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#! /bin/sh | ||
|
||
while : | ||
do | ||
socat TCP-LISTEN:${LISTEN_PORT},forever,reuseaddr,fork EXEC:'/app/chall.py' 2>/dev/null | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Hero{5p00ky_5c4ry_fl4w3d_cryp70_1mpl3m3n74710ns_53nd_5h1v3r5_d0wn_y0ur_5p1n3} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
FROM python:3.11-alpine | ||
|
||
RUN apk --update add socat \ | ||
&& adduser -D --home /app user \ | ||
&& pip3 install gostcrypto | ||
|
||
COPY --chown=user . /app | ||
|
||
RUN chmod 755 /app/entry.sh /app/chall.py | ||
|
||
WORKDIR /app | ||
|
||
EXPOSE ${LISTEN_PORT} | ||
|
||
ENTRYPOINT ["/app/entry.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env python3 | ||
import gostcrypto | ||
import os | ||
|
||
with open("flag.txt", "rb") as f: | ||
flag = f.read() | ||
|
||
key, iv = os.urandom(32), os.urandom(8) | ||
cipher = gostcrypto.gostcipher.new( | ||
"kuznechik", key, gostcrypto.gostcipher.MODE_CTR, init_vect=iv | ||
) | ||
|
||
print(f"It's almost Halloween, time to get sp00{cipher.encrypt(flag).hex()}00ky 👻!") | ||
|
||
while True: | ||
print(cipher.encrypt(bytes.fromhex(input())).hex()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#! /bin/sh | ||
|
||
while : | ||
do | ||
socat TCP-LISTEN:${LISTEN_PORT},forever,reuseaddr,fork EXEC:'/app/chall.py' 2>/dev/null | ||
done |
Oops, something went wrong.