Automated interaction within ssh session - python

I need to collect some output via ssh from different devices but there are two caveats:
The devices are interactively asking for credentials so login can't be easily automated
The output is paged, so it is required to press "Enter" a number of times to get to the end of it
I've tried using paramiko_expect, I can manage the authentication but then I can't figure out how to loop in a while-like style.
from paramiko_expect import SSHClientInteraction
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(addresses[0], username = username, password = password, look_for_keys = False, allow_agent = False)
output = ""
with SSHClientInteraction(client, timeout = 10, display = False) as interact:
interact.expect(['User:.*'])
interact.send(username)
interact.expect(['Password:.*'])
interact.send(password)
interact.expect(['.*>'])
interact.send('get output')
interact.expect(['.*>','.*More or (q)uit.*'])
keepOnLooping = True
while keepOnLooping == True:
if interact.last_match == '.*More or (q)uit.*':
interact.send(interact.send(' '))
interact.expect(['.*>','.*More or (q)uit.*'])
keepOnLooping = True
elif interact.last_match == '.*>':
interact.send(interact.send(' '))
keepOnLooping = False
output = interact.current_output
I've tried with pexpect (pxssh) but I'm failing at the authentication phase.
from pexpect import pxssh
import getpass
try:
s = pxssh.pxssh()
hostname = input('hostname: ')
username = input('username: ')
password = getpass.getpass('password: ')
s.login(hostname, username, password)
s.expect('User:.*')
s.sendline(username)
s.expect('Password:.*')
s.sendline(password)
Any suggestions on how to automate the mentioned proceedures?

Related

Python nTSecurityDescriptor setting PASSWD_CANT_CHANGE Access Control Entry

