I'm currently working on this Python port scanner, I'm trying to implement a feature that will allow this port scanner to scan a local subnet.
Currently when the target IP ends in .0, it scans every IP in that subnet range, (.1 - .255) except when I run the program, returns 'cannot resolve , unknown host' for every single IP within the subnet range. The code I currently have is below:
# import modules used in port scanner
import optparse
from socket import *
from threading import *
import ipaddress
# connect-scan function, deals with connecting to the host / determining if ports are open / closed, takes arguments tgtHost, tgtPort
def connScan(tgtHost, tgtPort):
try:
connSkt = socket(AF_INET, SOCK_STREAM)
connSkt.connect((tgtHost, tgtPort))
connSkt.send('\r\n')
result = connSkt.recv(100)
# prints result if port is open
print '[+] ' + str(tgtPort) + '/tcp open'
except:
# prints result if port is closed
print '[-] ' + str(tgtPort) + '/tcp closed'
finally:
connSkt.close()
# port-scan function, takes arguments tgtHost, tgtPorts
def portScan(tgtHost, tgtPorts):
try:
# tries to get target IP address
tgtIP = gethostbyname(tgtHost)
except:
# if unsuccesful, prints out following result
print '[-] cannot resolve ' + unicode(tgtHost) + ': unknown host'
return
try:
# tries to get target address
tgtName = gethostbyaddr(tgtIP)
print '\n[+] scan results for: ' + tgtName[0]
except:
print '\n[+] scan results for: ' + tgtIP
# sets default time out to 1
setdefaulttimeout(1)
# for every port in tgtPorts
for tgtPort in tgtPorts:
# creates thread, target is connScan function, arguments are tgtHost, int(tgtPort)
t = Thread(target=connScan, args=(tgtHost, int(tgtPort)))
# starts the thread
t.start()
def main():
parser = optparse.OptionParser('usage %prog -t <target-host> -p <target-port(s)>')
parser.add_option('-t', dest='tgtHost', type='string', help='specify target host, for local subnet, use 192.168.1.0 (scans range 192.168.1.1 - 192.168.1.255')
parser.add_option('-p', dest='tgtPort', type='string', help='specify target port(s), seperated by a comma, seperate ranges with a -')
(options, args) = parser.parse_args()
if (options.tgtHost == None) | (options.tgtPort == None):
print parser.usage
exit(0)
else:
tgtHost = options.tgtHost
if tgtHost.endswith('.0'):
hosts = ipaddress.ip_network(unicode(tgtHost+'/24'))
else:
hosts = [tgtHost]
# allows ranges of ports to be used, when seperated by a -
if '-' in str(options.tgtPort):
tgtPorts = options.tgtPort.split('-')
tgtPorts = range(int(tgtPorts[0]),int(tgtPorts[1]))
else:
tgtPorts = str(options.tgtPort).split(',')
for tgtHost in hosts:
portScan(tgtHost, tgtPorts)
if __name__ == '__main__':
main()
I've been trying to find the solution for this, however have come up empty. Does anyone know whats wrong with the code?
Related
My issue is that I have a ports.txt file in it has 4 port numbers. I wish for this program to scan all port numbers specified within the txt file. currently It will only scan the first port number listed in the txt file against the 40 odd IP addresses. I hope my formatting is correct and my detail is enough. ty
import socket
import os
import sys
from datetime import datetime
import win32evtlogutil
import win32evtlog
def main():
### call step 1 function
ipList = network_addr()
# call step 2 function
portList = read_ports()
print(portList)
#call step 3 function
for ip in ipList:
for port in portList:
scan_ports(ip,port)
# call step 4 function
report_to_EventViewer(ipList[0:10], 2) # warning
#report_to_EventViewer(ipList, 1) # error
# processing inputs
# Step 1: process input 1 (subnet or network address):
def network_addr():
while True:
ip_list = []
subnet_Addr = input('Enter a Class-C Network Address or subnet with format (x.x.x): ')
subnet = subnet_Addr.split('.') # subnet is a list of 3 items (octets)
try:
if (len(subnet)==3 and 192<=int(subnet[0])<=223 and 0<=int(subnet[1])<=255 and 0<=int(subnet[2])<=255):
#return subnet_Addr
print('valid subnet: ',subnet_Addr)
for ip in range(11,40,2):
ip_temp = subnet_Addr + '.' + str(ip)
ip_list.append(ip_temp)
return ip_list
else:
value = 'wrong subnet entered'
print(value)
except ValueError:
print('wrong subnet entered, octects must be digits')
# Step 2: process input 2 (read port numbers from ports.txt):
def read_ports():
with open("ports.txt", 'r') as file_path:
port_list = []
for port in file_path:
try:
if int(port) in port_list:
print(f'port: {port} already exists')
else:
port_list.append(int(port))
except:
print(f'the port number: {port} is not a valid integer')
return port_list
else:
print('ports.txt is empty \n .... Exiting Port Scan App')
sys.exit()
# Step 3: scan ports
def scan_ports(ip,port):
# to get and format system time
dateTimeObj = datetime.now()
timeStamp = dateTimeObj.strftime("%d-%b-%Y (%H:%M:%S)")
try:
# open log file
with open("ip_port_log.txt","+r") as log:
# create client socket
socket.setdefaulttimeout(0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((ip,port))
if result == 0:
data = "IP:" + ip + ":" + str(port) + " Open " + timeStamp
# write_to_console or display on screen
print(data)
# write in log file
log.write(data + "\n")
else:
data = "IP:" + ip + ":" + str(port) + " Closed/Filtered or host is offline " + timeStamp
# write_to_console or display on screen
print(data)
# write in log file
log.write(data + "\n")
# close the client socket
sock.close()
except socket.error:
print("Can't connect to IP: ", ip)
sys.exit()
except KeyboardInterrupt:
print("User pressed Ctrl+c")
sys.exit()
# Step 4: Report to Event Viewer
# output 3
def report_to_EventViewer(mylist, eventtype):
IP_EVT_APP_NAME = " CheckIPPort - IP-Port Scan Application"
IP_EVT_ID = 7040 ##According to ???
IP_EVT_CATEG = 9876 ##According to ???
IP_EVT_TYPE = win32evtlog.EVENTLOG_WARNING_TYPE # WARNING=2
IP_EVT_ERR = win32evtlog.EVENTLOG_ERROR_TYPE # ERROR=1
IP_EVT_STRS = mylist
IP_EVT_DATA = b"Scan IP Address Event Data"
win32evtlogutil.ReportEvent(IP_EVT_APP_NAME, \
IP_EVT_ID, \
eventCategory=IP_EVT_CATEG, \
eventType=eventtype, \
strings=IP_EVT_STRS, \
data=IP_EVT_DATA)
main()
you issue is in your read_ports method, you return inside the loop so it will ALWAYS only read the first one. Rewrite the method to something like:
def read_ports():
with open("ports.txt", 'r') as file_path:
port_list = []
for port in file_path:
try:
if int(port) in port_list:
print(f'port: {port} already exists')
else:
port_list.append(int(port))
except:
print(f'the port number: {port} is not a valid integer')
if not len(port_list):
print('ports.txt is empty \n .... Exiting Port Scan App')
sys.exit()
return port_list
I am trying to do the port scanner from the Violent Python and I ran into following problem. This post will be similar to this post ("https://stackoverflow.com/questions/17807992/violent-python-port-inputs-not-being-seperated") but it is a different problem. I want to run multiple port like this
python PortScanner.py -H www.google.com -p 21, 22, 80
but it scanned only the initial first port (21) then exited the program So I want to know how can I fix this code to run multiple ports.
Note: It also said that args in (option, args) = parser.parse_args() is not accessible by Pylance so is it concern to it or how can I fix it as well.
import optparse
import socket
from socket import *
def connscan(tgtHost,tgtPorts):
try:
connSkt= socket(AF_INET,SOCK_STREAM)
connSkt.connect((tgtHost, tgtPorts))
connSkt.send('Violent Python\r\n')
results = connSkt.recv(100)
print ('[+]%d/tcp open'% tgtPorts)
print ('[+]' + str(results))
connSkt.close()
except:
print ('[-]%d/tcp closed'% tgtPorts)
def PortScan(tgtHost,tgtPorts):
try:
tgtIP=gethostbyname(tgtHost)
except:
print ("[-] Cannot resolve '%s': Unkown host"%tgtHost)
return
try:
tgtName= gethostbyaddr(tgtIP)
print ("\n[+] Scan Result for: "+ tgtName[0])
except:
print ("\n[+] Scan Result for: " + tgtIP)
setdefaulttimeout(1)
for tgtPort in tgtPorts:
print ("Scanning Port " + tgtPort)
connscan(tgtHost,int(tgtPort))
def main():
parser = optparse.OptionParser('Usage: %prog -H ' +\
'<target host> -p <target port>')
parser.add_option('-H', dest = 'tgtHost', type = 'string', \
help = 'specify target host')
parser.add_option('-p', dest = 'tgtPort', type = 'int', \
help = 'Specify target port' )
(options,args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPorts = str(options.tgtPort).split(',')
if ( tgtHost == None) | (tgtPorts[0] == None):
print(parser.usage)
exit (0)
print(*tgtPorts, sep=", ")
PortScan(tgtHost,tgtPorts)
if __name__ == '__main__':
main()
I managed to solve the problem by changing the type of tgtPort from int to string and use quote as following at the command line python PortScanner.py -H www.google.com -p "21, 22, 80".
So this script is meant to telnet into a router and change the IP address on the given interface. However, my script runs into errors and I'm not sure why. The line that errors out is line 44.
This is my python script:
import os
import sys
import telnetlib
if (len(sys.argv) != 3):
print "syntax: python hw06.py <device> <newip>"
sys.exit()
router = sys.argv[1]
newip = sys.argv[2]
interface = "Serial0/0" # must hard code the interface to avoid disaster
TIMEOUT = 3
password1 = "user"
password2 = "cisco"
cmd = "ip address 111.11.111.11 255.255.255.0"
# 1. create a telnet object
tn = telnetlib.Telnet(router, timeout=TIMEOUT)
# 2. login/telnet to the router
tn.read_until("Password: ", TIMEOUT)
tn.write(password1 + "\n")
# 3. enter into the privilege mode
tn.write("enable\n")
tn.read_until("Password:")
tn.write(password2 + "\n")
# 4. enter into the configuration mode
tn.write("configure terminal\n")
tn.read_until("(config)#", TIMEOUT)
# 5. enter into the interface configuration mode
tn.write("int" + interface + "\n")
tn.read_until("(config-if)#", TIMEOUT)
# 6. set the new IP address
tn.write(cmd + "\r\n")
# 7. exit
# exit from the interface configruaiton mode
tn.write("exit\n")
# exit from the configuraiotn mode
tn.write("exit\n")
# exit from the privilege mode
tn.write("exit\n")
print tn.read_all() # this line is required, but not sure why?
tn.close()
oid = ".1.3.6.1.2.1.4.20.1.1"
snmp = "snmpwalk -v2c -c public %s %s" % (router, oid)
# Verify the output via SNMP
fp = os.popen( snmp )
snmp = fp.read().splitlines() # split the outout into a list of "lines"
flag = 0
for line in snmp:
inline = line.rstrip('\n')
list = inline.split()
ip = list[3] # IP address is the 4th item on the list
if ip == newip:
print "The new IP address (%s) is successfully configured on Serial0/0 of %s" % (ip, router)
flag = 1
break
if flag == 0:
print "failed operation: %s is not configured on Serial0/0 of %s" % (newip, router)
Now when I run the script, i input "python script.py deviceIPaddress newInterfaceIPaddress" this is what i get:
ip address 111.11.111.11 255.255.255.0
^
% Invalid input detected at '^' marker.
Router4(config)#exit
Router4#exit
failed operation: 111.11.111.11 is not configured on Serial0/0 of <device>
Any idea why I'm getting that invalid input error?
Thank you in advanced!
I am have an issue regarding a python assignment I was doing and would like to ask the community for some guidance. I am to use the socket module and argparse modules only for this assignment. I have created a socketserver.py file and a socketclient.py file. The connection between the server and client is fine. Now the purpose of the assignment is that the client is to send the Lottery game type, # of tickets, and # of lines per tickets using argparse. E.g. syntax for socketclient.py would be python3 -t Lotto_Max -n 2 -l 2. The output for the ticket game, ticket type and number of lines per ticket show up correctly on the server. However, they sometimes don't show correctly on the client, and am really stuck at the moment. Here is my following code....
Server Code
```socketserver.py code```
import socket
from random import sample
def main():
host = input("Please specify an IP address for this server's socket\t")
port = int(input('Please speciy a port number above 1024 for this socket.\t'))
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
kulmiye.bind((host, port))
except socket.error as egeh:
print('Socket bind failed. Error Code : ' + str(egeh[0]) + ' Message ' + egeh[1])
print('Socket bind accomplished...\n')
print("Listening for an incoming connection...")
kulmiye.listen()
conn, addr = kulmiye.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
while True:
server_data = conn.recv(1024).decode("utf-8")
game_data = server_data.split(",")
if not server_data:
break
if game_data[0] == "Lotto_Max":
nval = int(game_data[1])
lval = int(game_data[2])
for nval in range(nval):
for i in range(lval):
numbers = sample(range(1, 50), 7)
numbers.sort()
sortedd = str(numbers)
print(sortedd)
print("--------------------")
conn.sendall(sortedd.encode("utf-8"))
#conn.sendall(bytes(str(numbers),'utf-8'))
liners = "-----------------------"
conn.sendall(liners.encode("utf-8"))
print("From Client: " + str(game_data))
conn.sendall(b'goodbye')
# server_data = input('#\t')
break
else:
conn.close()
if __name__ == '__main__':
main()
Client Code
```socketclient.py code```
import socket
import argparse
def client():
host = input("Please specify the server's IP you want to connect to\t")
port = int(input("Please specify the server's port you want to connect to\t"))
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.connect((host, port))
# client_data = input("#\t")
# while True:
# client_data = input()
# if client_data == 'quit':
# kulmiye.close()
# sys.exit()
# if len(str.encode(client_data)) > 0:
# kulmiye.sendall(str.encode(client_data))
# server_response = str(kulmiye.recv(1024), "utf-8")
# print(server_response, end = " ")
kulmiye.sendall(bytes(tvar.encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(nval).encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(lval).encode("utf-8")))
server_data = kulmiye.recv(1024).decode("utf-8")
while server_data != 'goodbye':
server_data = kulmiye.recv(1024).decode("utf-8")
print('Server: \n' + server_data)
# client_data = input("#\t")
if not server_data:
break
kulmiye.close()
# this code block serves to give the user the ability to play lotto max
# with the amount of tickets and lines per ticket they would like
# Using the argparse module to allow the user to input command-line interfaces
parser = argparse.ArgumentParser(description='Welcome to OLG Gaming.')
parser.add_argument(
'-t',
type=str,
help="Pick the lottery you want to play",
required=True)
parser.add_argument(
'-n',
type=int,
help="Pick the amount of lottery tickets you want to play",
required=True)
parser.add_argument(
'-l',
type=int,
help="Pick the amount of lines you would like to play",
required=True)
# parser.add_argument('-o', type = str, help = "This is optional", required = False)
# parse_args will convert the argument strings into objects and will get
# stored in the cmdargs variable
cmdargs = parser.parse_args()
tvar = cmdargs.t # the t string argument that gets parsed into an object will get stored into a variable called tvar
# the n integer argument that gets parsed into an object will get stored
# into a variable called nval
nval = int(cmdargs.n)
# the l integer argument that gets parsed into an object will get stored
# into a variable called lval
lval = int(cmdargs.l)
if __name__ == "__main__":
client()
```code```
Server
python3 socketserver.py
specify localhost as IP
specify a port e.g. 4444
Client
python3 socketclient.py -t Lotto_Max -n 1 -l 1
specify an IP address to connect to the server (e.g. localhost or 127.0.0.1)
specify a port to connect to e.g. 4444
When the connection establishes between client and server, the server receives the client input and prints it on its end the gametype (Lotto_Max), number of tickets and lines per ticket
Server will output the resultse.g.
However, the client won't receive it indefinitely. Usually it'll get it about 25% of the time, and I am not sure why
One problem is here in the server:
server_data = conn.recv(1024).decode("utf-8")
conn.recv(1024) can receive any number of bytes from 0 (closed connection) to 1024. The line above assumes the whole message is received every time, but when it fails it only gets part of the message. Below I've modified your code so the server can process multiple client connections one at a time, and the client will connect/disconnect over and over again to hasten the failure:
Server:
import socket
from random import sample
def main():
host = ''
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.bind((host, port))
print('Socket bind accomplished...\n')
print("Listening for an incoming connection...")
kulmiye.listen()
while True:
conn, addr = kulmiye.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
with conn:
server_data = conn.recv(1024).decode("utf-8")
print(f'server_data={server_data}')
game_data = server_data.split(",")
print("From Client: " + str(game_data))
if server_data:
if game_data[0] == "Lotto_Max":
nval = int(game_data[1])
lval = int(game_data[2])
for nval in range(nval):
for i in range(lval):
numbers = sample(range(1, 50), 7)
numbers.sort()
sortedd = str(numbers)
print(sortedd)
print("--------------------")
conn.sendall(sortedd.encode("utf-8"))
liners = "-----------------------"
conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
if __name__ == '__main__':
main()
Client:
import socket
import argparse
def client():
host = 'localhost'
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.connect((host, port))
kulmiye.sendall(bytes(tvar.encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(nval).encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(lval).encode("utf-8")))
server_data = kulmiye.recv(1024).decode("utf-8")
while server_data != 'goodbye':
server_data = kulmiye.recv(1024).decode("utf-8")
print('Server: \n' + server_data)
# client_data = input("#\t")
if not server_data:
break
kulmiye.close()
tvar = 'Lotto_Max'
nval = 1
lval = 1
if __name__ == "__main__":
while True:
client()
Here's the result after 100s of successful connections. Note server_data between the successful and unsuccessful connection:
Connected with 127.0.0.1:12175
server_data=Lotto_Max,1,1
From Client: ['Lotto_Max', '1', '1']
[4, 7, 9, 12, 24, 31, 48]
--------------------
Connected with 127.0.0.1:12176
server_data=Lotto_Max,1,
From Client: ['Lotto_Max', '1', '']
Traceback (most recent call last):
File "C:\server.py", line 38, in <module>
main()
File "C:\server.py", line 24, in main
lval = int(game_data[2])
ValueError: invalid literal for int() with base 10: ''
conn.recv(1024) didn't receive the complete message (didn't get the final 1). TCP is a byte streaming protocol with no concept of message boundaries. You're code is responsible to call recv() and buffer the data until you have a complete message. You could send fixed-sized messages and call recv until you have that many bytes, terminate a message with a sentinel byte such as a newline(\n) and read until the sentinel is received, or send the size of the message first followed by the message bytes.
I won't solve it for you since it is an assignment, but as a hint socket.makefile can wrap the socket in a file-like object where you can call .read(n) to read exactly n bytes from a socket, or .readline() to read a \n-terminated line.
Here's a link to an answer of mine that demonstrates this: https://stackoverflow.com/a/55840026/235698
Another example of the streaming nature of TCP is on the client side. Sometimes, it prints:
-----------------------
Server:
goodbye
Server:
-----------------------goodbye
Server:
Server:
-----------------------
Server:
goodbye
The separate lines in the server:
conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
Sometimes get received by the single recv in the client:
server_data = kulmiye.recv(1024).decode("utf-8")
Again, this is due to the streaming nature of TCP and no message boundaries. If you sent each line terminated by a newline, you could call recv() a number of times until a newline was detected, then process just that line.
Another answer that illustrates this technique is here: https://stackoverflow.com/a/55186805/235698.
Thank you Mark Tolonen for your guidance. I still need to brush up how to handle TCP data stream. Nevertheless, I was able to achieve more desirable results using numerous
conn.sendall within my nested for loop. Happy camper!
I've been editing this port scanner for an information security project.
The code works but throws errors (Pycharm Edu) on lines 63 and 34 in that order.
The error message for line 63 is: 'line 63, in
checkhost(target). I've looked at this and can't see why this would throw an error specifically as it is defined on line 34.
The error message for line 34 is: 'NameError: global name 'conf' is not defined'. It's not clear why this is a problem either.
Any help is much appreciated.
The Python code environment is Python 2.7.10
#! /usr/bin/python
from logging import getLogger, ERROR # Import Logging Things
getLogger("scapy.runtime").setLevel(ERROR) # Get Rid if IPv6 Warning
import scapy
import sys
from datetime import datetime # Other stuff
from time import strftime
try:
target = raw_input("[*] Enter Target IP Address: ")
min_port = raw_input("[*] Enter Minumum Port Number: ")
max_port = raw_input("[*] Enter Maximum Port Number: ")
try:
if int(min_port) >= 0 and int(max_port) >= 0 and
int(max_port) >= int(min_port): # Test for valid range of ports
pass
else: # If range didn't raise error, but didn't meet criteria
print "\n[!] Invalid Range of Ports"
print "[!] Exiting..."
sys.exit(1)
except Exception: # If input range raises an error
print "\n[!] Invalid Range of Ports"
print "[!] Exiting..."
sys.exit(1)
except KeyboardInterrupt: # In case the user wants to quit
print "\n[*] User Requested Shutdown..."
print "[*] Exiting..."
sys.exit(1)
ports = range(int(min_port), int(max_port)+1)
start_clock = datetime.now() # Start clock for scan time
SYNACK = 0x12 # Set flag values for later reference
RSTACK = 0x14
def checkhost(target): # Function to check if target is up
conf.verb = 0 # Hide output
try:
ping = sr1(IP(dst = ip)/ICMP()) # Ping the target
print "\n[*] Target is Up, Beginning Scan..."
except Exception: # If ping fails
print "\n[!] Couldn't Resolve Target"
print "[!] Exiting..."
sys.exit(1)
def scanport(port): # Function to scan a given port
try:
srcport = RandShort() # Generate Port Number
conf.verb = 0 # Hide output
SYNACKpkt = sr1(IP(dst = target)/TCP(sport = srcport,
dport = port,flags = "S"))
pktflags = SYNACKpkt.getlayer(TCP).flags
if pktflags == SYNACK: # Cross reference Flags
return True # If open, return true
else:
return False
RSTpkt = IP(dst = target)/TCP(sport = srcport, dport = port,
flags = "R") # Construct RST packet send(RSTpkt)
except KeyboardInterrupt: # In case the user needs to quit
RSTpkt = IP(dst = target)/TCP(sport = srcport, dport = port,
flags = "R") send(RSTpkt)
print "\n[*] User Requested Shutdown..."
print "[*] Exiting..."
sys.exit(1)
checkhost(ip) # Run checkhost() function from earlier
print "[*] Scanning Started at " + strftime("%H:%M:%S") + "!\n"
for port in ports: # Iterate through range of ports
status = scanport(port) # Feed each port into scanning function
if status == True: # Test result
print "Port " + str(port) + ": Open" # Print status
stop_clock = datetime.now() # Stop clock for scan time
total_time = stop_clock - start_clock # Calculate scan time
print "\n[*] Scanning Finished!" # Confirm scan stop
print "[*] Total Scan Duration: " + str(total_time) # Print scan time
The problem is with your import statement, it should
be:
>>> import scapy
>>> from scapy.all import conf
>>> conf.verb = 0
or even better to get rid of possible similar errors in the future
just import scapy as:
>>> from scapy.all import *
>>> conf.verb = 0
Now it should work fine.