CTFZONE Quals 2024 | Youtube Unlock & Youtube Unlock Revenge (GGC Exploit)

Difficulty : Easy to Medium

I solved these two tasks but I don't understand them very much, sorry if there are any inconsistencies.

Youtube Unlock :

Let's start by reading the code to understand the task.

/app/nginx/nginx.conf :

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;
    
    keepalive_timeout  65;
    
    server {
        listen       80;

        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen       4431 ssl;
        ssl_certificate /cert.pem;
        ssl_certificate_key /cert.key;

        location / {
            return 301 https://blocked.org.uk:443;
        }
    }

    server {
        listen       4432 ssl;
        ssl_certificate /cert.pem;
        ssl_certificate_key /cert.key;

        location / {
            return 301 https://www.youtube.com/watch?v=WIRK_pGdIdA;
        }
    }
}

stream {
    map $ssl_preread_server_name $proxy {
        youtube.com              backend;
        www.youtube.com          backend;
        default                  backend_default;
    }

    upstream backend_default {
        server 127.0.0.1:4431;
    }

    upstream backend {
        server 127.0.0.1:4432;
    }

    server {
        listen 4430;
        ssl_preread on;
        proxy_pass  $proxy;
    }
}

/app/dpi/dpi.py :

import socket
import select
import os 

def server_connection(dst_ip, dst_port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((dst_ip, dst_port))
    return sock

BUFFER_SIZE = 140

dst_ip = 'nginx'
dst_port = 4430
srv_port = 443
sockets = []

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

srv.bind(("0.0.0.0", srv_port))
srv.listen(3)

print(f'listening connection on port {srv_port}')

sockets.append(srv)

while True:
    socks,_,_=select.select(sockets,[],[])
    
    for sock in socks:
        
        try:
            
            if sock==srv:
                print ("sock : " +str(sock))
                print ("srv : " + str(srv))
                buf ="empty"
                client,_=srv.accept()
                print(f"new connection")
                sockets.append(client)
                server=server_connection(dst_ip, dst_port)
                sockets.append(server)
                buff=sock.recv(BUFFER_SIZE)
                print("buffer : "+str(buff))
            else:
                buf=sock.recv(BUFFER_SIZE)
                if b'youtube' in buf:
                    print('BAN!!!')
                    os.system("echo BAN > ban.txt;")
                    continue
                id=sockets.index(sock)
                if id%2==1: 
                    if len(buf) == 0:
                        sockets[id].close()
                        sockets[id+1].close()
                        del sockets[id]
                        del sockets[id]
                    else:
                        sockets[id+1].sendall(buf)
                else: 
                    if len(buf) == 0:
                        sockets[id-1].close()
                        sockets[id].close()
                        del sockets[id-1]
                        del sockets[id-1]
                    else:
                        sockets[id-1].sendall(buf)
                        print("success")
        except Exception as e:
            print(e)

The nginx server hosts 2 servers each one under a service name, accessing the server normally will result to a redirect blocked.org.uk, what is needed is to use the Service name youtube.com to access the youtube video that will probably contain the flag.

So now checking the python code, we see that it acts as a proxy to our nginx server, it will block every request containing the string "youtube", but since it's case sensitive we can just bypass it by using "Youtube.com" instad of "youtube.com".

So now how do we do this ?

First we intercepted a request to the server and put in repeater.

Then you got edit target and change the check override SNI and enter Youtube.com

After it we follow the redirection and get to a youtube video

This video will contain the flag.

Pretty easy stuff

Youtube unlock | Revenge :

The second challenge is almost the same thing but with a little change to the files.

/app/nginx/nginx.conf :

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;
    
    keepalive_timeout  65;
    
    server {
        listen       80;

        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen       4431 ssl;
        ssl_certificate /cert.pem;
        ssl_certificate_key /cert.key;

        location / {
            return 301 https://blocked.org.uk:443;
        }
    }

    server {
        listen       4432 ssl;
        ssl_certificate /cert.pem;
        ssl_certificate_key /cert.key;

        location / {
            return 301 https://www.youtube.com/watch?v=WIRK_pGdIdA;
        }
    }
}

stream {
    map $ssl_preread_server_name $proxy {
        youtube.com              backend;
        www.youtube.com          backend;
        default                  backend_default;
    }

    upstream backend_default {
        server 127.0.0.1:4431;
    }

    upstream backend {
        server 127.0.0.1:4432;
    }

    server {
        listen 4430;
        ssl_preread on;
        proxy_pass  $proxy;
    }
}

/app/dpi/dpi.py :

import socket
import select

def server_connection(dst_ip, dst_port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((dst_ip, dst_port))
    return sock

BUFFER_SIZE = 140

dst_ip = 'nginx'
dst_port = 4430
srv_port = 443
sockets = []

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

srv.bind(("0.0.0.0", srv_port))
srv.listen(3)

print(f'listening connection on port {srv_port}')

sockets.append(srv)

while True:
    socks,_,_=select.select(sockets,[],[])

    for sock in socks:
        try:
            if sock==srv:
                client,_=srv.accept()
                print(f"new connection")
                sockets.append(client)
                server=server_connection(dst_ip, dst_port)
                sockets.append(server)
            else:
                buf=sock.recv(BUFFER_SIZE)
                if b'youtube' in buf.lower():
                    print('BAN!!!')
                    continue
                id=sockets.index(sock)
                if id%2==1: 
                    if len(buf) == 0:
                        sockets[id].close()
                        sockets[id+1].close()
                        del sockets[id]
                        del sockets[id]
                    else:
                        sockets[id+1].sendall(buf)
                else: 
                    if len(buf) == 0:
                        sockets[id-1].close()
                        sockets[id].close()
                        del sockets[id-1]
                        del sockets[id-1]
                    else:
                        sockets[id-1].sendall(buf)
        except Exception as e:
            print(e)

The key difference is now file upload is allowed on the server and secondly the server will require a pair socket id. To ensure we get two sockets in our request, we can upload a blank file so it would queue the file transfer in the socket queue.

so again with the same.

and for our request.

we get the flag appended to the youtube link.

I didn't understand this challenge very well, it tried this and worked, what I wrote here is me trying to understand why it works, so sorry if I'm wrong in some points.

Last updated