Git Product home page Git Product logo

roadtools's Introduction

ROADtools

(Rogue Office 365 and Azure (active) Directory tools)

Python 3 only License: MIT

ROADtools logo

ROADtools is a framework to interact with Azure AD. It consists of a library (roadlib) with common components, the ROADrecon Azure AD exploration tool and the ROADtools Token eXchange (roadtx) tool.

ROADlib

PyPI version

ROADlib is a library that can be used to authenticate with Azure AD or to build tools that integrate with a database containing ROADrecon data. The database model in ROADlib is automatically generated based on the metadata definition of the Azure AD internal API. ROADlib lives in the ROADtools namespace, so to import it in your scripts use from roadtools.roadlib import X

ROADrecon

PyPI version Build Status

ROADrecon is a tool for exploring information in Azure AD from both a Red Team and Blue Team perspective. In short, this is what it does:

  • Uses an automatically generated metadata model to create an SQLAlchemy backed database on disk.
  • Use asynchronous HTTP calls in Python to dump all available information in the Azure AD graph to this database.
  • Provide plugins to query this database and output it to a useful format.
  • Provide an extensive interface built in Angular that queries the offline database directly for its analysis.

ROADrecon uses async Python features and is only compatible with Python 3.7 and newer (development is done with Python 3.8, tests are run with versions up to Python 3.11).

Installation

There are multiple ways to install ROADrecon:

Using a published version on PyPi
Stable versions can be installed with pip install roadrecon. This will automatically add the roadrecon command to your PATH.

Using a version from GitHub
Every commit to master is automatically built into a release version with Azure Pipelines. This ensures that you can install the latest version of the GUI without having to install npm and all it's dependencies. You can download the roadlib and roadrecon build files from the Azure Pipelines artifacts (click on the button "1 Published". The build output files are stored in ROADtools.zip. You can either install the .whl or .tar.gz files directly using pip or unzip both and install the folders in the correct order (roadlib first):

pip install roadlib/
pip install roadrecon/

You can also install them in development mode with pip install -e roadlib/.

Developing the front-end
If you want to make changes to the Angular front-end, you will need to have node and npm installed. Then install the components from git:

git clone https://github.com/dirkjanm/roadtools.git
pip install -e roadlib/
pip install -e roadrecon/
cd roadrecon/frontend/
npm install

You can run the Angular frontend with npm start or ng serve using the Angular CLI from the roadrecon/frontend/ directory. To build the JavaScript files into ROADrecon's dist_gui directory, run npm build.

Using ROADrecon

See this Wiki page on how to get started.

ROADtools Token eXchange (roadtx)

PyPI version Build Status

roadtx is a tool for exchanging and using different types of Azure AD issued tokens. It supports many different authentication flows, device registration and PRT related operations. For an overview of the tool, see the roadtx Wiki.

Installation

There are multiple ways to install roadtx. Note that roadtx requires Python 3.7 or newer.

Using a published version on PyPi
Stable versions can be installed with pip install roadtx. This will automatically add the roadtx command to your PATH.

Using a version from GitHub You can clone this repository and install roadlib and then roadtx to make sure you have the latest versions of both the tool and the library:

pip install roadlib/
pip install roadtx/

You can also install them in development mode with pip install -e roadtx/.

Using roadtx

See the Wiki on how to use roadtx.

roadtools's People

Contributors

anthirian avatar bakkerjan avatar cnotin avatar damiengermonville avatar dirkjanm avatar dozernz avatar emil-muller avatar hugo-syn avatar kiwids0220 avatar mwgielen avatar notmedic avatar p0dalirius avatar palciny avatar paradoxis avatar pwnfoo avatar rcobb-scwx avatar rikvanduijn avatar six2dez avatar taufderl avatar twistedsim avatar vikerup avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

roadtools's Issues

Error while gathering data

Hello, I attempted to use your tool in an engagement about a week ago and ran into an issue while attempting to gather data. The authentication process worked without issue and generated the token/key file correctly. I don't have access to the environment anymore but do have a couple of snippets that may be helpful:

Traceback (most recent call last): File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 1175, in _execute_context context = constructor(dialect, self, conn, *args) File "/usr/lib/python3/dist-packages/sqlalchemy/engine/default.py", line 808, in _init_compiled param.append(processors[key](compiled_params[key])) File "/usr/lib/python3/dist-packages/sqlalchemy/sql/sqltypes.py", line 913, in process return DBAPIBinary(value) TypeError: memoryview: a bytes-like object is required, not 'str'

Maybe more helpful:

sqlalchemy.exc.StatementError: (builtins.TypeError) memoryview: a bytes-like object is required, not 'str' [SQL: INSERT INTO "TenantDetails" ("objectType", "objectId", "deletionTimestamp", "assignedPlans", "authorizedServiceInstance", city, "cloudRtcUserPolicies", "companyLastDirSyncTime", "companyTags", "compassEnabled", country, "countryLetterCode", "dirSyncEnabled", "displayName", "isMultipleDataLocationsForServicesEnabled", "marketingNotificationEmails", "postalCode", "preferredLanguage", "privacyProfile", "provisionedPlans", "provisioningErrors", "releaseTrack", "replicationScope", "securityComplianceNotificationMails", "securityComplianceNotificationPhones", "selfServePasswordResetPolicy", state, street, "technicalNotificationMails", "telephoneNumber", "tenantType", "verifiedDomains", "windowsCredentialsEncryptionCertificate") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)] [parameters: [{'odata.type': 'Microsoft.DirectoryServices.TenantDetail', 'objectType': 'Company', 'objectId': 'bbab6148-da32-4d6a-a330-5231314f3e75', 'deletionTime ... (13234 characters truncated) ... EXr65uJ+WtPvpp8VvFs1OEXzKu7SEeIkhtUR2Bo9dTL+7KMKhd5JdXiVlGNX/3b3jAmz6c4PG4jhoKoK/q0Thlpx7gmOvHYfqnD6iEgH356bqSUCvAk0aRn5RRnj2IOOfsNDE8stHIuUz/P6uyg'}]]

error during "gather"

all works fine until I get this error in phase 2:

Starting data gathering phase 1 of 2 (collecting objects)
Starting data gathering phase 2 of 2 (collecting properties and relationships)
[Errno 60] Operation timed out

Refreshed token
[Errno 54] Connection reset by peer ---> about 10 times