I have been trying to set an account attribute for an Active Directory user but this one attribute cannot be applied the same way as other account attributes (ACE type), im applying the other attributes but "User cannot change password" is the one attribute im unable to do with python programmatically.
This is the code im using to set the password in AD and set attributes for "Password never expires" and "Store password using reversable encyption"
My sources for the code came from here: https://blog.steamsprocket.org.uk/2011/07/04/user-cannot-change-password-using-python/
Someone else other attempt was here but i'm unable to apply it:https://web.archive.org/web/20150829114442/http://www.robertmeany.com/programming/python-and-the-active-directory-security_descriptor/
Hopefully someone may be able to assist me, thank you.
import ldap3
from ldap3 import Connection,Server,ALL,SUBTREE,MODIFY_REPLACE
zid = input("username: ")
zid = str(zid).lower()
print(f'Searching for {zid}')
server = Server('ldaps://IP_OF_MY_AD_SERVER', use_ssl=True, get_info=all)
conn = Connection(server, user='DOMAIN\\USERNAME', password='password', auto_bind=True)
conn.bind()
Path_Root = "DC=domain,DC=Wan"
Filter = f'(&(objectclass=user)(&(sAMAccountName={zid})(!(objectclass=computer))))'
conn.search(search_base = Path_Root,
search_filter = Filter,
search_scope = SUBTREE,
attributes = ["cn", "sAMAccountName", "displayName"]
)
if len(conn.entries) == 1:
USER_DN = conn.response[0].get("dn")
print(USER_DN)
try:
new_password = "A__PASSWORD22"
print(new_password)
print("New password successfully applied")
except:
print("New password could not be applied")
#setting the password:
try:
res = ldap3.extend.microsoft.modifyPassword.ad_modify_password(conn, USER_DN, new_password, old_password=None, controls=None)
res = conn.extend.microsoft.modify_password(USER_DN, new_password)
changeUACattribute = {'userAccountControl': [('MODIFY_REPLACE', 66236)]}
conn.modify(USER_DN, changes=changeUACattribute)
print(conn.result)
print(res)
if res:
print('user %s change password Success.')
print('password: %s' %new_password)
else:
print('user %s change password Failed.')
except Exception as e:
print(f'Error setting AD password: {e}')
This is the code im trying to apply the nTSecurityDescriptor:
import win32security
import win32com.client as win32
domains = ["FQDN","IP_OF_DOMAIN"]
username = "DOMAIN\\USERNAME"
print(username)
password = input("Password: ")
print ("AUTHENTICATING ACCOUNT...")
for d in domains:
try:
token = win32security.LogonUser(
username,
d,
password,
win32security.LOGON32_LOGON_NEW_CREDENTIALS,
win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = True
token.Close()
break
except:
authenticated = False
if (authenticated):
print ("VALID ACCOUNT!")
else:
print ("Wrong username or password!")
authenticated = bool(token)
ChangePasswordGuid = '{ab721a53-1e2f-11d0-9819-00aa0040529b}'
ADS_ACETYPE_ACCESS_DENIED_OBJECT = 0x6
SID_SELF = "S-1-5-10"
SID_EVERYONE = "S-1-1-0"
selfAccount = win32security.LookupAccountSid(None,
win32security.GetBinarySid(SID_SELF))
everyoneAccount = win32security.LookupAccountSid(None,
win32security.GetBinarySid(SID_EVERYONE))
selfName = ("%s\\%s" % (selfAccount[1], selfAccount[0])).strip('\\')
everyoneName = ("%s\\%s" % (everyoneAccount[1], everyoneAccount[0])).strip('\\')
print(USER_DN)
location = USER_DN
user = win32.GetObject("ldap://cn=%s,%s" % (zid, location))
print(user)
sd = user.nTSecurityDescriptor
dacl = sd.DiscretionaryAcl
for ace in dacl:
if ace.ObjectType.lower() == ChangePasswordGuid.lower():
if ace.Trustee == selfName or ace.Trustee == everyoneName:
ace.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
sd.DiscretionaryAcl = dacl
user.Put('ntSecurityDescriptor', sd)
user.SetInfo()
The Error:
sd = USER_DN.nTSecurityDescriptor
AttributeError: 'str' object has no attribute 'nTSecurityDescriptor'

How can I make my current code use Multithreading/concurrent.futures?

I am new to netmiko/Python scripting , Using online examples was able to make a script to take configuration backup. The backup is copied to the text file and output is saved.
Currently this backup is done sequentially and it does not connect to all device at once and take the backup. I want to connect to all the devices concurrently.
I understand multithreading or concurrent.futures can solve this issueenter code here but I was not able to do it so far.
Can anyone please suggest, how my existing code can be modified to achieve it. Below is the code.
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetMikoTimeoutException
from paramiko.ssh_exception import SSHException
from netmiko.ssh_exception import AuthenticationException
import getpass
import sys
import time
import os
from datetime import datetime
##getting system date
day=time.strftime('%d')
month=time.strftime('%m')
year=time.strftime('%Y')
today=day+"-"+month+"-"+year
enter code here
##initialising device
device = {
'device_type': 'cisco_ios',
'ip': '192.168.100.21',
'username': 'Cisco',
'password': 'Cisco',
'secret':'Cisco',
'session_log': 'log.txt'
}
##opening IP file
ipfile=open("iplist.txt")
print ("Script to take backup of devices, Please enter your credential")
device['username']=input("username ")
device['password']=getpass.getpass()
print("Enter enable password: ")
device['secret']=getpass.getpass()enter code here
##taking backup
for line in ipfile:
try:
device['ip']=line.strip("\n")
print("\n\nConnecting Device ",line)
net_connect = ConnectHandler(**device)
net_connect.enable()
time.sleep(1)
with open('config.txt') as f:
cmd = f.read().splitlines()
print ("Reading the running config ")
output = net_connect.send_config_set(cmd)
output4 = "Failed"
time.sleep(7)
filename=device['ip']+'-'+today+".txt"
folder = os.path.join(today)
file = os.path.join(folder,filename)
os.makedirs(folder,exist_ok=True)
saveconfig=open(file,'w+')
print("Writing Configuration to file")
saveconfig.write(output)
saveconfig.close()
time.sleep(10)
net_connect.disconnect()
print ("Configuration saved to file",filename)
except:
print ("Access to "+device['ip']+" failed,backup did not taken")
output4 = "Failed"
file= device['ip']+'-'+today+"Error"+".txt"
config=open(file,'w+')
config.write(output4)
config.close()
ipfile.close()
print ("\nAll device backup completed")enter code here
You can refer below script and modify it according to your requirement. Here I have used python multiprocessing for connecting devices in pools.
#This script will allow for user pick hosts and enter show commands interactively
#
#Enable Multiprocessing
from multiprocessing import Pool
#
#getpass will not display password
from getpass import getpass
#ConnectionHandler is the function used by netmiko to connect to devices
from netmiko import ConnectHandler
#Time tracker
from time import time
#create variables for username and password
#create variables for configs and hosts
uname = input("Username: ")
passwd = getpass("Password: ")
cmd = input("Enter show commands seperated by ',': ")
host = input("Enter the host IPs seperate with space: ")
#This will put hosts and commands entered into list format
hosts = host.split()
cmds = cmd.split(",")
starting_time = time()
#Each member of the pool of 5 will be run through this function
def run_script(host_ip):
ios_rtr = {
"device_type": "cisco_ios",
"ip": host_ip,
"username": uname,
"password": passwd,
}
#connect to the device via ssh
net_connect = ConnectHandler(**ios_rtr)
#print the device IP or Hostname
print("Connected to host:", host_ip)
#this for loop is used to iterate through the show commands
for show_commands in cmds:
output = net_connect.send_command(show_commands)
print("Connected to host:", host_ip)
print(output)
print('\n---- Elapsed time=', time()-starting_time)
if __name__ == "__main__":
# Pool(5) means 5 process will be run at a time, more hosts will go in the next group
with Pool(5) as p:
print(p.map(run_script, hosts))
#This is the key to sending show commands vs config commands
#show commands --> net_connect.send_command()
#config commmands --> net_connect.send_config_set()
With this code, you can run commands on many devices at the same time. You can also use it by hiding your identity information with user_pass. There is also a device prompt discovery feature.
with open("user_pass.txt", "r") as f5:
user_pass = f5.readlines()
for list_user_pass in user_pass:
if "username" in list_user_pass:
username = list_user_pass.split(":")[1].strip()
if "password" in list_user_pass:
password = list_user_pass.split(":")[1].strip()
def _ssh_(nodeip):
try:
access_mpls = {
'device_type': 'huawei_olt', 'ip': nodeip, 'username':
username, 'password': password, }
net_connect = Netmiko(**access_mpls)
print(nodeip.strip() + " " + "success enter")
except Exception as e:
print(e)
f_3.write(nodeip.strip() + "\n")
return
prompt_gpon_fnk = net_connect.find_prompt()
hostname_fnk = prompt_gpon_fnk.strip("<" + ">")
print(hostname_fnk)
net_connect.send_command_timing("enable")
net_connect.send_command_timing("undo smart")
output = net_connect.send_command_timing("config")
print("config moda girildi")
net_connect.send_command_timing("acl 2010 ")
net_connect.send_command_timing("quit")
net_connect.send_command_timing("save")
print("config done")
with open("MDU_OK_2.txt", "a") as f:
f.write(nodeip + "\n")
f.close()
net_connect.disconnect()
f_2 = open("ip_list_2.txt", "r") ip_list = f_2.readlines()
f_2.close() f_3 = open("ssh_unsuccess_2.txt", "w")
myPool = ThreadPool(100) result = myPool.map(ssh, ip_list)

mail-client issue in Python

My script should take the user inputs and login to the server but when I give it the inputs it false and I tried different servers and different emails and the passwords are correct. How can I determine what's wrong?
import smtplib
sent = 'true'
ss = 'true'
repeat = 1
while sent == 'true':
m_email = input ('Enter Your Email Address: ')
m_server = input ('Entere Your Email Server: ')
m_auth = input ('username?\n')
p_auth = input ('password?\n')
r_email = input ('enter the reciver email: ')
subject = input ('enter Your Subject: ')
subject = 'subject '+ subject
m_massege = input ('Your Massege: ')
massege = subject + '\n \n' + m_massege
while ss == 'true' or repeat == "5" :
try:
server = smtplib.SMTP(m_server)
server.ehlo()
server.starttls()
server.login(m_auth,p_auth)
server.Sendmail(m_email,r_mail,massege)
print ("Mail Sent Successfully!")
sent = 'false'
except:
print ('sending failed')
repeat =+ 1
exit()
I've also had issues with smtplib and what I found was that it was not actually a code issue but rather an issue with the email account. For example, in my case I was trying to log into my yahoo mail account to automate emails and it kept failing so I had to go to my yahoo account security settings and enable "allow unsecured application login".
Point is: the problem isn't with your code but with the security settings on the email accounts (For me neither gmail nor yahoo worked).

python sockets, trying to make a log in interaction betwen server and client

Hello so i have my server with a database (dictironay) and another passworddatabase
import socket
import sys
from _thread import *
host = ""
port = 8000
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket Created")
try:
serversocket.bind((host, port))
except socket.error as e:
print(str(e))
sys.exit()
database = {"name1" :{"hair" : "red", "size" : 1.50}}
password_database = {"name1": "1234",
"name2": "4321"}
def client_thread(conn): #threader client
welcome = "Welcome to the server. Type something and hit enter \n"
conn.send(welcome.encode("UTF-8"))
login(conn)
while True: # NOT IMPORTANT KEEP READING
data = conn.recv(24)
reply = data.decode("UTF-8")
if reply == "1":
menu1 = "Menu 1: Buy \n"
conn.send(menu1.encode("UTF-8"))
else:
wrong = "wrong option \n"
conn.send(wrong.encode("UTF-8"))
def login(conn): #MY LOGIC PROBLEM IS HERE
log = "Log in MENU: \n"
logi = log.encode("UTF-8")
conn.send(logi)
us = "Username: \n"
use = us.encode("UTF-8")
conn.send(use)
userr = conn.recv(24)
user = userr.decode("UTF-8")
pa = "Password: \n"
pasw = pa.encode("UTF-8")
conn.send(pasw)
passr = conn.recv(24)
passw = passr.decode("UTF-8")
tries = 0
while tries < 3:
if user in passwordDictionary and passwordDictionary[user] == passw:
print("Logged in")
menu()
else:
print("Wrong Username Or Password \n")
tries += 1
print("You failed the login too many times, blocking you out")
conn.close()
while 1: # NOT IMPORTANT
conn, addr = serversocket.accept()
print("Connected with " + addr[0] + ":" + str(addr[1]))
start_new_thread(client_thread, (conn, ))
serversocket.close()
Whats working:
The server is working fine, i'm having troubles doing the login on the client side.
client.py ==> client DOESNT go into the if data == Log in menu
is there a better way to do this?
#! /usr/bin/python3
import socket
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(('localhost', 8000))
print("Connected")
datae = clientsocket.recv(24)
data = datae.decode("UTF-8")
clientsocket.send(datae)
while data != "!q":
if data == "Log in MENU: \n":
usere = input()
user = usere.encode("UTF-8")
clientsocket.send(user)
What would be the best way to create an log in interaction with the server?
the server has the usernames and passwords, i need to log in and then i need to edit the database depending on what user was chossen, but i'm having a hard time doing the algorithm
theres problems with the code you provided... however ill assume it actually works for you somehow and rather than copy paste you manually typed it
you are recieveing the first message here
datae = clientsocket.recv(24)
data = datae.decode("UTF-8") # GOT A MESSAGE
You then have the message datae = b'Welcome to the server. '
which does not match "Log in MENU: \n", and data != "!q" so it goes back into your loop and checks if data == "Log in MENU: \n" it doesnt so it repeats ... but you never get the next message instead try something like this second message
data = ""
while data != "!q":
if data == "Log in MENU: \n":
usere = input()
user = usere.encode("UTF-8")
clientsocket.send(user)
data = clientsocket.recv(24).decode("UTF-8") # GET THE NEXT MESSAGE!
but even then you are going to have problems because your server continues to write so you will get something like "Log in MENU: \nUsername" or something .... basically you need to work out a better message passing scheme than recv(24)
To avoid Errors try using a header with something like 64 Bytes wich always is the first message send. This Header is then used to send the actual length of the following message to the server. For example:
def send_response(conn, msg):
message = msg.encode(FORMAT)
send_length = len(str(len(message)).encode(FORMAT))
res_len = bytes(len(message)) + (b' ' * (HEADER - send_length))
print(f"[SENDING MESSAGE] {msg}")
conn.send(res_len)
conn.send(response)

How do I recursively try different SSH passwords in Python?

We use multiple sets of predefined passwords here for test servers - I would like to try a portable Python SSH library (like the one below - spur.py) and get it to try each one in succession - but obviously stop when it is successfully connected or if it can't - ask me for a password. I'm after some sort of recursion with the exception handling I think.
def ssh_connection(user, host):
try:
shell = spur.SshShell(
hostname=host,
port=findport(host),
username=user,
password="abc123",
private_key_file= expanduser("~") + "/.ssh/id_rsa",
missing_host_key=spur.ssh.MissingHostKey.accept
)
shell.run(["true"])
return shell
except spur.ssh.ConnectionError as error:
print error
raise
Coming from the Java world I'd check if the object is null and iterate through a list until the end and then ask for a password. I can't see how to do it in Python... Here's an example I found for the list part:
passwords = ['abc123', 'abc456', 'abc789']
for password in passwords: # Second Example
print 'trying password :', password
As Joe mentioned in the comments you can do something similar:
def ssh_connection(user, host, passwords):
err = None
for password in passwords:
try:
shell = spur.SshShell(
hostname=host,
port=findport(host),
username=user,
password=password,
private_key_file= expanduser("~") + "/.ssh/id_rsa",
missing_host_key=spur.ssh.MissingHostKey.accept
)
shell.run(["true"])
return shell
except spur.ssh.ConnectionError as error:
err = error
if err:
raise error
I would cut it in 2 different functions:
def ssh_connection(user, host, password):
"""
try to connect to user:password#host
return None if failed
"""
try:
shell = spur.SshShell(
hostname=host,
port=findport(host),
username=user,
password=password,
private_key_file=expanduser("~") + "/.ssh/id_rsa",
missing_host_key=spur.ssh.MissingHostKey.accept
)
shell.run(["true"])
return shell
except spur.ssh.ConnectionError as error:
print error
return
def try_connection(user, host, passwords):
"""
try all password in passwords to connect to host
if all failed, ask for password via stdin
"""
for password in passwords:
conn = ssh_connection(user, host, password)
if not conn is None:
break
else:
# we never hit the break: ask for passwd
password = ""
while conn is None:
print "please insert password for %s#%s (empty for exit)" % (user,host)
password = raw_input("passwd:") # todo : insert Term seq for hide passwd and then restor
if password == "":
sys.exit(1)
conn = ssh_connection(user, host, password)
return conn
My comment above got mangled, so here is #Joe Doherty suggestion used with code from Ifthikan - thanks!
def loop_ssh_connection(user, host):
shell = None
passw = ['abc123', 'abc456', 'abc789']
while shell is None:
shell = ssh_connection(user, host, passw)
result = shell.run(["ls", "-l"])
print result.output # prints ouput
def ssh_connection(user, host, passw):
err = None
for password in passw:
try:
shell = spur.SshShell(
hostname=host,
port=findport(host),
username=user,
password=password,
private_key_file= expanduser("~") + "/.ssh/id_rsa",
missing_host_key=spur.ssh.MissingHostKey.accept
)
shell.run(["true"])
return shell
except spur.ssh.ConnectionError as error:
err = error
if err:
raise error

Categories

Resources