Search code examples
pythonsshscriptingpipetcpdump

script will not save locally over ssh


I am having some issues getting a script to run.

This works perfectly from command line:

ssh root@ip.add.re.ss /usr/sbin/tcpdump -i eth0 -w - | /usr/sbin/tcpdump -r - -w /home/cuckoo/cuckoo/storage/analyses/1/saveit.pcap

However when I use this script: #!/usr/bin/env python

import sys
import os
import subprocess

cmd = []
remote_cmd = []
local_cmd = []
connect_cmd = []
outfile = None

try:
    connect_cmd = str.split(os.environ["RTCPDUMP_CMD"], " ")
except:
    connect_cmd = str.split("ssh root@fw", " ")

remote_cmd.extend(str.split("/usr/sbin/tcpdump -w -", " "))
local_cmd.extend(str.split("/usr/sbin/tcpdump -r -", " "))

for argument in xrange(1, len(sys.argv)):
    if sys.argv[argument] == "-w":
        outfile=sys.argv[argument+1]
        sys.argv[argument] = None
        sys.argv[argument+1] = None

    if sys.argv[argument] == "-i":
        remote_cmd.append(sys.argv[argument])
        remote_cmd.append(sys.argv[argument+1])
        sys.argv[argument] = None
        sys.argv[argument+1] = None

    if not sys.argv[argument] == None:
        if " " in sys.argv[argument]:
            local_cmd.append("'" + sys.argv[argument] + "'")
            remote_cmd.append("'" + sys.argv[argument] + "'")
        else:
            local_cmd.append(sys.argv[argument])
            remote_cmd.append(sys.argv[argument])

if not outfile == None:
    local_cmd.insert(1, "-w")
    local_cmd.insert(2, outfile)

cmd.extend(connect_cmd)
cmd.extend(remote_cmd)
cmd.append("|")
cmd.extend(local_cmd)

try:
    subprocess.call(cmd)
except KeyboardInterrupt:
    exit(0)

It spawns both tcpdump processes on the remote host and the second tcpdump fails to save due to non working path. I added a print cmd at the end and the ssh command being passed to the prompt is exactly the same (when running the script itself, cuckoo passes a ton of options when it calls the script. Also it gets the -w - before the -i eth0, but I tested that and it works from command line as well).

So I am thoroughly stumped, why is the pipe to local not working in the script but it works from prompt?

Oh, and credit for the script belongs to Michael Boman http://blog.michaelboman.org/2013/02/making-cuckoo-sniff-remotely.html


Solution

  • So I am thoroughly stumped, why is the pipe to local not working in the script but it works from prompt?

    Because pipes are handled by the shell, and you're not running a shell.

    If you look at the docs, under Replacing Older Functions with the subprocess Module, it explains how to do the same thing shell pipelines do. Here's the example:

    output=`dmesg | grep hda`
    # becomes
    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
    output = p2.communicate()[0]
    

    So, in your terms:

    cmd.extend(connect_cmd)
    cmd.extend(remote_cmd)
    try:
        remote = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        local = subprocess.Popen(local_cmd, stdin=remote.stdout)
        remote.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
        local.communicate()
    except KeyboardInterrupt:
        exit(0)