Base project
This commit is contained in:
		
						commit
						50faafb86a
					
				
							
								
								
									
										12
									
								
								Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Readme.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | # Basic client for Dropbox Business | ||||||
|  | This client has been written for pentesting and offensive purposes. With a Dropbox Enterprise API Token, it is possible to list all the users and download and edit every file and folder. The client also allows to list a user's session with all the details and also to get recent activity. A 'tree' functionality returns the full file and folder structure allowing for easy grepping. | ||||||
|  | 
 | ||||||
|  | ## Dependencies | ||||||
|  | 
 | ||||||
|  | `python3-deepmerge` | ||||||
|  | 
 | ||||||
|  | ## Configuration | ||||||
|  | Add the `token` in the client.py file. | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | ... | ||||||
							
								
								
									
										110
									
								
								client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								client.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | import dropbox | ||||||
|  | import sys | ||||||
|  | import json | ||||||
|  | from pprint import pprint | ||||||
|  | from hashlib import sha1 | ||||||
|  | import sqlite3 | ||||||
|  | 
 | ||||||
|  | # dropbox organization api key | ||||||
|  | token = "api key" | ||||||
|  | db = "{}.sqlite".format(sha1(token.encode("ascii")).hexdigest()) | ||||||
|  | 
 | ||||||
|  | client = dropbox.Dropbox(token) | ||||||
|  | 
 | ||||||
|  | conn = sqlite3.connect(db) | ||||||
|  | cur = conn.cursor() | ||||||
|  | 
 | ||||||
|  | def init_db(conn, token): | ||||||
|  | 	conn.execute('CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, team_member_id TEXT, email TEXT, external_id TEXT, name TEXT, groups TEXT)') | ||||||
|  | 	members = client.members_list() | ||||||
|  | 	for member in members["members"]: | ||||||
|  | 		if "external_id" not in member["profile"]: | ||||||
|  | 			member["profile"]["external_id"] = None | ||||||
|  | 		cur.execute("INSERT INTO users (id, team_member_id, email, external_id, name, groups) VALUES (?, ?, ?, ?, ?, ?)", (member["profile"]["account_id"], member["profile"]["team_member_id"], member["profile"]["email"], member["profile"]["external_id"], member["profile"]["name"]["display_name"], json.dumps(member["profile"]["groups"]))) | ||||||
|  | 	conn.commit() | ||||||
|  | 
 | ||||||
|  | def get_team_member_id(cur, email): | ||||||
|  | 	return cur.execute("SELECT team_member_id FROM users where email = ?", (email,)).fetchone() | ||||||
|  | 
 | ||||||
|  | def get_account_id(cur, email): | ||||||
|  | 	return cur.execute("SELECT id FROM users where email = ?", (email,)).fetchone() | ||||||
|  | 
 | ||||||
|  | def search_account(cur, query): | ||||||
|  | 	query =  "%{}%".format(query.replace(" ", "%")) | ||||||
|  | 	return cur.execute("SELECT email,name FROM users where email like ? or name like ? or external_id like ? or id like ? or team_member_id like ?", (query, query, query, query, query)).fetchall() | ||||||
|  | 
 | ||||||
|  | def get_ids(cur, email): | ||||||
|  | 	id = get_account_id(conn, user) | ||||||
|  | 	team_member_id = get_team_member_id(conn, user) | ||||||
|  | 	if len(id) > 0 and len(team_member_id) > 0: | ||||||
|  | 		id = id[0] | ||||||
|  | 		team_member_id = team_member_id[0] | ||||||
|  | 		return id, team_member_id | ||||||
|  | 	else: | ||||||
|  | 		return None, None | ||||||
|  | try: | ||||||
|  |         cur.execute("SELECT count(id) FROM users") | ||||||
|  | except: | ||||||
|  |         init_db(conn, token) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if len(sys.argv) > 1: | ||||||
|  | 	cmd = sys.argv[1] | ||||||
|  | 
 | ||||||
|  | if cmd == "search": | ||||||
|  | 	query = sys.argv[2] | ||||||
|  | 	results = search_account(conn, query) | ||||||
|  | 	if len(results) > 0: | ||||||
|  | 		for result in results: | ||||||
|  | 			print("{}\t\t{}".format(result[0], result[1])) | ||||||
|  | elif cmd == "info": | ||||||
|  | 	if len(sys.argv) == 2: | ||||||
|  | 		pprint(client.get_info()) | ||||||
|  | 	elif len(sys.argv) == 3: | ||||||
|  | 		user = user = sys.argv[2] | ||||||
|  | 		id, team_member_id = get_ids(cur, user) | ||||||
|  | 		pprint(client.get_current_account(team_member_id)) | ||||||
|  | 	else: | ||||||
|  | 		user = user = sys.argv[2] | ||||||
|  | 		id, team_member_id = get_ids(cur, user) | ||||||
|  | 		operation = sys.argv[3] | ||||||
|  | 		if operation == "activity": | ||||||
|  | 			activity = client.get_events(id) | ||||||
|  | 			for event in activity["events"]: | ||||||
|  | 				for assets in event["assets"]: | ||||||
|  | 					print(assets["path"]["contextual"]) | ||||||
|  | elif cmd == "file": | ||||||
|  | 	user = sys.argv[2] | ||||||
|  | 	operation = sys.argv[3] | ||||||
|  | 	path = sys.argv[4] | ||||||
|  | 	id, team_member_id = get_ids(cur, user) | ||||||
|  | 	if operation == "ls": | ||||||
|  | 		ls = client.list_folder(team_member_id, path, False) | ||||||
|  | 		for file in ls["entries"]: | ||||||
|  | 			print(file["path_display"]) | ||||||
|  | 	elif operation == "tree": | ||||||
|  | 		tree = client.list_folder(team_member_id, path, True) | ||||||
|  | 		for file in tree["entries"]: | ||||||
|  | 			print(file["path_display"]) | ||||||
|  | 	elif operation == "download": | ||||||
|  | 		file = client.download(team_member_id, path) | ||||||
|  | 		filename = path.split('/')[-1] | ||||||
|  | 		with open(filename, "wb") as f: | ||||||
|  | 			f.write(file) | ||||||
|  | 	elif operation == "info": | ||||||
|  | 		print(client.get_metadata(team_member_id, path)) | ||||||
|  | 
 | ||||||
