🐎BroncoCTF 2024

All solutions in categories roughly sorted from easy to hard.

Beginner

Keyboard Elitist (125 Solves)

Description:

My buddy is bragging about how cool his Framework laptop is and how much faster he can type than me.

When I tried to type a message, it came out as garbage!

A;;apfkgij gj;ukd ar ut ghur war a Qwfpgj efjbyaps yk a Cyifmae uk;lg rchfmf maefr ghur iyye iuef dapbadf. Mj tpufks ur sftukugfij a efjbyaps rkyb, ylg hfpf wugh hur mysliap tpamfwype ia;gy;. Rudh, fughfp waj... hfpf ur ghf tiadO bpykcy{qwfpgj_vr_c0ifm@e}

Solution:

Keyboard Elitist and speed typing makes me immediately think of Colemak (as a fellow speed typer). Converter here: https://colemak.com/Converter

Apparently typing as if this was a Qwerty keyboard on a Colemak input scheme makes this look like garbage. My friend is definitely a keyboard snob, out here with his modular framework laptop. Sigh, either way... here is the flag: bronco{qwerty_vs_c0lem@k}

Shrekanana Banana (120 Solves)

Description:

I was given this image of Shrek in a Banana, but I can't help but feel like I am missing something...

Solution:

aperisolve.com, in one of the bit planes.

Stego-Snore-Us (50 Solves)

Description:

I'm not the only one tired after pulling an all-nighter for Hack for Humanity...

Solution:

Same as the previous, but it's encoded:

From pesxas to bronco seems like a mono-alphabetic cipher, use the manual decryption mode with this tool, using the description as a guideline. https://www.dcode.fr/monoalphabetic-substitution

bronco{no_more_all_nighters}

Forensics

Medieval Beats (48 Solves)

Description:

Check out my youtube video

Target Difficulty: Easy
https://youtu.be/rTsABVevwFk 

Solution:

This is a 1 hour video with characters of the flag coming up in random frames throughout. First I downloaded the video at the lowest resolution possible with some generic online tool. Then I extracted one frame each second (~3600 total) and deleted all the black frames which were 284 bytes.

ffmpeg -i flag.mp4 -vf "fps=1" output_%04d.png
find . -type f -size 284c -exec rm {} +

# Go through the remaining images to get the flag
bronco{1n_17_f0r_7h3_10n6_h4ul}

Wario Party (29 Solves)

Description:

Who is the true hero of the Mario Party games you might ask? Look inward and you might find it at the intersection of Mario's color and the number of brothers.

Target Difficulty: Easy/Medium

Note: This flag is wrapped in broncosec{}

Solution:

Opening the image in aperisolve, we can see some data encoded in one of the bits.

The data in a bitplane can be extracted with stegsolve.jar, download it to get the following jpg file.

I tried building a script that will use constant offsets to detect if a pixel is yellow or purple but it got off every 3-4 rows, so I ended up just typing it all into cyberchef binary decode. Not proud of it but it doesn't take that long.

bronco{b0ws3r_g0t_th4t_dumpy}

Boom (11 Solves)

Description:

With all these talks of arbitration, things are tense here around the office. I feel like people are going to explode at any moment. I gotta watch where I step before I accidentally bring something up and uncover something I didn't want to.

Solution:

A file is attached named HarvestBroom.mbf. I added the newlines where there was an obvious pattern (and left in my notes when I made initial observations).

