CyberSkiller Challenge Poland, Edition III, Stage 2, Day 3/3 Writeup

2023/06/25

This post is the final one in the series of writeups from the second stage of the competition CyberSkiller Challenge Poland III Edition.
Writeup for the day one: link

===== Task 11, 30 points =====

Task description translation:
Login to the server via SSH. The flag is located inside the encrypted network traffic, which you can intercept. The running webserver will help you achieve that.
[Provided: SSH credentials]

by this point I’m really tired of the tcpdump challs…

yet again, sudo -l and yet again, gtfobins for the win

===== Task 12, 20 points =====

Task description translation:
You have access to a webserver serving a simple HTTP page. Site is available under: [MACHINE IP].
The application is used to send e-mail messages and implements basic user data filtering mechanisms. A file with a random name is located inside the main WWW directory, containing the flag. Utilize the e-mail sending functionality in conjunction with an another vulnerability in order to read the answer.

Warning:  include(): open_basedir restriction in effect. File(/etc/passwd) is not within the allowed path(s): (/var/www/:/usr/share/php/Twig/:/tmp:/var/mail) in /var/www/html/index.php on line 40

Warning:  include(/etc/passwd): failed to open stream: Operation not permitted in /var/www/html/index.php on line 40

Warning:  include(): Failed opening '../../../../../../../etc/passwd' for inclusion (include_path='.:/usr/share/php') in /var/www/html/index.php on line 40

This is a yet another challenge, which I failed to solve within 45 minutes. Asking the competition organizers for the correct solution, here is the translated message I got back:

Task 12 was a “killer” type challenge :), in which you had to use the Local File Inclusion and Path Traversal vulnerabilities. Additionally, you needed to know how the mailserver is being handled locally, specifically how the email is being sent to localhost users.

===== Task 13, 30 points =====

Task description translation:
A HTTP client is running on the machine, which is sending the flag to https://localhost:8443/. Seems trivial? Too bad, the client is verifying SSL keys. Are you able to plant your own certificate into the system and read the answer?
Just to clarify, FQCN must be equal to localhost.
[Provided: SSH credentials]

FINALLY! An actual challenge! I have really enjoyed this one, because it was more than just following few steps that were hinted at or outright outlined in the description…

First of all, we need to somehow receive that packet. With the help of this cool blog, I have written a simple POST request handler, which also uses SSL:

from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl 
from io import BytesIO


class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'Hello, world!')

    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        self.send_response(200)
        self.end_headers()
        response = BytesIO()
        response.write(b'This is POST request. ')
        response.write(b'Received: ')
        print(body)
        response.write(body)
        self.wfile.write(response.getvalue())


httpd = HTTPServer(('localhost', 8443), SimpleHTTPRequestHandler)

httpd.socket = ssl.wrap_socket (httpd.socket, 
        keyfile="privatekey.pem", 
        certfile='certificate.pem', server_side=True)

httpd.serve_forever()

Now, we need to get our hands on the SSL certificate.
$ openssl req -newkey rsa:4096 -x509 -sha512 -days 365 -nodes -out certificate.pem -keyout privatekey.pem

With that, we need to complete three more steps:
1. Copy the certificate to /etc/ssl/certs
2. Append the certificate to /etc/ssl/certs/ca-certificates.crt
3. Run update-ca-certificates

Now, let’s launch our webserver and watch the flag pop up on our screen!

Incoming POST request with the coveted flag

===== Task 14, 10 points =====

return binary but every number is in new line and starting from the least significant

num = bin(int(input())).replace('0b''')

for i in range(len(num)):
    print(num[len(num)-(1+i)])

===== Task 15, 30 points =====

I don’t understand why was this task rated so highly. The goal was to connect to a port by 10000 higher number than default (outlined in challenge description, so you don’t even have to port scan) as an anonymous user and just get a file…

FTP anonymous login

===== Conclusion =====

Overall, this stage was enjoyable, although the challenges were mostly too simple in my opinion, and some of them weren’t clear enough. My favorite challenge by far was Task 13: it was clear what needs to be done from start to finish, research was required, and the process required multiple different actions to be taken, from putting together a server, to creating and adding an SSL certificate. Such challenges are more engaging than the “run this one command but different” ones by a landslide.

The finals writeup is coming up soon enough, stay tuned.