Write up's for HackTrinity 2020. This is a bit brief but I'll eventually add more.
I started preparing for this CTF around 3-4 days prior and this was my first CTF so it was certainly difficult.
There were quite a few helpful resources. Primarily Conor Mac Amhlaoibh's write up for last years HackTrinity which helped me get a good feel for competition.
Topic(s) | Points | Difficulty (in my opinion) |
---|---|---|
forensics |
388 |
My friend Wu said this was a better stegosaurus picture. Personally I can't see any DIFFERENCE, from the Previous Visual Depictions. Can you?
This problem was really interesting and took me a while to figure out.
The key was figuring out the few hints in the challenge description. Wu isn't some random person, he's the author of a paper on Pixel Value Differencing.
A quick read of the paper specifies an algorithm to encode and decode these images but I wasn't arsed to implement it myself so I looked one up on github and found one with nearly the exact same challenge description by zst-ctf.
I quickly tried his python script only to find that it didn't work. I read over the paper again and found another set of range widths [2, 2, 4, 4, 4,8, 8, 16, 16, 32, 32, 64, and 64] and adjusted the if statements to suit. Adjusted Python Script
Running the program outputted the following: With the flag being: HackTrinity{Th3_H4ck3r_M4n1f35t0}
Topic(s) | Points | Difficulty |
---|---|---|
Reversing |
288 |
So I found this program on a hacking forum. The OP attached it to the thread saying he'd found a way to share his flag and you can't read it without knowing the password. I have no idea what the password is, but there were a lot of others laughing at OP saying they got the flag. Can you get it for me?
This challenge actually has 2 solutions and the only reason I'm giving it a medium is because I took so long to find the reversing one. The second solution is discussed in Locked Out 2
The solution is rather simple and I think it's best described by a LiveOverflow Video
But all we're doing is going into Binary Ninja and patching the if statement so that it always outputs the flag. Save it is locked_out_cracked, run it and there's the flag.
Topic(s) | Points | Difficulty |
---|---|---|
Exploitation |
394 |
So back on the hacking forum, OP sick of being laughed at, said he's secured his flag by running his code on a remote server - he hasn't changed the code though.
This challenge was a lot handier because I had already had the idea of abusing bufferoverflows to retrieve the flag for Locked Out 1.
The code was the exact same, except this locked out file was located on a server and when you connect to it, there's no room for commands. If you decompiled or ran gdb on the source code from locked out 1, you'll notice the use of gets to take input from the console.
This could only be a buffer overflow attack.
A handy video I had found from John Hammond explains his solution from a similar challenge from the picoCTF series.
Since we had the code we just needed to figure out how many 'A's I'd need to overflow the buffer. I basically brute forced this by getting a really high number and a low number and found the number of A's needed .
Next I needed to find the location of the flag. I found a function called print_flag using gdb and then found its location.
After that I used python to prepare our overflow attack and execute the program
The struct module was handy because it converted our function location and transferred it instantly
python -c "import struct; print 'A'*264 + struct.pack('<I',0x000000004000139b)" | ./locked_out
Now that I verified it worked for my test, I was ready to do it remotely.
Place the following into the terminal, and our flag is revealed
python -c "import struct; print 'A'*264 + struct.pack('<I',0x000000004000139b)" | nc 192.168.146.1 1337
Flag: HackTrinity{bonfire_vet_TV_misplacement}
Topic(s) | Points | Difficulty (in my opinion) |
---|---|---|
web |
350 |
There's a new sysadmin in town and he thinks he's real cool. Apparently he's been working hard on his new website...
You can find the server at 192.168.140.1.
This challenge was by no means hard, it's actually rediculously easy. But rest assured, I've spent more time on this one question than I have on some of my modules.
See when you follow the website you're met with a static page. I checked if there was anything being sent to and from a server, nothing. The website said it was built under TodoMVC so I quickly checked for any exploits and even found the source code for the website. Still nothing.
The hint in the challenge is that he's a sysadmin. I ran an nmap scan, only port 80 was open. So I thought it must be something to do with directories. I checked /flag.txt, /flag.png and what not. I ran multiple different directory brute forces. Including dirb, dirbuster, dirsearch and gobuster. All for naught.
Finally, and depressingly I ran a nikto. Nikto specified something along the lines of
The server install allows the reading of any system file by adding an extra '/' to the URL
So I tried 192.168.140.1//flag.txt and would you believe, the flag was just sitting there - mocking me.
Flag: HackTrinity{representation_photograph_vote_reasoning}
I don't even understand what the flag is supposed to mean.
Topic(s) | Points | Difficulty |
---|---|---|
Crypto |
238 |
nby zfua zil nbcm wbuffyhay cm: RGVjb2RpbmdfY2FuX2JlX2Z1bl91bnRpbF95b3Vfc3RhcnRfbWl4aW5nX2l0X3Vw doqd! :)
This challenge had a few annoying red herrings. And took me longer than it should've to cop it.
See the first part, "nby zfua zil nbcm wbuffyhay cm:" is actually a rot 6 shift and translates to
the flag for this challenge is:
Basically useless.
So we go on to the next part "RGVjb2RpbmdfY2FuX2JlX2Z1bl91bnRpbF95b3Vfc3RhcnRfbWl4aW5nX2l0X3Vw"
Throwing that into CyberChef, it turns out that it's a base64 encoding and we get:
Decoding_can_be_fun_until_you_start_mixing_it_up
Wrap it and your flag is: HackTrinity{Decoding_can_be_fun_until_you_start_mixing_it_up}
I still don't know what doqd! is supposed to mean.
Topic(s) | Points | Difficulty |
---|---|---|
Recon |
379 |
Somebody pwned our DNS a while back and set up a website on a subdomain. They've since cleaned it out and we don't know what the website was called. We're all about transparency here at HackTrinity so we'd like to let our users know.
Note: This flag will not be in the standard HackTrinity{} format
This challenge required a particular attention to detail.
If you look up subdomain search it doesn't really help. There's a few tools that try and get all the subdomains that are currently active but this subdomain wasn't.
The challenge specifies we're all about transparency, where you had to notice that transparency was in italics.
If you look up subdomain trasparency a medium article comes up. Interestingly enough anytime you get a https:// for your domain it's logged in the certificate transparency logs.
The article also included a website to look up these logs called crt.sh.
If you look up hacktrinity.org on crt.sh a few subdomains pop up.
The only one that looked out of the blue is: xn---f0d-m-py-fg-dcb81av7aegg3f74afb6qka .hacktrinity.org
Typing that into the browser and we get:
Copy the flag subdomain in and claim our points.
Topic(s) | Points | Difficulty |
---|---|---|
Web |
360 |
With the current outbreak of COVID-19, Trinity have decided to hold all of the final examinations online on the "Exam-n" system.
Can you reverse engineer the system and recover the answers to score a perfect 100 on your Ancient Memes exam?
You can find the server at 192.168.151.1.
This was a super handy problem, hence the easy difficulty.
The website is pretty simple, you enter an answer and press check. If your answer is right, it outputs correct.
Scrolling down, we find a question that asks for the flag. We can assume that's where our flag is.
If you inspect element, we find that there exists a check.js
So I downloaded the website using:
wget -r -l 0 http://192.168.151.1:80/
Opening our check.js, we find a function which checks whether each character of our input is equal to the encrypted answer
function c(id, i, l) {
// debugger;
let answer = document.getElementById(`answer${id}`).value;
if(answer.length !== l) {
return false;
}
for(i_a=0; i_a<l; i_a++) {
let char = answer[i_a];
let blk = blks[i];
if (!blk || (enc(char) !== get_blk(i))) {
return false;
}
i++;
}
return true;
}
I wasn't bothered to decrypt the encrypted answer so instead I brute forced it. Using their encrypt function, I checked every single ascii character against the corresponding encrypted answer, until each encrypted character of ascii is equal to the encrypted answer. Simultaneously, I was appending each character to a flag variable.
Now when we put in any random answer, it triggers our check function(c). This will then trigger our brute force, solve and print the flag to the console.
Our flag is revealed!
Flag: HackTrinity{vibration_TV_mine_sky}