Skip to content

Fix #1349: skip non-SearchResultEntry objects in LDAP --query - #1388

Open
Diogo-Damasceno wants to merge 1 commit into
Pennyw0rth:mainfrom
Diogo-Damasceno:fix/ldap-query-non-entry-1349-clean
Open

Fix #1349: skip non-SearchResultEntry objects in LDAP --query#1388
Diogo-Damasceno wants to merge 1 commit into
Pennyw0rth:mainfrom
Diogo-Damasceno:fix/ldap-query-non-entry-1349-clean

Conversation

@Diogo-Damasceno

Copy link
Copy Markdown

Description

Fixes #1349. The query() loop iterated the parsed response but indexed the raw response with resp[idx], bumping idx in a way that never skipped the current iteration. When the LDAP server returned a non-SearchResultEntry object (e.g. a SearchResultReference), the code crashed with a TypeError ('<' not supported between instances of 'str' and 'int' / object not subscriptable).

Root cause (verified): the index-based skip was a no-op, so the next iteration still pointed at the non-entry object, which does not support integer indexing.

Change: iterate the raw response directly, continue on anything that is not a SearchResultEntry, and read objectName from the real entry. Display logic for valid entries is unchanged.

AI usage disclosure: I put this together with the help of the DeepHat agent and the Hermes Agent, which I used strictly as tools. I drove every step myself: traced the crash to the index-based skip, reviewed the diff line by line, wrote and ran the regression test, and confirmed valid entries still display the same way. The logic and the test are mine; the agents were just a faster keyboard.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Setup guide for the review

  • Trigger: nxc ldap <DC> -u <user> -p <pass> --query "(objectClass=user)" "sAMAccountName memberOf" against a DC that returns referrals/intermediate non-entry objects.
    • Before: TypeError / crash.
    • After: valid entries are printed; referrals are skipped silently.
  • Local test: pytest tests/test_ldap_query_iteration.py (2 tests: non-entry objects skipped without crash, multiple entries processed). Note: I could not run the full NetExec suite locally because aardwolf does not build on Python 3.14 (see Install fails with Python 3.14 #1241); the change is isolated to the query() loop and is covered by the new unit test.

Checklist

The `query()` loop iterated the parsed response but indexed the raw
response with `resp[idx]`, bumping `idx` in a way that never skipped the
current iteration. When the LDAP server returned a non-SearchResultEntry
object (e.g. a SearchResultReference), the code crashed with a TypeError
('<' not supported between instances of 'str' and 'int' / object not
subscriptable).

Now we iterate the raw response directly, `continue` on anything that is not
a `SearchResultEntry`, and read `objectName` from the real entry. The
display logic is unchanged for valid entries.

Added tests/test_ldap_query_iteration.py covering the skip behaviour.
Verified on Python 3.14.7.
@NeffIsBack

Copy link
Copy Markdown
Member

Thanks for the PR!

For the three recent PRs, please:

@Diogo-Damasceno

Diogo-Damasceno commented Sep 4, 2026

Copy link
Copy Markdown
Author
screenshot_2026-09-04_12-16-07 screenshot_2026-09-04_12-16-14

Thanks @NeffIsBack! Addressed both points:

  1. Format changes removed. Force-pushed fix/ssh-key-type-rejected so PR ssh: distinguish 'key type rejected by server' from invalid passphrase (issue #1356) #1384 now contains only nxc/protocols/ssh.py + tests/test_ssh_key_type_rejection.py. The earlier nxcdb.py / test changes (issue nxcdb CSV header mismatch #1385) and the stray ruff format commit are gone — they belong to Fix #1385: derive nxcdb hosts CSV header from the protocol's HostsTable #1387, which is tracked separately.

  2. Validation. The fix distinguishes "key type rejected by server" from an invalid passphrase. The unit test loads the real helper from nxc/protocols/ssh.py in isolation and asserts the detection against the actual Paramiko 5.x messages a server emits when it rejects a key algorithm (e.g. PubkeyAcceptedAlgorithms ssh-ed25519 while the key is RSA):

Before (upstream/main — helper absent, test collection errors):

ERROR collecting tests/test_ssh_key_type_rejection.py
AttributeError: module 'nxc_ssh_isolated' has no attribute '_is_key_type_rejected'

After (PR #1384):

tests/test_ssh_key_type_rejection.py::test_real_paramiko_rejection_messages_are_detected PASSED
tests/test_ssh_key_type_rejection.py::test_wrong_passphrase_is_not_flagged_as_rejection PASSED
tests/test_ssh_key_type_rejection.py::test_unrelated_ssh_exception_is_not_flagged PASSED
tests/test_ssh_key_type_rejection.py::test_private_key_encrypted_is_not_flagged PASSED
============================== 4 passed ==============================

Note / honest caveat: against a live nxc ssh run the Paramiko exception surfaces as Unable to agree on a pubkey algorithm for signing a 'ssh-rsa' key! (which the helper catches), but I want to flag that nxc opens the transport once in create_conn_obj() and again in plaintext_login(), and that second connect can mask the rejection as a generic Invalid key. I can follow up with a change so the auth attempt uses a fresh client and the clearer message is what the user actually sees. Happy to adjust if you'd prefer the detection target the Invalid key path instead.

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.

"--query" crashes with TypeError when LDAP response contains non-SearchResultEntry objects

2 participants