7d 19 01 2e 
# Missing 0c
03 01 04 01 05 01 06 01 07 01 08 01 09 01 0a 01 0b 01 0d 01 0e 01 0f 01 10 01 11 01 12 01 13 01 14 01 15 01 16 01 17 01 18 01 19 01 1a 01 1b 01 1c 01 1d 01 1e 01 1f 01 20 01 21 01 22 01 23 01 24 01 25 01 26 01 27 01 28 01 29 01 2a 01 2b 01 2c 01 2d 01 2e 01 2f 01 30 01 31 01 32 01 33 01 34 01 35 01 36 01 37 01 38 01 39 01 3a 01 3b 01 3c 01 3d 01 3e 01 3f 01 
03 02 3f 02 
03 03 3f 03 
03 04 3f 04 
# 1f 20 39 3a 3f
03 05 1f 05 20 05 39 05 3a 05 3f 05 
# 06 1f 2b 2c 2d 2e 2f 3a 3f
03 06 06 06 1f 06 2b 06 2c 06 2d 06 2e 06 2f 06 3a 06 3f 06 
# 06 1e 23 2b 2f 37 3b 3f
03 07 06 07 1e 07 23 07 2b 07 2f 07 37 07 3b 07 3f 07 
# 06 1f 23 2b 2e 2f 31 37 3a 3f 53 57 59 5a 5b
03 08 06 08 1f 08 23 08 2b 08 2e 08 2f 08 31 08 37 08 3a 08 3f 08 53 08 57 08 59 08 5a 08 5b 08 
# missing 09, 0d, 11, 15, 19, 1d, 1f, 20, 21, 22, 26, 2a, 2c, 2e, 30, 33, 35, 36, 38, 39, 3a, 3c, 3d, 3e
03 09 06 09 07 09 08 09 0a 09 0b 09 0c 09 0e 09 0f 09 10 09 12 09 13 09 14 09 16 09 17 09 18 09 1a 09 1b 09 1c 09 1e 09 23 09 24 09 25 09 27 09 28 09 29 09 2b 09 2d 09 2f 09 31 09 32 09 34 09 37 09 3b 09 3f 09 54 09 56 09 59 09 5c 09 
03 0a 06 0a 08 0a 0a 0a 0e 0a 10 0a 12 0a 14 0a 16 0a 1a 0a 1c 0a 1f 0a 23 0a 25 0a 27 0a 29 0a 2b 0a 2c 0a 2f 0a 31 0a 33 0a 35 0a 3a 0a 3f 0a 55 0a 59 0a 5c 0a 
03 0b 06 0b 07 0b 08 0b 0a 0b 0e 0b 0f 0b 10 0b 12 0b 14 0b 16 0b 17 0b 18 0b 1a 0b 1b 0b 1c 0b 1f 0b 20 0b 23 0b 24 0b 25 0b 27 0b 28 0b 29 0b 2b 0b 2c 0b 2d 0b 2e 0b 2f 0b 31 0b 33 0b 35 0b 37 0b 39 0b 3a 0b 3f 0b 54 0b 56 0b 59 0b 5c 0b 
03 0c 3f 0c 53 0c 57 0c 59 0c 5a 0c 5b 0c 
03 0d 3f 0d 
03 0e 04 0e 05 0e 06 0e 07 0e 08 0e 09 0e 0a 0e 0b 0e 0c 0e 0d 0e 0e 0e 0f 0e 10 0e 11 0e 12 0e 13 0e 14 0e 15 0e 16 0e 17 0e 18 0e 19 0e 1a 0e 1b 0e 1c 0e 1d 0e 1e 0e 1f 0e 20 0e 21 0e 22 0e 23 0e 24 0e 25 0e 26 0e 27 0e 28 0e 29 0e 2a 0e 2b 0e 2c 0e 2d 0e 2e 0e 2f 0e 30 0e 31 0e 32 0e 33 0e 34 0e 35 0e 36 0e 37 0e 38 0e 39 0e 3a 0e 3b 0e 3c 0e 3d 0e 3e 0e 3f 0e 1c 13 1e 13 2e 13 30 13 1b 15 1f 15 2d 15 2e 15 2f 15 30 15 31 15 1c 16 1d 16 1e 16 2d 16 31 16 2e 17 2f 17 30 17

Boom and Broom, as well as the fact that these seem to be coordinates makes me think of a minesweeper field. If every pair of numbers (ignoring the 4-byte header and the 03 designating a row) is an x/y location, it may be able to print a flag.