|  | elif cmd == "activity": | ||||||
|  | 	# Returns the file activity of the last 10 days | ||||||
|  | 	# This call wants the dbid (Dropbox ID) instead of the dbmid (Dropbox Team Member ID) | ||||||
|  | 	user = sys.argv[2] | ||||||
|  | 	id, team_member_id = get_ids(cur, user) | ||||||
|  | 	activity = client.get_events(id) | ||||||
|  | 	pprint(activity) | ||||||
|  | 	for event in activity["events"]: | ||||||
|  | 		for assets in event["assets"]: | ||||||
|  | 			try: | ||||||
|  | 				print(assets["path"]["contextual"]) | ||||||
|  | 			except: | ||||||
|  | 				pass | ||||||
|  | 
 | ||||||
							
								
								
									
										73
									
								
								dropbox/__client__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								dropbox/__client__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | |||||||
|  | import requests | ||||||
|  | import logging | ||||||
|  | import json | ||||||
|  | from datetime import datetime, timedelta | ||||||
|  | from deepmerge import always_merger | ||||||
|  | from pprint import pprint | ||||||
|  | 
 | ||||||
|  | BASE = 'https://api.dropbox.com/2' | ||||||
|  | 
 | ||||||
|  | class Dropbox: | ||||||
|  | 	def __init__(self, token, proxy=None): | ||||||
|  | 		self.token = token | ||||||
|  | 		if proxy: | ||||||
|  | 			self.proxies = {'http': "socks5://{}".format(proxy)} | ||||||
|  | 		else: | ||||||
|  | 			self.proxies = {} | ||||||
|  | 		info = self.get_info() | ||||||
|  | 		if info: | ||||||
|  | 			self.name = info["name"] | ||||||
|  | 			self.team_id = info["team_id"] | ||||||
|  | 			self.num_users = info["num_provisioned_users"] | ||||||
|  | 		else: | ||||||
|  | 			logging.error("Wrong token") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	def call(self, endpoint, args=None, member=None, nested=False, cursor=True, base=BASE, params=None): | ||||||
|  | 		if params: | ||||||
|  | 			params =  {"arg": json.dumps(params)} | ||||||
|  | 		r = requests.post('{}/{}'.format(base, endpoint), headers={"Authorization": "Bearer {}".format(self.token), "Dropbox-API-Select-User": member}, json=args, proxies=self.proxies, params=params) | ||||||
|  | 		if r.status_code == 200: | ||||||
|  | 			if 'json' not in r.headers['content-type']: | ||||||
|  | 				return r.content | ||||||
|  | 			data = r.json() | ||||||
|  | 			result = data | ||||||
|  | 			while nested == False and "has_more" in data and data["has_more"] == True and cursor == True: | ||||||
|  | 				args = {"cursor": data["cursor"]} | ||||||
|  | 				data = self.call("{}/continue".format(endpoint), args, member, True) | ||||||
|  | 				result = always_merger.merge(result, data) | ||||||
|  | 			return result | ||||||
|  | 		else: | ||||||
|  | 			logging.debug(r.text) | ||||||
|  | 			print(r.text) | ||||||
|  | 			return False | ||||||
|  | 
 | ||||||
|  | 	def get_info(self): | ||||||
|  | 		return self.call("team/get_info") | ||||||
|  | 
 | ||||||
|  | 	def members_list(self): | ||||||
|  | 		return self.call("team/members/list") | ||||||
|  | 
 | ||||||
|  | 	def list_member_devices(self, team_member_id): | ||||||
|  | 		return self.call("team/devices/list_member_devices", {"team_member_id": team_member_id, "include_web_sessions": True, "include_desktop_clients": True, "include_mobile_clients": True}) | ||||||
|  | 
 | ||||||
|  | 	def get_current_account(self, team_member_id): | ||||||
|  | 		return self.call("users/get_current_account", None, team_member_id) | ||||||
|  | 
 | ||||||
|  | 	def list_folder(self, team_member_id, path, recursive=False): | ||||||
|  | 		return self.call("files/list_folder", {"path": path, "recursive": recursive}, team_member_id) | ||||||
|  | 
 | ||||||
|  | 	def list_namespaces(self): | ||||||
|  | 		return self.call("team/namespaces/list") | ||||||
|  | 
 | ||||||
|  | 	def get_events(self, team_member_id): | ||||||
|  | 		end = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") | ||||||
|  | 		start = (datetime.now() - timedelta(days=10)).strftime("%Y-%m-%dT%H:%M:%SZ") | ||||||
|  | 		return self.call("team_log/get_events", {"limit": 100, "account_id": team_member_id, "time": {"start_time": start, "end_time": end}}) | ||||||
|  | 
 | ||||||
|  | 	def download(self, team_member_id, path): | ||||||
|  | 		return self.call("files/download", params={"path": path}, member=team_member_id, base="https://content.dropboxapi.com/2") | ||||||
|  | 
 | ||||||
|  | 	def get_metadata(self, team_member_id, path): | ||||||
|  | 		return self.call("files/get_metadata", {"path": path}, member=team_member_id) | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user