15 Jan, 2024 (Last updated: 12 Jun, 2024 )
9 minutes
Autocompletion for Impacket (and other tools)
Having to remember which arguments to use and what to add can be quite a lot, especially with tools such as Impacket. Recently there’s this pull request which added autocompletion functionalities to NetExec (the successor to CrackMapExec), so I thought I’d enable autocompletion for Impacket, and other python command line tools which use argparse
.
This guide will be aimed at the pipx
installation of Impacket, the steps will be similar if your Impacket is installed with pip
or just a local repository.
The process is quite straightforward, here’s an overview.
First, we need to ensure argcomplete
is installed:
pip install argcomplete
Enable argcomplete
automatically for all compatible scripts:
activate-global-python-argcomplete
Add the argcomplete
package to the tool by using pipx inject <name> argcomplete
.
For Impacket, we will do:
pipx inject impacket argcomplete
Then, we will need to modify the files a little:
- Add
import argcomplete
afterimport argparse
argcomplete.autocomplete(parser)
should be added beforeoptions = parser.parse_args()
andif len(sys.argv)==1:
The modified files should look something like this:
import argparse
import argcomplete
# Rest of the code
argcomplete.autocomplete(parser)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
options = parser.parse_args()
# More code
Finally, run eval "$(register-python-argcomplete <name>)"
to enable autocompletion.
This would be easy if the tool has a single __main__.py
or cli.py
or entry.py
used to parse all arguments, such as the NetExec example earlier or Certipy. But the Impacket examples are a number of different tools, all with their own argparse
and arguments, so it can be quite a pain to do it manually.
I have written a script to simplify the process, I would highly recommend making a snapshot or backup of the files before running it.
#!/usr/bin/env python
import os
import sys
import re
def modify_file(file_path):
with open(file_path, 'r') as file:
lines = file.readlines()
modified = False
autocomplete_inserted = False
# Find and insert `import argcomplete` after any import that includes `argparse`
for i, line in enumerate(lines):
if 'import' in line and 'argparse' in line:
lines.insert(i + 1, 'import argcomplete\n')
modified = True
break
# Find and insert `argcomplete.autocomplete(parser)` with the same indentation for `if len(sys.argv) == 1:`
pattern_if = re.compile(r'^(\s*)if len\(sys\.argv\) ?== ?1:')
pattern_parse_args = re.compile(r'^(\s*).*parser\.parse_args\(\)')
for i, line in enumerate(lines):
match_if = pattern_if.match(line)
if match_if:
indent = match_if.group(1)
lines.insert(i, f'{indent}argcomplete.autocomplete(parser)\n')
modified = True
autocomplete_inserted = True
break
# If `argcomplete.autocomplete(parser)` was not inserted above, find `parser.parse_args()` and insert before it
if not autocomplete_inserted:
for i, line in enumerate(lines):
match_parse_args = pattern_parse_args.match(line)
if match_parse_args:
indent = match_parse_args.group(1)
lines.insert(i, f'{indent}argcomplete.autocomplete(parser)\n')
modified = True
break
if modified:
with open(file_path, 'w') as file:
file.writelines(lines)
print(f"Modified file: {file_path}")
return modified
def main(directory):
if not os.path.isdir(directory):
print(f"Error: {directory} is not a valid directory.")
return
count = 0
for filename in os.listdir(directory):
if filename.endswith('.py'):
file_path = os.path.join(directory, filename)
if modify_file(file_path):
count += 1
print(f"{count} files modified.")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: ./addAutocomplete.py <directory>")
sys.exit(1)
directory = sys.argv[1]
main(directory)
The Impacket examples should be located at ~/.local/pipx/venvs/impacket/bin/
for pipx
. Do not run it against ~/.local/bin/
, it will remove the symlinks used by pipx
. If you aren’t sure where the files are located, run which <any impacket scripts>
, then run ls -l
on the output, that should show you the symlinks.
For example, running which psexec.py
returned ~/.local/bin/psexec.py
, and running ls -l ~/.local/bin/psexec.py
shows that it points to ~/.local/bin/smbclient.py -> ~/.local/pipx/venvs/impacket/bin/smbclient.py
, I will run the python script against that directory: ./addAutocomplete.py ~/.local/pipx/venvs/impacket/bin/
Finally, activate argcomplete
for the examples:
eval "$(register-python-argcomplete addcomputer.py)"
eval "$(register-python-argcomplete atexec.py)"
eval "$(register-python-argcomplete changepasswd.py)"
eval "$(register-python-argcomplete dcomexec.py)"
eval "$(register-python-argcomplete describeTicket.py)"
eval "$(register-python-argcomplete dpapi.py)"
eval "$(register-python-argcomplete DumpNTLMInfo.py)"
eval "$(register-python-argcomplete esentutl.py)"
eval "$(register-python-argcomplete exchanger.py)"
eval "$(register-python-argcomplete findDelegation.py)"
eval "$(register-python-argcomplete GetADUsers.py)"
eval "$(register-python-argcomplete getArch.py)"
eval "$(register-python-argcomplete Get-GPPPassword.py)"
eval "$(register-python-argcomplete GetNPUsers.py)"
eval "$(register-python-argcomplete getPac.py)"
eval "$(register-python-argcomplete getST.py)"
eval "$(register-python-argcomplete getTGT.py)"
eval "$(register-python-argcomplete GetUserSPNs.py)"
eval "$(register-python-argcomplete goldenPac.py)"
eval "$(register-python-argcomplete karmaSMB.py)"
eval "$(register-python-argcomplete keylistattack.py)"
eval "$(register-python-argcomplete kintercept.py)"
eval "$(register-python-argcomplete lookupsid.py)"
eval "$(register-python-argcomplete machine_role.py)"
eval "$(register-python-argcomplete mimikatz.py)"
eval "$(register-python-argcomplete mqtt_check.py)"
eval "$(register-python-argcomplete mssqlclient.py)"
eval "$(register-python-argcomplete mssqlinstance.py)"
eval "$(register-python-argcomplete net.py)"
eval "$(register-python-argcomplete netview.py)"
eval "$(register-python-argcomplete ntfs-read.py)"
eval "$(register-python-argcomplete ntlmrelayx.py)"
eval "$(register-python-argcomplete ping6.py)"
eval "$(register-python-argcomplete ping.py)"
eval "$(register-python-argcomplete psexec.py)"
eval "$(register-python-argcomplete raiseChild.py)"
eval "$(register-python-argcomplete rbcd.py)"
eval "$(register-python-argcomplete rdp_check.py)"
eval "$(register-python-argcomplete registry-read.py)"
eval "$(register-python-argcomplete reg.py)"
eval "$(register-python-argcomplete rpcdump.py)"
eval "$(register-python-argcomplete rpcmap.py)"
eval "$(register-python-argcomplete sambaPipe.py)"
eval "$(register-python-argcomplete samrdump.py)"
eval "$(register-python-argcomplete secretsdump.py)"
eval "$(register-python-argcomplete services.py)"
eval "$(register-python-argcomplete smbclient.py)"
eval "$(register-python-argcomplete smbexec.py)"
eval "$(register-python-argcomplete smbrelayx.py)"
eval "$(register-python-argcomplete smbserver.py)"
eval "$(register-python-argcomplete ticketConverter.py)"
eval "$(register-python-argcomplete ticketer.py)"
eval "$(register-python-argcomplete tstool.py)"
eval "$(register-python-argcomplete wmiexec.py)"
eval "$(register-python-argcomplete wmipersist.py)"
eval "$(register-python-argcomplete wmiquery.py)"
eval "$(register-python-argcomplete dacledit.py)"
But wait, those are just a temporary activation, we will need to add that again every reboot or .*rc
file is sourced.
For a more permanent solution run register-python-argcomplete psexec.py >> ~/.zshrc
, which seems to be a lot faster than adding all those eval
lines, it creates the following functions in the file, instead of running the commands one by one, I have added them all to the same functions, so just paste them in:
# Run something, muting output or redirecting it to the debug stream
# depending on the value of _ARC_DEBUG.
# If ARGCOMPLETE_USE_TEMPFILES is set, use tempfiles for IPC.
__python_argcomplete_run() {
if [[ -z "${ARGCOMPLETE_USE_TEMPFILES-}" ]]; then
__python_argcomplete_run_inner "$@"
return
fi
local tmpfile="$(mktemp)"
_ARGCOMPLETE_STDOUT_FILENAME="$tmpfile" __python_argcomplete_run_inner "$@"
local code=$?
cat "$tmpfile"
rm "$tmpfile"
return $code
}
__python_argcomplete_run_inner() {
if [[ -z "${_ARC_DEBUG-}" ]]; then
"$@" 8>&1 9>&2 1>/dev/null 2>&1
else
"$@" 8>&1 9>&2 1>&9 2>&1
fi
}
_python_argcomplete() {
local IFS=$'\013'
if [[ -n "${ZSH_VERSION-}" ]]; then
local completions
completions=($(IFS="$IFS" \
COMP_LINE="$BUFFER" \
COMP_POINT="$CURSOR" \
_ARGCOMPLETE=1 \
_ARGCOMPLETE_SHELL="zsh" \
_ARGCOMPLETE_SUPPRESS_SPACE=1 \
__python_argcomplete_run "${words[1]}") )
_describe "${words[1]}" completions -o nosort
else
local SUPPRESS_SPACE=0
if compopt +o nospace 2> /dev/null; then
SUPPRESS_SPACE=1
fi
COMPREPLY=($(IFS="$IFS" \
COMP_LINE="$COMP_LINE" \
COMP_POINT="$COMP_POINT" \
COMP_TYPE="$COMP_TYPE" \
_ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" \
_ARGCOMPLETE=1 \
_ARGCOMPLETE_SHELL="bash" \
_ARGCOMPLETE_SUPPRESS_SPACE=$SUPPRESS_SPACE \
__python_argcomplete_run "$1"))
if [[ $? != 0 ]]; then
unset COMPREPLY
elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
compopt -o nospace
fi
fi
}
if [[ -z "${ZSH_VERSION-}" ]]; then
complete -o nospace -o default -o bashdefault -F _python_argcomplete nxc
complete -o nospace -o default -o bashdefault -F _python_argcomplete certipy
complete -o nospace -o default -o bashdefault -F _python_argcomplete addcomputer.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete atexec.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete changepasswd.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete dcomexec.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete describeTicket.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete dpapi.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete DumpNTLMInfo.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete esentutl.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete exchanger.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete findDelegation.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete GetADUsers.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete getArch.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete Get-GPPPassword.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete GetNPUsers.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete getPac.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete getST.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete getTGT.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete GetUserSPNs.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete goldenPac.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete karmaSMB.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete keylistattack.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete kintercept.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete lookupsid.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete machine_role.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete mimikatz.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete mqtt_check.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete mssqlclient.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete mssqlinstance.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete net.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete netview.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ntfs-read.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ntlmrelayx.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ping6.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ping.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete psexec.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete raiseChild.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete rbcd.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete rdp_check.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete registry-read.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete reg.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete rpcdump.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete rpcmap.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete sambaPipe.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete samrdump.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete secretsdump.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete services.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete smbclient.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete smbexec.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete smbrelayx.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete smbserver.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ticketConverter.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete ticketer.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete tstool.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete wmiexec.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete wmipersist.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete wmiquery.py
complete -o nospace -o default -o bashdefault -F _python_argcomplete dacledit.py
else
compdef _python_argcomplete nxc
compdef _python_argcomplete certipy
compdef _python_argcomplete addcomputer.py
compdef _python_argcomplete atexec.py
compdef _python_argcomplete changepasswd.py
compdef _python_argcomplete dcomexec.py
compdef _python_argcomplete describeTicket.py
compdef _python_argcomplete dpapi.py
compdef _python_argcomplete DumpNTLMInfo.py
compdef _python_argcomplete esentutl.py
compdef _python_argcomplete exchanger.py
compdef _python_argcomplete findDelegation.py
compdef _python_argcomplete GetADUsers.py
compdef _python_argcomplete getArch.py
compdef _python_argcomplete Get-GPPPassword.py
compdef _python_argcomplete GetNPUsers.py
compdef _python_argcomplete getPac.py
compdef _python_argcomplete getST.py
compdef _python_argcomplete getTGT.py
compdef _python_argcomplete GetUserSPNs.py
compdef _python_argcomplete goldenPac.py
compdef _python_argcomplete karmaSMB.py
compdef _python_argcomplete keylistattack.py
compdef _python_argcomplete kintercept.py
compdef _python_argcomplete lookupsid.py
compdef _python_argcomplete machine_role.py
compdef _python_argcomplete mimikatz.py
compdef _python_argcomplete mqtt_check.py
compdef _python_argcomplete mssqlclient.py
compdef _python_argcomplete mssqlinstance.py
compdef _python_argcomplete net.py
compdef _python_argcomplete netview.py
compdef _python_argcomplete ntfs-read.py
compdef _python_argcomplete ntlmrelayx.py
compdef _python_argcomplete ping6.py
compdef _python_argcomplete ping.py
compdef _python_argcomplete psexec.py
compdef _python_argcomplete raiseChild.py
compdef _python_argcomplete rbcd.py
compdef _python_argcomplete rdp_check.py
compdef _python_argcomplete registry-read.py
compdef _python_argcomplete reg.py
compdef _python_argcomplete rpcdump.py
compdef _python_argcomplete rpcmap.py
compdef _python_argcomplete sambaPipe.py
compdef _python_argcomplete samrdump.py
compdef _python_argcomplete secretsdump.py
compdef _python_argcomplete services.py
compdef _python_argcomplete smbclient.py
compdef _python_argcomplete smbexec.py
compdef _python_argcomplete smbrelayx.py
compdef _python_argcomplete smbserver.py
compdef _python_argcomplete ticketConverter.py
compdef _python_argcomplete ticketer.py
compdef _python_argcomplete tstool.py
compdef _python_argcomplete wmiexec.py
compdef _python_argcomplete wmipersist.py
compdef _python_argcomplete wmiquery.py
compdef _python_argcomplete dacledit.py
fi
Here it is in action:
![argcomplete-demo.gif](https://Xre0uS.io/img/argcomplete-demo.gif)
![argcomplete-demo.png](https://Xre0uS.io/img/argcomplete-demo.png)
1775 Words