hex_data = "7d 19 01 2e 03 01 04 01 05 01 06 01 07 01 08 01 09 01 0a 01 0b 01 0d 01 0e 01 0f 01 10 01 11 01 12 01 13 01 14 01 15 01 16 01 17 01 18 01 19 01 1a 01 1b 01 1c 01 1d 01 1e 01 1f 01 20 01 21 01 22 01 23 01 24 01 25 01 26 01 27 01 28 01 29 01 2a 01 2b 01 2c 01 2d 01 2e 01 2f 01 30 01 31 01 32 01 33 01 34 01 35 01 36 01 37 01 38 01 39 01 3a 01 3b 01 3c 01 3d 01 3e 01 3f 01 03 02 3f 02 03 03 3f 03 03 04 3f 04 03 05 1f 05 20 05 39 05 3a 05 3f 05 03 06 06 06 1f 06 2b 06 2c 06 2d 06 2e 06 2f 06 3a 06 3f 06 03 07 06 07 1e 07 23 07 2b 07 2f 07 37 07 3b 07 3f 07 03 08 06 08 1f 08 23 08 2b 08 2e 08 2f 08 31 08 37 08 3a 08 3f 08 53 08 57 08 59 08 5a 08 5b 08 03 09 06 09 07 09 08 09 0a 09 0b 09 0c 09 0e 09 0f 09 10 09 12 09 13 09 14 09 16 09 17 09 18 09 1a 09 1b 09 1c 09 1e 09 23 09 24 09 25 09 27 09 28 09 29 09 2b 09 2d 09 2f 09 31 09 32 09 34 09 37 09 3b 09 3f 09 54 09 56 09 59 09 5c 09 03 0a 06 0a 08 0a 0a 0a 0e 0a 10 0a 12 0a 14 0a 16 0a 1a 0a 1c 0a 1f 0a 23 0a 25 0a 27 0a 29 0a 2b 0a 2c 0a 2f 0a 31 0a 33 0a 35 0a 3a 0a 3f 0a 55 0a 59 0a 5c 0a 03 0b 06 0b 07 0b 08 0b 0a 0b 0e 0b 0f 0b 10 0b 12 0b 14 0b 16 0b 17 0b 18 0b 1a 0b 1b 0b 1c 0b 1f 0b 20 0b 23 0b 24 0b 25 0b 27 0b 28 0b 29 0b 2b 0b 2c 0b 2d 0b 2e 0b 2f 0b 31 0b 33 0b 35 0b 37 0b 39 0b 3a 0b 3f 0b 54 0b 56 0b 59 0b 5c 0b 03 0c 3f 0c 53 0c 57 0c 59 0c 5a 0c 5b 0c 03 0d 3f 0d 03 0e 04 0e 05 0e 06 0e 07 0e 08 0e 09 0e 0a 0e 0b 0e 0c 0e 0d 0e 0e 0e 0f 0e 10 0e 11 0e 12 0e 13 0e 14 0e 15 0e 16 0e 17 0e 18 0e 19 0e 1a 0e 1b 0e 1c 0e 1d 0e 1e 0e 1f 0e 20 0e 21 0e 22 0e 23 0e 24 0e 25 0e 26 0e 27 0e 28 0e 29 0e 2a 0e 2b 0e 2c 0e 2d 0e 2e 0e 2f 0e 30 0e 31 0e 32 0e 33 0e 34 0e 35 0e 36 0e 37 0e 38 0e 39 0e 3a 0e 3b 0e 3c 0e 3d 0e 3e 0e 3f 0e 1c 13 1e 13 2e 13 30 13 1b 15 1f 15 2d 15 2e 15 2f 15 30 15 31 15 1c 16 1d 16 1e 16 2d 16 31 16 2e 17 2f 17 30 17"

# Convert the hex data string into a list of bytes
data_bytes = bytes.fromhex(hex_data)

# Define a function to parse the hex data into a structure representing the map
def parse_map(data):
    # Skipping the first 4 bytes (header)
    data = data[4:]

    # Initialize map representation
    map_representation = [["O" for _ in range(0x5c)] for _ in range(0x17)]

    # Iterate over the data to fill in the map
    row = -1
    for i in range(0, len(data), 2):
        if data[i] == 0x03:  # New row marker
            row += 1
        else:
            if row >= 0:  # Ensure we've started processing rows
                col = data[i] - 1  # Adjust for 0-index
                map_representation[row][col] = "X"

    return map_representation

# Parse the map
map_representation = parse_map(data_bytes)

# Function to print the map
def print_map(map_representation):
    for row in map_representation:
        print(" ".join(row))

# Print the map
print_map(map_representation)

