Skip to content

fix: NameError job_message_buffer not defined in background python jobs - #844

Closed
satanonsteroids2024-zzz wants to merge 1 commit into
BC-SECURITY:mainfrom
satanonsteroids2024-zzz:fix/job-message-buffer-namerror
Closed

satanonsteroids2024-zzz wants to merge 1 commit into
BC-SECURITY:mainfrom
satanonsteroids2024-zzz:fix/job-message-buffer-namerror

Conversation

@satanonsteroids2024-zzz

Copy link
Copy Markdown

Describe your changes

Fixes #827.

python_job_func (task 112) execs module-supplied scripts inside a purpose-built globals dict containing only print:

output_capture = io.StringIO()
script_globals = {'print': lambda *a, **k: print(*a, **k, file=output_capture)}
try:
    exec(data, script_globals)

Several built-in modules stream output by calling job_message_buffer(msg) as a bare name from inside the script body they hand to the agent — python/collection/linux/xkeylogger, python/collection/linux/sniffer, python/collection/linux/port_scanner, and any custom module doing the same. Under the exec scope above the name is unresolved, so the script raises NameError, surfaced to the operator as:

[!] Error executing script: name 'job_message_buffer' is not defined

Separately (and this is what shapes the fix): MainAgent has both a string instance attribute self.job_message_buffer = "" (the accumulating buffer, set in __init__) and a method def job_message_buffer(self, message) with the same name. The instance attribute shadows the method, so even self.job_message_buffer(message) would raise 'str' object is not callable. That's a pre-existing tangle independent of this bug — left alone here rather than bundled into this fix.

Fix

Inject a small closure named job_message_buffer into script_globals that appends directly to the self.job_message_buffer string attribute, bypassing the shadowed method entirely:

def _append_job_message(msg):
    try:
        self.job_message_buffer += str(msg)
    except Exception as e:
        print("[!] Error adding job output to buffer: %s" % e, file=output_capture)

script_globals = {
    'print': lambda *a, **k: print(*a, **k, file=output_capture),
    'job_message_buffer': _append_job_message,
}

Only python_job_func is touched. get_job_message_buffer's existing flush-and-reset behavior on checkin is unchanged. dynamic_code_execute_wait_nosave (task 110) and dynamic_code_execution_wait_save (task 111) — the immediate-execute paths — don't run modules that stream via job_message_buffer, so they're untouched too.

Also added a CHANGELOG.md entry per the contribution checklist.

Verification

  • python3 -m py_compile empire/server/data/agent/agent.py — compiles cleanly.
  • Reproduced the exact exec-scope scenario in isolation (a standalone FakeAgent mirroring python_job_func's structure) with a script that calls job_message_buffer(msg) as a bare name, exactly like xkeylogger.yaml does: confirmed it previously raised NameError, and with the fix it correctly appends to the agent's real job_message_buffer string attribute with no exception.

Checklist before requesting a review

  • I have performed a self-review of my code
  • If it is a core feature, I have added thorough tests. (This is a scoped bugfix to existing background-job handling, not a new core feature; the existing test suite for MainAgent covers the surrounding paths.)
  • I have added an entry to CHANGELOG.md
  • I have updated the documentation in docs/ (not applicable — no user-facing behavior/interface change, just makes existing documented module behavior work)

Prepared with the assistance of Claude (Anthropic) for investigation and drafting; root cause and fix verified locally by me before submission.

python_job_func (task 112) execs module-supplied scripts inside a
purpose-built globals dict containing only 'print'. Several built-in
modules (e.g. python/collection/linux/xkeylogger,
python/collection/linux/sniffer) call job_message_buffer(msg) as a
bare name from inside that script to stream output, which is
unresolved in that scope and raises:

  [!] Error executing script: name 'job_message_buffer' is not defined

Separately, MainAgent has both a string instance attribute
self.job_message_buffer (the accumulating buffer, set in __init__)
and a like-named method def job_message_buffer(self, message). The
instance attribute shadows the method, so even
self.job_message_buffer(message) would raise 'str' object is not
callable - that pre-existing tangle is left alone here.

Inject a small closure named job_message_buffer into script_globals
that appends straight to the self.job_message_buffer string
attribute, bypassing the shadowed method entirely. Only
python_job_func is touched; get_job_message_buffer's flush-and-reset
behavior on checkin is unchanged.

Fixes BC-SECURITY#827.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Cx01N

Cx01N commented Oct 12, 2026

Copy link
Copy Markdown
Member

Thanks @satanonsteroids2024-zzz! Your commit was cherry-picked (authorship preserved) into our development branch, then refined to bind the shadowed method and mirrored to the IronPython agent. It will ship here with the next release. Closing as superseded.

@Cx01N Cx01N closed this Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Error executing script: name 'job_message_buffer' is not defined

2 participants