
The Space Heroes 2022 CTF was an online CTF from April 1st (4pm UTC) to April 3rd (9pm UTC) 2022. It was hosted byFITSEC and it even was their first time organizing such an event! Lots of applause to them for their hard work 👏 As a newbie CTF player, there were lots of challenges to have fun on and to successfully solve. This of course will improve my experience with CTFs and get me even more motivated to do more. The entire CTF was space themed, which made me even more motivated since I love space :D
I've solved much more challenges compared to theInsomni'hack 2022 CTF, one reason is that there was more time; and also that some challenges were much more easier. This was an overall awesome CTF, especially for me as a newbie. I've learned a lot and hope to participate in their future CTFs!
As always, all flags had the same format which wasshctf{...}
. Let's get right into the write-up:
🆗 k?
This was a warm up challenge. The description said:
MEE6 was busted! Help us out and unlock the flag in #mee6...
So here it's pretty obvious, let's head over to#mee6
on their Discord server and see what we can try out. When using the/help commands
commaannd, you can see a list of custom commands made by the Discord server administrators. There was a command that looked interesting:!k (optional text) - An awesome command!
.
When typing!k
you will get the flag sent in your private messages by the bot:k? shctf{WhY_iS_K_BaNnEd} 😭
. Free points for that one!
💬 Discord
Another challenge on Discord, this time the flag was hiddensomewhere in the Discord server. I've seen lots of people trying random things in the#mee6
channel to get that flag while it saidsomewhere. So I've used the search function to search for some flags; nothing. I looked at every channel topic and pinned messages; nothing alarming. But when I went back on the#mee6
channel, I clicked on MEE6's profile; and there it was. MEE6 had a custom role named:shctf{4ut0b0ts_r013_0u7}
.

🛡️ Guardians of the Galaxy
We are given a netcat connection and the binary of the program (Download here). When testing the program locally it crashes, but why? Let's investigate by opening the file in a disassembler.

This is the source of the crash, and it's really easy to understand. Iffopen
returns0x0
, then the file doesn't exist, and therefore the binary crashes. So let's create a dummyflag.txt
file with the contentFLAG_____FLAG
. But before running the binary again, we can see that the data for the file is stored at the locationrbp-0x30
with a size of0x20
.

To confirm that, we can run the file with gdb and check the content:

The binary printsexactly what we send withprintf
according to this assembly code:

So let's use some string formats such as%x
or others. When using%p
we get a nice hexadecimal representation of the address returned. So let's print lots of them.