The above code prints the map with O/X, and then by optionally searching for X in a text editor to highlight it, we get the flag.

bronco{bo0m!}

Mystery Sound (9 Solves)

Description:

This transmission supposedly contains a secret flag, but I can't decode it because of some interference. Can you help?

Solution:

Playing the audio in the wav file with sonic visualizer, we see a square wave in the spectrogram. I considered screen capturing it and building a program to analyze it programatically but it wasn't too long so I just turned on the grid, scrolled in until the grid lines lined up roughly with the start/end, and typed the 0/1 into cyberchef. It's slightly off but every byte starts with 0 and it's pretty clear if you make a mistake.

bronco{y0u_mu57_h4v3_4m4z1ng_h34r1ng}

LAN Party (13 Solves)

Description:

My friend is SO MEAN! He changed my password on my home router and hid it in this Minecraft world. He even unmined the chunk I dug out...what a jerk. Ugh, now I am just here at the top of the world rather than at bedrock mining diamonds.

Target Difficulty: Medium
https://drive.google.com/file/d/12omOpKMzAvrg3lo9_rTXzGuTX53_lEOa/view?usp=drive_link 

Solution:

The attachment is a minecraft source with various files including mca files. Looking at similar CTF challenges, the flag could either be encoded in the files like in a book, or displayed visually in the map. Going for the easier option, I downloaded chunky to see if anything stood out, and saw a red squiggle in the top right of the map. Zooming in with the scale option, we see the flag.

Web

ACM Borg Members (40 Solves)

Description:

I am convinced the board members of Santa Clara's ACM clubs are cyborgs! They are definitely digitally enhanced! ACM Board? More like, ACM-BORG! If only I had a way of proving it.

Target Difficulty: Easy

Solution:

With the mention of robots and a random official website, we eventually try https://www.scuacm.com/robots.txt

bronco{be3p_b0op_@CM_are_cyb0rgs}

Blue Boy Storage (122 Solves)

Description:

This blue boy saved something on his home planet but cannot seem to find it. Can you help him?

Target Difficulty: Easy

Note: flag wrapped in broncoctf{}

https://blue.web.broncoctf.xyz

Solution:

At the website, we see a main page with some text and a video, and a very long javascript file in the developer tools. Searching bronco in the js file, we will get the flag, but the javascript file will also store it into the browser storage tab of the developer tools which is likely the intended solution.

broncoctf{ab4_d3_4ba_d1e_1m_blu3}

Blue Herring (25 Solves)

Description:

This page contains the elusive blue herring, however it's never been seen by the human eye. See if you can catch it and rip it open to find a flag.

Target Difficulty: Easy/Medium

Note: flag wrapped in broncoctf{}

https://blue.web.broncoctf.xyz

Solution:

In the network tab of developer tools, we can see files that are received, so we can eventually find and download BlueHerring-CPmowcv1.png. Running zsteg with the --all flag gives us the answer.

There's an option to enable zsteg --all on aperisolve before submitting but it still says nothing found for some reason (which is a clear indication that it's not working since this should match many things in a png). It did work at one point but even then it's hard to notice since all the text is white.

All I Do Is (42 Solves)

Description:

I LOVE TO ROLE PLAY! for my upcoming convention, i am reliving my glory days of being a minecrafter.

https://www.youtube.com/watch?v=DLgYt-569jc

https://diamonds.broncoctf.xyz

Target Difficulty: Easy/Medium

Solution:

The link goes to a video called "All I Do Is Dig", hinting we need dig. If we go to the url, we don't find anything because the default DNS server doesn't know how to access diamonds.broncoctf.xyz.

Here's the flow to using dig to find the DNS server that knows about it, getting its IP address, and then getting the TXT info from it.

Edit: somehow I missed it but all that's necessary is dig diamonds.broncoctf.xyz txt (I thought I would have tried that first though, leaving below in just in case it was necessary for some reason)

└─$ dig diamonds.broncoctf.xyz    

; <<>> DiG 9.18.16-1-Debian <<>> diamonds.broncoctf.xyz
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15536
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;diamonds.broncoctf.xyz.                IN      A

;; AUTHORITY SECTION:
broncoctf.xyz.          300     IN      SOA     ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 259200 300

