BC-SECURITY / Empire

Empire is a post-exploitation and adversary emulation framework that is used to aid Red Teams and Penetration Testers.
https://bc-security.gitbook.io/empire-wiki/
BSD 3-Clause "New" or "Revised" License
4.06k stars 564 forks source link

[BUG] Exception in ASGI application: AttributeError: 'NoneType' object has no attribute 'replace' #718

Closed b3nEx closed 4 months ago

b3nEx commented 5 months ago

Is there an existing issue for this?

Empire Version

Starkiller: 2.7.1 Empire: 5.9.1

Python Version

Python 3.12.1

Operating System

Docker on Linux

Database

SQLite

Current Behavior

I created a listener http_malleable based off of the following profile.

http-stager {
    set uri_x86 "/empire/uri1";
    set uri_x64 "/empire/uri2";
    set uri "/empire/uri3";
}

http-get {
    set uri "/empire/g";

    client {
        metadata {
            base64url;
            uri-append;
        }
    }
}

http-post {
    set uri "/empire/p";
    set verb "POST";

    client {
        output {
            base64url;
            uri-append;
        }
        id {
            base64url;
            print;
        }
    }
}

If I try to create a stager of type multi_launcher language powershell and try to obfuscate using all default values, I get an 500 error code from the server and the following log output.

empire  | [ERROR]: Exception in ASGI application
empire  |
empire  | Traceback (most recent call last):
empire  |   File "/usr/local/lib/python3.12/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
empire  |     result = await app(  # type: ignore[func-returns-value]
empire  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/usr/local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
empire  |     return await self.app(scope, receive, send)
empire  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/usr/local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__
empire  |     await super().__call__(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__
empire  |     await self.middleware_stack(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__
empire  |     raise exc
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__
empire  |     await self.app(scope, receive, _send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/gzip.py", line 24, in __call__
empire  |     await responder(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/gzip.py", line 44, in __call__
empire  |     await self.app(scope, receive, self.send_with_gzip)
empire  |   File "/empire/empire/server/api/middleware.py", line 36, in __call__
empire  |     await super().__call__(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__
empire  |     await self.simple_response(scope, receive, send, request_headers=headers)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response
empire  |     await self.app(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
empire  |     raise exc
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
empire  |     await self.app(scope, receive, sender)
empire  |   File "/usr/local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
empire  |     raise e
empire  |   File "/usr/local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
empire  |     await self.app(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__
empire  |     await route.handle(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle
empire  |     await self.app(scope, receive, send)
empire  |   File "/usr/local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app
empire  |     response = await func(request)
empire  |                ^^^^^^^^^^^^^^^^^^^
empire  |   File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app
empire  |     raw_response = await run_endpoint_function(
empire  |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/usr/local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
empire  |     return await dependant.call(**values)
empire  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/api/v2/stager/stager_api.py", line 60, in create_stager
empire  |     resp, err = stager_service.create_stager(
empire  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/core/stager_service.py", line 85, in create_stager
empire  |     generated, err = self.generate_stager(template_instance)
empire  |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/core/stager_service.py", line 153, in generate_stager
empire  |     resp = template_instance.generate()
empire  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/stagers/multi/launcher.py", line 132, in generate
empire  |     launcher = self.mainMenu.stagers.generate_launcher(
empire  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/common/stagers.py", line 103, in generate_launcher
empire  |     launcher_code = active_listener.generate_launcher(
empire  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/listeners/http_malleable.py", line 440, in generate_launcher
empire  |     stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager)
empire  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
empire  |   File "/empire/empire/server/core/obfuscation_service.py", line 197, in obfuscate_keywords
empire  |     data = data.replace(keyword.keyword, keyword.replacement)
empire  |            ^^^^^^^^^^^^
empire  | AttributeError: 'NoneType' object has no attribute 'replace'

After looking into all the files mentioned in the stacktrace I found line 440 in /empire/empire/server/listeners/http_malleable.py where I am not sure what it is supposed to do.

 435             if obfuscate:
 436                 launcherBase = self.mainMenu.obfuscationv2.obfuscate(
 437                     launcherBase,
 438                     obfuscation_command=obfuscation_command,
 439                 )
 440                 stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager)
 441
 442             if encode and (
 443                 (not obfuscate) or ("launcher" not in obfuscation_command.lower())
 444             ):
 445                 return helpers.powershell_launcher(launcherBase, launcher)
 446             else:
 447                 return launcherBase

After commenting it out, everything worked fine.

 435             if obfuscate:
 436                 launcherBase = self.mainMenu.obfuscationv2.obfuscate(
 437                     launcherBase,
 438                     obfuscation_command=obfuscation_command,
 439                 )
 440                 #stager = self.mainMenu.obfuscationv2.obfuscate_keywords(stager)
 441
 442             if encode and (
 443                 (not obfuscate) or ("launcher" not in obfuscation_command.lower())
 444             ):
 445                 return helpers.powershell_launcher(launcherBase, launcher)
 446             else:
 447                 return launcherBase

Expected Behavior

The expected behavior would be that the multi_launcher powershell stager is properly generated,

Steps To Reproduce

  1. Create Listener of type http_malleable
  2. Create Stager of type multi_launcher powershell
  3. Enable obfuscation
  4. Submit
  5. Error 500

Anything else?

No response