Cannot connect to host graph.windows.net:443 ssl:default [nodename nor servname provided, or not known]
Cannot connect to host graph.windows.net:443 ssl:default [Too many open files] ---> 100s of times
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1256, in _execute_context
self.dialect.do_executemany(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 605, in do_executemany
cursor.executemany(statement, parameters)
sqlite3.OperationalError: unable to open database file

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/usr/local/bin/roadrecon", line 8, in
sys.exit(main())
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/main.py", line 118, in main
gathermain(args)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/gather.py", line 422, in main
asyncio.run(run(args, dburl))
File "/usr/local/Cellar/[email protected]/3.9.1_4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/Cellar/[email protected]/3.9.1_4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/gather.py", line 371, in run
await asyncio.gather(*tasks)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/gather.py", line 197, in dump_mfa
self.session.commit()
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1046, in commit
self.transaction.commit()
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 504, in commit
self._prepare_impl()
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 483, in _prepare_impl
self.session.flush()
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 2540, in flush
self._flush(objects)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 2682, in flush
transaction.rollback(capture_exception=True)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 68, in exit
compat.raise
(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 182, in raise

raise exception
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 2642, in _flush
flush_context.execute()
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 422, in execute
rec.execute(self)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 540, in execute
self.dependency_processor.process_saves(uow, states)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/dependency.py", line 1176, in process_saves
self._run_crud(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/orm/dependency.py", line 1239, in _run_crud
connection.execute(statement, secondary_insert)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1011, in execute
return meth(self, multiparams, params)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/sql/elements.py", line 298, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1124, in _execute_clauseelement
ret = self._execute_context(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1316, in _execute_context
self.handle_dbapi_exception(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1510, in handle_dbapi_exception
util.raise
(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 182, in raise

raise exception
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1256, in _execute_context
self.dialect.do_executemany(
File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 605, in do_executemany
cursor.executemany(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
[SQL: INSERT INTO lnk_group_member_user ("Group", "User") VALUES (?, ?)]
[parameters: (('27218c8d-3980-41ae-a41d-b31559898e92', 'd1f1bdb0-2241-4d63-a880-d24a5ea8b8f5'), ('27218c8d-3980-41ae-a41d-b31559898e92', 'ea3c8cfc-5bfd-4d99-b359-72c187cdcc8a'), ('27218c8d-3980-41ae-a41d-b31559898e92', 'de8c5914-7fd7-4670-8eab-9bb58d8a17cb'), ('27218c8d-3980-41ae-a41d-b31559898e92', '1a42fa2e-5793-4ec7-84d9-02b73a750c01'), ('27218c8d-3980-41ae-a41d-b31559898e92', '408d1b0b-e012-4caf-b825-02912315eb95'), ('27218c8d-3980-41ae-a41d-b31559898e92', '5b655b0f-2d44-4075-a170-e313e07f40cd'), ('27218c8d-3980-41ae-a41d-b31559898e92', 'e9064cb0-63d0-4336-b261-680b4d08c760'), ('27218c8d-3980-41ae-a41d-b31559898e92', '0b3df032-bdea-4af5-ab46-a03f6107b07a') ... displaying 10 of 300 total bound parameter sets ... ('27218c8d-3980-41ae-a41d-b31559898e92', 'eaa0e2b9-05f7-45f9-8939-ae525f523150'), ('27218c8d-3980-41ae-a41d-b31559898e92', '8dddc835-087c-49be-a269-237bdcc04e7e'))]
(Background on this error at: http://sqlalche.me/e/13/e3q8)

Error for plugin policies

When running "roadrecon plugin policies", I get:
Traceback (most recent call last):
File "/usr/local/bin/roadrecon", line 8, in
sys.exit(main())
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/main.py", line 124, in main
plugin_module.main(args)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/plugins/policies.py", line 409, in main
plugin.main(args.print)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/plugins/policies.py", line 352, in main
out['who'] = self._parse_who(conditions)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/plugins/policies.py", line 273, in _parse_who
ot += self._parse_ucrit(icrit)
File "/usr/local/lib/python3.9/site-packages/roadtools/roadrecon/plugins/policies.py", line 184, in _parse_ucrit
raise Exception('Unmatched object(s): {0}'.format(','.join(clist)))
Exception: Unmatched object(s): 8c0c485c-ce78-49b2-b938-481e7b370dc9

Feature request: Add "--no-workers" option

I just came along an Azure AD where the 3-phase approach ran into a deadlock situation.

My workaround was to increase the MAX_GROUP value within the gather.py to be greater than the current group number in the tenant.

Can you add a simple --no-workers option to the gather phase/function to allow an override ?

Empty strongAuthenticationDetail - How to get MFA status of each user

Hello,

All my AAD users have this following configuration in my roadrecon database:

strongAuthenticationDetail => {'encryptedPinHash': None, 'encryptedPinHashHistory': None, 'methods': [], 'oathTokenMetadata': [], 'requirements': [], 'phoneAppDetails': [], 'proofupTime': None, 'verificationDetail': None}

If I have well understood, the strongAuthenticationDetail key should give information about the MFA status for a user.

Why all my users have an "empty" strongAuthenticationDetail while some of them have MFA enable? Is it a privilege problem of the AAD user which has been used for running Roadrecon ? This user was the "Gloabl reader" role.

How I can get the MFA status of each AAD user through Roadtools ?

Thank you in advance,

404 error when using Gather

I continually have this 404 error when running the gather module. This results in broken data displaying in bloodhound as well as the GUI. Nothing actually displays in either although you can tell data was imported. Any ideas?

Macbook-Pro:ldap user$ roadrecon gather
Starting data gathering phase 1 of 2 (collecting objects)
Gathered 1440 groups, switching to 3-phase approach for efficiency
Starting data gathering phase 2 of 3 (collecting properties and relationships)
Error 404 for URL https://graph.windows.net/e40ghd9b-e1f4-4b3c-8532-e09c64944488/roleAssignments?api-version=1.61-internal&$filter=roleDefinitionId eq 'a0b1b346-2i3k-4e8b-98f8-7539k20e4970'
{"odata.error":{"code":"Request_ResourceNotFound","message":{"lang":"en","value":"Resource 'a0b1b346-2i3k-4e8b-98f8-7539k20e4970' does not exist or one of its queried reference-property objects are not present."},"requestId":"17e7ede0-2222-4102-8ddd-3k8df013d2fe","date":"2021-06-02T00:47:42"}}
Starting data gathering phase 3 of 3 (collecting group memberships and device owners)
Refreshed token
ROADrecon gather executed in 493.92 seconds and issued 5185 HTTP requests.

sqlalchemy.exc.StatementError: (builtins.ValueError) time data '2019-02-10T19:39:13.' does not match format '%Y-%m-%dT%H:%M:%S.%f'

Hello could you please help to resolve next issue with SQLAlchemy parsing ?

PS C:\Tools\roadtools> roadrecon gather  --skip-first-phase
Refreshed token
Starting data gathering phase 2 of 2 (collecting properties and relationships)
Traceback (most recent call last):
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 1702, in _execute_context
    context = constructor(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\default.py", line 1070, in _init_compiled
    param = [
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\default.py", line 1071, in <listcomp>
    processors[key](compiled_params[key])
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\sql\type_api.py", line 1631, in process
    return impl_processor(process_param(value, dialect))
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadlib-0.12.1-py3.10.egg\roadtools\roadlib\metadef\database.py", line 32, in process_bind_param
    value = datetime.datetime.strptime(value[:-2], '%Y-%m-%dT%H:%M:%S.%f')
  File "C:\Python310\lib\_strptime.py", line 568, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "C:\Python310\lib\_strptime.py", line 349, in _strptime
    raise ValueError("time data %r does not match format %r" %
ValueError: time data '2019-02-10T19:39:13.' does not match format '%Y-%m-%dT%H:%M:%S.%f'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\Scripts\roadrecon-script.py", line 33, in <module>
    sys.exit(load_entry_point('roadrecon==0.11.0', 'console_scripts', 'roadrecon')())
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\main.py", line 119, in main
    gathermain(args)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\gather.py", line 613, in main
    loop.run_until_complete(run(args))
  File "C:\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
    return future.result()
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\gather.py", line 537, in run
    await asyncio.gather(*tasks)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\gather.py", line 366, in dump_linked_objects
    await asyncio.gather(*jobs)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\gather.py", line 342, in dump_lo_to_db
    commit(self.session, linkobjecttype, cache, ignore=ignore_duplicates)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadtools\roadrecon\gather.py", line 157, in commit
    engine.execute(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\orm\session.py", line 1692, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 1614, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\sql\elements.py", line 325, in _execute_on_connection
    return connection._execute_clauseelement(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 1481, in _execute_clauseelement
    ret = self._execute_context(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 1708, in _execute_context
    self._handle_dbapi_exception(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 2026, in _handle_dbapi_exception
    util.raise_(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\util\compat.py", line 207, in raise_
    raise exception
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\base.py", line 1702, in _execute_context
    context = constructor(
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\default.py", line 1070, in _init_compiled
    param = [
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\engine\default.py", line 1071, in <listcomp>
    processors[key](compiled_params[key])
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\sqlalchemy\sql\type_api.py", line 1631, in process
    return impl_processor(process_param(value, dialect))
  File "C:\Users\<USERNAME>\.virtualenvs\roadtools-y8aBU9zU\lib\site-packages\roadlib-0.12.1-py3.10.egg\roadtools\roadlib\metadef\database.py", line 32, in process_bind_param
    value = datetime.datetime.strptime(value[:-2], '%Y-%m-%dT%H:%M:%S.%f')
  File "C:\Python310\lib\_strptime.py", line 568, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "C:\Python310\lib\_strptime.py", line 349, in _strptime
    raise ValueError("time data %r does not match format %r" %
sqlalchemy.exc.StatementError: (builtins.ValueError) time data '2019-02-10T19:39:13.' does not match format '%Y-%m-%dT%H:%M:%S.%f'
[SQL: INSERT OR IGNORE INTO "AppRoleAssignments" ("objectType", "objectId", "deletionTimestamp", "creationTimestamp", id, "principalDisplayName", "principalId", "principalType", "resourceDisplayName", "resourceId") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]
[parameters: [{'odata.type': 'Microsoft.DirectoryServices.AppRoleAssignment', 'objectType': 'AppRoleAssignment', 'objectId': '4g5ctr3V5U-UAdIujNqadHYdjdYKivtGiH7oF ... (506378 characters truncated) ... ccf-f20d-4c28-9f17-9448ea3b4648', 'principalType': 'User', 'resourceDisplayName': 'Salesforce', 'resourceId': 'cd4964a1-1b35-46c9-a678-0ba47f1d1921'}]]
PS C:\Tools\roadtools>

Thank you in advance!

RoadRecon breaks due to SQLAlchemy dependency

A recent change in SQLAlchemy appears to have broken roadrecon. When running the tool with no dependencies, the following stack trace is printed:

$ roadrecon
Traceback (most recent call last):
  File "/home/kali/.local/bin/roadrecon", line 5, in <module>
    from roadtools.roadrecon.main import main
  File "/home/kali/.local/pipx/venvs/roadrecon/lib/python3.8/site-packages/roadtools/roadrecon/main.py", line 6, in <module>
    from roadtools.roadrecon.gather import getargs as getgatherargs
  File "/home/kali/.local/pipx/venvs/roadrecon/lib/python3.8/site-packages/roadtools/roadrecon/gather.py", line 14, in <module>
    from roadtools.roadlib.metadef.database import User, ServicePrincipal, Application, Group, Device, DirectoryRole, RoleAssignment,  ExtensionProperty, Contact, OAuth2PermissionGrant, Policy, RoleDefinition, AppRoleAssignment, TenantDetail
  File "/home/kali/.local/pipx/venvs/roadrecon/lib/python3.8/site-packages/roadtools/roadlib/metadef/database.py", line 5, in <module>
    from sqlalchemy import Column, Text, Boolean, BigInteger as Integer, Binary, create_engine, Table, ForeignKey
ImportError: cannot import name 'Binary' from 'sqlalchemy' (/home/kali/.local/pipx/venvs/roadrecon/lib/python3.8/site-packages/sqlalchemy/__init__.py)

The package was installed like so:

$ pipx install roadrecon

The issue is present on both Python 3.8, as well as Python 3.10. I also attempted to downgrade SQLAchemy to 1.4.40, 1.4.35 and 1.3.24 which did not work.

Bloodhound plugin: Connection reset by peer

Hi Dirk-jan

Thank you for the amazing work!!

Quick question regarding the bloodhound plugin: I get the following error while running the bloodhound plugin when I load a massive amount of data:

ConnectionResetError: [Errno 104] Connection reset by peer
self.Error("Failed to write to defunct connection "nebolt.exceptions.ServiceUnavailable: Failed to write to defunct connection Address....)

debug.log:
Bolt connection will be closed because the client did not consume outgoing buffers for 00:15:00.000 which is not expected

The line that leads to that is 191:

for memberuser in group.memberUsers:
   add_edge(neosession,memberuser.objectId, 'AzureUser', group.objectId, 'AzureGroup', 'MemberOf')

Tried to change the timeout on neo4j side but still running into the same issue. Just wanted to ask if you known this problem already. Otherwise I will let you known when I find a solution.

Thanks

M

[bug] OverflowError: mktime argument out of range

Hi!

When working on a huge database (2,5GB+, the same one mentioned in the previous issue) I've stumbled upon the following exception:

127.0.0.1 - - [17/Jan/2022 02:17:57] "GET /api/oauth2permissions HTTP/1.1" 500 -
Traceback (most recent call last):
  File "C:\Python310\Lib\site-packages\flask\app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Python310\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Python310\Lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\Python310\Lib\site-packages\flask\app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Python310\Lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Python310\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Python310\Lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Python310\Lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\Python310\Lib\site-packages\flask\app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Python310\Lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Python310\Lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Python310\Lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Python310\Lib\site-packages\roadtools\roadrecon\server.py", line 337, in get_oauth2permissions
    return jsonify(oauth2permissions)
  File "C:\Python310\Lib\site-packages\flask\json\__init__.py", line 370, in jsonify
    dumps(data, indent=indent, separators=separators) + "\n",
  File "C:\Python310\Lib\site-packages\flask\json\__init__.py", line 211, in dumps
    rv = _json.dumps(obj, **kwargs)
  File "C:\Python310\Lib\json\__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "C:\Python310\Lib\json\encoder.py", line 201, in encode
    chunks = list(chunks)
  File "C:\Python310\Lib\json\encoder.py", line 429, in _iterencode
    yield from _iterencode_list(o, _current_indent_level)
  File "C:\Python310\Lib\json\encoder.py", line 325, in _iterencode_list
    yield from chunks
  File "C:\Python310\Lib\json\encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "C:\Python310\Lib\json\encoder.py", line 438, in _iterencode
    o = _default(o)
  File "C:\Python310\Lib\site-packages\flask\json\__init__.py", line 91, in default
    return http_date(o.utctimetuple())
  File "C:\Python310\Lib\site-packages\werkzeug\http.py", line 995, in http_date
    timestamp = mktime(timestamp)
OverflowError: mktime argument out of range

My initial guess is that there might be some discrepancies between various timestamp formats (when collected from a huge Azure deployment). The question is, can we do anything about the pulled data's model consistency?

Or maybe the error is just simply result of overly-enormous data collection fed to the JSON serializer? Causing enormous RAM consumption and crashing serializer in a process? Have no idea...

Regards,
Mariusz.

Error when running gather?

After i auth and run the gather command, I get this error.

Starting data gathering phase 1 of 2 (collecting objects)
Traceback (most recent call last):
  File "/home/user/.local/bin/roadrecon", line 10, in <module>
    sys.exit(main())
  File "/home/user/.local/lib/python3.7/site-packages/roadtools/roadrecon/main.py", line 119, in main
    gathermain(args)
  File "/home/user/.local/lib/python3.7/site-packages/roadtools/roadrecon/gather.py", line 613, in main
    loop.run_until_complete(run(args))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/user/.local/lib/python3.7/site-packages/roadtools/roadrecon/gather.py", line 469, in run
    await asyncio.gather(*tasks)
  File "/home/user/.local/lib/python3.7/site-packages/roadtools/roadrecon/gather.py", line 213, in dump_object
    commit(self.engine, dbtype, cache)
  File "/home/user/.local/lib/python3.7/site-packages/roadtools/roadrecon/gather.py", line 157, in commit
    engine.execute(
AttributeError: 'Engine' object has no attribute 'execute

I have tried latest version from github and version in pip

from sqlalchemy import Binary issue (on Windows)

Should Binary be BINARY on line 5 of the following file?
roadlib/roadtools/roadlib/metadef/database.py

Tested on Python3.9.1 x64 on Win10 2004 with the Visual Studio tools installed and after compiling via
git clone https://github.com/dirkjanm/ROADtools
python3 setup.py install

Trying to confirm it now on Win10 20H2

FYI: love your work and blogs !

Feature request: Latest BloodHound / AzureHound compatibility

After running roadrecon's bloodhound plugin it appears that the queries are no longer compatible with the latest version of BloodHound as lots of relationships are created in the backend, however no azure data is found. Are there any plans of making roadtools compatible with the latest bloodhound version?

Screenshots for reference

image

image

Keep up the good work :)

Error on "gather" module

Hi, I've ran across an issue on multiple clients (ubuntu 18.04, kali 2020.2), that I'm just not experienced enough to fix it seems, pardon the inexperience:

  • i did a "pip3 install roadrecon" & everything seems to look good
  • i do a "roadrecon auth" and I'm able to authenticate and get a token
  • i go to do "roadrecon gather -f [TOKEN]" & I get this error:
    "File "/usr/local/lib/python3.6/dist-packages/roadtools/roadrecon/gather.py", line 416, in main
    asyncio.run(run(args, dburl))
    AttributeError: module 'asyncio' has no attribute 'run'"
  • i went and rechecked that 'asyncio' is installed (asyncio-3.4.3)
    I'm just not versed enough in python, despite trying to unravel this over the weekend

Comical enough, my Win10 WSL environment had no issues getting the entire process to run :)

any ideas, just for my own edification? I'm sure its PEBKAT

GUI internal server error

i can not use the GUI, it is answered with a 500 internal server error.
Apparently a file is missing, maybe i misunderstood the install instructions. I used:

git clone https://github.com/dirkjanm/ROADtools.git
pip3 install roadlib/
pip3 install roadrecon/

Error Message:

─$ roadrecon gui -d roadrecon.db --debug
 * Serving Flask app 'roadtools.roadrecon.server' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 733-781-644
127.0.0.1 - - [16/Aug/2022 12:21:41] "GET / HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/flask/app.py", line 2088, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/lib/python3/dist-packages/flask/app.py", line 2073, in wsgi_app
    response = self.handle_exception(e)
  File "/home/user/.local/lib/python3.10/site-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/lib/python3/dist-packages/flask/app.py", line 2070, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1515, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/user/.local/lib/python3.10/site-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1513, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1499, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/home/user/.local/lib/python3.10/site-packages/roadtools/roadrecon/server.py", line 157, in get_index
    return send_file('dist_gui/index.html')
  File "/usr/lib/python3/dist-packages/flask/helpers.py", line 612, in send_file
    return werkzeug.utils.send_file(
  File "/usr/lib/python3/dist-packages/werkzeug/utils.py", line 701, in send_file
    stat = os.stat(path)
FileNotFoundError: [Errno 2] No such file or directory: '/home/user/.local/lib/python3.10/site-packages/roadtools/roadrecon/dist_gui/index.html'

Incorrect authority URL for Azure Government

get_authority_url of .\roadlib\auth.py needs to be updated to support Azure Government deployments. For example, in the US the URL would be login.microsoftonline.us, not .com.

Attempting to auth to login.microsoftonline.com results in an "unknown user" error.

Dates are ordered alphabetically in GUI

Behavior:

Dates are ordered alphabetically in the GUI. See the below image. This is not useful or intuitive.
So far I have only encountered this in the OAuth2 Permissions tab, given that other places uses the format %Y-%m-%dT%H:%M:%S where lexicographical ordering is equivalent to chronological ordering.

image

Expected behavior

The dates should be ordered in a chronological fashion to improve the user experience and the utility of the tool.

Browser core PRT injection not working

Trying to use the browsercore method of PRT injection isn't working for me. The bctest.py works fine, but when the login loads, it still prompts for a username and password. After a bit of troubleshooting, I was thinking maybe it has to do with the PRT without a nonce update mentioned in the article here: https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/.

Similarly, PRT injection methods like the one listed in this stealthbits article don't appear to be working.

Noteworthy though, the selenium PRT browserauth method in roadtools still works!

Problem requesting access token for certain clients

When using the following command with a valid refresh token:

roadrecon auth --refresh-token "XXXX" -s "https://graph.windows.net/.default openid profile offline_access" -c c44b4083-3bb0-49c1-b47d-974e53cbdf3c

The server response with:

"AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests."

I debuged the issue and found out the problem is the user agent. After setting it to a browser like value, the call works as expected.
Maybe it is possible to add a parameter for the user agent.

RoadRecon - TypeError: 'NoneType' object is not subscriptable

Hello

I installed roadtools in UBUNTU 22.04 and KALI and I am getting this error when I execute roadrecon auth -u -p

Hoping for your guidance in getting this resolved.

Thanks


Traceback (most recent call last):
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/roadtools/roadlib/auth.py", line 1188, in get_tokens
return self.authenticate_username_password()
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/roadtools/roadlib/auth.py", line 193, in authenticate_username_password
self.tokendata = context.acquire_token_with_username_password(self.resource_uri, self.username, self.password, self.client_id)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/authentication_context.py", line 164, in acquire_token_with_username_password
return self._acquire_token(token_func)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/authentication_context.py", line 128, in _acquire_token
return token_func(self)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/authentication_context.py", line 162, in token_func
return token_request.get_token_with_username_password(username, password)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/token_request.py", line 285, in get_token_with_username_password
token = self._get_token_username_password_federated(username, password)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/token_request.py", line 256, in _get_token_username_password_federated
return self._perform_username_password_for_access_token_exchange(wstrust_endpoint, wstrust_version,
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/token_request.py", line 209, in _perform_username_password_for_access_token_exchange
wstrust_response = self._perform_wstrust_exchange(wstrust_endpoint, wstrust_endpoint_version, cloud_audience_urn,
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/token_request.py", line 197, in _perform_wstrust_exchange
result = wstrust.acquire_token(username, password)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/wstrust_request.py", line 169, in acquire_token
return self._handle_rstr(resp.text)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/wstrust_request.py", line 126, in _handle_rstr
wstrust_resp.parse()
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/adal/wstrust_response.py", line 238, in parse
raise AdalError(error_template.format(str_error_code, str_fault_message))
adal.adal_error.AdalError: Server returned error in RSTR - ErrorCode: FailedAuthentication : FaultMessage: Authentication failed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/########/roadtools/roadtools_venv/bin/roadrecon", line 8, in
sys.exit(main())
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/roadtools/roadrecon/main.py", line 108, in main
res = auth.get_tokens(args)
File "/home/########/roadtools/roadtools_venv/lib/python3.10/site-packages/roadtools/roadlib/auth.py", line 1231, in get_tokens
print(ex.error_response['error_description'])
TypeError: 'NoneType' object is not subscriptable

SSL: WRONG_VERSION_NUMBER when sending roadrecon traffic via Burp

Windows machine proxy settings are configured to use Burp.

C:\utilities\ROAD>netsh winhttp show proxy

Current WinHTTP proxy settings:

    Proxy Server(s) :  192.168.0.80:8080
    Bypass List     :  (none)

Burp works fine with TLS traffic sent from other clients (web browser, Outlook)
However when running roadrecon to obtain nonce following SSL error is returned. What is interesting is that on Burp I see response from login.microsoftonline.com with nonce.
Does Burp need to be configured in a specific way or is python's request module fault?

C:\utilities\ROAD>roadrecon auth --prt-init
Traceback (most recent call last):
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\connectionpool.py", line 696, in urlopen
    self._prepare_proxy(conn)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\connectionpool.py", line 964, in _prepare_proxy
    conn.connect()
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\connection.py", line 359, in connect
    conn = self._connect_tls_proxy(hostname, conn)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\connection.py", line 496, in _connect_tls_proxy
    return ssl_wrap_socket(
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\util\ssl_.py", line 432, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\util\ssl_.py", line 474, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\ssl.py", line 1040, in _create
    self.do_handshake()
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\requests\adapters.py", line 439, in send
    resp = conn.urlopen(
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\connectionpool.py", line 755, in urlopen
    retries = retries.increment(
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\urllib3\util\retry.py", line 573, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='login.microsoftonline.com', port=443): Max retries exceeded with url: /Common/oauth2/authorize?resource=https%3A%2F%2Fgraph.windows.net%2F&client_id=1b730954-1685-4b74-9bfd-dac224a7b894&response_type=code&haschrome=1&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&client-request-id=97270c27-da1d-4fe9-9659-ff5ad9bcefeb&x-client-SKU=PCL.Desktop&x-client-Ver=3.19.7.16602&x-client-CPU=x64&x-client-OS=Microsoft+Windows+NT+10.0.19569.0&site_id=501358&mscrid=361e6c6a-b91c-4965-ad6b-fbfef26fb518 (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)')))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\johndoe\AppData\Local\Programs\Python\Python39\Scripts\roadrecon-script.py", line 33, in <module>
    sys.exit(load_entry_point('roadrecon==0.9.0', 'console_scripts', 'roadrecon')())
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\roadtools\roadrecon\main.py", line 106, in main
    res = auth.get_tokens(args)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\roadtools\roadlib\auth.py", line 372, in get_tokens
    nonce = self.get_prt_cookie_nonce()
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\roadtools\roadlib\auth.py", line 143, in get_prt_cookie_nonce
    res = ses.get('https://login.microsoftonline.com/Common/oauth2/authorize', params=params, headers=headers, allow_redirects=False)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\requests\sessions.py", line 555, in get
    return self.request('GET', url, **kwargs)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\requests\sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\requests\sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "c:\users\johndoe\appdata\local\programs\python\python39\lib\site-packages\requests\adapters.py", line 514, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='login.microsoftonline.com', port=443): Max retries exceeded with url: /Common/oauth2/authorize?resource=https%3A%2F%2Fgraph.windows.net%2F&client_id=1b730954-1685-4b74-9bfd-dac224a7b894&response_type=code&haschrome=1&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&client-request-id=97270c27-da1d-4fe9-9659-ff5ad9bcefeb&x-client-SKU=PCL.Desktop&x-client-Ver=3.19.7.16602&x-client-CPU=x64&x-client-OS=Microsoft+Windows+NT+10.0.19569.0&site_id=501358&mscrid=361e6c6a-b91c-4965-ad6b-fbfef26fb518 (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)')))

Support for graph.microsoft.com

Yet another question (or maybe issue while running roadrecon) - sorry for being a bother! :)

Are there any plans for adding support for https://graph.microsoft.com based enumeration?

My use case is that I came in possession of access token scoped precisely for that client with User.Read User.ReadBasic.All scope and found that ROADtools are not able to help me pull data using this token.
Ultimately I guess I need to poke around manually?

(Invoke-RestMethod @{Uri="https://graph.microsoft.com";Headers=@{'Authorization'="Bearer $token"}; Method='GET'}).value

Regards,
Mariusz.

Feature: Ability to resume gather phase when roadtools is interrupted

It would be pretty awesome if we could have a way to resume the gather phase when the connection is interrupted (internet drops, system crashes etc.).

I was just doing a pull against a MASSIVE Tenant (roadtools gather running for 4.5 days) and had a system crash. All of that work halted, with only a portion of the results in the database.

SQLAlchemy.orm has no attribute 'DeclarativeBase'

Using commit (latest?) : 312a55c

When trying to use RoadRecon w/ Python 3.9 on Debian 11
Might be similar issue to #49

Traceback (most recent call last):
  File "/usr/local/bin/roadrecon", line 33, in <module>
    sys.exit(load_entry_point('roadrecon==1.1.3', 'console_scripts', 'roadrecon')())
  File "/usr/local/lib/python3.9/dist-packages/roadrecon-1.1.3-py3.9.egg/roadtools/roadrecon/main.py", line 86, in main
    plugin_module = importlib.import_module('roadtools.roadrecon.plugins.{}'.format(plugin))
  File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/usr/local/lib/python3.9/dist-packages/roadrecon-1.1.3-py3.9.egg/roadtools/roadrecon/plugins/xlsexport.py", line 43, in <module>
    from roadtools.roadrecon.server import (
  File "/usr/local/lib/python3.9/dist-packages/roadrecon-1.1.3-py3.9.egg/roadtools/roadrecon/server.py", line 2, in <module>
    from flask_sqlalchemy import SQLAlchemy
  File "/usr/local/lib/python3.9/dist-packages/flask_sqlalchemy-3.1.1-py3.9.egg/flask_sqlalchemy/__init__.py", line 5, in <module>
    from .extension import SQLAlchemy
  File "/usr/local/lib/python3.9/dist-packages/flask_sqlalchemy-3.1.1-py3.9.egg/flask_sqlalchemy/extension.py", line 40, in <module>
    t.Type[sa_orm.DeclarativeBase],
AttributeError: module 'sqlalchemy.orm' has no attribute 'DeclarativeBase'

Installing flask-sqlalchemy manually solved it for some reason:
pip3 install flask-sqlalchemy

UI performance

Hey,

regarding to performance on big datasets, I'm doing in roadtools/roadrecon/server.py:

all_foo = db.session.query(Foo).limit(1000).all()

and having 1000 in sync with the paging proposed in foo.component.html:

  <mat-paginator [pageSizeOptions]="[50, 100, 500, 1000]"></mat-paginator>

(was motived by perf issues mentionned in #6

roadtx prtenrich crashes with AttributeError

I got an error with roadtx prtenrich after successful MFA:

❯ roadtx prtenrich
Traceback (most recent call last):
  File "/home/daniel/.local/bin/roadtx", line 8, in <module>
    sys.exit(main())
  File "/home/daniel/.local/pipx/venvs/roadtx/lib/python3.10/site-packages/roadtools/roadtx/main.py", line 629, in main
    if args.ngcmfa_drs_auth:
AttributeError: 'Namespace' object has no attribute 'ngcmfa_drs_auth'

This is happens because args.ngcmfa_drs_auth is accessed but never assigned.
The accompanying add_argument() call is commented out in line 370.

After commenting out line 629 to 633 prtenrich worked as intended.

By the way, thanks for your nice work!

Runtime Error faced while gathering data

Hello,

I've tried running the "gather" command twice, but I'm still facing a runtime error and as a result the data seems to be incomplete.

image

Any idea what might be causing this?

Any help would be greatly appreciated!

[bug] [feature request] No results when database is huge - introduce results paging

Hi there Dirk!

Thank you for a splendid tool! :-)

I've just collected a rather big database (2,5GB) containing more than 100k users, 500k groups, 260k devices etc.
The gather phase went just fine, but when I attempted to review results from GUI - no records could be rendered.

Whenever frontend app launches Ajax request, the server is unable to serialize JSON in a timely manner, making frontend wait extremely long for the response. This results in GUI displaying no records until server responds.

In my situation, the server was unable to come up with a response in 30 minutes.

Maybe there could be a paging functionality added with frontend API calling out to specific results-pages as a workaround?

Leaving this as a food for thought! :-)

Regards,
Mariusz.

[bug] Some users missing

Hello,

Thank you for this very useful tool.

I collected a big database (1,2GB) containing more than 80k users, many groups, etc.
Some users are skipped during the dump step. I don't know why because I don't remember errors in Roadrecon outpout.
I have not checked groups or devices. Perhaps the same problem.

I have tested through the web interface and the python API:

[...]
session = database.get_session(database.init())
for user in session.query(User):
[...]

If I use MicroBurst or Get-MsolUser (MSOnline), these missing users are collected.

Best regards,

Error while gathering data

Hi!
Attempting to run roadrecon gather -t xxxx python 3.9.0 on Windows 10. I get multiple exceptions of the same type. First two are shown below. Any fix or suggestion would be greatly appreciated!

(venv) D:\tools\az-tools>roadrecon gather -t
Starting data gathering phase 1 of 2 (collecting objects)
Starting data gathering phase 2 of 2 (collecting properties and relationships)
ROADrecon gather executed in 13.50 seconds and issued 1181 HTTP requests.
Exception ignored in: <function _ProactorBasePipeTransport.del at 0x00000177675B7A60>
Traceback (most recent call last):
File "c:\python39\lib\asyncio\proactor_events.py", line 116, in del
self.close()
File "c:\python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "c:\python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "c:\python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.del at 0x00000177675B7A60>
Traceback (most recent call last):
File "c:\python39\lib\asyncio\proactor_events.py", line 116, in del
self.close()
File "c:\python39\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "c:\python39\lib\asyncio\base_events.py", line 746, in call_soon
self._check_closed()
File "c:\python39\lib\asyncio\base_events.py", line 510, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Question: Can this be used to obtain a BPRT for AzureAD join?

The only supported way to programmatically join a device to AzureAD is to apply a provisioning profile .ppkg file generated from the Windows Imaging Configuration Designer.

I know you are primarily interested in BrowserCore.exe but since you are all geared up for sniffing namedpipes and finding other opportunities to retrieve refresh tokens, I figure you may want to have a look at icd.exe since it obtains a refresh token using a different built in exe.

Azure Graph rate limit solution with powershell

@dirkjanm this a snip of what I use in powershell to get around graph rate limits on subscription and resources. A short one or two second pause should be worked into the loop so graph is not taxed.

`# Fetch the full array of subscription IDs
$subscriptions = Get-AzSubscription
$subscriptionIds = $subscriptions.Id

query

$query = "resources | order by subscriptionId asc";

Create a subscription counter, set the batch size, and prepare a variable for the results

$counter = [PSCustomObject] @{ Value = 0 }
$batchSize = 1000

Create array to hold results

$response = @()

Group the subscriptions into batches

$subscriptionsBatch = $subscriptionIds | Group -Property { [math]::Floor($counter.Value++ / $batchSize) }

Run the query for each batch

foreach ($batch in $subscriptionsBatch)
{

Create a resource counter, set the batch size, and prepare a variable for the results

$Skip = 0;
$First = 1000;

Get the data

$response += do {if ($Skip -eq 0) {$y = Search-AzGraph -Query $query -First $First -Subscription $batch.Group ; }
else {$y = Search-AzGraph -Query $query -Skip $Skip -First $First -Subscription $batch.Group } $cont = $y.Count -eq $First; $Skip = $Skip + $First; $y; } while ($cont) }

xlsreport traceback

:~$ roadrecon plugin xlsexport

Traceback (most recent call last):
File "/usr/local/bin/roadrecon", line 8, in
sys.exit(main())
File "/usr/local/lib/python3.7/dist-packages/roadtools/roadrecon/main.py", line 124, in main
plugin_module.main(args)
File "/usr/local/lib/python3.7/dist-packages/roadtools/roadrecon/plugins/xlsexport.py", line 415, in main
plugin.main()
File "/usr/local/lib/python3.7/dist-packages/roadtools/roadrecon/plugins/xlsexport.py", line 362, in main
self.get_app_roles(wb)
File "/usr/local/lib/python3.7/dist-packages/roadtools/roadrecon/plugins/xlsexport.py", line 251, in get_app_roles
'objid': sp.objectId,
AttributeError: 'NoneType' object has no attribute 'objectId'

xlsreport fails, no output.

TypeError when running roadrecon pugin policies

After successfully retrieving all azure data, i get the following error when generating the conditional access policies overview:

roadrecon plugin policies
Warning: Not all object IDs could be resolved for this policy
Warning: Not all object IDs could be resolved for this policy
Warning: Not all object IDs could be resolved for this policy
Traceback (most recent call last):
  File "/usr/local/bin/roadrecon", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/main.py", line 125, in main
    plugin_module.main(args)
  File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/plugins/policies.py", line 508, in main
    plugin.main(args.print)
  File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/plugins/policies.py", line 448, in main
    out['who'] = self._parse_who(conditions)
  File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/plugins/policies.py", line 344, in _parse_who
    ucond = cond['Users']
TypeError: 'NoneType' object is not subscriptable

I'm running the latest roadrecon in kali installed trough pip.

Keep open option doesn't keep the browser open

It seems that using the -k option doesn't keep the browser open for longer than about a minute.

For instance...
roadtx browserprtauth -d ./geckodriver -k -url https://outlook.office.com --prt MC5[snip] --prt-sessionkey 2e[snip]
will close out after about a minute.

To fix this, in the file /roadtools/roadtx/roadtools/roadtx/selenium.py, I added this code to the end of the selenium_login function before the last return (return False), at line 210:

if keep:
    time.sleep(1800)

I also had to import time at the top of that file. If I were cooler/had more time, I would have made it a variable and checked the other places this needed to go.

Also, if I didn't specify the redirect url, I believe it still closed out the browser even with my addition.

Error 403 on Gather

Starting data gathering phase 1 of 2 (collecting objects)
Error 403 for URL https://graph.windows.net/xxxx-xxxx-xxxx-xxxx-xxxxxxxxxx/users?api-version=1.61-internal

Starting data gathering phase 2 of 2 (collecting properties and relationships)
....
ROADrecon gather executed in 11.47 seconds and issued 1896 HTTP requests.

Seems to complete and data in DB but reporting fails (Will open tickets for these)

Going to the URL provides the following error:

<error><code>Authentication_MissingOrMalformed</code><message xml:lang="en">Access Token missing or malformed.</message></error>

error during "gui" - missing index.html

I am getting this error during the roadrecon gui. It seems like ROADtools/roadrecon/roadtools/roadrecon/dist_gui/index.htm is missing:

  • Serving Flask app "roadtools.roadrecon.server" (lazy loading)
  • Environment: production
    WARNING: This is a development server. Do not use it in a production deployment.
    Use a production WSGI server instead.
  • Debug mode: off
  • Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    [2021-02-12 08:49:06,680] ERROR in app: Exception on / [GET]
    Traceback (most recent call last):
    File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
    File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "/usr/local/lib/python3.9/site-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
    File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
    File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
    raise value
    File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
    File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functionsrule.endpoint
    File "/Users/Do_Not_Scan/repos/ROADtools/roadrecon/roadtools/roadrecon/server.py", line 154, in get_index
    return send_file('dist_gui/index.html')
    File "/usr/local/lib/python3.9/site-packages/flask/helpers.py", line 629, in send_file
    file = open(filename, "rb")
    FileNotFoundError: [Errno 2] No such file or directory: '/Users/Do_Not_Scan/repos/ROADtools/roadrecon/roadtools/roadrecon/dist_gui/index.html'
    127.0.0.1 - - [12/Feb/2021 08:49:06] "GET / HTTP/1.1" 500 -

Proxy option enhancement

The proxy option currently expects an http/https proxy. In practice, I've found what I need is a socks proxy so I can tunnel my connection through an environment to get around conditional access policies.

To do that, I changed lines 62 and 63 in file /roadtools/roadtx/roadtools/roadtx/selenium.py to...

'http': f'socks5://{self.proxy}',
'https': f'socks5://{self.proxy}',

adding owner in device view

Hi,

First of all thanks for this great tool!
I'm trying to add owner column in the device view but so far am failing.

I see that row available in the context of roadrecon/frontend/src/app/appmain/devices/devices.component.html does contain a restricted view of what angular gets from /api/devices/[objectid]. I'm trying to understand how the row view could be extended to contain the owner list.

row is seen by the gui is:

{
  "accountEnabled": true,
  "deviceId": "xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxxx",
  "deviceManufacturer": null,
  "deviceModel": null,
  "deviceOSType": "Android",
  "deviceOSVersion": "10.0.0",
  "deviceTrustType": "Workplace",
  "dirSyncEnabled": null,
  "displayName": "samsung",
  "isCompliant": null,
  "isManaged": null,
  "isRooted": null,
  "objectId": "xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "objectType": "Device"
}

and what the API returns from /api/devices/[objectid]:

{                                                                                                                                                                                                                                     
  "accountEnabled": true,
  [...]
  "deviceId": "[UUID]",
  "deviceKey": [
    {
      "creationTime": "2018-XXX",
      "customKeyInformation": "[base64]",
      "keyIdentifier": "[UUID]",
      "keyMaterial": "[base64 blob]",
      "usage": "STK"
    }
  ],
  "deviceManagementAppId": null,
  "deviceManufacturer": null,
  "deviceMetadata": null,
  "deviceModel": null,
  "deviceOSType": "Android",
  "deviceOSVersion": "10.0.0",
  "displayName": "samsung",
  "isCompliant": null,
  [...]
  "owner": [
    {
      "accountEnabled": false,
      "department": "BAR-FOO",
      "displayName": "Foo BAR",
      "jobTitle": null,
      "lastPasswordChangeDateTime": "2020-xxxxxx",
      "mail": "[email protected]",
      "mobile": null,
      "objectId": "[UUID]",
      "objectType": "User",
      [...]
      "userPrincipalName": "[email protected]"
    }
  ],
  "profileType": "RegisteredDevice",
}

So far my attempts at adding fields into the interface DevicesItem (file roadrecon/frontend/src/app/appmain/aadobjects.service.ts) are failing. My debug tip to check what is seen in the row object is doing a {{row | json}} inside the additional "owner" column I want to add.

Note on dev setup: ng serve is being run from roadrecon/frontend (browser hitting 127.0.0.1:4200 and being properly refreshing after any code update) and API is available at 127.0.0.1:5000 from roadrecon gui. I found out I can use that to have the API up on 5000 and GUI moving part on 4200 using it.

Thanks for any help!

-- Mathieu

Cryptography>=39 dropping _x509 which breaks the samltoken if using PEM and KEY

The debug trace for roadtx samltoken -c ./roadtx_adfs.pem -k ./roadtx_adfs.key .....

Traceback (most recent call last):
  File "/home/kiwi/impacket/bin/roadtx", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/kiwi/impacket/lib/python3.11/site-packages/roadtools/roadtx/main.py", line 917, in main
    signed = signer.sign_xml(template, assertionid)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kiwi/impacket/lib/python3.11/site-packages/roadtools/roadtx/federation.py", line 388, in sign_xml
    signed_xml = signer.sign(data,
                 ^^^^^^^^^^^^^^^^^
  File "/home/kiwi/impacket/lib/python3.11/site-packages/signxml/signer.py", line 239, in sign
    signature_annotator(sig_root, signing_settings=signing_settings)
  File "/home/kiwi/impacket/lib/python3.11/site-packages/signxml/signer.py", line 313, in _add_key_info
    x509_certificate.text = strip_pem_header(dump_certificate(FILETYPE_PEM, cert))
                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kiwi/impacket/lib/python3.11/site-packages/OpenSSL/crypto.py", line 2052, in dump_certificate
    result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
                                               ^^^^^^^^^^
AttributeError: 'cryptography.hazmat.bindings._rust.x509.Certificat' object has no attribute '_x509'

Temp Fix (try to use venv when using ROADtools if possible):

pip uninstall -y cryptography
pip install 'cryptography<39'

Unable to authenticate in a number of ways.

I've been trying to leverage roadrecon for a red team assessment I'm working on and no matter which way I try to authenticate, I get a URL parsing error from Urllib or some other error. I believe I am doing everything right, I have no idea what's going on.

┌──(root㉿kali)-[/home/kali/VMShared]
└─# roadrecon auth --access-token $(cat _____CENSORED______AzureAccessToken.json)
usage: roadrecon [-h] {auth,gather,dump,gui,plugin} ...
roadrecon: error: unrecognized arguments: "DefaultContextKey": "a8966302-3a5c-43fd-accf-_____CENSORED______ - [email protected] "CacheData": "eyJB_____CENSORED______WE5ZS________CENSORED_____________NhZTg1MzViOGYuYT_____CENSORED______NmE1MTRlZThiMTg3LWxvZ2luLndpbmRvd3MubmV0LWFjY2Vzc3Rva2VuLTE5NTBhMjU4LTIyN2ItNGUzMS1hOWNmLTcxNzQ5NTk0NWZjMi1hODk2NjMwMi0zYTVjLTQzZmQtYW________CENSORED_____________VtZW50LmNvcmUud2luZ________CENSORED_____________1wZXJzb25hdGlvbiBodHRwczovL21hbmFnZW1lbnQuY29yZS53aW5kb3dzLm5ldC8vLmRlZmF1bHQiOnsiaG9tZV9hY2NvdW50X2lkIjoiYmQ1Y2VhOWUtOWI3OC00NzJiLTkxODMtYTJjYWU4N________CENSORED_____________C1hY2NmLTZhNTE0ZWU4YjE4NyIsImVudmlyb25tZW50IjoibG9na________CENSORED_____________mbyI6ImV5SjFhV1FpT2lKaVpEVmpaV0U1WlMwNVlqYzRMVFEzTW1JdE9URTRNeTFoTW1OaFpUZzFNelZpT0dZaUxDSjFkR2xrSWpvaVlUZzVOall6TURJdE0yR________CENSORED_____________TFZeTAwTTJaa0xXRmpZMll0Tm1FMU1UUmxaVGhpTVRnM0luMCIsImNsaWVudF9pZCI6IjE5NT_____CENSORED______GUzMS1hOWNmLTcxNzQ5NTk0NWZjMiIsInNlY3JldCI6I.________CENSORED_____________WUtOWI3OC00NzJiLTkxODMtYTJjYWU4NTM_____CENSORED______NWMtNDNmZC1hY2NmLTZhNTE0ZWU4YjE4NyIsImVudmlyb25tZW50IjoibG9naW4ud2luZG93cy5uZXQiLCJjbGllbnRfaW5mbyI6ImV5SjFhV1FpT2lKaVpEVmpaV0U1WlMwNVlqY________CENSORED_____________pUZzFNelZpT0d________CENSORED_____________RhZGF0YSI6eyJhcHBtZXRhZGF0YS1sb2dpbi53aW5kb3dzLm5ldC0xOTUwYTI1OC0yMjdiLTRlMzEtYTljZi03MTc_____CENSORED______1lbnQiOiJsb2dpbi53aW5kb3dzLm5ldCIsI }ExtendedProperties": {}_____CENSORED______"
                                                                                                                   
┌──(root㉿kali)-[/home/kali/VMShared]
└─# roadrecon auth --device-code                                      
Traceback (most recent call last):
 File "/usr/lib/python3/dist-packages/requests/models.py", line 384, in prepare_url
   scheme, auth, host, port, path, query, fragment = parse_url(url)
 File "/usr/lib/python3/dist-packages/urllib3/util/url.py", line 394, in parse_url
   return six.raise_from(LocationParseError(source_url), None)
 File "<string>", line 2, in raise_from
urllib3.exceptions.LocationParseError: Failed to parse: https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
 File "/usr/local/bin/roadrecon", line 8, in <module>
   sys.exit(main())
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/main.py", line 107, in main
   res = auth.get_tokens(args)
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadlib/auth.py", line 755, in get_tokens
   return self.authenticate_device_code()
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadlib/auth.py", line 97, in authenticate_device_code
   code = context.acquire_user_code(self.resource_uri, self.client_id)
 File "/usr/local/lib/python3.10/dist-packages/adal/authentication_context.py", line 284, in acquire_user_code
   return code_request.get_user_code_info(language)
 File "/usr/local/lib/python3.10/dist-packages/adal/code_request.py", line 65, in get_user_code_info
   return self._get_user_code_info(oauth_parameters)
 File "/usr/local/lib/python3.10/dist-packages/adal/code_request.py", line 45, in _get_user_code_info
   return client.get_user_code_info(oauth_parameters)
 File "/usr/local/lib/python3.10/dist-packages/adal/oauth2_client.py", line 298, in get_user_code_info
   resp = requests.post(device_code_url.geturl(), 
 File "/usr/lib/python3/dist-packages/requests/api.py", line 117, in post
   return request('post', url, data=data, json=json, **kwargs)
 File "/usr/lib/python3/dist-packages/requests/api.py", line 61, in request
   return session.request(method=method, url=url, **kwargs)
 File "/usr/lib/python3/dist-packages/requests/sessions.py", line 515, in request
   prep = self.prepare_request(req)
 File "/usr/lib/python3/dist-packages/requests/sessions.py", line 443, in prepare_request
   p.prepare(
 File "/usr/lib/python3/dist-packages/requests/models.py", line 318, in prepare
   self.prepare_url(url, params)
 File "/usr/lib/python3/dist-packages/requests/models.py", line 386, in prepare_url
   raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0
                                                                                                                   
──(root㉿kali)-[/home/kali/VMShared]
└─# roadrecon auth -u pentestuser -p "_____CENSORED______" -t a8966302-3a5c-43fd-accf-_____CENSORED______
Traceback (most recent call last):
 File "/usr/lib/python3/dist-packages/requests/models.py", line 384, in prepare_url
   scheme, auth, host, port, path, query, fragment = parse_url(url)
 File "/usr/lib/python3/dist-packages/urllib3/util/url.py", line 394, in parse_url
   return six.raise_from(LocationParseError(source_url), None)
 File "<string>", line 2, in raise_from
urllib3.exceptions.LocationParseError: Failed to parse: https://login.microsoftonline.com/common/UserRealm/pentestuser?api-version=1.0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
 File "/usr/local/bin/roadrecon", line 8, in <module>
   sys.exit(main())
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadrecon/main.py", line 107, in main
   res = auth.get_tokens(args)
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadlib/auth.py", line 751, in get_tokens
   return self.authenticate_username_password()
 File "/usr/local/lib/python3.10/dist-packages/roadtools/roadlib/auth.py", line 109, in authenticate_username_password
   self.tokendata = context.acquire_token_with_username_password(self.resource_uri, self.username, self.password, self.client_id)
 File "/usr/local/lib/python3.10/dist-packages/adal/authentication_context.py", line 164, in acquire_token_with_username_password
   return self._acquire_token(token_func)
 File "/usr/local/lib/python3.10/dist-packages/adal/authentication_context.py", line 128, in _acquire_token
   return token_func(self)
 File "/usr/local/lib/python3.10/dist-packages/adal/authentication_context.py", line 162, in token_func
   return token_request.get_token_with_username_password(username, password)
 File "/usr/local/lib/python3.10/dist-packages/adal/token_request.py", line 279, in get_token_with_username_password
   self._user_realm.discover()
 File "/usr/local/lib/python3.10/dist-packages/adal/user_realm.py", line 147, in discover
   resp = requests.get(user_realm_url.geturl(), headers=options['headers'],
 File "/usr/lib/python3/dist-packages/requests/api.py", line 75, in get
   return request('get', url, params=params, **kwargs)
 File "/usr/lib/python3/dist-packages/requests/api.py", line 61, in request
   return session.request(method=method, url=url, **kwargs)
 File "/usr/lib/python3/dist-packages/requests/sessions.py", line 515, in request
   prep = self.prepare_request(req)
 File "/usr/lib/python3/dist-packages/requests/sessions.py", line 443, in prepare_request
   p.prepare(
 File "/usr/lib/python3/dist-packages/requests/models.py", line 318, in prepare
   self.prepare_url(url, params)
 File "/usr/lib/python3/dist-packages/requests/models.py", line 386, in prepare_url
   raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: https://login.microsoftonline.com/common/UserRealm/pentestuser?api-version=1.0

[bug] MFA policies dump crashed with KeyError: KnownNetworkPolicies

Hi there Jan!

Yet another bug found while trying to dump MFA policies via plugin. It started smoothly by enumerating first two correctly but then crashed:

PS> roadrecon plugin policies -d .\roadrecon3.db -p
Traceback (most recent call last):
  File "c:\program files\python38\lib\runpy.py", line 192, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\program files\python38\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\studentuser24\.virtualenvs\ROADTools-iANiAUBN\Scripts\roadrecon.exe\__main__.py", line 7, in <module>
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\main.py", line 123, in main
    plugin_module.main(args)
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\plugins\policies.py", line 395, in main
    plugin.main(args.print)
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\plugins\policies.py", line 346, in main
    out['locations'] = self._parse_locations(conditions)
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\plugins\policies.py", line 236, in _parse_locations
    ot += self._parse_locationcrit(icrit)
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\plugins\policies.py", line 248, in _parse_locationcrit
    objects = self._translate_locations(clist)
  File "c:\users\administrator\.virtualenvs\roadtools-ianiaubn\lib\site-packages\roadtools\roadrecon\plugins\policies.py", line 261, in _translate_locations
    if detaildata['KnownNetworkPolicies']['NetworkId'] in locs:
KeyError: 'KnownNetworkPolicies'

Mind taking a look? :)

Regards,
Mariusz.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.