;; Query time: 108 msec
;; SERVER: 8.8.4.4#53(8.8.4.4) (UDP)
;; WHEN: Sun Feb 18 10:23:56 PST 2024
;; MSG SIZE  rcvd: 144



└─$ ping ns-cloud-e1.googledomains.com 
PING ns-cloud-e1.googledomains.com (216.239.32.110) 56(84) bytes of data.
64 bytes from ns-cloud-e1.googledomains.com (216.239.32.110): icmp_seq=1 ttl=63 time=59.5 ms
64 bytes from ns-cloud-e1.googledomains.com (216.239.32.110): icmp_seq=2 ttl=63 time=59.7 ms
^C
--- ns-cloud-e1.googledomains.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 59.538/59.604/59.671/0.066 ms
                                                                                                                     


└─$ dig TXT diamonds.broncoctf.xyz @216.239.32.110

; <<>> DiG 9.18.16-1-Debian <<>> TXT diamonds.broncoctf.xyz @216.239.32.110
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22488
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
; COOKIE: ea2b9b63307dfa100167985f6bfd1bb2202bde1b35bd87c4e754b178f9 (good)
;; QUESTION SECTION:
;diamonds.broncoctf.xyz.                IN      TXT

;; ANSWER SECTION:
diamonds.broncoctf.xyz. 300     IN      TXT     "bronco{Finding_diamonds_aint_so_hard_just_dig_baby_dig}"

;; Query time: 60 msec
;; SERVER: 216.239.32.110#53(216.239.32.110) (UDP)
;; WHEN: Sun Feb 18 10:24:46 PST 2024
;; MSG SIZE  rcvd: 152

Crypto

Preschool Lessons (70 Solves)

Description:

a b c... easy as 1 2 3...

Do you REALLY know your ABCs?abbaaabacabbbaabacabbabbbbcabbabbbacabbaaabbcabbabbbbcabbbbabbcabbabaabcababbbbbcabbabbabcaabbaaabcabbbaabbcabbbaabbcababbbbbcabbbaaaacabbbaabacaabbaabbcabbbaabbcabbaaabbcabbabaaacabbabbbbcaabbaaaacabbabbaacabbbbbab

Target Difficulty: Easy

Solution:

This looks like binary, with c representing space. Find replace a with 0, b with 1, and c with space to get:

bronco{i_m1ss_pr3scho0l}

Zodiac Killer (84 Solves)

Description:

The Zodiac Killer is on the loose! I saw this message spray painted on a wall.

Wrap the flag in bronco{}

Target Difficulty: Easy

Solution:

The attached picture shows a Zodiac cipher, solve with this: https://www.dcode.fr/zodiac-killer-cipher

bronco{LOOKOVERYOURSHOULDER}

Electrical Engineering (52 Solves)

Description:

I hate electrical engineering

Target Difficulty: Easy

Solution:

We're given a pdf with many 6-band resistors.

The last three bands never change in color so we just have the first 3. The first band is either black (0) or brown (1) so we know we're likely dealing with 3-digit decimal ASCII. Decoding the rest with resistor color codes, we get:

bronco{rEsi5t_ev1L}

Oh, Danny (13 Solves)

Description:

When using AES in CBC mode, Danny has a habit of leaving messages in his initialization vectors. Can you find his secret message?

Flag Format: Wrap the IV in bronco{ }

key = 73757065725f6b65795f73747265616d
pt1 = 4163636f7264696e6720746f20616c6c
pt2 = 206b6e6f776e206c617773206f662061
ct2 = 817ed4df4521cc2d6e746c45a834aa2d

Target Difficulty: Medium

Solution:

Here's what AES CBC is:

Conveniently everything's already in 16-byte blocks. We know the input into the 2nd XOR operation since we have pt2/ct2, and then we reverse once more to use pt1 to get IV.

from Crypto.Cipher import AES
from binascii import unhexlify, hexlify

# Known values
key = unhexlify("73757065725f6b65795f73747265616d")
ct2 = unhexlify("817ed4df4521cc2d6e746c45a834aa2d")
pt2 = unhexlify("206b6e6f776e206c617773206f662061")
pt1 = unhexlify("4163636f7264696e6720746f20616c6c")

