Browse Source

Base project

Giulio 3 years ago
commit
50faafb86a
3 changed files with 195 additions and 0 deletions
  1. 12 0
      Readme.md
  2. 110 0
      client.py
  3. 73 0
      dropbox/__client__.py

+ 12 - 0
Readme.md

@@ -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 - 0
client.py

@@ -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 - 0
dropbox/__client__.py

@@ -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)
+