Project Ideas
1. Playlist maker based on music's emotion
Perform Emotional Analysis on music in a playlist and create a new playlist based on the emotions of the songs. or reorder the songs in the playlist based on the emotions of the songs.
Have not even started work on it
2. Ascii Doc lexer and writer which is compatible with the Asciidoctor
Self Explanatory
Currently working on it
3. Music Player Daemon, with integrated support for Notifications
Self Explanatory
Haven't even started
4. Operating System for risc V architecture
Self Explanatory
Basically on hold
5. A concise proc macro for generating everything a CRUD App might need
It must have permissions, import, export, frontend component generation
Working on it locally, not in a state to be built
Software
General pieces of advice for me
- Exercising regularly really does help.
- Use bash for scripts when the script will run less than 10 times in a lifetime.
- Use python for scripts when you want to be able to edit them.
- Use PlatformIO for embedded development, unless there is no mature rust HAL for a MCU.
- Prefer wgpu over platform specific APIs for graphics programming.
- Always benchmark stuff when optimizing, no exception.
- Try to avoid web development if you can, its hell incarnate.
- After some testing, Music actually slows you down, unless you are doing something that requires no thinking.
- For downloading music,
yt-dlp -x --embed-subs --embed-metadata --embed-thumbnail --add-metadata "https://youtube.com/playlist?list=PLNPkZsUXzlEjvQemMGAnBifR4yNFO4dpb" -N 8 -I -1:-10:-1 --parse-metadata ":(?P<meta_synopsis>)"
More detailed info
2D Rendering
- Denote an image with a single array and a pixel's index can be found by
width * y + x
. - The x coordinate is
i % width
, y isi / width
. - To get a point at a distance r and angle t, relative to point (x0, y0)
- For drawing a simple primitive, use its derivative to get the next pixel, usually the derivative is simpler
- Ok, Fk, This stuff is sub optimal, since it kinda encourages drawing vertically, which is not optimal for the cache.
Line
- A line's equation is
or, where
- When drawing line, a simple
for (x in x0..x1)
usually leaves gaps if , andfor (y in y0..y1)
leaves gaps when , use both with if cases. - Use when when drawing lines to avoid division.
Circle
- A circle's equation is
or,
- Its not worth doing the derivative for a circle, just use the equation.
- A circle can be drawn by only finding 1/8th of it, and mirroring it to the other 7 parts.
Ellipse
- An ellipse's equation is
or,
- Its not worth doing the derivative for a circle, just use the equation.
- An ellipse can be drawn by only finding 1/4th of it, and mirroring it to the other 3 parts.
Rotated Rectangle
- Find the points of upper line and the corresponding point at the bottom part at the same x coordinate.
- Draw a vertical line between these two points.
- Bam, you have a rotated rectangle.
Electronics chapter
General words of caution
- Isolate the grounds of power and signal circuitry
- Prototype a PCB before ordering it.
- Make soldered connections before changing anything else.
- Check code before changing circuitry.
Component sellers
PCB Manufacturing
Quirks of devices
Quirks
NodeMCU
- NodeMCU is a development board that uses the ESP8266 chip, packaged as a ESP-12E module.
- The NodeMCU Board maps the ESP 12E's pins to custom pins named as DX pins.
To Program
-
Using the Arduino IDE.
- Install the ESP8266 board package.
- Select the board as NodeMCU 1.0 (ESP-12E Module).
- Code like you would for an Arduino.
NOTE: The pin numbers in the code are the DX pin numbers, not the GPIO numbers. So, D8 GPIO8.
-
Using platformio.
- PlatformIO has native support for it, go look at the website.
Quirks
- Most boards use CP2102 Serial to USB converter, so if on windows, download it's driver, and if on linux, gentoo in particular, compile that in.
- One may think that the NodeMCU shouldn't be powered by more than 3.3V, but it can be powered by 5V.
- However, you can't have the signal be 5V, as the ESP8266 is a 3.3V device. You can fry GPIOs like this.
- It also has an upper current limit of 12mA per GPIO pin, that's not much.
- Don't connect it directly to relays, have an optocoupler.
- Sudden current demand spikes can also crash it.
- Remember to regularly
yield()
when taking up a core for too long, otherwise it will crash. - Default Baud rate for errors is 76800.
- D3 is mapped to GPIO0, D4 is mapped to GPIO2, D8 is mapped to GPIO15
- GPIO0, GPIO2 and GPIO15 determine the boot mode, so if you are unable to upload code to it, check whether the states of these pins is in the correct state at early boot.
- GPIO15 also acts as chip select for SPI.
GPIO0 (D3) | GPIO2 (D4) | GPIO15 (D8) | |
---|---|---|---|
UART (aka. When you can upload code to it) | LOW | HIGH | LOW |
Flash Boot (aka. When code runs) | HIGH | HIGH | LOW |
- You can pull down a pin by attaching a high value resistor to a ground.
- You can pull up a pin by attaching a high value resistor to a VCC.
- If there is literally no response from the nodeMCU, check the EN pin and the RST Pin, both of these should be high and not fluctuating.
- Serial.print sends data to both USB and the RX, TX pins on board, if using them for something, make sure you are printing only relevant stuff.
- The antenna sucks a little, may dire wiring the antenna manually, some people have reported success, haven't verified personally.
- SPI can be finicky, when a connection is broken, it needs to be reset. My current solution is to just reset SPI and begin a new connection everytime data needs to be sent.
- In particular, MFRC522 module fks with it, sending it to a different boot mode if you connect it's pins to the ones specified above without care.
RC522 RFID Reader
I am referring to the complete module, not just the chip.
If you have metal behind the reader OR the tag, it won't be able to read it.
To mitigate, get a piece of dielectric material, like ferrite and put that between the tag and metal, that is actually how the commercial solution is made.
The better solution is to just buy the metal tags, they are more expensive, but they work better with metal.
Just know this before starting your project.
It fking SUCKS, but is the cheapest, you can get it as low as 50 rupees.
Actually, MFRC522 is the name of the chip, but also commonly refers to the cheap board it is commonly found on.
Somehow the IRQ pin is not supported by the most popular library for reading rfid tags using it for arduino, idk how, that is just how it is.
It alternates between having a tag and not having a tag when sending the command to read a tag, Ping multiple times to get the actual result.
If the boot mode of NodeMCU is wrong, this fker is probably the culprit.
Also, buy in bulk, these things are fragile AF, and can randomly stop working if voltage is not to their liking. Could be dirty DC, could be slightly more voltage, could be slightly less voltage.
These don't have any VRMs or filtering caps, so make sure power is good.
Sometimes you may need to do a SPI Reset, in my experience, even when i had soldered the connections, at this point, i can't figure out why, may be the mfrc522 chip crashes for some reason. Just do a SPI reset regularly.
CTF Section
This section will contain the writeups for the CTF I have participated in.
ACECTF Writeups
ACECTF was a CTF hosted at acectf.tech in 2025. I participated with team name Cat4Ever
Broken Secrets
You’ve found a suspicious file, but it seems broken and cannot be opened normally. Your goal is to uncover its secrets.
Submit your answer in the following format: ACECTF{3x4mpl3_fl4g}
Attachments: file named brokenfr
Solution
The obvious first step, ran file on it and got the following output:
brokenfr: 7-zip archive data, version 0.4
So, it's a 7z archive. Renamed it to brokenfr.7z and extracted it, out came the following file tree:
.
├── Brokenfr.7z
└── _
├── [Content_Types].xml
├── _rels
├── docProps
│ ├── app.xml
│ └── core.xml
└── word
├── _rels
│ └── document.xml.rels
├── document.xml
├── fontTable.xml
├── media
│ └── not_so_suspicious_file
├── settings.xml
├── styles.xml
├── theme
│ └── theme1.xml
└── webSettings.xml
8 directories, 13 files
Ran straight to the not_so_suspicious_file
, and ran file on it:
not_so_suspicious_file: data
So it needed a little more digging, opened it in nvim
, just for checking it.
Saw the IHDR and IDAT, figured it was some form of corrupted PNG
ran :%!xxd
to convert it to hex, and saw the following:
on the top of the file, it seems to be missing the PNG magic bytes
00000000: 122e d4a7 0d0a 1a0a 0000 000d 4948 4452 ............IHDR
00000010: 0000 015e 0000 00c8 0800 0000 0085 08d6 ...^............
00000020: 2c00 0000 0467 414d 4100 00b1 8f0b fc61 ,....gAMA......a
00000030: 0500 0000 2063 4852 4d00 007a 2600 0080 .... cHRM..z&...
Copied the section from a working png to here, as follows:
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 015e 0000 00c8 0800 0000 0085 08d6 ...^............
00000020: 2c00 0000 0467 414d 4100 00b1 8f0b fc61 ,....gAMA......a
00000030: 0500 0000 2063 4852 4d00 007a 2600 0080 .... cHRM..z&...
renamed the file to not_so_suspicious_file.png
and opened it:
ACECTF{h34dr_15_k3y}
Another Reading between the Lines?
Question: Is this another one of those hidden in plain sight typical normie challenges? Answer: No.
This challenge is very simple, here you have a file named hidden and all you need to do is get the flag. My focus for this year's CTF is not just the beginning but also ending on a high note, I won't rely on overused "read between the line" challenges and would rather have you guys do some research.
Good Luck!
Attachment: hidden
Solution
Ran file on the attachment
hidden: ASCII text, with CRLF, LF line terminators
Seems to be an ASCII file with mixed line terminators.
Luckily, neovim
immediately gave away what this was
Those ^M
are what we were looking for, DOS Line endings in a Unix file.
00000000: 0a0d 0a0a 0a0a 0a0a 0d0a 0a0d 0a0a 0a0a ................
00000010: 0a0d 0a0d 0a0a 0d0a 0a0a 0a0d 0a0a 0d0a ................
00000020: 0a0d 0a0a 0a0a 0a0d 0a0d 0a0a 0d0a 0a0d ................
00000030: 0a0a 0d0a 0a0a 0a0d 0a0a 0a0a 0d0a 0d0a ................
00000040: 0a0a 0d0a 0d0a 0d0a 0d0a 0a0d 0a0d 0a0a ................
00000050: 0d0a 0d0a 0a0d 0a0d 0a0d 0a0a 0a0a 0d0a ................
00000060: 0d0a 0a0a 0a0a 0a0d 0a0a 0d0a 0d0a 0d0a ................
00000070: 0d0a 0d0a 0a0d 0a0d 0a0d 0a0a 0a0d 0a0a ................
00000080: 0a0a 0d0a 0d0a 0a0a 0d0a 0d0a 0a0a 0d0a ................
00000090: 0d0a 0a0d 0a0a 0a0a 0d0a 0d0a 0a0a 0d0a ................
A simple script to treat 0a
as 0
and 0a0d
as 1
#!/usr/bin/env python3
file = open("hidden", "rb")
output = open("line.bin", "wb")
content = file.read()
content = content.replace(b"\r\n", (1).to_bytes(1, byteorder="big"))
content = content.replace(b"\n", (0).to_bytes(1, byteorder="big"))
chunk_size = 8
content = [content[i:i+chunk_size] for i in range(0, len(content), chunk_size)]
for byte_str in content:
current_byte = 0
for byte_char in byte_str:
current_byte = current_byte << 1
current_byte = current_byte | byte_char
output.write(current_byte.to_bytes(1, byteorder="big"))
this gave the output:
ACECTF{n0_r34d1n6_be7w33n_7h3_l1n35}
Significance of Reversing
Over the years, we hackers have been reversing stuff, thinking we understand how everything works and feel good about it. But, sometimes it feels like do we really understand what reversing means in mordern days? Anyways, here's a PNG, let's see if you can reverse your way out of this one.
Attachment: Reverseme.png
Solution
Downloaded the image and tried to open it, but imv came up with nothing, So as standard procedure, i opened it in neovim
and found the following:
Reversed strings which looked like dynamically linked library paths, and the FLE
at the end which was ELF
reversed gave it away
This was a reversed ELF executable
A simple script for reversing it and we were golden
file = open("Reverseme.png", "rb")
data = file.read()
data = data[::-1]
data = data[1:]
file.close()
bin = open("Forward.elf", "wb")
bin.write(data)
bin.close()
Running the Forward.elf gave us:
Decrypted string: ACECTF{w3_74lk_4b0u7_r3v3r53}
The Chemistry Of Code
During a discussion with hackers, one idea stuck: every hacker must be able to understand code, no matter how cryptic.
Hidden within obfuscated Rust code is a function that holds the flag. But it only unlocks when you reverse its logic and uncover the correct username and password.
Do you have what it takes to decode this tangled masterpiece? Dive into the chemistry of code and prove your skills.
Hint: Some secrets are worth their salt.
use base64::{engine::general_purpose::STANDARD, Engine}; use hex::encode as hex_encode; use num_bigint::BigUint; use std::io::{self, Write}; const FERROUS_OXIDE_USERNAME: &str = "AdminFeroxide"; const ANIONIC_PASSWORD: &str = "NjQzMzcyNzUzNTM3MzE2Njc5MzE2ZTM2"; const ALKALINE_SECRET: &str = "4143454354467B34707072336E373163335F3634322C28010D3461302C392E"; fn ionic_bond(cation_input: &str, anion_input: &str) { let cation_hex = hex_encode(cation_input); let anion_hex = hex_encode(anion_input); let cation_value = BigUint::parse_bytes(cation_hex.as_bytes(), 16).unwrap(); let anion_value = BigUint::parse_bytes(anion_hex.as_bytes(), 16).unwrap(); let covalent_link = &cation_value ^ &anion_value; let alkaline_secret_value = BigUint::parse_bytes(ALKALINE_SECRET.as_bytes(), 16).unwrap(); let metallic_alloy = &covalent_link ^ &alkaline_secret_value; let precipitate = format!("{:x}", metallic_alloy); let alloy_compound = (0..precipitate.len()) .step_by(2) .map(|i| u8::from_str_radix(&precipitate[i..i + 2], 16).unwrap() as char) .collect::<String>(); println!("Crystallized Flag (ASCII): {}", alloy_compound); } fn reaction_chamber() { let mut username = String::new(); print!("Introduce the Catalyst: "); io::stdout().flush().unwrap(); io::stdin().read_line(&mut username).unwrap(); let username = username.trim(); let mut password = String::new(); print!("Introduce the Reagent: "); io::stdout().flush().unwrap(); io::stdin().read_line(&mut password).unwrap(); let password = password.trim(); if username != FERROUS_OXIDE_USERNAME { println!("Reaction denied: Unstable molecule detected."); return; } let reagent_ion = STANDARD.encode(hex_encode(password).as_bytes()); if reagent_ion != ANIONIC_PASSWORD { println!("Reaction denied: Unstable molecule detected."); return; } ionic_bond(username, password); } fn main() { reaction_chamber(); }
Solution
Overall, one of the easier ones, reaction_chamber
acts as the main
function.
The program does the following:
- Read the username from
stdin
as a line - Read the password from
stdin
as a line - Early returns if username is not equal to AdminFeroxide
- Encodes the password as follows:
- Consider the password as raw bytes and encode that as hex
- Encode the result of previous step as base64
- Early returns if the encoded password is not equal to the constant ANIONIC_PASSWORD
- Proceeds to print the flag
So, to get the correct password, we need to reverse the encoding process.
We decode the ANIONIC_PASSWORD from base64 and get
643372753537316679316e36
Decoding this as hex, we get
d3ru571fy1n6
Inputting this as the password, we get:
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/chemistryofcode`
Introduce the Catalyst: AdminFeroxide
Introduce the Reagent: d3ru571fy1n6
Crystallized Flag (ASCII): ACECTF{4ppr3n71c3_w4l73r_wh1t3}
ACECTF{4ppr3n71c3_w4l73r_wh1t3}
DONOTOPEN
A suspicious script file seems to be hiding something important, but it refuses to cooperate. It's obfuscated, tampered with, and demands a password. Unravel the mystery to uncover the hidden flag.
Attachment: DONTOPEN
Solution
The top of the script looks something like this:
#!/bin/bash
TMP_DIR=$(mktemp -d)
PYTHON_SCRIPT="$TMP_DIR/embedded_script.py"
CHECKSUM_FILE="$TMP_DIR/checksum.txt"
EXPECTED_CHECKSUM="g5c533c0e5e1dd82051e9ee6109144b6"
ARCHIVE_START=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0")
tail -n +$ARCHIVE_START "$0" | gzip -d > "$PYTHON_SCRIPT"
CALCULATED_CHECKSUM=$(md5sum "$PYTHON_SCRIPT" | awk '{ print $1 }')
if [ "$CALCULATED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]; then
echo "Checksum mismatch! The embedded script may have been corrupted."
echo "Doesnt match with the MD5 checksum - a3c533c0e5e1dd82051e9ee6109144b6"
rm -rf "$TMP_DIR"
exit 1
fi
python3 "$PYTHON_SCRIPT"
rm -rf "$TMP_DIR"
exit 0
__ARCHIVE_BELOW__
# Apparently bytes for an archive
Apparently, this script does the following:
- Create a temporary dir
- Extract the archive at the end of this script into the temporary file
- Check if the checksum of the python script inside of the archive is as the expected checksum
- if not, wipe the temp directory and exit
- else, run the python file
When we first ran this script, we got the following:
Checksum mismatch! The embedded script may have been corrupted.
Doesnt match with the MD5 checksum - a3c533c0e5e1dd82051e9ee6109144b6
The easiest solution to this was just removing the checksum check, while doing that, i also ended up echo' the temp directory's location and removing the
rm -rf "$TMP_DIR"` to simplify inspection
#!/bin/bash
TMP_DIR=$(mktemp -d)
PYTHON_SCRIPT="<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">TM</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord">/</span><span class="mord mathnormal">e</span><span class="mord mathnormal">mb</span><span class="mord mathnormal">e</span><span class="mord mathnormal">dd</span><span class="mord mathnormal">e</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">cr</span><span class="mord mathnormal">i</span><span class="mord mathnormal">pt</span><span class="mord">.</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord">"</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07153em;">RC</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.22222em;">V</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.05764em;">S</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">RT</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span></span></span></span>(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">0"</span><span class="mclose">)</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ai</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mord">+</span></span></span></span>ARCHIVE_START "<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">0"∣</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mord mathnormal">i</span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">"</span></span></span></span>PYTHON_SCRIPT"
echo <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">TM</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal">Rp</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mord">3"</span></span></span></span>PYTHON_SCRIPT"
exit 0
Running this script, we get the following output:
/tmp/tmp.1bSIP4aSd9
It looks like the box is locked with some kind of password, determine the pin to open the box!
What is the pin code?
It also opened https://vipsace.org/
for some reason
Going into the tmp directory, /tmp/tmp.1bSIP4aSd9
in this case, we find
.
└── embedded_script.py
1 directory, 1 file
A single python script, embedded_script.py
.
import hashlib
import requests
import webbrowser
NOT_THE_FLAG = "flag{this-is-not-the-droid-youre-looking-for}"
# Bunch of lines with flag0 - flag999
FLAG_PREFIX = "ACE{%s}"
print("It looks like the box is locked with some kind of password, determine the pin to open the box!")
req = requests.get("http://google.com")
req.raise_for_status()
pin = input("What is the pin code?")
if pin == "ACE@SE7EN":
print("Looks good to me...")
print("I guess I'll generate a flag")
req = requests.get("http://example.com")
req.raise_for_status()
print(FLAG_PREFIX % hashlib.blake2b((pin + "Vansh").encode("utf-8")).hexdigest()[:32])
else:
print("Bad pin!")
After removing the network requests, and entering the pin ACE@SE7EN
, we get:
It looks like the box is locked with some kind of password, determine the pin to open the box!
What is the pin code?ACE@SE7EN
Looks good to me...
I guess I'll generate a flag
ACE{e2e3619b630b3be9de762910fd58dba7}
ACE{e2e3619b630b3be9de762910fd58dba7}
For some reason this one doesn't follow the general flag pattern of the CTF
Pipher - Piano Cipher
Back in my school days, we were required to pick a "Leisure Time Activity" as part of the curriculum. Four days a week, we had to attend those classes and learn whatever we chose. I opted for the piano—or more specifically, the keyboard.
From junior school through high school, I gradually improved. Over time, I moved beyond simply memorizing notes and developed the ability to judge sounds and map notes instinctively, even when hearing a song for the first time. When I discovered this skill, it felt incredible.
But this joy was short-lived. My musical journey ended when I entered high school, as academics took precedence. Later, I pursued my bachelor's degree far from home, leaving my piano behind. It's a decision I've often regretted. Now, all I have are fond, fleeting memories of those starry-eyed days as a kid.
In honor of that time, I've created a cipher called the Pipher. There's a bug in it, though—every 6th character of the plaintext leaks. So, yeah, it’s still a work in progress.
Attachment: File named cipher.txt containing:
Ciphertext - DC# DD# DF DD# EC '70' G#B CE F#C FC# C#C# '104' C#A FC# F#A# C#A C#A '108' CF AF# C#C FC# CE '102' FC# C#A# FC# GA# CE '112' FC# C#B C#C# C#A# GC '125'
Solution
Having only rudimentary knowledge about music theory, I just assumed that notes represented numbers and started from there,
After a bit of googling around, i stumbled upon an image explaining piano scales
From here, i just wrote a script which mapped the above cipher text into integers based on this and then to chars, strung them together and that was that:
#!/usr/bin/env python3
input = "DC# DD# DF DD# EC '70' G#B CE F#C FC# C#C# '104' C#A FC# F#A# C#A C#A '108' CF AF# C#C FC# CE '102' FC# C#A# FC# GA# CE '112' FC# C#B C#C# C#A# GC '125'"
map = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
output = []
print(len(input.split()))
for char in input.split():
current = char
if current.startswith("'"):
current = current.strip("'")
output.append(int(current))
continue
for i in range(len(map) - 1, -1, -1):
if current.startswith(map[i]):
output.append(i + 1)
current = current[len(map[i]) :]
break
for i in range(len(map) - 1, -1, -1):
if current.startswith(map[i]):
output[len(output) - 1] = output[len(output) - 1] * 10 + i + 1
break
print(len(output))
print("".join([chr(x) for x in output]))
Running this gave the output of:
36
36
ACECTF{0h_7h3_f33l16_0f_4_p0p_574r}
But there was a problem, the site didn't accept this flag, i ended up one of the organizer via discord, and he told me there was a typo.
I figured, that 0h_7h3_f33l16_0f_4_p0p_574r
is probably oh the feelig of a pop star
i manually added an n in f33l1n6 and the site accepted it, idk if this was how it was supposed to be solved, but hey, it worked
ACECTF{0h_7h3_f33l1n6_0f_4_p0p_574r}