# Initialize AES cipher in ECB mode for decryption (CBC effects manually applied)
cipher = AES.new(key, AES.MODE_ECB)

# Decrypt ct2 to get "pt2 XOR ct1"
decrypted_ct2 = cipher.decrypt(ct2)

# Calculate ct1 using decrypted ct2 and pt2
ct1 = bytes(a ^ b for a, b in zip(decrypted_ct2, pt2))

# Decrypt ct1 to get "pt1 XOR IV"
decrypted_ct1 = cipher.decrypt(ct1)

# Calculate IV using decrypted ct1 and pt1
iv = bytes(a ^ b for a, b in zip(decrypted_ct1, pt1))

print(iv)
# b'd0nt_l3@k_ur_k3y'
bronco{d0nt_l3@k_ur_k3y}

Birthday Bash (8 Solves)

Description:

22 years ago today, my dearest neighbor gave birth to a child, my best friend. I got an invite to their birthday party, but I cannot understand it for the life of me. I will feel guilty 100 times over if I don't attend their birthday bash! Can you help?

Target Difficulty: Hard Hint 1: Based. Hint 2: Think about 100 and 22 together.

Solution:

The attached text file seems like random bytes, not much we can get from it directly so we need to go off of other info. I don't think this is solvable without the hints, but with them, we think of either some base operation followed by something related to 100 and 22, or them combined (base 122). Googling base122, we find the following Github repo which lets us know we're on the right track: https://github.com/kevinAlbs/Base122

└─$ node
Welcome to Node.js v18.13.0.
Type ".help" for more information.
> let base122 = require('./base122'), fs = require('fs');
undefined
> let fileData = fs.readFileSync('../mybirthday.txt', {encoding: 'utf-8'});
undefined
> let decodedData = base122.decode(fileData);
undefined
> decodedData
[
   91,  86, 101, 114, 115, 101,  32,  49,  93,  10,  73, 116,
   32, 102, 101, 101, 108, 115,  32, 108, 105, 107, 101,  32,
   97,  32, 112, 101, 114, 102, 101,  99, 116,  32, 110, 105,
  103, 104, 116,  10,  84, 111,  32, 100, 114, 101, 115, 115,
   32, 117, 112,  32, 108, 105, 107, 101,  32, 104, 105, 112,
  115, 116, 101, 114, 115,  10,  65, 110, 100,  32, 109,  97,
  107, 101,  32, 102, 117, 110,  32, 111, 102,  32, 111, 117,
  114,  32, 101, 120, 101, 115,  10,  85, 104,  45, 117, 104,
   44,  32, 117, 104,
  ... 2419 more items
]