When looking at the data being given back, we can see some hexadecimal values of ASCII characters. Starting at0x6d697b6674636873
and ending at0x55f6d2000a7d
. So let's write a Python script to extract that data:
"""Useless data:0x7ffd7417b6f00x55f6d353b2a00x25702570257025700x25702570257025700x25702570257025700x70257025702570---------------Important data:0x6d697b66746368730x636172747369645f0x756f795f676e69740x55f6d2000a7d"""frombinasciiimportunhexlifyflag=b"".join([unhexlify("6d697b6674636873")[::-1],unhexlify("636172747369645f")[::-1],unhexlify("756f795f676e6974")[::-1],unhexlify("55f6d2000a7d")[::-1],])print(flag)
This gave back:b'shctf{im_distracting_you}\n\x00\xd2\xf6U'
, and there we have the flag,shctf{im_distracting_you}
.
🧑🚀 Space traveler
We were given a URL:https://spaceheroes-web-explore.chals.io
. When going on the website we could hit theGuess The Flag
button. We had to give a flag as input and it would say if it's valid or not. Looking at the network tab in the developers tool, not external requests were made. So the check is done locally. When looking at the source code there was some obfuscated source:
var_0xb645=["\x47\x75\x65\x73\x73\x20\x54\x68\x65\x20\x46\x6C\x61\x67","\x73\x68\x63\x74\x66\x7B\x66\x6C\x61\x67\x7D","\x59\x6F\x75\x20\x67\x75\x65\x73\x73\x65\x64\x20\x72\x69\x67\x68\x74\x2E","\x73\x68\x63\x74\x66\x7B\x65\x69\x67\x68\x74\x79\x5F\x73\x65\x76\x65\x6E\x5F\x74\x68\x6F\x75\x73\x61\x6E\x64\x5F\x6D\x69\x6C\x6C\x69\x6F\x6E\x5F\x73\x75\x6E\x73\x7D","\x59\x6F\x75\x20\x67\x75\x65\x73\x73\x65\x64\x20\x77\x72\x6F\x6E\x67\x2E","\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C","\x64\x65\x6D\x6F","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64"];functionmyFunction(){let_0xb729x2;let_0xb729x3=prompt(_0xb645[0],_0xb645[1]);switch(_0xb729x3){case_0xb645[3]:_0xb729x2=_0xb645[2];break;default:_0xb729x2=_0xb645[4]};document[_0xb645[7]](_0xb645[6])[_0xb645[5]]=_0xb729x2}
When looking at it, we can see it's obfuscated, so let'sdeobfuscate it!
functionmyFunction(){letazante;letkarynna=prompt("Guess The Flag","shctf{flag}");switch(karynna){case"shctf{eighty_seven_thousand_million_suns}":azante="You guessed right.";break;default:azante="You guessed wrong.";};document.getElementById("demo").innerHTML=azante;}
Well, that's much more readable and we can see the flag in plaintext:shctf{eighty_seven_thousand_million_suns}
.
🕵️♂️ Curious?
This challenge was pretty straight forward, it was an OSINT challenge. For this one is was basically"Who can search better on Google?". Well in my case, I usedTinEye since we were given a picture:
When searching for that picture, there were some websites that had this picture. Here is a list of them:http://www.dailytechinfo.org/tags/%C7%E0%E4%E5%F0%E6%EA%E0/ - Russian, nothing important for the challengehttps://dailytechinfo.org/space/5613-marsohod-curiosity-napolovinu-preodolel-voznikshee-pered-nim-prepyatstvie.html - Russian, nothing important for the challengehttp://news.discovery.com/space/the-moment-when-curiosity-breached-a-mars-dune-140205.htm - Offline
https://www.hjkc.de/_blog/2014/02/05/2391-mars-curiosity-chroniken---curiosity-news-sol-529-533/ - Could be interesting
https://www.space.com/24592-mars-rover-curiosity-dune-jump.html - Could be interesting
When looking at the last result, it clearly has as title"The Moment When Curiosity Breached a Mars Dune". Considering the flag format was given,shctf{SOL_xxx}
, we can see that this picture was taken at SOL 533. So pretty simple, right?shctf{SOL_533}
is the flag.
The other website, hjkc.de also contained the SOL 533 picture, you just have to scrolla lot.
🚀 Launched
Another OSINT challenge, this time we are given the picture of a rocket that just launched.

Considering the flag format wasshctf{rocket_payload}
, it's pretty easy to know we need to find the rocket and its payload name. It's also the first time I know payloads can have names 🤯
So let's getexiftool in my hands. When looking at the data we got back, we can see some interesting information:
ExifTool Version Number : 12.40File Name : launched.jpg...Date/Time Original : 2019:04:11 18:36:33Create Date : 2019:04:11 18:36:33...
One of them being the exact date and time when the picture was taken. So we can see that the rocket was launched at2019:04:11 18:36:33
. Just need to find the rocket name and its payload now.
A simple Google search showed that the rocket was aFalcon Heavy. Now we need the payload name; let's tryWikipedia. Yup, there we go:

So now let's put everything in the flag format,shctf{rocket_payload}
, and we getshctf{falcon_heavy_arabsat-6A}
.
🌌 Flag in space
A web challenge. We are greeted with a website that has a grid with empty content. We URL washttp://172.105.154.14/?flag=, so let's try to put some garbage in the GET parameter. When trying some characters you can see that some grids now contain the character that was correct, so if you put theflag
parameter toshctf{aaa
, you get the following:

Looking at the source code it's a basic<div>s</div>
for every character. We could try each character ourselves but some flags are known to have special characters or numbers so it would take ages. Therefore I made a simple script that appends every character, and if it gets the<div>
element, then it gets added in a variableres
. I've already put the known characters as an element in theres
variable.
Then we simply make a request with all the characters fromres
and append the currently looped character. Here is my source code, you might understand it better:
importrequestsflag=["","","","","","","","","","","","","","","","","","","}"]res=["s","h","c","t","f","{"]foriinrange(0,len(flag)):forjinrange(0x21,0x7d):char=chr(j)url="http://172.105.154.14/?flag="+"".join(res)+charr=requests.get(url)response="".join(r.text.split())previous=""forkinrange(0,len(res)):previous+="<div>"+res[k]+"</div>"iff"{previous}<div>{char}</div>"inresponse:res+=charprint("".join(res),end="\r")breakprint("".join(res))
After quite some time, the script gives the following flag back:shctf{2_explor3_fronti3r}
.
🤖 R2D2
Looking back at this one, it was pretty obvious... We are greeted on a website that looks like that:
Looking at the source code, nothing. Looking at the local storage, nothing. Looking at the cookies, nothing. I decided to rungobuster on the website with awordlist. Guess what kind of file was detected...robots.txt, of course......
Getting on that file gives the flag back,shctf{th1s-aster0id-1$-n0t-3ntir3ly-stable}
.
🌟 Starman
Another OSINT challenge. This time the description says already a lot:
How far away from earth was the space car on January, 20 2021 at 1515 UTC? Enter distance in terms of Million Km. (Rounded to two decimals) (e.g shctf{12.34})
Searching up on Google what thespace car is, I came acrossthis website. And at the right we can give a date and time, and we get anawesome map. When looking at the map we see that it was at56.68
million km away from earth. Therefore the flag was:shctf{56.68}
.
🐕 Space Buds
One of the puppies got into the web server. Can you help find out who it was?
With that description there also was a picture of the Space Buds.
There also was a website, that pretty much containednothing. But when inspecting the source code, there was a hidden input element.
So I searched up on the Internet what the names of the puppies were and put them one by one in the input field. But still nothing. However, when sending the form, there was a request made to/getcookie
. So maybe there's something in my cookies?
But we canchange the value of that cookie, so let's put the name of each dog in the cookie and reload the page. When typingMudbud, there was a flag given.
After literallydecrypting that flag, it results toshctf{tastes_like_raspberries}
.
🛰️ Cape Kennedy
This was a reversing challenge. We were given a Python file that contains a password check.
importsysdefmain():iflen(sys.argv)!=2:print("Invalid args")returnpassword=sys.argv[1]builder=0forcinpassword:builder+=ord(c)ifbuilder==713andlen(password)==8and(ord(password[2])==ord(password[5])):if(ord(password[3])==ord(password[4]))and((ord(password[6]))==ord(password[7])):print("correct")else:print("incorrect")else:print("incorrect")if__name__=="__main__":main()
This one was quite easy to reverse. The password must have a length of 8. The characters and index 2 and 5 must be the same, the characters at index 3 and 4 must be the same and the characters and index 6 and 7 must be the same. The sum of the hexadecimal value of the characters must be 713.
Let's make a bruteforce script:
importrandomfromstringimportascii_letterspwds=[]defsolve():whileTrue:s=["A"]*8s[0]=random.choice(ascii_letters)s[1]=random.choice(ascii_letters)s[2]=random.choice(ascii_letters)s[5]=s[2]s[3]=random.choice(ascii_letters)s[4]=s[3]s[6]=random.choice(ascii_letters)s[7]=s[6]builder=0password="".join(s)forcinpassword:builder+=ord(c)if(builder==713andlen(password)==8and(ord(password[2])==ord(password[5]))):if(ord(password[3])==ord(password[4]))and((ord(password[6]))==ord(password[7])):ifpasswordnotinpwds:pwds.append(password)withopen("moon.txt","a")asf:f.write(password+"\n")solve()
And yes, there wasA LOT of valid passwords, over 3 millions.
Considering it was space themed (It was mentioned in the description of the challenge again.), I searched what happened at Cape Kennedy and that was related to the moon, since the file was namedmoon.py
. It didn't took long until I've found that Apollo 11 started from there, a historic moment in space exploration! Looking at the results inmoon.txt
I've found a string generated that wasAPOllOaa
. So with the knowledge of before and that valid string, the flag is simplyshctf{Apollo11}
.
⭐ Star Pcap
There was no description, just a pcap file (Download here). When opening the file with Wireshark, we can see that there is just one slight change in all those ICMP packets, which is the ICMP code.
Usingpyshark
it was easy to put all these codes together, convert them to an decimal value and then to a character.
importpysharkcapture=pyshark.FileCapture("star.pcap")data=""forpacketincapture:data+=chr(int(packet.layers[2]._all_fields["icmp.code"]))print(data)
This resulted in the following string:c2hjdGZ7TDBnMWMtaSQtdGgzLWJlZ2lOTmluZy0wZi13aSRkb019
. Typical for CTFs, the data is base64 encoded. After decoding it, we can get the flag:shctf{L0g1c-i$-th3-begiNNing-0f-wi$doM}
.
👁️🗨️ Mysterious Broadcast
Another web challenge.
There used to be 8 Models of humanoid cylon but now there are only 7. We've located one of their broadcast nodes but we can't decode it. Are you able to decipher their technologies?
When going on the website, there is a random ID generated in the URL, it looks like this:http://173.230.134.127/seq/710a1f63-57b9-4b86-a880-f413418375d9
The website had nothing besides an~
as response, interesting. When reloading; it turned to a 1, when reloading again; it didn't changed. But when reloading for the third time, it turned to a 0. Here is how it looked like:

Binary! But I don't want to write everything down as it might be a lot of 0's and 1's in the end, so let's make a quick Python script and save the output in a variable:
importrequestsbinary=""whileTrue:r=requests.get("http://173.230.134.127/seq/710a1f63-57b9-4b86-a880-f413418375d9")if(r.text=="~"):breakbinary+=r.textprint(binary)print("\n[+] Received:"+binary)# 1100011011001011010001101010110010010001111011010011011110100011011000100111011010101100001101011111011001001010110001101100001000101011001110100011101101110110001100001010101011001110100101101000110001011011011010010110100011000111101101101001001110011000011110011101111010111101
Here we go, we got the binary and now we can just decode it.
ÆËF¬í7£bv¬5öJÆÂ+:;v0ªÎ[ihǶyÞ½
ehhh, I don't think that's correct 🤔 Let's look at the description again -There used to be *8* Models of humanoid cylon but now there are only *7*. [...]
. Remember, when representing a character, for exampleA, in binary there are8 1's or 0's such as01000001
. And according the the description, there are now only7. So let's put a space every 7th character and decode that.
Most of the decoders give the same output, as they don't take in consideration the space. Butthis one did take in consideration the space. It resulted inc2hjdGZ7QXNjaWlJc0E3Qml0U3RhbmRhcmR9Cg==
. Again, the==
is typical for base64 encoding. So let's decode it:shctf{AsciiIsA7BitStandard}
.
🐈 Space Captain Garfield
This one was more about OSINT at the beginning. We have the following picture:

There was just the number2254
notencrypted. So by searchinggarfield dreaming 2254
on Google I've found this picture:

So yes, what had to be done was to map each character to its sign and then reconstruct the flag in the last picture. I started and gotshctf{lasa..alo.er}
, after some guessing for the last ones it wasshctf{lasagnalover}
.
🚩 Netflix and CTF
This one was very similar to the Star Pcap challenge above. We are given a pcap file (Download here) and we have to analyze it. When looking at it, there is always request made tohttp://10.10.100.124:8060/keypress/Lit_X
whereX
always varies. Sometimes there is a request made to/browse
, this puts a line between the keypresses, and show names.
So let's make a Python script usingtshark again and save the output of each show in a list:
importpysharkimporturllib.parsecapture=pyshark.FileCapture("netflix-and-ctf.pcap")data=[]show_data=""forpacketincapture:try:if"browse"inpacket.layers[3]._all_fields["http.response_for.uri"]:data.append(show_data)show_data=""continueshow_data+=urllib.parse.unquote(packet.layers[3]._all_fields["http.response_for.uri"].replace("http://10.10.100.124:8060/keypress/Lit_",""))except:passforshowindata:if"shctf"inshow:print(f"Special show found:{show}")break
The special show found was:shctf{T1m3-is-th3-ultimat3-curr3Ncy}
.
🚦 Strange Traffic
My favorite forensics challenge. We were given again a pcap file (Download here). There also was a free hint, so let's take it:
Hint: alt,esc,1,2,3,4,5,6,7,8,9,0,-,=,backspace,tab,q,w,...
All right, now let's investigate the pcap file.
The number encircled in purple is the only number that changes and appears in all packets. So we need to get this value for each packet. For this example, the35
is formed thanks to the33
and35
which if decoded to in the ASCII table, they are3
and5
. Now with35
what can we do? Let's look at the hint again. It's clearly a keyboard layout. Now if we look at the query keyboard layout that was sent on Discord:
If we start counting each key and count up to35
, we get the keys
, which could fit for thes
in theshctf{...}
format. After checking with the other packets, this theory is right. Now let's code a script for that:
importpyshark,binasciicapture=pyshark.FileCapture("strangetraffic.pcap")# Map the entire keyboardmap={"1":"`","2":"1","3":"2","4":"3","5":"4","6":"5","7":"6","8":"7","9":"8","10":"9","11":"0","12":"-","13":"=","14":"<-","15":"tab","16":"q","17":"w","18":"e","19":"r","20":"t","21":"y","22":"u","23":"i","24":"o","25":"p","26":"[","27":"]","28":"enter","29":"caps","30":"a","31":"s","32":"d","33":"f","34":"g","35":"h","36":"j","37":"k","38":"l","39":";","40":"'","41":"#","42":"shift","43":"\\","44":"z","45":"x","46":"c","47":"v","48":"b","49":"n","50":"m","51":",","52":".","53":"/","54":"ctrl","55":"win","56":"alt","57":"space","58":"alt","59":"win","60":"menu","61":"ctrl",}flag=[]forpacketincapture:payload=packet.layers[2]._all_fields["udp.payload"][75:].split(":")# Ignore the fist 75 characters from the payloadforiinrange(0,len(payload)):payload[i]=str(binascii.unhexlify(payload[i]),"ascii")# Coinvert to ASCII representationflag.append("".join(payload))res=""forfinflag:res+=map[str(f)]print(res.replace("shift[","{").replace("shift]","}").replace("enter","").replace("space","_"))# Description said we can swap spaces with underscores
In the end we get the following flag:shctf{thanks_f0r_th3_t4nk._he_n3ver_get5_me_anyth1ng}
.
🔮 Future Stego
For this challenge there were two pictures, one to download which was:
There also was another picture in the description, as a hint:
After trying lots of steganography techniques, I couldn't find any that lead me to the flag. One of the last was to usestegcracker
. I tried to bruteforce the password with the rockyou wordlist, but stopped at around 300'000 words tried. Nothing.
But the picture wasn't here fornothing.. Let's try some passwords that are in the news paper picture and usesteghide --extract -sf shuttle.jpg
. After playing around and trying some combinations such asspacewoman
,newsweek
orsally k. ride
, I tried the file name:sallyride
. This was the password and extracted a text file which contained the flag:shctf{weightlessness_is_a_great_equalizer}
. It also would've worked withstegcracker
and the right password in a text file.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse