3

I am trying to automate nmap scans and I am using the subprocess module to do so. I am pretty much passing three variables to subprocess.call and having the command be run. Here is my code

import subprocess

TOOL = 'nmap'
joined = '-p1 5000'
target = 'localhost'

subprocess.call([TOOL, joined, target], shell=True)

This should lead to nmap -p1 5000 localhost being ran on my system which is a valid command, however, the call method seems to only be recognizing TOOL(nmap) and it just prints out the options for nmap. Does anyone know what I'm missing here?

UCProgrammer
  • 517
  • 7
  • 21
  • 3
    I think you need to separate `joined`, since it will be quoted and interpreted as a single argument otherwise. – Aankhen Jul 11 '18 at 12:08
  • @Aankhen I have tried that as well as other nmap options like -A or -v and they haven't worked either – UCProgrammer Jul 11 '18 at 12:11
  • You can try this `subprocess.call([TOOL, 'p1 5000', target], shell=False)` – Kishan Mehta Jul 11 '18 at 12:11
  • 2
    As Kishan said, you shouldn’t need to set `shell=True`, since you’re not using any of its features; you can use [`distutils.spawn.find_executable`](https://docs.python.org/3/distutils/apiref.html#module-distutils.spawn) to locate `nmap` if you need to. – Aankhen Jul 11 '18 at 12:11
  • @Kishan Unfortunately, I need them passed from variables and that does not work as well – UCProgrammer Jul 11 '18 at 12:12
  • Yes @UCProgrammer then pass `joined= 'p1 5000'` and `shell=False` – Kishan Mehta Jul 11 '18 at 12:13
  • use full path: /usr/bin/nmap – hootnot Jul 11 '18 at 12:15
  • @hootnot, that has nothing at all to do with the issue. `subprocess` behaves equivalently to `execlp()`, doing PATH lookups; moreover with `shell=True`, the shell it starts is doing another lookup layer as well. – Charles Duffy Jul 11 '18 at 12:19
  • no I see that now , I should have read it better – hootnot Jul 11 '18 at 12:21

1 Answers1

3

I don't have nmap installed but you need set shell=False and split parameters:

import subprocess

TOOL = 'ls'
joined = '-a -l'
target = '/tmp'

print(subprocess.call([TOOL, *joined.split(), target], shell=False))
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • 1
    That is correct. Thank you. I guess I need to look at the difference between shell=True and shell=False. – UCProgrammer Jul 11 '18 at 12:17
  • 1
    @UCProgrammer, with `shell=True`, the arguments `['sh', '-c']` get prepended to your list. That's literally all it does. – Charles Duffy Jul 11 '18 at 12:17
  • 1
    @UCProgrammer, ...however, only the argument immediately after `-c` is parsed by `sh` as a shell script; other arguments are parsed as *arguments to that script*. – Charles Duffy Jul 11 '18 at 12:18
  • 1
    We already have a lot of instances of this question in the knowledge base -- it should have been closed as a dupe, not answered. – Charles Duffy Jul 11 '18 at 12:18
  • 1
    I also strongly advise against using `split()` in this context. Much, **much** less error-prone to explicitly pass `'-a', '-l'`; otherwise, you get into serious trouble when trying to process a filename with spaces. If you **must** use a split function, use `shlex.split()`, not `string.split()`. – Charles Duffy Jul 11 '18 at 12:21
  • 1
    @CharlesDuffy thank you for the feedback. I will see what I can do about this. – UCProgrammer Jul 11 '18 at 12:31