> let decodedString = String.fromCharCode.apply(null, decodedData);
undefined
> console.log(decodedString);
[Verse 1]
It feels like a perfect night
To dress up like hipsters
...
[Chorus]
(Hey!) I don't know about you (I don't know about you)
bronco{But I'm feeling (base one) twenty-two}
...

Reversing

Serpent's Pass (64 Solves)

Description:

Snakes! Snakes! Snakes!

Target Difficulty: Medium/Hard

nc serpant.broncoctf.xyz 8000

Solution:

The attachment is a python server where three questions are asked and if they are correctly answered, we get the flag. The following courtesy of GPT-4.

Gate 1

Gate 1 requires you to return the result of the expression pow(10 * 9 + 7 - 2, 2). This is a straightforward calculation.

Gate 2

For Gate 2, the function gate2(guess: int) returns True if the binary representation of a number (formed by appending guess number of 1s to a 0) when converted to an integer, corresponds to the ASCII character '?'. We need to find the correct guess that satisfies this condition.

Gate 3

Gate 3 involves the Fibonacci sequence, calculated by the mystery(n: int) function through recursion. The function gate3(guess: int) will return True if the Fibonacci number at position guess is a perfect square. We need to find such a guess.

Let's calculate the inputs for each gate.

The inputs required to pass the three gates in the CTF challenge are as follows:

bronco{w0w_uR_@_g00d_gu3ss3r}

MZ (6 Solves)

Description:

Can you reveal the secrets hidden within this binary?

(Note: this is a Windows executable, but it's been saved with a .BIN extension to avoid antivirus problems. You will need to replace .BIN with .EXE to run it.)

Solution:

Doing some research, MZ (the first two bytes in the file) means it's an executable format where if it's run in DOS, it can have some other behavior. More info: https://en.wikipedia.org/wiki/DOS_MZ_executable

We can use an online DOS emulator to run the binary to see what would happen. https://virtualconsoles.com/online-emulators/dos/ It wouldn't work for me on firefox for some reason, but in Chromium, we get the flag.

bronco{th1s_pr0gr4m_c4n_b3_run_1n_D0S_m0d3}

OSINT

Wiki Wiki Wiki (118 Solves)

Description:

Not much to go off here, but it’s all you need: Wikipedia and 128.125.52.138.

The flag is not in the typical format, but wrap it in bronco{} before submitting. You will know when you find it.

Target Difficulty: Easy/Medium

Solution:

Searching that IP address on Wikipedia, we see a user with a single contribution to the Flag Wiki page. Clicking on "diff", we can see what that was.

Side Quest (15 Solves)

Description:

There is a side-quest hidden midway through the Lost Valentine Challenge. You will know when you find it.

Target Difficulty: Medium/Hard

Solution:

In the description of one of the google drive folders for Lost Valentine (can be seen either in the page source or in the social preview associated with the link), we get the following ciphertext along with some message referring to 1000 that I didn't keep.

ΡŠΡšΡ—Ρ–Ρ‹Ρ—Ρ£Ρ”Ρ—Ρ›ΡœΡ‡Ρ•Ρ‘Ρ‡Ρ”Ρ—ΡžΡΡšΡ‡ΡŠΡΡœΡ‡ΡœΡ—Ρ—Ρ“Ρ‡Ρ‰Ρ‡ΡŒΡΡœΡ—ΡΡšΡ₯

My unintended solution was removing the first byte for each character (d1) to make it one byte for each character, then running XOR brute force in cyberchef and noticing the flag is a combination of characters from the c8 and d8 decryptions.

8a 9a 97 96 8b 97 a3 94 97 9b 9c 87 95 a1 87 94 97 9e 8d 9a 87 8a 9d 9c 87 9c 97 97 93 87 89 87 8c 8d 9c 97 9d 9a a5


RBONSO{LOCD_My_LOFUB_RED_DOOK_Q_TUDOEB}
BR_^C_k\_STO]iO\_VEROBUTOT__[OAODET_URm

BRONCO{LOST_My_LOVER_BUT_TOOK_A_DETOUR}

This actually isn't the intended solution, which was supposed to be just using https://www.dcode.fr/unicode-shift-cipher with the default shift of 1000 to get:

bronco{lost_my_lover_but_took_a_detour}

Some weird math property is involved here why my solution even worked, and I don't even know how the y became lowercase, maybe there's some magic in here that would make a good CTF challenge.

Lost Valentine (6 Solves)

Description:

Valentine's day came and past, and I am still pretty upset. My girlfriend didn't show up for dinner at the restaurant she made a reservation at. After about 30 minutes, the waiter came and left me a note in her handwriting: "cupid-is-upset"

What could that mean!!

Solution:

This was a long one and I didn't take good notes but here's my best attempt at a writeup. The only thing we have to go off of is "cupid-is-upset", and through a username search https://instantusername.com we find it is taken by github.

Going to https://github.com/cupid-is-upset, we see flag parts scattered around, such as 5 rg/ji in the description, 12 TnTa_Z in the README, etc. There's a thought bubble next to the icon with 6, the lost repository with 2 in the workflows, 1 in the issues, 10 and 11 in the wiki, etc.

Here's all the pieces I found:

1 htt
2 ps:/
5 rg/ji
6 gsa
7 w/pla
8 y?p=
9 -NqoEdz
10 0zSA
11 gBI
12 TnTa_Z 

Put together to get https://puzzel.org/jigsaw/play?p=-NqoEdz0zSAgBITnTa_Z

I didn't find 3/4 but looking up jigsaw sites, puzzel was the first one. I don't know if that was intended or if I just missed 3/4.

Solving this jigsaw manually (since I couldn't find a method to extracting/solving it) actually had some strategy to it. The pieces snap into place when you place them in the right spot so all edges can be handled right away as well as the heart outline. Then, just put all the purple into a pile and go from there. Online QR solvers couldn't decode it but my phone could which was https://qrcc.me/s8gjjl3yizv8

This link went to a google drive with an aup3 file. The page source has the sidequest described above, and when clicking on the file and then the three dots for details, we see a hint in the description:

gordan told me its raw :( i hope he doesn't get mono. 44100 

The aup3 extension is an audacity project, opening it there and exporting the data as raw (following online instructions) gives the following image.

Looking up the user on namemc.com, we see their profile has an instagram linked.

The instagram has two photos with alt text (viewable in the page source directly on instagram.com which is replaced by some 3rd party instagram viewers) leading to a puzzle where you have to click four related words, below is the solved image:

It says to look at california state parks yelp review check when looking at the categories. In the previous step with the two images, they were location-tagged to Castle De haar and The Rock Hazelwood. Using that as a hint to look up the Castle Rock page specifically, we see the review when sorting by latest. Fun challenge and nudges were provided for each stage at the helpdesk as was advertised in the discord chat.

Misc

Countries Unite (98 Solves)

Description:

"yoshie" sent me a peculiar message. What could he possibly be trying to say?

Target Difficulty: Easy

Solution:

We're given a picture of a bunch of flags. We can see from the first few that the flag is represented by the first letter of the country represented by the flag. I used a generic page to look at the country flags and solved it manually, it may also be more convenient for some to mouse over the emojis when searching for flags in discord.

bronco{diveristyequityinclusion}

BroncoCTF Crossword (23 Solves)

Description:

I am really annoyed. I work at Bronco Venture Accelerator and instead of doing work, my boss is just sitting doing a crossword. And drinking lemon juice? WHY! I want to dump it on him and his paper. We need to make MONEY.

Target Difficulty: Medium

Solution:

We're given a pdf file, and when opening it, we can see the solution flash for a second so we know the image is embedded. Running pdfimages on it gives us the extracted image solution but it doesn't seem helpful. I then noticed my ranger preview showed the flag, so the pdf must have had this text below the image or something.

World's Hardest Flag (8 Solves)

Description:

Good luck. Be sure to read the game description.

Note: this does require a Roblox account.

Target Difficulty: Hard

https://www.roblox.com/games/16323057979/Worlds-Hardest-Flag-Early-Access

Solution:

This was a fun one. A Roblox account is necessary but the link leads us to a game where we need to get to checkpoints while avoiding enemies. We have access to a Lua console so we can type in commands to affect the game state. Here are some general commands I worked out.

-- Print out location of found objects, change 10 with length of the search
for i, object in ipairs(workspace:GetDescendants()) do
    if object:IsA("BasePart") and string.sub(object.Name, 1, 10) == "Checkpoint" then
        print(object.Name .. " is at " .. tostring(object.Position))
    end
end

-- Delete matched objects
for i, object in ipairs(workspace:GetDescendants()) do
    if object.Name == "Dehnemy" then
        object:Destroy()
    end
end

-- Print current location
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local position = character.PrimaryPart.Position
print("Current Location: ", position)

-- Teleport to a new location
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local targetPosition = Vector3.new(x, y, z) -- x,y,z are the coordinates like in the first command output

if character and character:FindFirstChild("HumanoidRootPart") then
    character.HumanoidRootPart.CFrame = CFrame.new(targetPosition)
end

I'm not sure on the last two since I didn't save the last ones I ended up using, but it's something very close to that if they don't work directly. I tried teleporting initially to the "WinPad" found with the first function but kept falling into a pit so instead just despawned the enemies and walked through the game. At the end I saw there was a block needing 100 coins so I needed to walk back and collect them all, and although there were exactly 100 coins, the door wasn't unlocking. It may have been bugged since I had errors on every room I walked into because of the enemies being gone. In the last room however, I saw the glowing green win pad and was able to stand next to it, walk away and get my location, to then extrapolate what my location would be if I was able to walk to it without the door in the way. Teleporting to that location gave the flag.

bronco{hard35t_f14g_0f_my_l1f3}

Last updated