From f21bf854c118420d4e79b348f2a898eab4454c49 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Fri, 5 Nov 2021 12:18:44 +0100 Subject: [PATCH 01/12] To Python3 --- birp.py | 112 +++++++++++++++++++++++------------------------ py3270wrapper.py | 16 +++---- tn3270.py | 22 +++++----- 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/birp.py b/birp.py index e88891b..c927b74 100755 --- a/birp.py +++ b/birp.py @@ -54,7 +54,7 @@ Alt-F12 - PF24\n\n\ Hitting Enter, any of the PF/PA keys, or Ctrl-u will record a transaction." -color_key = u"\nColor Key\n\ +color_key = "\nColor Key\n\ =========\n\n\ \u2219\t\t\t- Start of field marker" + Style.RESET_ALL + "\n\ Hidden Fields\t\t- " + Back.RED + "Red background" + Style.RESET_ALL + "\n\ @@ -77,7 +77,7 @@ def logger(text, kind='clear', level=0): if level == 1: lvldisp = "\t" elif level == 2: lvldisp = "\t\t" elif level == 3: lvldisp = "\t\t\t" - print lvldisp+typdisp+text + print(lvldisp+typdisp+text) # Update a screen object with the latest x3270 screen def update_screen(em,screen): @@ -200,11 +200,11 @@ def interactive(em,history): em.exec_command('Right()') elif key == getch.KEY_ENTER: # Enter trans = exec_trans(em,history,'enter') - print trans.response.colorbuffer + print(trans.response.colorbuffer) logger('Enter entered',kind='info') elif key == getch.KEY_CTRLr: # Ctrl-r print screen screen = update_screen(em,screen) - print screen.colorbuffer + print(screen.colorbuffer) logger('Screen refreshed',kind='info') elif key == getch.KEY_CTRLu: # Ctrl-u manually push transaction screen = update_screen(em,screen) @@ -213,12 +213,12 @@ def interactive(em,history): host = hostinfo[1]+':'+hostinfo[2] trans = tn3270.Transaction(history.last().response,screen,data,'manual',host) history.append(trans) - print screen.colorbuffer + print(screen.colorbuffer) logger('Transaction added',kind='info') elif key == getch.KEY_CTRLh: # Ctrl-h help - print interactive_help + print(interactive_help) elif key == getch.KEY_CTRLk: # Ctrl-k color key - print color_key + print(color_key) elif key == getch.KEY_CTRLp: # Ctrl-p python shell embed() elif key == getch.KEY_CTRLs: # Ctrl-s screenshot @@ -234,66 +234,66 @@ def interactive(em,history): em.exec_command('Clear()') elif key == getch.KEY_CTRLq: # Ctrl-q PA1 trans = exec_trans(em,history,25) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_CTRLw: # Ctrl-w PA2 trans = exec_trans(em,history,26) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_CTRLe: # Ctrl-e PA3 trans = exec_trans(em,history,27) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key > 31 and key < 127: # Alphanumeric em.safe_send(chr(key)) elif key == getch.KEY_F1: trans = exec_trans(em,history,1) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F2: trans = exec_trans(em,history,2) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F3: trans = exec_trans(em,history,3) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F4: trans = exec_trans(em,history,4) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F5: trans = exec_trans(em,history,5) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F6: trans = exec_trans(em,history,6) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F7: trans = exec_trans(em,history,7) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F8: trans = exec_trans(em,history,8) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F9: trans = exec_trans(em,history,9) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F10: trans = exec_trans(em,history,10) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F11: trans = exec_trans(em,history,11) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_F12: trans = exec_trans(em,history,12) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_AltF8: trans = exec_trans(em,history,13) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_AltF9: trans = exec_trans(em,history,14) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_AltF10: trans = exec_trans(em,history,15) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_AltF11: trans = exec_trans(em,history,16) - print trans.response.colorbuffer + print(trans.response.colorbuffer) elif key == getch.KEY_AltF12: trans = exec_trans(em,history,24) - print trans.response.colorbuffer + print(trans.response.colorbuffer) def save_history(history,savefile): if path.exists(savefile): @@ -324,29 +324,29 @@ def load_history(loadfile): def print_trans(history,num,header): trans = history[num] if header: - print "\n",Fore.BLUE,"View Transaction",Fore.RESET - print Fore.BLUE,"================",Fore.RESET - print "\n",Fore.YELLOW,num,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ - "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET - print " Req : ",trans.request.stringbuffer[0] + print("\n",Fore.BLUE,"View Transaction",Fore.RESET) + print(Fore.BLUE,"================",Fore.RESET) + print("\n",Fore.YELLOW,num,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ + "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET) + print(" Req : ",trans.request.stringbuffer[0]) for field in trans.data: - print " Data: row:",field.row,"col:",field.col,"str:",Fore.RED,field.contents,Fore.RESET - print " Resp: ",trans.response.stringbuffer[0],'\n' + print(" Data: row:",field.row,"col:",field.col,"str:",Fore.RED,field.contents,Fore.RESET) + print(" Resp: ",trans.response.stringbuffer[0],'\n') # todo have print_history call print_trans rather def print_history(history): - print "\n",Fore.BLUE,"Transaction List",Fore.RESET - print Fore.BLUE,"================",Fore.RESET,"\n" + print("\n",Fore.BLUE,"Transaction List",Fore.RESET) + print(Fore.BLUE,"================",Fore.RESET,"\n") count = 0 for trans in history: - print Fore.YELLOW,count,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ - "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET - print " Req : ",trans.request.stringbuffer[0] + print(Fore.YELLOW,count,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ + "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET) + print(" Req : ",trans.request.stringbuffer[0]) for field in trans.data: fieldtxt = field.contents.strip() if len(fieldtxt) > 0: - print " Data: row:",field.row,"col:",field.col,"str:",Fore.RED,fieldtxt,Fore.RESET - print " Resp: ",trans.response.stringbuffer[0],"\n" + print(" Data: row:",field.row,"col:",field.col,"str:",Fore.RED,fieldtxt,Fore.RESET) + print(" Resp: ",trans.response.stringbuffer[0],"\n") count += 1 def menu_save(history): @@ -357,14 +357,14 @@ def menu_save(history): logger(''.join([Fore.CYAN,'History saved to ',savefile,Fore.RESET]),kind='info') def print_seq(history,start,stop): - print '\n' * 100 + print('\n' * 100) for trans in history[start:stop+1]: - print '\n' * 101 - print trans.request + print('\n' * 101) + print(trans.request) sleep(1) - print '\n' * 100 - print Fore.RED,trans.key,Fore.RESET - print trans.response + print('\n' * 100) + print(Fore.RED,trans.key,Fore.RESET) + print(trans.response) sleep(1) # this will print two copies of the individual screen @@ -381,29 +381,29 @@ def menu_screen(transaction, reqres): if reqres: screen = transaction.request else: screen = transaction.response key = '' - print screen.colorbuffer + print(screen.colorbuffer) while key != getch.KEY_x: logger(''.join([Fore.CYAN,"Type 'f' to view the screen's fields or 'p' to view the un-markedup screen, 'e' to view the screen as an emulator would, 'r' to switch between the Request/Response, or 's' to export a copy to a text file (.brp/.emu). Type 'x' to go back.",Fore.RESET]),kind='info') key = getch() if key == getch.KEY_f or key == getch.KEY_F: - print Fore.BLUE,"View Fields",Fore.RESET - print Fore.BLUE,"===========",Fore.RESET,"\n" + print(Fore.BLUE,"View Fields",Fore.RESET) + print(Fore.BLUE,"===========",Fore.RESET,"\n") pprint(screen.fields) logger(''.join([Fore.RED,"Dropping into shell, check the",Fore.BLUE," screen ",Fore.RED,"object. Type quit() to return here.",Fore.RESET,"\n\n"]),kind='info') embed() elif key == getch.KEY_p or key == getch.KEY_p: - print '\n',screen + print('\n',screen) elif key == getch.KEY_e or key == getch.KEY_e: - print '\n',screen.emubuffer + print('\n',screen.emubuffer) elif key == getch.KEY_r or key == getch.KEY_r: reqres = not reqres if reqres: screen = transaction.request - print Fore.BLUE,'REQUEST',Fore.RESET + print(Fore.BLUE,'REQUEST',Fore.RESET) else: screen = transaction.response - print Fore.BLUE,'RESPONSE',Fore.RESET - print screen.colorbuffer + print(Fore.BLUE,'RESPONSE',Fore.RESET) + print(screen.colorbuffer) elif key == getch.KEY_s or key == getch.KEY_s: filename = transaction.host+'_'+str(transaction.timestamp.date())+'_'+str(transaction.timestamp.time()) screentofile(screen, filename) @@ -463,7 +463,7 @@ def menu_find(history): def menu(em, history): key = '' while key != getch.KEY_CTRLc: - print menu_list + print(menu_list) key = getch() if key == getch.KEY_1: diff --git a/py3270wrapper.py b/py3270wrapper.py index 5818e5f..4a76b10 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -12,8 +12,8 @@ def __init__(self, visible=True, delay=0): try: Emulator.__init__(self, visible) self.delay = delay - except OSError, e: - print("Can't run x3270, are you sure it's in the right place? Actual error: "+str(e)) + except OSError as e: + print(("Can't run x3270, are you sure it's in the right place? Actual error: "+str(e))) exit(1) def send_enter(self): # Allow a delay to be configured @@ -27,7 +27,7 @@ def screen_get(self): # Send text without triggering field protection def safe_send(self, text): - for i in xrange(0,len(text)): + for i in range(0,len(text)): self.send_string(text[i]) if self.status.field_protection == 'P': return False # We triggered field protection, stop @@ -45,19 +45,19 @@ def safe_fieldfill(self, ypos, xpos, tosend, length): return True # Hah, we win, take that mainframe else: return False # we entered what we could, bailing - except CommandError, e: + except CommandError as e: # We hit an error, get mad return False # if str(e) == 'Keyboard locked': # Search the screen for text when we don't know exactly where it is, checking for read errors def find_response(self, response): - for rows in xrange(1,int(self.status.row_number)+1): - for cols in xrange(1,int(self.status.col_number)+1-len(response)): + for rows in range(1,int(self.status.row_number)+1): + for cols in range(1,int(self.status.col_number)+1-len(response)): try: if self.string_found(rows, cols, response): return True - except CommandError, e: + except CommandError as e: # We hit a read error, usually because the screen hasn't returned # increasing the delay works sleep(self.delay) @@ -93,5 +93,5 @@ class WrappedEmulator(EmulatorIntermediate): logger('Your Platform:', platform.system(), 'is not supported at this time.',kind='err') sys.exit(1) if not path.isfile(x3270App.executable): - print("Can't find the x3270 executable at "+x3270App.executable+" You can configure the location at the bottom of py3270wrapper.py") + print(("Can't find the x3270 executable at "+x3270App.executable+" You can configure the location at the bottom of py3270wrapper.py")) exit(1) diff --git a/tn3270.py b/tn3270.py index 92d94bb..328f581 100644 --- a/tn3270.py +++ b/tn3270.py @@ -20,7 +20,7 @@ def __init__(self, contents, row, col, rawstatus, printable=0, protected=0, nume self.modify = modify def __repr__(self): - a = "" + a = "" return ''.join(a) def __str__(self): @@ -76,7 +76,7 @@ def __str__(self): return '\n'.join(self.stringbuffer).replace('\x00',' ') def __repr__(self): - a = "" + a = "" return ''.join(a) @property @@ -120,11 +120,11 @@ def colorbuffer(self): if not styleflag: newline.append(Style.NORMAL) - newline.append(u'\u2219') #Field marker + newline.append('\u2219') #Field marker elif len(i) == 2: if i == '00': - newline.append(u"\u2400") + newline.append("\u2400") else: newline.append(i.decode("hex")) #newline.append(Fore.RESET+Back.RESET+Style.RESET_ALL) @@ -146,7 +146,7 @@ def emubuffer(self): attrib = int(i[3:5],16) val = int(i[6:8],16) - newline.append(u' ') #Field marker + newline.append(' ') #Field marker modflag = False hideflag = False @@ -162,9 +162,9 @@ def emubuffer(self): elif len(i) == 2: if i == '00': - newline.append(u' ') + newline.append(' ') elif hideflag: - newline.append(u' ') + newline.append(' ') else: newline.append(i.decode("hex")) colbuf.append(''.join(newline)) @@ -232,7 +232,7 @@ def fields(self): @property def protected_fields(self): try: - res = filter(lambda x: x.protected == 1, self.fields) + res = [x for x in self.fields if x.protected == 1] except IndexError: res = [] return res @@ -240,7 +240,7 @@ def protected_fields(self): @property def input_fields(self): try: - res = filter(lambda x: x.protected == 0, self.fields) + res = [x for x in self.fields if x.protected == 0] except IndexError: res = [] return res @@ -248,7 +248,7 @@ def input_fields(self): @property def hidden_fields(self): try: - res = filter(lambda x: x.hidden == 1, self.fields) + res = [x for x in self.fields if x.hidden == 1] except IndexError: res = [] return res @@ -256,7 +256,7 @@ def hidden_fields(self): @property def modified_fields(self): try: - res = filter(lambda x: x.modify == 1, self.fields) + res = [x for x in self.fields if x.modify == 1] except IndexError: res = [] return res From c41b5dc688d6ade2c8523c5e40555fd3e1fae155 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Fri, 5 Nov 2021 12:30:07 +0100 Subject: [PATCH 02/12] refactoring --- birp.py | 926 +++++++++++++++++++------------------- getch.py | 1108 +++++++++++++++++++++++----------------------- py3270wrapper.py | 157 +++---- tn3270.py | 583 ++++++++++++------------ 4 files changed, 1414 insertions(+), 1360 deletions(-) diff --git a/birp.py b/birp.py index c927b74..838b85a 100755 --- a/birp.py +++ b/birp.py @@ -2,13 +2,12 @@ from py3270wrapper import WrappedEmulator import tn3270 -import sys +import sys import argparse -import re import platform from time import sleep from os import path -from colorama import Fore,Back,Style,init +from colorama import Fore, Back, Style, init from IPython import embed from getch import getch import pickle @@ -61,487 +60,524 @@ Modified Fields\t\t- " + Fore.YELLOW + "Yellow text" + Style.RESET_ALL + "\n\ Input Fields\t\t- " + Back.GREEN + "Green background" + Style.RESET_ALL + "\n\ " -#Intensified Fields\t- " + Style.BRIGHT + "Bright text" + Style.RESET_ALL + "\n\ + + +# Intensified Fields\t- " + Style.BRIGHT + "Bright text" + Style.RESET_ALL + "\n\ # Print output that can be surpressed by a CLI opt def logger(text, kind='clear', level=0): - if results.quiet and (kind == 'warn' or kind == 'info'): - return - else: - typdisp = '' - lvldisp = '' - if kind == 'warn': typdisp = '[!] ' - elif kind == 'info': typdisp = '[+] ' - elif kind == 'err': typdisp = '[#] ' - elif kind == 'good': typdisp = '[*] ' - if level == 1: lvldisp = "\t" - elif level == 2: lvldisp = "\t\t" - elif level == 3: lvldisp = "\t\t\t" - print(lvldisp+typdisp+text) - -# Update a screen object with the latest x3270 screen -def update_screen(em,screen): - screen = tn3270.Screen(em.exec_command('ReadBuffer(Ascii)').data) - return screen + if results.quiet and (kind == 'warn' or kind == 'info'): + return + else: + typdisp = '' + lvldisp = '' + if kind == 'warn': + typdisp = '[!] ' + elif kind == 'info': + typdisp = '[+] ' + elif kind == 'err': + typdisp = '[#] ' + elif kind == 'good': + typdisp = '[*] ' + if level == 1: + lvldisp = "\t" + elif level == 2: + lvldisp = "\t\t" + elif level == 3: + lvldisp = "\t\t\t" + print(lvldisp + typdisp + text) + + +# Update a screen object with the latest x3270 screen +def update_screen(em, screen): + screen = tn3270.Screen(em.exec_command('ReadBuffer(Ascii)').data) + return screen + # Record the current screen, hit enter, and record the response -def exec_trans(em,history,key='enter'): - request = tn3270.Screen - response = tn3270.Screen - check = tn3270.Screen - request = update_screen(em,request) - keypress = '' - hostinfo = em.exec_command('Query(Host)').data[0].split(' ') - host = hostinfo[1]+':'+hostinfo[2] - data = request.modified_fields - if key == 'enter': - em.send_enter() - keypress = key - # PF1=1, PF24=24, PA1=25, PA3=27 - elif key > 0 and key < 25: - keypress = 'PF(' + str(key) + ')' - em.exec_command(keypress) - elif key > 25 and key < 28: - keypress = 'PA(' + str(key - 24) + ')' - em.exec_command(keypress) - em.exec_command('Wait(1,3270Mode)') #Capture the whole 3270 screen - response = update_screen(em,response) - trans = tn3270.Transaction(request,response,data,keypress,host) - history.append(trans) - return trans +def exec_trans(em, history, key='enter'): + request = tn3270.Screen + response = tn3270.Screen + check = tn3270.Screen + request = update_screen(em, request) + keypress = '' + hostinfo = em.exec_command('Query(Host)').data[0].split(' ') + host = hostinfo[1] + ':' + hostinfo[2] + data = request.modified_fields + if key == 'enter': + em.send_enter() + keypress = key + # PF1=1, PF24=24, PA1=25, PA3=27 + elif 0 < key < 25: + keypress = 'PF(' + str(key) + ')' + em.exec_command(keypress) + elif 25 < key < 28: + keypress = 'PA(' + str(key - 24) + ')' + em.exec_command(keypress) + em.exec_command('Wait(1,3270Mode)') # Capture the whole 3270 screen + response = update_screen(em, response) + trans = tn3270.Transaction(request, response, data, keypress, host) + history.append(trans) + return trans + # Compare two screens, allow a "fuzzy" match to account for time/terminal fields -def compare_screen(screen1,screen2,exact=False): - diffcount = 0 - linecount = 0 - for line in screen1.rawbuffer: - if screen1.rawbuffer[linecount] != screen2.rawbuffer[linecount]: - diffcount += 1 - if exact: - return 0 - elif diffcount > 2: - return 0 # More than two lines different they're different - return True # screens are the same - +def compare_screen(screen1, screen2, exact=False): + diffcount = 0 + linecount = 0 + for line in screen1.rawbuffer: + if screen1.rawbuffer[linecount] != screen2.rawbuffer[linecount]: + diffcount += 1 + if exact: + return 0 + elif diffcount > 2: + return 0 # More than two lines different they're different + return True # screens are the same + + # Currently unused -def find_first(history,text): - transid = 0 - row = 0 - rr = 0 - col = 0 - for trans in history: - row = 0 - # Check the request - for line in trans.request.stringbuffer: - rr = 0 - col = line.find(text) - if col >= 0: - return (transid,rr,row,col) - row += 1 - row = 0 - # Check the response - for line in trans.response.stringbuffer: - rr = 1 - col = line.find(text) - if col >= 0: - return (transid,rr,row,col) - row += 1 - transid += 1 - return (-1,-1,-1,-1) # Not found +def find_first(history, text): + transid = 0 + for trans in history: + row = 0 + # Check the request + for line in trans.request.stringbuffer: + rr = 0 + col = line.find(text) + if col >= 0: + return transid, rr, row, col + row += 1 + row = 0 + # Check the response + for line in trans.response.stringbuffer: + rr = 1 + col = line.find(text) + if col >= 0: + return transid, rr, row, col + row += 1 + transid += 1 + return -1, -1, -1, -1 # Not found + # Find text within the transaction history -def find_all(history,text): - result = list() - transid = 0 - row = 0 - rr = 0 - col = 0 - for trans in history: - row = 0 - # Check the request - for line in trans.request.stringbuffer: - rr = 0 - col = line.find(text) - if col >= 0: - result.append((transid,rr,row,col)) - row += 1 - row = 0 - # Check the response - for line in trans.response.stringbuffer: - rr = 1 - col = line.find(text) - if col >= 0: - result.append((transid,rr,row,col)) - row += 1 - transid += 1 - return result +def find_all(history, text): + result = list() + transid = 0 + for trans in history: + row = 0 + # Check the request + for line in trans.request.stringbuffer: + rr = 0 + col = line.find(text) + if col >= 0: + result.append((transid, rr, row, col)) + row += 1 + row = 0 + # Check the response + for line in trans.response.stringbuffer: + rr = 1 + col = line.find(text) + if col >= 0: + result.append((transid, rr, row, col)) + row += 1 + transid += 1 + return result + # Interactive mode, will record transactions, and display hacker view companion -def interactive(em,history): - key = '' - trans = '' - screen = '' - data = '' - logger("Interactive mode started! Hit ESC to exit",kind="info") - logger("Hit Ctrl-h for help. Start typing ...",kind="info") - while key != getch.KEY_ESC: - if not em.is_connected(): - logger(Fore.RED+"Emulator not connected, interactive mode prevented."+Fore.RESET,kind="err") - return - key = getch() - - if key == getch.KEY_UP: # Up - em.exec_command('Up()') - elif key == getch.KEY_DOWN: # Down - em.exec_command('Down()') - elif key == getch.KEY_LEFT: # Left - em.exec_command('Left()') - elif key == getch.KEY_RIGHT: # Right - em.exec_command('Right()') - elif key == getch.KEY_ENTER: # Enter - trans = exec_trans(em,history,'enter') - print(trans.response.colorbuffer) - logger('Enter entered',kind='info') - elif key == getch.KEY_CTRLr: # Ctrl-r print screen - screen = update_screen(em,screen) - print(screen.colorbuffer) - logger('Screen refreshed',kind='info') - elif key == getch.KEY_CTRLu: # Ctrl-u manually push transaction - screen = update_screen(em,screen) - data = screen.modified_fields - hostinfo = em.exec_command('Query(Host)').data[0].split(' ') - host = hostinfo[1]+':'+hostinfo[2] - trans = tn3270.Transaction(history.last().response,screen,data,'manual',host) - history.append(trans) - print(screen.colorbuffer) - logger('Transaction added',kind='info') - elif key == getch.KEY_CTRLh: # Ctrl-h help - print(interactive_help) - elif key == getch.KEY_CTRLk: # Ctrl-k color key - print(color_key) - elif key == getch.KEY_CTRLp: # Ctrl-p python shell - embed() - elif key == getch.KEY_CTRLs: # Ctrl-s screenshot - em.save_screen(str(trans.timestamp.date())+'_'+str(trans.timestamp.time())+'.html') - logger('Screenshot saved',kind='info') - elif key == getch.KEY_TAB: # Tab 9 - em.exec_command('Tab()') - elif key == getch.KEY_BACKSPACE: # Backspace - em.exec_command('BackSpace()') - elif key == getch.KEY_DELETE: # Delete - em.exec_command('Delete()') - elif key == getch.KEY_CTRLc: # Ctrl-c Clear - em.exec_command('Clear()') - elif key == getch.KEY_CTRLq: # Ctrl-q PA1 - trans = exec_trans(em,history,25) - print(trans.response.colorbuffer) - elif key == getch.KEY_CTRLw: # Ctrl-w PA2 - trans = exec_trans(em,history,26) - print(trans.response.colorbuffer) - elif key == getch.KEY_CTRLe: # Ctrl-e PA3 - trans = exec_trans(em,history,27) - print(trans.response.colorbuffer) - elif key > 31 and key < 127: # Alphanumeric - em.safe_send(chr(key)) - elif key == getch.KEY_F1: - trans = exec_trans(em,history,1) - print(trans.response.colorbuffer) - elif key == getch.KEY_F2: - trans = exec_trans(em,history,2) - print(trans.response.colorbuffer) - elif key == getch.KEY_F3: - trans = exec_trans(em,history,3) - print(trans.response.colorbuffer) - elif key == getch.KEY_F4: - trans = exec_trans(em,history,4) - print(trans.response.colorbuffer) - elif key == getch.KEY_F5: - trans = exec_trans(em,history,5) - print(trans.response.colorbuffer) - elif key == getch.KEY_F6: - trans = exec_trans(em,history,6) - print(trans.response.colorbuffer) - elif key == getch.KEY_F7: - trans = exec_trans(em,history,7) - print(trans.response.colorbuffer) - elif key == getch.KEY_F8: - trans = exec_trans(em,history,8) - print(trans.response.colorbuffer) - elif key == getch.KEY_F9: - trans = exec_trans(em,history,9) - print(trans.response.colorbuffer) - elif key == getch.KEY_F10: - trans = exec_trans(em,history,10) - print(trans.response.colorbuffer) - elif key == getch.KEY_F11: - trans = exec_trans(em,history,11) - print(trans.response.colorbuffer) - elif key == getch.KEY_F12: - trans = exec_trans(em,history,12) - print(trans.response.colorbuffer) - elif key == getch.KEY_AltF8: - trans = exec_trans(em,history,13) - print(trans.response.colorbuffer) - elif key == getch.KEY_AltF9: - trans = exec_trans(em,history,14) - print(trans.response.colorbuffer) - elif key == getch.KEY_AltF10: - trans = exec_trans(em,history,15) - print(trans.response.colorbuffer) - elif key == getch.KEY_AltF11: - trans = exec_trans(em,history,16) - print(trans.response.colorbuffer) - elif key == getch.KEY_AltF12: - trans = exec_trans(em,history,24) - print(trans.response.colorbuffer) - -def save_history(history,savefile): - if path.exists(savefile): - logger('Savefile exists, I won\'t overwrite yet',kind='err') - return False # Don't overwrite existing saves just yet - try: - sav = open(savefile,'w') - pickle.dump(history, sav) - sav.close() - except IOError: - logger('Saving didn\'t work.',kind='err') - return False - return True +def interactive(em, history): + key = '' + trans = '' + screen = '' + logger("Interactive mode started! Hit ESC to exit", kind="info") + logger("Hit Ctrl-h for help. Start typing ...", kind="info") + while key != getch.KEY_ESC: + if not em.is_connected(): + logger(Fore.RED + "Emulator not connected, interactive mode prevented." + Fore.RESET, kind="err") + return + key = getch() + + if key == getch.KEY_UP: # Up + em.exec_command('Up()') + elif key == getch.KEY_DOWN: # Down + em.exec_command('Down()') + elif key == getch.KEY_LEFT: # Left + em.exec_command('Left()') + elif key == getch.KEY_RIGHT: # Right + em.exec_command('Right()') + elif key == getch.KEY_ENTER: # Enter + trans = exec_trans(em, history, 'enter') + print(trans.response.colorbuffer) + logger('Enter entered', kind='info') + elif key == getch.KEY_CTRLr: # Ctrl-r print screen + screen = update_screen(em, screen) + print(screen.colorbuffer) + logger('Screen refreshed', kind='info') + elif key == getch.KEY_CTRLu: # Ctrl-u manually push transaction + screen = update_screen(em, screen) + data = screen.modified_fields + hostinfo = em.exec_command('Query(Host)').data[0].split(' ') + host = hostinfo[1] + ':' + hostinfo[2] + trans = tn3270.Transaction(history.last().response, screen, data, 'manual', host) + history.append(trans) + print(screen.colorbuffer) + logger('Transaction added', kind='info') + elif key == getch.KEY_CTRLh: # Ctrl-h help + print(interactive_help) + elif key == getch.KEY_CTRLk: # Ctrl-k color key + print(color_key) + elif key == getch.KEY_CTRLp: # Ctrl-p python shell + embed() + elif key == getch.KEY_CTRLs: # Ctrl-s screenshot + em.save_screen(str(trans.timestamp.date()) + '_' + str(trans.timestamp.time()) + '.html') + logger('Screenshot saved', kind='info') + elif key == getch.KEY_TAB: # Tab 9 + em.exec_command('Tab()') + elif key == getch.KEY_BACKSPACE: # Backspace + em.exec_command('BackSpace()') + elif key == getch.KEY_DELETE: # Delete + em.exec_command('Delete()') + elif key == getch.KEY_CTRLc: # Ctrl-c Clear + em.exec_command('Clear()') + elif key == getch.KEY_CTRLq: # Ctrl-q PA1 + trans = exec_trans(em, history, 25) + print(trans.response.colorbuffer) + elif key == getch.KEY_CTRLw: # Ctrl-w PA2 + trans = exec_trans(em, history, 26) + print(trans.response.colorbuffer) + elif key == getch.KEY_CTRLe: # Ctrl-e PA3 + trans = exec_trans(em, history, 27) + print(trans.response.colorbuffer) + elif 31 < key < 127: # Alphanumeric + em.safe_send(chr(key)) + elif key == getch.KEY_F1: + trans = exec_trans(em, history, 1) + print(trans.response.colorbuffer) + elif key == getch.KEY_F2: + trans = exec_trans(em, history, 2) + print(trans.response.colorbuffer) + elif key == getch.KEY_F3: + trans = exec_trans(em, history, 3) + print(trans.response.colorbuffer) + elif key == getch.KEY_F4: + trans = exec_trans(em, history, 4) + print(trans.response.colorbuffer) + elif key == getch.KEY_F5: + trans = exec_trans(em, history, 5) + print(trans.response.colorbuffer) + elif key == getch.KEY_F6: + trans = exec_trans(em, history, 6) + print(trans.response.colorbuffer) + elif key == getch.KEY_F7: + trans = exec_trans(em, history, 7) + print(trans.response.colorbuffer) + elif key == getch.KEY_F8: + trans = exec_trans(em, history, 8) + print(trans.response.colorbuffer) + elif key == getch.KEY_F9: + trans = exec_trans(em, history, 9) + print(trans.response.colorbuffer) + elif key == getch.KEY_F10: + trans = exec_trans(em, history, 10) + print(trans.response.colorbuffer) + elif key == getch.KEY_F11: + trans = exec_trans(em, history, 11) + print(trans.response.colorbuffer) + elif key == getch.KEY_F12: + trans = exec_trans(em, history, 12) + print(trans.response.colorbuffer) + elif key == getch.KEY_AltF8: + trans = exec_trans(em, history, 13) + print(trans.response.colorbuffer) + elif key == getch.KEY_AltF9: + trans = exec_trans(em, history, 14) + print(trans.response.colorbuffer) + elif key == getch.KEY_AltF10: + trans = exec_trans(em, history, 15) + print(trans.response.colorbuffer) + elif key == getch.KEY_AltF11: + trans = exec_trans(em, history, 16) + print(trans.response.colorbuffer) + elif key == getch.KEY_AltF12: + trans = exec_trans(em, history, 24) + print(trans.response.colorbuffer) + + +def save_history(history, savefile): + if path.exists(savefile): + logger('Savefile exists, I won\'t overwrite yet', kind='err') + return False # Don't overwrite existing saves just yet + try: + sav = open(savefile, 'w') + pickle.dump(history, sav) + sav.close() + except IOError: + logger('Saving didn\'t work.', kind='err') + return False + return True + def load_history(loadfile): - if not path.exists(loadfile): - logger("Couldn't find the history file" + loadfile + " bailing.",kind='err') - sys.exit(1) - try: - lod = open(loadfile,'r') - hist = pickle.load(lod) - lod.close() - except KeyError: - logger("That doesn't look like a BIRP file",kind='err') - sys.exit(1) - return hist - -def print_trans(history,num,header): - trans = history[num] - if header: - print("\n",Fore.BLUE,"View Transaction",Fore.RESET) - print(Fore.BLUE,"================",Fore.RESET) - print("\n",Fore.YELLOW,num,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ - "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET) - print(" Req : ",trans.request.stringbuffer[0]) - for field in trans.data: - print(" Data: row:",field.row,"col:",field.col,"str:",Fore.RED,field.contents,Fore.RESET) - print(" Resp: ",trans.response.stringbuffer[0],'\n') + if not path.exists(loadfile): + logger("Couldn't find the history file" + loadfile + " bailing.", kind='err') + sys.exit(1) + try: + lod = open(loadfile, 'r') + hist = pickle.load(lod) + lod.close() + except KeyError: + logger("That doesn't look like a BIRP file", kind='err') + sys.exit(1) + return hist + + +def print_trans(history, num, header): + trans = history[num] + if header: + print("\n", Fore.BLUE, "View Transaction", Fore.RESET) + print(Fore.BLUE, "================", Fore.RESET) + print("\n", Fore.YELLOW, num, Fore.BLUE, trans.timestamp, Fore.CYAN, trans.key, \ + "\t", Fore.BLUE, trans.host, trans.comment, Fore.RESET) + print(" Req : ", trans.request.stringbuffer[0]) + for field in trans.data: + print(" Data: row:", field.row, "col:", field.col, "str:", Fore.RED, field.contents, Fore.RESET) + print(" Resp: ", trans.response.stringbuffer[0], '\n') + # todo have print_history call print_trans rather def print_history(history): - print("\n",Fore.BLUE,"Transaction List",Fore.RESET) - print(Fore.BLUE,"================",Fore.RESET,"\n") - count = 0 - for trans in history: - print(Fore.YELLOW,count,Fore.BLUE,trans.timestamp,Fore.CYAN,trans.key,\ - "\t",Fore.BLUE,trans.host,trans.comment,Fore.RESET) - print(" Req : ",trans.request.stringbuffer[0]) - for field in trans.data: - fieldtxt = field.contents.strip() - if len(fieldtxt) > 0: - print(" Data: row:",field.row,"col:",field.col,"str:",Fore.RED,fieldtxt,Fore.RESET) - print(" Resp: ",trans.response.stringbuffer[0],"\n") - count += 1 + print("\n", Fore.BLUE, "Transaction List", Fore.RESET) + print(Fore.BLUE, "================", Fore.RESET, "\n") + count = 0 + for trans in history: + print(Fore.YELLOW, count, Fore.BLUE, trans.timestamp, Fore.CYAN, trans.key, \ + "\t", Fore.BLUE, trans.host, trans.comment, Fore.RESET) + print(" Req : ", trans.request.stringbuffer[0]) + for field in trans.data: + fieldtxt = field.contents.strip() + if len(fieldtxt) > 0: + print(" Data: row:", field.row, "col:", field.col, "str:", Fore.RED, fieldtxt, Fore.RESET) + print(" Resp: ", trans.response.stringbuffer[0], "\n") + count += 1 + def menu_save(history): - savefile = '' - logger(''.join([Fore.CYAN,'What file should I save to (must not exist): ',Fore.RESET]),kind='info') - savefile = sys.stdin.readline().strip() - if save_history(history,savefile): - logger(''.join([Fore.CYAN,'History saved to ',savefile,Fore.RESET]),kind='info') - -def print_seq(history,start,stop): - print('\n' * 100) - for trans in history[start:stop+1]: - print('\n' * 101) - print(trans.request) - sleep(1) - print('\n' * 100) - print(Fore.RED,trans.key,Fore.RESET) - print(trans.response) - sleep(1) + savefile = '' + logger(''.join([Fore.CYAN, 'What file should I save to (must not exist): ', Fore.RESET]), kind='info') + savefile = sys.stdin.readline().strip() + if save_history(history, savefile): + logger(''.join([Fore.CYAN, 'History saved to ', savefile, Fore.RESET]), kind='info') + + +def print_seq(history, start, stop): + print('\n' * 100) + for trans in history[start:stop + 1]: + print('\n' * 101) + print(trans.request) + sleep(1) + print('\n' * 100) + print(Fore.RED, trans.key, Fore.RESET) + print(trans.response) + sleep(1) + # this will print two copies of the individual screen -def screentofile(screen,path): - f = open(path+'.emu','w') - g = open(path+'.brp','w') - f.write(utf_8.encode(screen.emubuffer)[0]) - g.write(utf_8.encode(screen.colorbuffer)[0]) - f.close() - g.close() +def screentofile(screen, path): + f = open(path + '.emu', 'w') + g = open(path + '.brp', 'w') + f.write(utf_8.encode(screen.emubuffer)[0]) + g.write(utf_8.encode(screen.colorbuffer)[0]) + f.close() + g.close() + def menu_screen(transaction, reqres): - #If reqres is True, we show the request, if False, we show the response - if reqres: screen = transaction.request - else: screen = transaction.response - key = '' - print(screen.colorbuffer) - while key != getch.KEY_x: - logger(''.join([Fore.CYAN,"Type 'f' to view the screen's fields or 'p' to view the un-markedup screen, 'e' to view the screen as an emulator would, 'r' to switch between the Request/Response, or 's' to export a copy to a text file (.brp/.emu). Type 'x' to go back.",Fore.RESET]),kind='info') - key = getch() - if key == getch.KEY_f or key == getch.KEY_F: - print(Fore.BLUE,"View Fields",Fore.RESET) - print(Fore.BLUE,"===========",Fore.RESET,"\n") - pprint(screen.fields) - logger(''.join([Fore.RED,"Dropping into shell, check the",Fore.BLUE," screen ",Fore.RED,"object. Type quit() to return here.",Fore.RESET,"\n\n"]),kind='info') - embed() - elif key == getch.KEY_p or key == getch.KEY_p: - print('\n',screen) - elif key == getch.KEY_e or key == getch.KEY_e: - print('\n',screen.emubuffer) - elif key == getch.KEY_r or key == getch.KEY_r: - reqres = not reqres - if reqres: - screen = transaction.request - print(Fore.BLUE,'REQUEST',Fore.RESET) - else: - screen = transaction.response - print(Fore.BLUE,'RESPONSE',Fore.RESET) - print(screen.colorbuffer) - elif key == getch.KEY_s or key == getch.KEY_s: - filename = transaction.host+'_'+str(transaction.timestamp.date())+'_'+str(transaction.timestamp.time()) - screentofile(screen, filename) - -def menu_trans(history,num): - if num >= len(history) or num < 0: - logger(''.join([Fore.CYAN,"Whoops, that transaction doesn't exist.",Fore.RESET]),kind='info') - return 1 - trans = history[num] - key = '' - while key != getch.KEY_x: - print_trans(history,num,True) - logger(''.join([Fore.CYAN,"Choose '1' to view the Request, and '2' to view the Response. Type 'j' to move to the next transaction, and 'k' to the previous. Type 'x' to go back.",Fore.RESET]),kind='info') - - key = getch() - if key == getch.KEY_1: - menu_screen(trans, reqres=True) #reqres True shows request, False shows response - elif key == getch.KEY_2: - menu_screen(trans, reqres=False) - elif key == getch.KEY_j: - return menu_trans(history,num+1) - elif key == getch.KEY_k: - return menu_trans(history,num-1) - return 0 + # If reqres is True, we show the request, if False, we show the response + if reqres: + screen = transaction.request + else: + screen = transaction.response + key = '' + print(screen.colorbuffer) + while key != getch.KEY_x: + logger(''.join([Fore.CYAN, + "Type 'f' to view the screen's fields or 'p' to view the un-markedup screen, 'e' to view the screen as an emulator would, 'r' to switch between the Request/Response, or 's' to export a copy to a text file (.brp/.emu). Type 'x' to go back.", + Fore.RESET]), kind='info') + key = getch() + if key == getch.KEY_f or key == getch.KEY_F: + print(Fore.BLUE, "View Fields", Fore.RESET) + print(Fore.BLUE, "===========", Fore.RESET, "\n") + pprint(screen.fields) + logger(''.join([Fore.RED, "Dropping into shell, check the", Fore.BLUE, " screen ", Fore.RED, + "object. Type quit() to return here.", Fore.RESET, "\n\n"]), kind='info') + embed() + elif key == getch.KEY_p or key == getch.KEY_p: + print('\n', screen) + elif key == getch.KEY_e or key == getch.KEY_e: + print('\n', screen.emubuffer) + elif key == getch.KEY_r or key == getch.KEY_r: + reqres = not reqres + if reqres: + screen = transaction.request + print(Fore.BLUE, 'REQUEST', Fore.RESET) + else: + screen = transaction.response + print(Fore.BLUE, 'RESPONSE', Fore.RESET) + print(screen.colorbuffer) + elif key == getch.KEY_s or key == getch.KEY_s: + filename = transaction.host + '_' + str(transaction.timestamp.date()) + '_' + str( + transaction.timestamp.time()) + screentofile(screen, filename) + + +def menu_trans(history, num): + if num >= len(history) or num < 0: + logger(''.join([Fore.CYAN, "Whoops, that transaction doesn't exist.", Fore.RESET]), kind='info') + return 1 + trans = history[num] + key = '' + while key != getch.KEY_x: + print_trans(history, num, True) + logger(''.join([Fore.CYAN, + "Choose '1' to view the Request, and '2' to view the Response. Type 'j' to move to the next transaction, and 'k' to the previous. Type 'x' to go back.", + Fore.RESET]), kind='info') + + key = getch() + if key == getch.KEY_1: + menu_screen(trans, reqres=True) # reqres True shows request, False shows response + elif key == getch.KEY_2: + menu_screen(trans, reqres=False) + elif key == getch.KEY_j: + return menu_trans(history, num + 1) + elif key == getch.KEY_k: + return menu_trans(history, num - 1) + return 0 + def menu_history(history): - choice = '' - while choice.lower() != 'x': - print_history(history) - logger(''.join([Fore.CYAN,'Choose a transaction to view with the appropriate numeric key. Hit x, then enter to go back.',Fore.RESET]),kind='info') - - # We'll have more than just single digits here, so readline - choice = sys.stdin.readline().strip() - if choice.isdigit(): - key = int(choice) - if key >= 0 and key < len(history): - menu_trans(history,key) + choice = '' + while choice.lower() != 'x': + print_history(history) + logger(''.join( + [Fore.CYAN, 'Choose a transaction to view with the appropriate numeric key. Hit x, then enter to go back.', + Fore.RESET]), kind='info') + + # We'll have more than just single digits here, so readline + choice = sys.stdin.readline().strip() + if choice.isdigit(): + key = int(choice) + if 0 <= key < len(history): + menu_trans(history, key) + def menu_find(history): - choice = '' - while choice.lower() != 'x': - logger(''.join([Fore.CYAN,'Type the text you would like to search for and hit enter. Hit x, then enter to go back.',Fore.RESET]),kind='info') - - # We'll have more than just single digits here, so readline - choice = sys.stdin.readline().strip() - if choice.lower() == 'x': break - results = find_all(history,choice) # execute the search - for result in results: # print out the results, suppressing the header - print_trans(history,result[0],False) - logger(''.join([Fore.CYAN,'Choose a transaction to view with the appropriate numeric key. Hit x, then enter to go back.',Fore.RESET]),kind='info') - choice = sys.stdin.readline().strip() - if choice.isdigit(): - key = int(choice) - if key >= 0 and key < len(history): - return menu_trans(history,key) + choice = '' + while choice.lower() != 'x': + logger(''.join( + [Fore.CYAN, 'Type the text you would like to search for and hit enter. Hit x, then enter to go back.', + Fore.RESET]), kind='info') + + # We'll have more than just single digits here, so readline + choice = sys.stdin.readline().strip() + if choice.lower() == 'x': break + results = find_all(history, choice) # execute the search + for result in results: # print out the results, suppressing the header + print_trans(history, result[0], False) + logger(''.join( + [Fore.CYAN, 'Choose a transaction to view with the appropriate numeric key. Hit x, then enter to go back.', + Fore.RESET]), kind='info') + choice = sys.stdin.readline().strip() + if choice.isdigit(): + key = int(choice) + if 0 <= key < len(history): + return menu_trans(history, key) + def menu(em, history): - key = '' - while key != getch.KEY_CTRLc: - print(menu_list) - key = getch() - - if key == getch.KEY_1: - interactive(em,history) - elif key == getch.KEY_2: - menu_history(history) - elif key == getch.KEY_3: - menu_find(history) - elif key == getch.KEY_4: - embed() - elif key == getch.KEY_5: - menu_save(history) - elif key == getch.KEY_X or key == getch.KEY_x: - logger('Do big irons dream of electric paddocks? Goodnight.',kind='info') - sys.exit(0) + key = '' + while key != getch.KEY_CTRLc: + print(menu_list) + key = getch() + + if key == getch.KEY_1: + interactive(em, history) + elif key == getch.KEY_2: + menu_history(history) + elif key == getch.KEY_3: + menu_find(history) + elif key == getch.KEY_4: + embed() + elif key == getch.KEY_5: + menu_save(history) + elif key == getch.KEY_X or key == getch.KEY_x: + logger('Do big irons dream of electric paddocks? Goodnight.', kind='info') + sys.exit(0) + # Just an excuse to wrap this away in a fold def prestartup(): - init() # initialise coloured output from colorama - - # Define and fetch commandline arguments - parser = argparse.ArgumentParser(\ - description = 'Big Iron Recon & Pwnage (BIRP) by @singe',\ - epilog = "It's easier than you think" ) - parser.add_argument('-t', '--target',\ - help='Target IP address or hostname & port: TARGET[:PORT]. The default port is 23. If you don\'t specify a target, you can manually specify it in the emulator',\ - required = False, dest = 'target', default = "") - parser.add_argument('-s', '--sleep',\ - help='Seconds to sleep between actions (increase on slower systems). The default is 0 seconds.',\ - default = 0, type = float, dest = 'sleep') - parser.add_argument('-l', '--load', help='Load a previously saved history file', default='',\ - dest = 'loadfile', type = str) - parser.add_argument('-q', '--quiet', help="Ssssh! Don't print info text.",\ - default = False, dest = 'quiet', action = 'store_true') - results = parser.parse_args() - return results + init() # initialise coloured output from colorama + + # Define and fetch commandline arguments + parser = argparse.ArgumentParser( \ + description='Big Iron Recon & Pwnage (BIRP) by @singe', \ + epilog="It's easier than you think") + parser.add_argument('-t', '--target', \ + help='Target IP address or hostname & port: TARGET[:PORT]. The default port is 23. If you don\'t specify a target, you can manually specify it in the emulator', \ + required=False, dest='target', default="") + parser.add_argument('-s', '--sleep', \ + help='Seconds to sleep between actions (increase on slower systems). The default is 0 seconds.', \ + default=0, type=float, dest='sleep') + parser.add_argument('-l', '--load', help='Load a previously saved history file', default='', \ + dest='loadfile', type=str) + parser.add_argument('-q', '--quiet', help="Ssssh! Don't print info text.", \ + default=False, dest='quiet', action='store_true') + results = parser.parse_args() + return results + # Just an excuse to wrap this away in a fold def startup(): - # Parse commandline arguments - logger('Big Iron Recon & Pwnage (BIRP) by @singe',kind='info') - if not results.target: - logger('Manual target selection chosen.',kind='info') - else: - logger('Target Acquired\t\t: ' + results.target,kind='info') - logger('Slowdown is\t\t\t: ' + str(results.sleep),kind='info') - logger('Attack platform\t\t: ' + platform.system(),kind='info') - - if not platform.system() == 'Windows': - em = WrappedEmulator(visible=True,delay=results.sleep) - elif platform.system() == 'Windows': - logger('x3270 not supported on Windows',kind='err') - sys.exit(1) - if results.quiet: - logger('Quiet Mode Enabled\t: Shhhhhhhhh!',kind='warn') - history = tn3270.History() - if results.loadfile: - logger('Load history from\t\t: ' + results.loadfile,kind='info') - history = load_history(results.loadfile) - - return (em,history) + # Parse commandline arguments + logger('Big Iron Recon & Pwnage (BIRP) by @singe', kind='info') + if not results.target: + logger('Manual target selection chosen.', kind='info') + else: + logger('Target Acquired\t\t: ' + results.target, kind='info') + logger('Slowdown is\t\t\t: ' + str(results.sleep), kind='info') + logger('Attack platform\t\t: ' + platform.system(), kind='info') + + if not platform.system() == 'Windows': + em = WrappedEmulator(visible=True, delay=results.sleep) + elif platform.system() == 'Windows': + logger('x3270 not supported on Windows', kind='err') + sys.exit(1) + if results.quiet: + logger('Quiet Mode Enabled\t: Shhhhhhhhh!', kind='warn') + history = tn3270.History() + if results.loadfile: + logger('Load history from\t\t: ' + results.loadfile, kind='info') + history = load_history(results.loadfile) + + return em, history + results = prestartup() -(em,history) = startup() +(em, history) = startup() if results.target: - logger('Connecting to ' + results.target,kind='info') - try: - em.connect(results.target) - except: - logger('Connection failure',kind='err') - sys.exit(1) - if not em.is_connected(): - logger('Could not connect to ' + results.target + '. Aborting.',kind='err') - sys.exit(1) - - hostinfo = em.get_hostinfo() - host = hostinfo[1]+':'+hostinfo[2] + logger('Connecting to ' + results.target, kind='info') + try: + em.connect(results.target) + except: + logger('Connection failure', kind='err') + sys.exit(1) + if not em.is_connected(): + logger('Could not connect to ' + results.target + '. Aborting.', kind='err') + sys.exit(1) + + hostinfo = em.get_hostinfo() + host = hostinfo[1] + ':' + hostinfo[2] menu(em, history) # And we're done. Close the connection diff --git a/getch.py b/getch.py index 39d0fea..be2cfff 100644 --- a/getch.py +++ b/getch.py @@ -14,570 +14,578 @@ todo: map keypresses on windows todo: optimise decision tree on linux ''' -class TimeoutException(Exception): - pass + + +class TimeoutException(Exception): + pass + class _Getch: - # Gets a single character from standard input. Does not echo to the screen. - def __init__(self): - if platform.system() == 'Darwin': - self.impl = _GetchMac() - if platform.system() == 'Linux': - self.impl = _GetchUnix() - if platform.system() == 'Windows': - self.impl = _GetchWindows() + # Gets a single character from standard input. Does not echo to the screen. + def __init__(self): + if platform.system() == 'Darwin': + self.impl = _GetchMac() + if platform.system() == 'Linux': + self.impl = _GetchUnix() + if platform.system() == 'Windows': + self.impl = _GetchWindows() + + self.KEY_TAB = self.impl.KEY_TAB + self.KEY_ESC = self.impl.KEY_ESC + self.KEY_a = self.impl.KEY_a + self.KEY_b = self.impl.KEY_b + self.KEY_c = self.impl.KEY_c + self.KEY_d = self.impl.KEY_d + self.KEY_e = self.impl.KEY_e + self.KEY_f = self.impl.KEY_f + self.KEY_g = self.impl.KEY_g + self.KEY_h = self.impl.KEY_h + self.KEY_i = self.impl.KEY_i + self.KEY_j = self.impl.KEY_j + self.KEY_k = self.impl.KEY_k + self.KEY_l = self.impl.KEY_l + self.KEY_m = self.impl.KEY_m + self.KEY_n = self.impl.KEY_n + self.KEY_o = self.impl.KEY_o + self.KEY_p = self.impl.KEY_p + self.KEY_q = self.impl.KEY_q + self.KEY_r = self.impl.KEY_r + self.KEY_s = self.impl.KEY_s + self.KEY_t = self.impl.KEY_t + self.KEY_u = self.impl.KEY_u + self.KEY_v = self.impl.KEY_v + self.KEY_w = self.impl.KEY_w + self.KEY_x = self.impl.KEY_x + self.KEY_y = self.impl.KEY_y + self.KEY_z = self.impl.KEY_z + self.KEY_A = self.impl.KEY_A + self.KEY_B = self.impl.KEY_B + self.KEY_C = self.impl.KEY_C + self.KEY_D = self.impl.KEY_D + self.KEY_E = self.impl.KEY_E + self.KEY_F = self.impl.KEY_F + self.KEY_G = self.impl.KEY_G + self.KEY_H = self.impl.KEY_H + self.KEY_I = self.impl.KEY_I + self.KEY_J = self.impl.KEY_J + self.KEY_K = self.impl.KEY_K + self.KEY_L = self.impl.KEY_L + self.KEY_M = self.impl.KEY_M + self.KEY_N = self.impl.KEY_N + self.KEY_O = self.impl.KEY_O + self.KEY_P = self.impl.KEY_P + self.KEY_Q = self.impl.KEY_Q + self.KEY_R = self.impl.KEY_R + self.KEY_S = self.impl.KEY_S + self.KEY_T = self.impl.KEY_T + self.KEY_U = self.impl.KEY_U + self.KEY_V = self.impl.KEY_V + self.KEY_W = self.impl.KEY_W + self.KEY_X = self.impl.KEY_X + self.KEY_Y = self.impl.KEY_Y + self.KEY_Z = self.impl.KEY_Z + self.KEY_0 = self.impl.KEY_0 + self.KEY_1 = self.impl.KEY_1 + self.KEY_2 = self.impl.KEY_2 + self.KEY_3 = self.impl.KEY_3 + self.KEY_4 = self.impl.KEY_4 + self.KEY_5 = self.impl.KEY_5 + self.KEY_6 = self.impl.KEY_6 + self.KEY_7 = self.impl.KEY_7 + self.KEY_8 = self.impl.KEY_8 + self.KEY_9 = self.impl.KEY_9 + self.KEY_CTRLa = self.impl.KEY_CTRLa + self.KEY_CTRLb = self.impl.KEY_CTRLb + self.KEY_CTRLc = self.impl.KEY_CTRLc + self.KEY_CTRLd = self.impl.KEY_CTRLd + self.KEY_CTRLe = self.impl.KEY_CTRLe + self.KEY_CTRLf = self.impl.KEY_CTRLf + self.KEY_CTRLg = self.impl.KEY_CTRLg + self.KEY_CTRLh = self.impl.KEY_CTRLh + self.KEY_CTRLi = self.impl.KEY_CTRLi + self.KEY_CTRLj = self.impl.KEY_CTRLj + self.KEY_CTRLk = self.impl.KEY_CTRLk + self.KEY_CTRLl = self.impl.KEY_CTRLl + self.KEY_CTRLm = self.impl.KEY_CTRLm + self.KEY_CTRLn = self.impl.KEY_CTRLn + self.KEY_CTRLo = self.impl.KEY_CTRLo + self.KEY_CTRLp = self.impl.KEY_CTRLp + self.KEY_CTRLq = self.impl.KEY_CTRLq + self.KEY_CTRLr = self.impl.KEY_CTRLr + self.KEY_CTRLs = self.impl.KEY_CTRLs + self.KEY_CTRLt = self.impl.KEY_CTRLt + self.KEY_CTRLu = self.impl.KEY_CTRLu + self.KEY_CTRLv = self.impl.KEY_CTRLv + self.KEY_CTRLw = self.impl.KEY_CTRLw + self.KEY_CTRLx = self.impl.KEY_CTRLx + self.KEY_CTRLy = self.impl.KEY_CTRLy + self.KEY_CTRLz = self.impl.KEY_CTRLz + self.KEY_SPACE = self.impl.KEY_SPACE + self.KEY_BACKSPACE = self.impl.KEY_BACKSPACE + self.KEY_BANG = self.impl.KEY_BANG + self.KEY_DOUBLEQUOTE = self.impl.KEY_DOUBLEQUOTE + self.KEY_HASH = self.impl.KEY_HASH + self.KEY_DOLLAR = self.impl.KEY_DOLLAR + self.KEY_PERCENT = self.impl.KEY_PERCENT + self.KEY_QUOTE = self.impl.KEY_QUOTE + self.KEY_OPENBRACKET = self.impl.KEY_OPENBRACKET + self.KEY_CLOSEBRACKET = self.impl.KEY_CLOSEBRACKET + self.KEY_ASTERISK = self.impl.KEY_ASTERISK + self.KEY_PLUS = self.impl.KEY_PLUS + self.KEY_MINUS = self.impl.KEY_MINUS + self.KEY_COMMA = self.impl.KEY_COMMA + self.KEY_DASH = self.impl.KEY_DASH + self.KEY_PERIOD = self.impl.KEY_PERIOD + self.KEY_FSLASH = self.impl.KEY_FSLASH + self.KEY_BSLASH = self.impl.KEY_BSLASH + self.KEY_DASH = self.impl.KEY_DASH + self.KEY_SQUAREOPEN = self.impl.KEY_SQUAREOPEN + self.KEY_SQUARECLOSE = self.impl.KEY_SQUARECLOSE + self.KEY_CARET = self.impl.KEY_CARET + self.KEY_UNDERSCORE = self.impl.KEY_UNDERSCORE + self.KEY_BACKTICK = self.impl.KEY_BACKTICK + self.KEY_CURLEYOPEN = self.impl.KEY_CURLEYOPEN + self.KEY_CURLEYCLOSE = self.impl.KEY_CURLEYCLOSE + self.KEY_PIPE = self.impl.KEY_PIPE + self.KEY_TILDE = self.impl.KEY_TILDE + self.KEY_UP = self.impl.KEY_UP + self.KEY_DOWN = self.impl.KEY_DOWN + self.KEY_LEFT = self.impl.KEY_LEFT + self.KEY_RIGHT = self.impl.KEY_RIGHT + self.KEY_DELETE = self.impl.KEY_DELETE + self.KEY_ENTER = self.impl.KEY_ENTER + self.KEY_SECTION = self.impl.KEY_SECTION + self.KEY_PLUSMINUS = self.impl.KEY_PLUSMINUS + self.KEY_F1 = self.impl.KEY_F1 + self.KEY_F2 = self.impl.KEY_F2 + self.KEY_F3 = self.impl.KEY_F3 + self.KEY_F4 = self.impl.KEY_F4 + self.KEY_F5 = self.impl.KEY_F5 + self.KEY_F6 = self.impl.KEY_F6 + self.KEY_F7 = self.impl.KEY_F7 + self.KEY_F8 = self.impl.KEY_F8 + self.KEY_F9 = self.impl.KEY_F9 + self.KEY_F10 = self.impl.KEY_F10 + self.KEY_F11 = self.impl.KEY_F11 + self.KEY_F12 = self.impl.KEY_F12 + self.KEY_AltF8 = self.impl.KEY_AltF8 + self.KEY_AltF9 = self.impl.KEY_AltF9 + self.KEY_AltF10 = self.impl.KEY_AltF10 + self.KEY_AltF11 = self.impl.KEY_AltF11 + self.KEY_AltF11 = self.impl.KEY_AltF11 + self.KEY_AltF12 = self.impl.KEY_AltF12 - self.KEY_TAB = self.impl.KEY_TAB - self.KEY_ESC = self.impl.KEY_ESC - self.KEY_a = self.impl.KEY_a - self.KEY_b = self.impl.KEY_b - self.KEY_c = self.impl.KEY_c - self.KEY_d = self.impl.KEY_d - self.KEY_e = self.impl.KEY_e - self.KEY_f = self.impl.KEY_f - self.KEY_g = self.impl.KEY_g - self.KEY_h = self.impl.KEY_h - self.KEY_i = self.impl.KEY_i - self.KEY_j = self.impl.KEY_j - self.KEY_k = self.impl.KEY_k - self.KEY_l = self.impl.KEY_l - self.KEY_m = self.impl.KEY_m - self.KEY_n = self.impl.KEY_n - self.KEY_o = self.impl.KEY_o - self.KEY_p = self.impl.KEY_p - self.KEY_q = self.impl.KEY_q - self.KEY_r = self.impl.KEY_r - self.KEY_s = self.impl.KEY_s - self.KEY_t = self.impl.KEY_t - self.KEY_u = self.impl.KEY_u - self.KEY_v = self.impl.KEY_v - self.KEY_w = self.impl.KEY_w - self.KEY_x = self.impl.KEY_x - self.KEY_y = self.impl.KEY_y - self.KEY_z = self.impl.KEY_z - self.KEY_A = self.impl.KEY_A - self.KEY_B = self.impl.KEY_B - self.KEY_C = self.impl.KEY_C - self.KEY_D = self.impl.KEY_D - self.KEY_E = self.impl.KEY_E - self.KEY_F = self.impl.KEY_F - self.KEY_G = self.impl.KEY_G - self.KEY_H = self.impl.KEY_H - self.KEY_I = self.impl.KEY_I - self.KEY_J = self.impl.KEY_J - self.KEY_K = self.impl.KEY_K - self.KEY_L = self.impl.KEY_L - self.KEY_M = self.impl.KEY_M - self.KEY_N = self.impl.KEY_N - self.KEY_O = self.impl.KEY_O - self.KEY_P = self.impl.KEY_P - self.KEY_Q = self.impl.KEY_Q - self.KEY_R = self.impl.KEY_R - self.KEY_S = self.impl.KEY_S - self.KEY_T = self.impl.KEY_T - self.KEY_U = self.impl.KEY_U - self.KEY_V = self.impl.KEY_V - self.KEY_W = self.impl.KEY_W - self.KEY_X = self.impl.KEY_X - self.KEY_Y = self.impl.KEY_Y - self.KEY_Z = self.impl.KEY_Z - self.KEY_0 = self.impl.KEY_0 - self.KEY_1 = self.impl.KEY_1 - self.KEY_2 = self.impl.KEY_2 - self.KEY_3 = self.impl.KEY_3 - self.KEY_4 = self.impl.KEY_4 - self.KEY_5 = self.impl.KEY_5 - self.KEY_6 = self.impl.KEY_6 - self.KEY_7 = self.impl.KEY_7 - self.KEY_8 = self.impl.KEY_8 - self.KEY_9 = self.impl.KEY_9 - self.KEY_CTRLa = self.impl.KEY_CTRLa - self.KEY_CTRLb = self.impl.KEY_CTRLb - self.KEY_CTRLc = self.impl.KEY_CTRLc - self.KEY_CTRLd = self.impl.KEY_CTRLd - self.KEY_CTRLe = self.impl.KEY_CTRLe - self.KEY_CTRLf = self.impl.KEY_CTRLf - self.KEY_CTRLg = self.impl.KEY_CTRLg - self.KEY_CTRLh = self.impl.KEY_CTRLh - self.KEY_CTRLi = self.impl.KEY_CTRLi - self.KEY_CTRLj = self.impl.KEY_CTRLj - self.KEY_CTRLk = self.impl.KEY_CTRLk - self.KEY_CTRLl = self.impl.KEY_CTRLl - self.KEY_CTRLm = self.impl.KEY_CTRLm - self.KEY_CTRLn = self.impl.KEY_CTRLn - self.KEY_CTRLo = self.impl.KEY_CTRLo - self.KEY_CTRLp = self.impl.KEY_CTRLp - self.KEY_CTRLq = self.impl.KEY_CTRLq - self.KEY_CTRLr = self.impl.KEY_CTRLr - self.KEY_CTRLs = self.impl.KEY_CTRLs - self.KEY_CTRLt = self.impl.KEY_CTRLt - self.KEY_CTRLu = self.impl.KEY_CTRLu - self.KEY_CTRLv = self.impl.KEY_CTRLv - self.KEY_CTRLw = self.impl.KEY_CTRLw - self.KEY_CTRLx = self.impl.KEY_CTRLx - self.KEY_CTRLy = self.impl.KEY_CTRLy - self.KEY_CTRLz = self.impl.KEY_CTRLz - self.KEY_SPACE = self.impl.KEY_SPACE - self.KEY_BACKSPACE = self.impl.KEY_BACKSPACE - self.KEY_BANG = self.impl.KEY_BANG - self.KEY_DOUBLEQUOTE = self.impl.KEY_DOUBLEQUOTE - self.KEY_HASH = self.impl.KEY_HASH - self.KEY_DOLLAR = self.impl.KEY_DOLLAR - self.KEY_PERCENT = self.impl.KEY_PERCENT - self.KEY_QUOTE = self.impl.KEY_QUOTE - self.KEY_OPENBRACKET = self.impl.KEY_OPENBRACKET - self.KEY_CLOSEBRACKET = self.impl.KEY_CLOSEBRACKET - self.KEY_ASTERISK = self.impl.KEY_ASTERISK - self.KEY_PLUS = self.impl.KEY_PLUS - self.KEY_MINUS = self.impl.KEY_MINUS - self.KEY_COMMA = self.impl.KEY_COMMA - self.KEY_DASH = self.impl.KEY_DASH - self.KEY_PERIOD = self.impl.KEY_PERIOD - self.KEY_FSLASH = self.impl.KEY_FSLASH - self.KEY_BSLASH = self.impl.KEY_BSLASH - self.KEY_DASH = self.impl.KEY_DASH - self.KEY_SQUAREOPEN = self.impl.KEY_SQUAREOPEN - self.KEY_SQUARECLOSE = self.impl.KEY_SQUARECLOSE - self.KEY_CARET = self.impl.KEY_CARET - self.KEY_UNDERSCORE = self.impl.KEY_UNDERSCORE - self.KEY_BACKTICK = self.impl.KEY_BACKTICK - self.KEY_CURLEYOPEN = self.impl.KEY_CURLEYOPEN - self.KEY_CURLEYCLOSE = self.impl.KEY_CURLEYCLOSE - self.KEY_PIPE = self.impl.KEY_PIPE - self.KEY_TILDE = self.impl.KEY_TILDE - self.KEY_UP = self.impl.KEY_UP - self.KEY_DOWN = self.impl.KEY_DOWN - self.KEY_LEFT = self.impl.KEY_LEFT - self.KEY_RIGHT = self.impl.KEY_RIGHT - self.KEY_DELETE = self.impl.KEY_DELETE - self.KEY_ENTER = self.impl.KEY_ENTER - self.KEY_SECTION = self.impl.KEY_SECTION - self.KEY_PLUSMINUS = self.impl.KEY_PLUSMINUS - self.KEY_F1 = self.impl.KEY_F1 - self.KEY_F2 = self.impl.KEY_F2 - self.KEY_F3 = self.impl.KEY_F3 - self.KEY_F4 = self.impl.KEY_F4 - self.KEY_F5 = self.impl.KEY_F5 - self.KEY_F6 = self.impl.KEY_F6 - self.KEY_F7 = self.impl.KEY_F7 - self.KEY_F8 = self.impl.KEY_F8 - self.KEY_F9 = self.impl.KEY_F9 - self.KEY_F10 = self.impl.KEY_F10 - self.KEY_F11 = self.impl.KEY_F11 - self.KEY_F12 = self.impl.KEY_F12 - self.KEY_AltF8 = self.impl.KEY_AltF8 - self.KEY_AltF9 = self.impl.KEY_AltF9 - self.KEY_AltF10 = self.impl.KEY_AltF10 - self.KEY_AltF11 = self.impl.KEY_AltF11 - self.KEY_AltF11 = self.impl.KEY_AltF11 - self.KEY_AltF12 = self.impl.KEY_AltF12 + def __call__(self): + return self.impl() - def __call__(self): return self.impl() class _GetchMac: - def __init__(self): - # General - self.KEY_ESC = 27 - self.KEY_TAB = 9 - self.KEY_a = ord('a') - self.KEY_b = ord('b') - self.KEY_c = ord('c') - self.KEY_d = ord('d') - self.KEY_e = ord('e') - self.KEY_f = ord('f') - self.KEY_g = ord('g') - self.KEY_h = ord('h') - self.KEY_i = ord('i') - self.KEY_j = ord('j') - self.KEY_k = ord('k') - self.KEY_l = ord('l') - self.KEY_m = ord('m') - self.KEY_n = ord('n') - self.KEY_o = ord('o') - self.KEY_p = ord('p') - self.KEY_q = ord('q') - self.KEY_r = ord('r') - self.KEY_s = ord('s') - self.KEY_t = ord('t') - self.KEY_u = ord('u') - self.KEY_v = ord('v') - self.KEY_w = ord('w') - self.KEY_x = ord('x') - self.KEY_y = ord('y') - self.KEY_z = ord('z') - self.KEY_A = ord('A') - self.KEY_B = ord('B') - self.KEY_C = ord('C') - self.KEY_D = ord('D') - self.KEY_E = ord('E') - self.KEY_F = ord('F') - self.KEY_G = ord('G') - self.KEY_H = ord('H') - self.KEY_I = ord('I') - self.KEY_J = ord('J') - self.KEY_K = ord('K') - self.KEY_L = ord('L') - self.KEY_M = ord('M') - self.KEY_N = ord('N') - self.KEY_O = ord('O') - self.KEY_P = ord('P') - self.KEY_Q = ord('Q') - self.KEY_R = ord('R') - self.KEY_S = ord('S') - self.KEY_T = ord('T') - self.KEY_U = ord('U') - self.KEY_V = ord('V') - self.KEY_W = ord('W') - self.KEY_X = ord('X') - self.KEY_Y = ord('Y') - self.KEY_Z = ord('Z') - self.KEY_0 = ord('0') - self.KEY_1 = ord('1') - self.KEY_2 = ord('2') - self.KEY_3 = ord('3') - self.KEY_4 = ord('4') - self.KEY_5 = ord('5') - self.KEY_6 = ord('6') - self.KEY_7 = ord('7') - self.KEY_8 = ord('8') - self.KEY_9 = ord('9') - self.KEY_CTRLa = 1 - self.KEY_CTRLb = 2 - self.KEY_CTRLc = 3 - self.KEY_CTRLd = 4 - self.KEY_CTRLe = 5 - self.KEY_CTRLf = 6 - self.KEY_CTRLg = 7 - self.KEY_CTRLh = 8 - self.KEY_CTRLi = 9 #Sigh, that's a tab - self.KEY_CTRLj = 10 - self.KEY_CTRLk = 11 - self.KEY_CTRLl = 12 - self.KEY_CTRLm = 13 - self.KEY_CTRLn = 14 - self.KEY_CTRLo = 15 - self.KEY_CTRLp = 16 - self.KEY_CTRLq = 17 - self.KEY_CTRLr = 18 - self.KEY_CTRLs = 19 - self.KEY_CTRLt = 20 - self.KEY_CTRLu = 21 - self.KEY_CTRLv = 22 - self.KEY_CTRLw = 23 - self.KEY_CTRLx = 24 - self.KEY_CTRLy = 25 - self.KEY_CTRLz = 26 - self.KEY_SPACE = ord(' ') - self.KEY_BACKSPACE = 127 - self.KEY_BANG = ord('!') - self.KEY_DOUBLEQUOTE = ord('"') - self.KEY_HASH = ord('#') - self.KEY_DOLLAR = ord('$') - self.KEY_PERCENT = ord('%') - self.KEY_QUOTE = ord("'") - self.KEY_OPENBRACKET = ord('(') - self.KEY_CLOSEBRACKET = ord(')') - self.KEY_ASTERISK = ord('*') - self.KEY_PLUS = ord('+') - self.KEY_MINUS = ord('-') - self.KEY_COMMA = ord(',') - self.KEY_DASH = ord('-') - self.KEY_PERIOD = ord('.') - self.KEY_FSLASH = ord('/') - self.KEY_BSLASH = ord('\\') - self.KEY_DASH = ord('-') - self.KEY_SQUAREOPEN = ord('[') - self.KEY_SQUARECLOSE = ord(']') - self.KEY_CARET = ord('^') - self.KEY_UNDERSCORE = ord('_') - self.KEY_BACKTICK = ord('`') - self.KEY_CURLEYOPEN = ord('{') - self.KEY_CURLEYCLOSE = ord('}') - self.KEY_PIPE = ord('|') - self.KEY_TILDE = ord('~') - # Unix Specific - self.KEY_UP = 113179 - self.KEY_DOWN = 114203 - self.KEY_LEFT = 116251 - self.KEY_RIGHT = 115227 - self.KEY_DELETE = 356891 - self.KEY_ENTER = 13 - self.KEY_F6 = 725531 - self.KEY_F7 = 727579 - self.KEY_F8 = 729627 - self.KEY_F9 = 712219 - self.KEY_F10 = 714267 - self.KEY_F11 = 718363 - self.KEY_F12 = 720411 - #OSX Specific - # I have not gotten around to osx's Alt-SpecialChars - self.KEY_SECTION = 85698 - self.KEY_PLUSMINUS = 90818 - self.KEY_F1 = 122395 - self.KEY_F2 = 123419 - self.KEY_F3 = 124443 - self.KEY_F4 = 125467 - self.KEY_F5 = 721435 - # AltF1-Alt-F7 = F6-F12 - self.KEY_AltF8 = 722459 - self.KEY_AltF9 = 724507 - self.KEY_AltF10 = 728603 - self.KEY_AltF11 = 730651 - self.KEY_AltF12 = 715291 + def __init__(self): + # General + self.KEY_ESC = 27 + self.KEY_TAB = 9 + self.KEY_a = ord('a') + self.KEY_b = ord('b') + self.KEY_c = ord('c') + self.KEY_d = ord('d') + self.KEY_e = ord('e') + self.KEY_f = ord('f') + self.KEY_g = ord('g') + self.KEY_h = ord('h') + self.KEY_i = ord('i') + self.KEY_j = ord('j') + self.KEY_k = ord('k') + self.KEY_l = ord('l') + self.KEY_m = ord('m') + self.KEY_n = ord('n') + self.KEY_o = ord('o') + self.KEY_p = ord('p') + self.KEY_q = ord('q') + self.KEY_r = ord('r') + self.KEY_s = ord('s') + self.KEY_t = ord('t') + self.KEY_u = ord('u') + self.KEY_v = ord('v') + self.KEY_w = ord('w') + self.KEY_x = ord('x') + self.KEY_y = ord('y') + self.KEY_z = ord('z') + self.KEY_A = ord('A') + self.KEY_B = ord('B') + self.KEY_C = ord('C') + self.KEY_D = ord('D') + self.KEY_E = ord('E') + self.KEY_F = ord('F') + self.KEY_G = ord('G') + self.KEY_H = ord('H') + self.KEY_I = ord('I') + self.KEY_J = ord('J') + self.KEY_K = ord('K') + self.KEY_L = ord('L') + self.KEY_M = ord('M') + self.KEY_N = ord('N') + self.KEY_O = ord('O') + self.KEY_P = ord('P') + self.KEY_Q = ord('Q') + self.KEY_R = ord('R') + self.KEY_S = ord('S') + self.KEY_T = ord('T') + self.KEY_U = ord('U') + self.KEY_V = ord('V') + self.KEY_W = ord('W') + self.KEY_X = ord('X') + self.KEY_Y = ord('Y') + self.KEY_Z = ord('Z') + self.KEY_0 = ord('0') + self.KEY_1 = ord('1') + self.KEY_2 = ord('2') + self.KEY_3 = ord('3') + self.KEY_4 = ord('4') + self.KEY_5 = ord('5') + self.KEY_6 = ord('6') + self.KEY_7 = ord('7') + self.KEY_8 = ord('8') + self.KEY_9 = ord('9') + self.KEY_CTRLa = 1 + self.KEY_CTRLb = 2 + self.KEY_CTRLc = 3 + self.KEY_CTRLd = 4 + self.KEY_CTRLe = 5 + self.KEY_CTRLf = 6 + self.KEY_CTRLg = 7 + self.KEY_CTRLh = 8 + self.KEY_CTRLi = 9 # Sigh, that's a tab + self.KEY_CTRLj = 10 + self.KEY_CTRLk = 11 + self.KEY_CTRLl = 12 + self.KEY_CTRLm = 13 + self.KEY_CTRLn = 14 + self.KEY_CTRLo = 15 + self.KEY_CTRLp = 16 + self.KEY_CTRLq = 17 + self.KEY_CTRLr = 18 + self.KEY_CTRLs = 19 + self.KEY_CTRLt = 20 + self.KEY_CTRLu = 21 + self.KEY_CTRLv = 22 + self.KEY_CTRLw = 23 + self.KEY_CTRLx = 24 + self.KEY_CTRLy = 25 + self.KEY_CTRLz = 26 + self.KEY_SPACE = ord(' ') + self.KEY_BACKSPACE = 127 + self.KEY_BANG = ord('!') + self.KEY_DOUBLEQUOTE = ord('"') + self.KEY_HASH = ord('#') + self.KEY_DOLLAR = ord('$') + self.KEY_PERCENT = ord('%') + self.KEY_QUOTE = ord("'") + self.KEY_OPENBRACKET = ord('(') + self.KEY_CLOSEBRACKET = ord(')') + self.KEY_ASTERISK = ord('*') + self.KEY_PLUS = ord('+') + self.KEY_MINUS = ord('-') + self.KEY_COMMA = ord(',') + self.KEY_DASH = ord('-') + self.KEY_PERIOD = ord('.') + self.KEY_FSLASH = ord('/') + self.KEY_BSLASH = ord('\\') + self.KEY_DASH = ord('-') + self.KEY_SQUAREOPEN = ord('[') + self.KEY_SQUARECLOSE = ord(']') + self.KEY_CARET = ord('^') + self.KEY_UNDERSCORE = ord('_') + self.KEY_BACKTICK = ord('`') + self.KEY_CURLEYOPEN = ord('{') + self.KEY_CURLEYCLOSE = ord('}') + self.KEY_PIPE = ord('|') + self.KEY_TILDE = ord('~') + # Unix Specific + self.KEY_UP = 113179 + self.KEY_DOWN = 114203 + self.KEY_LEFT = 116251 + self.KEY_RIGHT = 115227 + self.KEY_DELETE = 356891 + self.KEY_ENTER = 13 + self.KEY_F6 = 725531 + self.KEY_F7 = 727579 + self.KEY_F8 = 729627 + self.KEY_F9 = 712219 + self.KEY_F10 = 714267 + self.KEY_F11 = 718363 + self.KEY_F12 = 720411 + # OSX Specific + # I have not gotten around to osx's Alt-SpecialChars + self.KEY_SECTION = 85698 + self.KEY_PLUSMINUS = 90818 + self.KEY_F1 = 122395 + self.KEY_F2 = 123419 + self.KEY_F3 = 124443 + self.KEY_F4 = 125467 + self.KEY_F5 = 721435 + # AltF1-Alt-F7 = F6-F12 + self.KEY_AltF8 = 722459 + self.KEY_AltF9 = 724507 + self.KEY_AltF10 = 728603 + self.KEY_AltF11 = 730651 + self.KEY_AltF12 = 715291 - def __call__(self): - def timeout_handler(signum, frame): - raise TimeoutException() + def __call__(self): + def timeout_handler(signum, frame): + raise TimeoutException() + + import sys, tty, termios + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + tty.setcbreak(sys.stdin.fileno()) + ch0 = ord(sys.stdin.read(1)) + od = ch0 + # print ch0 + if od == 194: # mac section/plusminus key kludge + ch1 = ord(sys.stdin.read(1)) + # print ch1 + od += ch1 * 512 + if od == 27: # special key + # This is some horrible, kludge, upfu*kery but curses/tkinter won't work for my needs + old_handler = signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(1) + try: + ch1 = ord(sys.stdin.read(1)) + # print ch1 + od += ch1 * 512 + ch2 = ord(sys.stdin.read(1)) + # print ch2 + od += ch2 * 1024 + pos = 2048 + if ch2 > 64 and ch2 < 69: + pass + elif ch1 == 91: + while True: + chx = ord(sys.stdin.read(1)) + # print chx + od += chx * pos + pos += pos + if chx == 126: + break + signal.alarm(0) + except TimeoutException: + pass + finally: + signal.signal(signal.SIGALRM, old_handler) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return od - import sys, tty, termios - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - tty.setcbreak(sys.stdin.fileno()) - ch0 = ord(sys.stdin.read(1)) - od = ch0 - #print ch0 - if od == 194: #mac section/plusminus key kludge - ch1 = ord(sys.stdin.read(1)) - #print ch1 - od += ch1 * 512 - if od == 27: #special key - # This is some horrible, kludge, upfu*kery but curses/tkinter won't work for my needs - old_handler = signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(1) - try: - ch1 = ord(sys.stdin.read(1)) - #print ch1 - od += ch1 * 512 - ch2 = ord(sys.stdin.read(1)) - #print ch2 - od += ch2 * 1024 - pos = 2048 - if ch2 > 64 and ch2 < 69: - pass - elif ch1 == 91: - while True: - chx = ord(sys.stdin.read(1)) - #print chx - od += chx * pos - pos += pos - if chx == 126: - break - signal.alarm(0) - except TimeoutException: - pass - finally: - signal.signal(signal.SIGALRM, old_handler) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return od class _GetchUnix: - def __init__(self): - # General - self.KEY_ESC = 27 - self.KEY_TAB = 9 - self.KEY_a = ord('a') - self.KEY_b = ord('b') - self.KEY_c = ord('c') - self.KEY_d = ord('d') - self.KEY_e = ord('e') - self.KEY_f = ord('f') - self.KEY_g = ord('g') - self.KEY_h = ord('h') - self.KEY_i = ord('i') - self.KEY_j = ord('j') - self.KEY_k = ord('k') - self.KEY_l = ord('l') - self.KEY_m = ord('m') - self.KEY_n = ord('n') - self.KEY_o = ord('o') - self.KEY_p = ord('p') - self.KEY_q = ord('q') - self.KEY_r = ord('r') - self.KEY_s = ord('s') - self.KEY_t = ord('t') - self.KEY_u = ord('u') - self.KEY_v = ord('v') - self.KEY_w = ord('w') - self.KEY_x = ord('x') - self.KEY_y = ord('y') - self.KEY_z = ord('z') - self.KEY_A = ord('A') - self.KEY_B = ord('B') - self.KEY_C = ord('C') - self.KEY_D = ord('D') - self.KEY_E = ord('E') - self.KEY_F = ord('F') - self.KEY_G = ord('G') - self.KEY_H = ord('H') - self.KEY_I = ord('I') - self.KEY_J = ord('J') - self.KEY_K = ord('K') - self.KEY_L = ord('L') - self.KEY_M = ord('M') - self.KEY_N = ord('N') - self.KEY_O = ord('O') - self.KEY_P = ord('P') - self.KEY_Q = ord('Q') - self.KEY_R = ord('R') - self.KEY_S = ord('S') - self.KEY_T = ord('T') - self.KEY_U = ord('U') - self.KEY_V = ord('V') - self.KEY_W = ord('W') - self.KEY_X = ord('X') - self.KEY_Y = ord('Y') - self.KEY_Z = ord('Z') - self.KEY_0 = ord('0') - self.KEY_1 = ord('1') - self.KEY_2 = ord('2') - self.KEY_3 = ord('3') - self.KEY_4 = ord('4') - self.KEY_5 = ord('5') - self.KEY_6 = ord('6') - self.KEY_7 = ord('7') - self.KEY_8 = ord('8') - self.KEY_9 = ord('9') - self.KEY_CTRLa = 1 - self.KEY_CTRLb = 2 - self.KEY_CTRLc = 3 - self.KEY_CTRLd = 4 - self.KEY_CTRLe = 5 - self.KEY_CTRLf = 6 - self.KEY_CTRLg = 7 - self.KEY_CTRLh = 8 - self.KEY_CTRLi = 9 - self.KEY_CTRLj = 10 - self.KEY_CTRLk = 11 - self.KEY_CTRLl = 12 - self.KEY_CTRLm = 13 - self.KEY_CTRLn = 14 - self.KEY_CTRLo = 15 - self.KEY_CTRLp = 16 - self.KEY_CTRLq = 17 - self.KEY_CTRLr = 18 - self.KEY_CTRLs = 19 - self.KEY_CTRLt = 20 - self.KEY_CTRLu = 21 - self.KEY_CTRLv = 22 - self.KEY_CTRLw = 23 - self.KEY_CTRLx = 24 - self.KEY_CTRLy = 25 - self.KEY_CTRLz = 26 - self.KEY_SPACE = ord(' ') - self.KEY_BACKSPACE = 127 - self.KEY_BANG = ord('!') - self.KEY_DOUBLEQUOTE = ord('"') - self.KEY_HASH = ord('#') - self.KEY_DOLLAR = ord('$') - self.KEY_PERCENT = ord('%') - self.KEY_QUOTE = ord("'") - self.KEY_OPENBRACKET = ord('(') - self.KEY_CLOSEBRACKET = ord(')') - self.KEY_ASTERISK = ord('*') - self.KEY_PLUS = ord('+') - self.KEY_MINUS = ord('-') - self.KEY_COMMA = ord(',') - self.KEY_DASH = ord('-') - self.KEY_PERIOD = ord('.') - self.KEY_FSLASH = ord('/') - self.KEY_BSLASH = ord('\\') - self.KEY_DASH = ord('-') - self.KEY_SQUAREOPEN = ord('[') - self.KEY_SQUARECLOSE = ord(']') - self.KEY_CARET = ord('^') - self.KEY_UNDERSCORE = ord('_') - self.KEY_BACKTICK = ord('`') - self.KEY_CURLEYOPEN = ord('{') - self.KEY_CURLEYCLOSE = ord('}') - self.KEY_PIPE = ord('|') - self.KEY_TILDE = ord('~') - # Unix Specific - self.KEY_UP = 113179 - self.KEY_DOWN = 114203 - self.KEY_LEFT = 116251 - self.KEY_RIGHT = 115227 - self.KEY_DELETE = 356891 - self.KEY_ENTER = 13 - #Linux Specific - self.KEY_F1 = 272923 - self.KEY_F2 = 274971 - self.KEY_F3 = 277019 - self.KEY_F4 = 279061 - self.KEY_F5 = 281115 - self.KEY_F6 = 722531 - #Common - self.KEY_F7 = 727579 - self.KEY_F8 = 729627 - self.KEY_F9 = 712219 - self.KEY_F10 = 714267 - self.KEY_F11 = 718363 - self.KEY_F12 = 720411 - #OSX Specific - self.KEY_AltF8 = 0 - self.KEY_AltF9 = 0 - self.KEY_AltF10 = 0 - self.KEY_AltF11 = 0 - self.KEY_AltF12 = 0 - self.KEY_SECTION = 0 - self.KEY_PLUSMINUS = 0 + def __init__(self): + # General + self.KEY_ESC = 27 + self.KEY_TAB = 9 + self.KEY_a = ord('a') + self.KEY_b = ord('b') + self.KEY_c = ord('c') + self.KEY_d = ord('d') + self.KEY_e = ord('e') + self.KEY_f = ord('f') + self.KEY_g = ord('g') + self.KEY_h = ord('h') + self.KEY_i = ord('i') + self.KEY_j = ord('j') + self.KEY_k = ord('k') + self.KEY_l = ord('l') + self.KEY_m = ord('m') + self.KEY_n = ord('n') + self.KEY_o = ord('o') + self.KEY_p = ord('p') + self.KEY_q = ord('q') + self.KEY_r = ord('r') + self.KEY_s = ord('s') + self.KEY_t = ord('t') + self.KEY_u = ord('u') + self.KEY_v = ord('v') + self.KEY_w = ord('w') + self.KEY_x = ord('x') + self.KEY_y = ord('y') + self.KEY_z = ord('z') + self.KEY_A = ord('A') + self.KEY_B = ord('B') + self.KEY_C = ord('C') + self.KEY_D = ord('D') + self.KEY_E = ord('E') + self.KEY_F = ord('F') + self.KEY_G = ord('G') + self.KEY_H = ord('H') + self.KEY_I = ord('I') + self.KEY_J = ord('J') + self.KEY_K = ord('K') + self.KEY_L = ord('L') + self.KEY_M = ord('M') + self.KEY_N = ord('N') + self.KEY_O = ord('O') + self.KEY_P = ord('P') + self.KEY_Q = ord('Q') + self.KEY_R = ord('R') + self.KEY_S = ord('S') + self.KEY_T = ord('T') + self.KEY_U = ord('U') + self.KEY_V = ord('V') + self.KEY_W = ord('W') + self.KEY_X = ord('X') + self.KEY_Y = ord('Y') + self.KEY_Z = ord('Z') + self.KEY_0 = ord('0') + self.KEY_1 = ord('1') + self.KEY_2 = ord('2') + self.KEY_3 = ord('3') + self.KEY_4 = ord('4') + self.KEY_5 = ord('5') + self.KEY_6 = ord('6') + self.KEY_7 = ord('7') + self.KEY_8 = ord('8') + self.KEY_9 = ord('9') + self.KEY_CTRLa = 1 + self.KEY_CTRLb = 2 + self.KEY_CTRLc = 3 + self.KEY_CTRLd = 4 + self.KEY_CTRLe = 5 + self.KEY_CTRLf = 6 + self.KEY_CTRLg = 7 + self.KEY_CTRLh = 8 + self.KEY_CTRLi = 9 + self.KEY_CTRLj = 10 + self.KEY_CTRLk = 11 + self.KEY_CTRLl = 12 + self.KEY_CTRLm = 13 + self.KEY_CTRLn = 14 + self.KEY_CTRLo = 15 + self.KEY_CTRLp = 16 + self.KEY_CTRLq = 17 + self.KEY_CTRLr = 18 + self.KEY_CTRLs = 19 + self.KEY_CTRLt = 20 + self.KEY_CTRLu = 21 + self.KEY_CTRLv = 22 + self.KEY_CTRLw = 23 + self.KEY_CTRLx = 24 + self.KEY_CTRLy = 25 + self.KEY_CTRLz = 26 + self.KEY_SPACE = ord(' ') + self.KEY_BACKSPACE = 127 + self.KEY_BANG = ord('!') + self.KEY_DOUBLEQUOTE = ord('"') + self.KEY_HASH = ord('#') + self.KEY_DOLLAR = ord('$') + self.KEY_PERCENT = ord('%') + self.KEY_QUOTE = ord("'") + self.KEY_OPENBRACKET = ord('(') + self.KEY_CLOSEBRACKET = ord(')') + self.KEY_ASTERISK = ord('*') + self.KEY_PLUS = ord('+') + self.KEY_MINUS = ord('-') + self.KEY_COMMA = ord(',') + self.KEY_DASH = ord('-') + self.KEY_PERIOD = ord('.') + self.KEY_FSLASH = ord('/') + self.KEY_BSLASH = ord('\\') + self.KEY_DASH = ord('-') + self.KEY_SQUAREOPEN = ord('[') + self.KEY_SQUARECLOSE = ord(']') + self.KEY_CARET = ord('^') + self.KEY_UNDERSCORE = ord('_') + self.KEY_BACKTICK = ord('`') + self.KEY_CURLEYOPEN = ord('{') + self.KEY_CURLEYCLOSE = ord('}') + self.KEY_PIPE = ord('|') + self.KEY_TILDE = ord('~') + # Unix Specific + self.KEY_UP = 113179 + self.KEY_DOWN = 114203 + self.KEY_LEFT = 116251 + self.KEY_RIGHT = 115227 + self.KEY_DELETE = 356891 + self.KEY_ENTER = 13 + # Linux Specific + self.KEY_F1 = 272923 + self.KEY_F2 = 274971 + self.KEY_F3 = 277019 + self.KEY_F4 = 279061 + self.KEY_F5 = 281115 + self.KEY_F6 = 722531 + # Common + self.KEY_F7 = 727579 + self.KEY_F8 = 729627 + self.KEY_F9 = 712219 + self.KEY_F10 = 714267 + self.KEY_F11 = 718363 + self.KEY_F12 = 720411 + # OSX Specific + self.KEY_AltF8 = 0 + self.KEY_AltF9 = 0 + self.KEY_AltF10 = 0 + self.KEY_AltF11 = 0 + self.KEY_AltF12 = 0 + self.KEY_SECTION = 0 + self.KEY_PLUSMINUS = 0 + + def __call__(self): + def timeout_handler(signum, frame): + raise TimeoutException() - def __call__(self): - def timeout_handler(signum, frame): - raise TimeoutException() + import sys, tty, termios + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + tty.setcbreak(sys.stdin.fileno()) + ch0 = ord(sys.stdin.read(1)) + od = ch0 + # print ch0 + if od == 194: # mac section/plusminus key kludge + ch1 = ord(sys.stdin.read(1)) + # print ch1 + od += ch1 * 512 + if od == 27: # special key + # This is some horrible, kludge, upfu*kery but curses/tkinter won't work for my needs + old_handler = signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(1) + try: + ch1 = ord(sys.stdin.read(1)) + # print ch1 + od += ch1 * 512 + ch2 = ord(sys.stdin.read(1)) + # print ch2 + od += ch2 * 1024 + pos = 2048 + if 64 < ch2 < 69: + pass + elif ch1 == 91: + while True: + chx = ord(sys.stdin.read(1)) + # print chx + od += chx * pos + pos += pos + if chx == 126: + break + signal.alarm(0) + except TimeoutException: + od = od + finally: + signal.signal(signal.SIGALRM, old_handler) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return od - import sys, tty, termios - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - tty.setcbreak(sys.stdin.fileno()) - ch0 = ord(sys.stdin.read(1)) - od = ch0 - #print ch0 - if od == 194: #mac section/plusminus key kludge - ch1 = ord(sys.stdin.read(1)) - #print ch1 - od += ch1 * 512 - if od == 27: #special key - # This is some horrible, kludge, upfu*kery but curses/tkinter won't work for my needs - old_handler = signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(1) - try: - ch1 = ord(sys.stdin.read(1)) - #print ch1 - od += ch1 * 512 - ch2 = ord(sys.stdin.read(1)) - #print ch2 - od += ch2 * 1024 - pos = 2048 - if ch2 > 64 and ch2 < 69: - pass - elif ch1 == 91: - while True: - chx = ord(sys.stdin.read(1)) - #print chx - od += chx * pos - pos += pos - if chx == 126: - break - signal.alarm(0) - except TimeoutException: - od = od - finally: - signal.signal(signal.SIGALRM, old_handler) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return od class _GetchWindows: - def __init__(self): - self.KEY_UP = 0 #todo + def __init__(self): + self.KEY_UP = 0 # todo + + def __call__(self): + import msvcrt + return msvcrt.getch() - def __call__(self): - import msvcrt - return msvcrt.getch() getch = _Getch() diff --git a/py3270wrapper.py b/py3270wrapper.py index 4a76b10..7c3760c 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -1,97 +1,102 @@ #!/usr/bin/env python -from py3270 import Emulator,CommandError,FieldTruncateError,TerminatedError,WaitError,KeyboardStateError,FieldTruncateError,x3270App,s3270App +from py3270 import Emulator, CommandError, FieldTruncateError, X3270App, S3270App import platform from time import sleep from sys import exit from os import path + # Override some behaviour of py3270 library class EmulatorIntermediate(Emulator): - def __init__(self, visible=True, delay=0): - try: - Emulator.__init__(self, visible) - self.delay = delay - except OSError as e: - print(("Can't run x3270, are you sure it's in the right place? Actual error: "+str(e))) - exit(1) + def __init__(self, visible=True, delay=0): + try: + Emulator.__init__(self, visible) + self.delay = delay + except OSError as e: + print("Can't run x3270, are you sure it's in the right place? Actual error: " + str(e)) + exit(1) + + def send_enter(self): # Allow a delay to be configured + self.exec_command('Enter') + if self.delay > 0: + sleep(self.delay) + + def screen_get(self): + response = self.exec_command('Ascii()') + return response.data - def send_enter(self): # Allow a delay to be configured - self.exec_command('Enter') - if self.delay > 0: - sleep(self.delay) + # Send text without triggering field protection + def safe_send(self, text): + for i in range(0, len(text)): + self.send_string(text[i]) + if self.status.field_protection == 'P': + return False # We triggered field protection, stop + return True # Safe - def screen_get(self): - response = self.exec_command('Ascii()') - return response.data + # Fill fields in carefully, checking for triggering field protections + def safe_fieldfill(self, ypos, xpos, tosend, length): + if length - len(tosend) < 0: + raise FieldTruncateError('length limit %d, but got "%s"' % (length, tosend)) + if xpos is not None and ypos is not None: + self.move_to(ypos, xpos) + try: + self.delete_field() + if safe_send(self, tosend): + return True # Hah, we win, take that mainframe + else: + return False # we entered what we could, bailing + except CommandError as e: + # We hit an error, get mad + return False + # if str(e) == 'Keyboard locked': - # Send text without triggering field protection - def safe_send(self, text): - for i in range(0,len(text)): - self.send_string(text[i]) - if self.status.field_protection == 'P': - return False # We triggered field protection, stop - return True # Safe + # Search the screen for text when we don't know exactly where it is, checking for read errors + def find_response(self, response): + for rows in range(1, int(self.status.row_number) + 1): + for cols in range(1, int(self.status.col_number) + 1 - len(response)): + try: + if self.string_found(rows, cols, response): + return True + except CommandError as e: + # We hit a read error, usually because the screen hasn't returned + # increasing the delay works + sleep(self.delay) + self.delay += 1 + whine( + 'Read error encountered, assuming host is slow, increasing delay by 1s to: ' + str(self.delay), + kind='warn') + return False + return False - # Fill fields in carefully, checking for triggering field protections - def safe_fieldfill(self, ypos, xpos, tosend, length): - if length - len(tosend) < 0: - raise FieldTruncateError('length limit %d, but got "%s"' % (length, tosend)) - if xpos is not None and ypos is not None: - self.move_to(ypos, xpos) - try: - self.delete_field() - if safe_send(self, tosend): - return True # Hah, we win, take that mainframe - else: - return False # we entered what we could, bailing - except CommandError as e: - # We hit an error, get mad - return False - # if str(e) == 'Keyboard locked': + # Get the current x3270 cursor position + def get_pos(self): + results = self.exec_command('Query(Cursor)') + row = int(results.data[0].split(' ')[0]) + col = int(results.data[0].split(' ')[1]) + return row, col - # Search the screen for text when we don't know exactly where it is, checking for read errors - def find_response(self, response): - for rows in range(1,int(self.status.row_number)+1): - for cols in range(1,int(self.status.col_number)+1-len(response)): - try: - if self.string_found(rows, cols, response): - return True - except CommandError as e: - # We hit a read error, usually because the screen hasn't returned - # increasing the delay works - sleep(self.delay) - self.delay += 1 - whine('Read error encountered, assuming host is slow, increasing delay by 1s to: ' + str(self.delay),kind='warn') - return False - return False - - # Get the current x3270 cursor position - def get_pos(self): - results = self.exec_command('Query(Cursor)') - row = int(results.data[0].split(' ')[0]) - col = int(results.data[0].split(' ')[1]) - return (row,col) + def get_hostinfo(self): + return self.exec_command('Query(Host)').data[0].split(' ') - def get_hostinfo(self): - return self.exec_command('Query(Host)').data[0].split(' ') # Set the emulator intelligently based on your platform if platform.system() == 'Darwin': - class WrappedEmulator(EmulatorIntermediate): - x3270App.executable = './x3270' - s3270App.executable = 's3270' + class WrappedEmulator(EmulatorIntermediate): + X3270App.executable = './x3270' + S3270App.executable = 's3270' elif platform.system() == 'Linux': - class WrappedEmulator(EmulatorIntermediate): - x3270App.executable = './x3270' - s3270App.executable = 's3270' + class WrappedEmulator(EmulatorIntermediate): + X3270App.executable = './x3270' + S3270App.executable = 's3270' elif platform.system() == 'Windows': - class WrappedEmulator(EmulatorIntermediate): - #x3270_executable = 'Windows_Binaries/wc3270.exe' - x3270App.executable = 'wc3270.exe' + class WrappedEmulator(EmulatorIntermediate): + # x3270_executable = 'Windows_Binaries/wc3270.exe' + X3270App.executable = 'wc3270.exe' else: - logger('Your Platform:', platform.system(), 'is not supported at this time.',kind='err') - sys.exit(1) -if not path.isfile(x3270App.executable): - print(("Can't find the x3270 executable at "+x3270App.executable+" You can configure the location at the bottom of py3270wrapper.py")) - exit(1) + logger('Your Platform:', platform.system(), 'is not supported at this time.', kind='err') + exit(1) +if not path.isfile(X3270App.executable): + print(( + "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py")) + exit(1) diff --git a/tn3270.py b/tn3270.py index 328f581..229a438 100644 --- a/tn3270.py +++ b/tn3270.py @@ -1,307 +1,312 @@ from datetime import datetime -from colorama import Fore,Back,Style,init +from colorama import Fore, Back, Style + # Object to hold field details class Field: - def __init__(self, contents, row, col, rawstatus, printable=0, protected=0, numeric=0, hidden=0, normnsel=0, normsel=0, highsel=0, zeronsel=0, reserved=0, modify=0): - self.contents = contents - self.row = row - self.col = col - self.rawstatus = rawstatus - self.printable = printable - self.protected = protected - self.numeric = numeric - self.hidden = hidden - self.normnsel = normnsel - self.normsel = normsel - self.highsel = highsel - self.zeronsel = zeronsel - self.reserved = reserved - self.modify = modify - - def __repr__(self): - a = "" - return ''.join(a) - - def __str__(self): - return self.contents - - def __len__(self): - return len(self.contents) + def __init__(self, contents, row, col, rawstatus, printable=0, protected=0, numeric=0, hidden=0, normnsel=0, + normsel=0, highsel=0, zeronsel=0, reserved=0, modify=0): + self.contents = contents + self.row = row + self.col = col + self.rawstatus = rawstatus + self.printable = printable + self.protected = protected + self.numeric = numeric + self.hidden = hidden + self.normnsel = normnsel + self.normsel = normsel + self.highsel = highsel + self.zeronsel = zeronsel + self.reserved = reserved + self.modify = modify + + def __repr__(self): + a = "" + return ''.join(a) + + def __str__(self): + return self.contents + + def __len__(self): + return len(self.contents) + # Object to hold a screen from x3270 class Screen: - def __init__(self, rawbuff): - self.rawbuffer = rawbuff - self.rows = len(self.rawbuffer) - self.cols = len(self.rawbuffer[0]) - #From x3270 defines - self.__FA_PRINTABLE = 0xc0 #these make the character "printable" - self.__FA_PROTECT = 0x20 #unprotected (0) / protected (1) - self.__FA_NUMERIC = 0x10 #alphanumeric (0) /numeric (1)Skip? - self.__FA_HIDDEN = 0x0c #display/selector pen detectable: - self.__FA_INT_NORM_NSEL = 0x00 # 00 normal, non-detect - self.__FA_INT_NORM_SEL = 0x04 # 01 normal, detectable - self.__FA_INT_HIGH_SEL = 0x08 # 10 intensified, detectable - self.__FA_INT_ZERO_NSEL = 0x0c # 11 nondisplay, non-detect, same as hidden - self.__FA_RESERVED = 0x02 #must be 0 - self.__FA_MODIFY = 0x01 #modified (1) - - @property - # Dump the hex without the field & formatting markers - def plainbuffer(self): - plnbuf = list() - for line in self.rawbuffer: - splitline = line.split(' ') - plainline = [] - for i in splitline: - if len(i) == 2: #Not a field marker - plainline.append(i) - else: - plainline.append('00') #Use a NULL instead of a field marker - plnbuf.append(plainline) - return plnbuf - - @property - # Give us a string version of plainbuffer - def stringbuffer(self): - strbuf = list() - for line in self.plainbuffer: - newstr = ''.join(line).decode("hex") - strbuf.append(newstr) - return strbuf - - # A pretty printed version converting NULL to ' ' - def __str__(self): - return '\n'.join(self.stringbuffer).replace('\x00',' ') - - def __repr__(self): - a = "" - return ''.join(a) - - @property - # Highlight different fields so we can see what is really going on on the screen - # This looks at field markers only and ignores colours asked for by the host - def colorbuffer(self): - colbuf = list() - colbuf.append(Fore.RED) #Highlight unfield'ed text - counter = 0 #for line numbers - for line in self.rawbuffer: - newline = list() - newline.append('{:>2}'.format(counter)+' ') #line no - counter += 1 - for i in line.split(' '): - # SF(c0=c8) is example of StartField markup - if len(i) > 3 and i.find('SF(') >= 0: - attrib = int(i[3:5],16) - val = int(i[6:8],16) - - foreflag = False - backflag = False - styleflag = False - if (val | self.__FA_HIDDEN) == val: - newline.append(Back.RED) - backflag = True - if (val | self.__FA_MODIFY) == val: - newline.append(Fore.YELLOW) - newline.append(Style.BRIGHT) - foreflag = True - styleflag = True - if (val | self.__FA_PROTECT) != val: - newline.append(Back.GREEN) - backflag = True - #if (val | self.__FA_INT_HIGH_SEL) == val: - #newline.append(Style.BRIGHT) - #styleflag = True - if not foreflag: - newline.append(Fore.RESET) - if not backflag: - newline.append(Back.RESET) - if not styleflag: - newline.append(Style.NORMAL) - - newline.append('\u2219') #Field marker - - elif len(i) == 2: - if i == '00': - newline.append("\u2400") - else: - newline.append(i.decode("hex")) - #newline.append(Fore.RESET+Back.RESET+Style.RESET_ALL) - colbuf.append(''.join(newline)) - strcolbuf = '\n'.join(colbuf) + Fore.RESET + Back.RESET - return strcolbuf - - @property - # Display the screen as it would look in an emulator - # This looks at field markers only and ignores colours asked for by the host - # TODO: implement CF parsing - def emubuffer(self): - colbuf = list() - for line in self.rawbuffer: - newline = list() - for i in line.split(' '): - # SF(c0=c8) is example of StartField markup - if len(i) > 3 and i.find('SF(') >= 0: - attrib = int(i[3:5],16) - val = int(i[6:8],16) - - newline.append(' ') #Field marker - - modflag = False - hideflag = False - if (val | self.__FA_PROTECT) != val: - modflag = True - newline.append(Back.WHITE) - newline.append(Fore.BLACK) - if (val | self.__FA_HIDDEN) == val: - hideflag = True - if not modflag: - newline.append(Fore.RESET) - newline.append(Back.RESET) - - elif len(i) == 2: - if i == '00': - newline.append(' ') - elif hideflag: - newline.append(' ') - else: - newline.append(i.decode("hex")) - colbuf.append(''.join(newline)) - strcolbuf = '\n'.join(colbuf) - return strcolbuf - - @property - # Return a DOM of sorts with each field and it's characteristics - def fields(self): - field_list = list() - row = 0 - for line in self.rawbuffer: - col = 0 - for i in line.split(' '): - # SF(c0=c8) is example of StartField markup - if len(i) > 3 and i.find('SF(') >= 0: - attrib = int(i[3:5],16) - val = int(i[6:8],16) - - printable = 0 - protected = 0 - numeric = 0 - hidden = 0 - normnsel = 0 - normsel = 0 - highsel = 0 - zeronsel = 0 - reserved = 0 - modify = 0 - rawstatus = i #store the raw status for later implementation of SA() - if (val | self.__FA_PRINTABLE) == val: - printable = 1 - if (val | self.__FA_PROTECT ) == val: - protected = 1 - if (val | self.__FA_NUMERIC ) == val: - numeric = 1 - if (val | self.__FA_HIDDEN) == val: - hidden = 1 - if (val | self.__FA_INT_NORM_NSEL) == val: - normnsel = 1 - if (val | self.__FA_INT_NORM_SEL) == val: - normsel = 1 - if (val | self.__FA_INT_HIGH_SEL) == val: - highsel = 1 - if (val | self.__FA_INT_ZERO_NSEL) == val: - zeronsel = 1 - if (val | self.__FA_RESERVED) == val: - reserved = 1 - if (val | self.__FA_MODIFY) == val: - modify = 1 - - field = Field('', row, col, rawstatus, printable, protected, numeric, hidden, normnsel, normsel, highsel, zeronsel, reserved, modify) - field_list.append(field) - - # Add the character to the last field entity added - elif len(i) == 2: - contents = i.decode("hex") - if len(field_list) > 0: - field_list[len(field_list)-1].contents += contents - - col += 1 - row += 1 - return field_list - - @property - def protected_fields(self): - try: - res = [x for x in self.fields if x.protected == 1] - except IndexError: - res = [] - return res - - @property - def input_fields(self): - try: - res = [x for x in self.fields if x.protected == 0] - except IndexError: - res = [] - return res - - @property - def hidden_fields(self): - try: - res = [x for x in self.fields if x.hidden == 1] - except IndexError: - res = [] - return res - - @property - def modified_fields(self): - try: - res = [x for x in self.fields if x.modify == 1] - except IndexError: - res = [] - return res + def __init__(self, rawbuff): + self.rawbuffer = rawbuff + self.rows = len(self.rawbuffer) + self.cols = len(self.rawbuffer[0]) + # From x3270 defines + self.__FA_PRINTABLE = 0xc0 # these make the character "printable" + self.__FA_PROTECT = 0x20 # unprotected (0) / protected (1) + self.__FA_NUMERIC = 0x10 # alphanumeric (0) /numeric (1)Skip? + self.__FA_HIDDEN = 0x0c # display/selector pen detectable: + self.__FA_INT_NORM_NSEL = 0x00 # 00 normal, non-detect + self.__FA_INT_NORM_SEL = 0x04 # 01 normal, detectable + self.__FA_INT_HIGH_SEL = 0x08 # 10 intensified, detectable + self.__FA_INT_ZERO_NSEL = 0x0c # 11 nondisplay, non-detect, same as hidden + self.__FA_RESERVED = 0x02 # must be 0 + self.__FA_MODIFY = 0x01 # modified (1) + + @property + # Dump the hex without the field & formatting markers + def plainbuffer(self): + plnbuf = list() + for line in self.rawbuffer: + splitline = line.split(' ') + plainline = [] + for i in splitline: + if len(i) == 2: # Not a field marker + plainline.append(i) + else: + plainline.append('00') # Use a NULL instead of a field marker + plnbuf.append(plainline) + return plnbuf + + @property + # Give us a string version of plainbuffer + def stringbuffer(self): + strbuf = list() + for line in self.plainbuffer: + newstr = ''.join(line).decode("hex") + strbuf.append(newstr) + return strbuf + + # A pretty printed version converting NULL to ' ' + def __str__(self): + return '\n'.join(self.stringbuffer).replace('\x00', ' ') + + def __repr__(self): + a = "" + return ''.join(a) + + @property + # Highlight different fields so we can see what is really going on on the screen + # This looks at field markers only and ignores colours asked for by the host + def colorbuffer(self): + colbuf = list() + colbuf.append(Fore.RED) # Highlight unfield'ed text + counter = 0 # for line numbers + for line in self.rawbuffer: + newline = list() + newline.append('{:>2}'.format(counter) + ' ') # line no + counter += 1 + for i in line.split(' '): + # SF(c0=c8) is example of StartField markup + if len(i) > 3 and i.find('SF(') >= 0: + attrib = int(i[3:5], 16) + val = int(i[6:8], 16) + + foreflag = False + backflag = False + styleflag = False + if (val | self.__FA_HIDDEN) == val: + newline.append(Back.RED) + backflag = True + if (val | self.__FA_MODIFY) == val: + newline.append(Fore.YELLOW) + newline.append(Style.BRIGHT) + foreflag = True + styleflag = True + if (val | self.__FA_PROTECT) != val: + newline.append(Back.GREEN) + backflag = True + # if (val | self.__FA_INT_HIGH_SEL) == val: + # newline.append(Style.BRIGHT) + # styleflag = True + if not foreflag: + newline.append(Fore.RESET) + if not backflag: + newline.append(Back.RESET) + if not styleflag: + newline.append(Style.NORMAL) + + newline.append('\u2219') # Field marker + + elif len(i) == 2: + if i == '00': + newline.append("\u2400") + else: + newline.append(i.decode("hex")) + # newline.append(Fore.RESET+Back.RESET+Style.RESET_ALL) + colbuf.append(''.join(newline)) + strcolbuf = '\n'.join(colbuf) + Fore.RESET + Back.RESET + return strcolbuf + + @property + # Display the screen as it would look in an emulator + # This looks at field markers only and ignores colours asked for by the host + # TODO: implement CF parsing + def emubuffer(self): + colbuf = list() + for line in self.rawbuffer: + newline = list() + for i in line.split(' '): + # SF(c0=c8) is example of StartField markup + if len(i) > 3 and i.find('SF(') >= 0: + attrib = int(i[3:5], 16) + val = int(i[6:8], 16) + + newline.append(' ') # Field marker + + modflag = False + hideflag = False + if (val | self.__FA_PROTECT) != val: + modflag = True + newline.append(Back.WHITE) + newline.append(Fore.BLACK) + if (val | self.__FA_HIDDEN) == val: + hideflag = True + if not modflag: + newline.append(Fore.RESET) + newline.append(Back.RESET) + + elif len(i) == 2: + if i == '00': + newline.append(' ') + elif hideflag: + newline.append(' ') + else: + newline.append(i.decode("hex")) + colbuf.append(''.join(newline)) + strcolbuf = '\n'.join(colbuf) + return strcolbuf + + @property + # Return a DOM of sorts with each field and it's characteristics + def fields(self): + field_list = list() + row = 0 + for line in self.rawbuffer: + col = 0 + for i in line.split(' '): + # SF(c0=c8) is example of StartField markup + if len(i) > 3 and i.find('SF(') >= 0: + attrib = int(i[3:5], 16) + val = int(i[6:8], 16) + + printable = 0 + protected = 0 + numeric = 0 + hidden = 0 + normnsel = 0 + normsel = 0 + highsel = 0 + zeronsel = 0 + reserved = 0 + modify = 0 + rawstatus = i # store the raw status for later implementation of SA() + if (val | self.__FA_PRINTABLE) == val: + printable = 1 + if (val | self.__FA_PROTECT) == val: + protected = 1 + if (val | self.__FA_NUMERIC) == val: + numeric = 1 + if (val | self.__FA_HIDDEN) == val: + hidden = 1 + if (val | self.__FA_INT_NORM_NSEL) == val: + normnsel = 1 + if (val | self.__FA_INT_NORM_SEL) == val: + normsel = 1 + if (val | self.__FA_INT_HIGH_SEL) == val: + highsel = 1 + if (val | self.__FA_INT_ZERO_NSEL) == val: + zeronsel = 1 + if (val | self.__FA_RESERVED) == val: + reserved = 1 + if (val | self.__FA_MODIFY) == val: + modify = 1 + + field = Field('', row, col, rawstatus, printable, protected, numeric, hidden, normnsel, normsel, + highsel, zeronsel, reserved, modify) + field_list.append(field) + + # Add the character to the last field entity added + elif len(i) == 2: + contents = i.decode("hex") + if len(field_list) > 0: + field_list[len(field_list) - 1].contents += contents + + col += 1 + row += 1 + return field_list + + @property + def protected_fields(self): + try: + res = [x for x in self.fields if x.protected == 1] + except IndexError: + res = [] + return res + + @property + def input_fields(self): + try: + res = [x for x in self.fields if x.protected == 0] + except IndexError: + res = [] + return res + + @property + def hidden_fields(self): + try: + res = [x for x in self.fields if x.hidden == 1] + except IndexError: + res = [] + return res + + @property + def modified_fields(self): + try: + res = [x for x in self.fields if x.modify == 1] + except IndexError: + res = [] + return res + # Object to hold an single tn3270 "transaction" i.e. request/response & timestamp class Transaction: - def __init__(self, request, response, data, key='enter', host='', comment=''): - # these should be Screen objects - self.request = request - self.response = response - self.data = data #Data that was submitted - # For now I'm going to assume the last item in the list is the newest - self.timestamp = datetime.now() - # What key initiated the transaction - self.key = key - self.comment = comment - self.host = host - - def __repr__(self): - a = "" - return ''.join(a) + def __init__(self, request, response, data, key='enter', host='', comment=''): + # these should be Screen objects + self.request = request + self.response = response + self.data = data # Data that was submitted + # For now I'm going to assume the last item in the list is the newest + self.timestamp = datetime.now() + # What key initiated the transaction + self.key = key + self.comment = comment + self.host = host + + def __repr__(self): + a = "" + return ''.join(a) -class History: - def __init__(self): - self.timeline = list() - def __getitem__(self, index): - return self.timeline[index] +class History: + def __init__(self): + self.timeline = list() - def __repr__(self): - return " Date: Fri, 5 Nov 2021 12:38:20 +0100 Subject: [PATCH 03/12] removed old decoded method(hex) --- tn3270.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tn3270.py b/tn3270.py index 229a438..109fedd 100644 --- a/tn3270.py +++ b/tn3270.py @@ -70,7 +70,7 @@ def plainbuffer(self): def stringbuffer(self): strbuf = list() for line in self.plainbuffer: - newstr = ''.join(line).decode("hex") + newstr = bytearray.fromhex(b''.join(line).decode('utf-8')).decode('ascii') strbuf.append(newstr) return strbuf @@ -129,7 +129,7 @@ def colorbuffer(self): if i == '00': newline.append("\u2400") else: - newline.append(i.decode("hex")) + newline.append(chr(int(i, 16))) # newline.append(Fore.RESET+Back.RESET+Style.RESET_ALL) colbuf.append(''.join(newline)) strcolbuf = '\n'.join(colbuf) + Fore.RESET + Back.RESET @@ -169,7 +169,7 @@ def emubuffer(self): elif hideflag: newline.append(' ') else: - newline.append(i.decode("hex")) + newline.append(chr(int(i, 16))) colbuf.append(''.join(newline)) strcolbuf = '\n'.join(colbuf) return strcolbuf @@ -225,7 +225,7 @@ def fields(self): # Add the character to the last field entity added elif len(i) == 2: - contents = i.decode("hex") + contents = chr(int(i, 16)) if len(field_list) > 0: field_list[len(field_list) - 1].contents += contents From 73fd6bb2ad600c46d8d70073a6dfc4fac7f89111 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Fri, 5 Nov 2021 12:51:20 +0100 Subject: [PATCH 04/12] added support to proxy --- birp.py | 28 ++++++++++++++++------------ py3270wrapper.py | 16 +++++++++++++--- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/birp.py b/birp.py index 838b85a..2cef2e2 100755 --- a/birp.py +++ b/birp.py @@ -519,20 +519,24 @@ def prestartup(): init() # initialise coloured output from colorama # Define and fetch commandline arguments - parser = argparse.ArgumentParser( \ - description='Big Iron Recon & Pwnage (BIRP) by @singe', \ - epilog="It's easier than you think") - parser.add_argument('-t', '--target', \ - help='Target IP address or hostname & port: TARGET[:PORT]. The default port is 23. If you don\'t specify a target, you can manually specify it in the emulator', \ + parser = argparse.ArgumentParser(description='Big Iron Recon & Pwnage (BIRP) by @singe', + epilog="It's easier than you think") + parser.add_argument('-t', '--target', + help='Target IP address or hostname & port: TARGET[:PORT]. The default port is 23. If you don\'t specify a target, you can manually specify it in the emulator', required=False, dest='target', default="") - parser.add_argument('-s', '--sleep', \ - help='Seconds to sleep between actions (increase on slower systems). The default is 0 seconds.', \ + parser.add_argument('-s', '--sleep', + help='Seconds to sleep between actions (increase on slower systems). The default is 0 seconds.', default=0, type=float, dest='sleep') - parser.add_argument('-l', '--load', help='Load a previously saved history file', default='', \ - dest='loadfile', type=str) - parser.add_argument('-q', '--quiet', help="Ssssh! Don't print info text.", \ - default=False, dest='quiet', action='store_true') + parser.add_argument('-l', '--load', help='Load a previously saved history file.', default='', dest='loadfile', + type=str) + parser.add_argument('-q', '--quiet', help="Ssssh! Don't print info text.", default=False, dest='quiet', + action='store_true') + parser.add_argument('-p', '--proxy', help="Set proxy.", default=None, dest='proxy', action='store') results = parser.parse_args() + + if results.proxy: + results.proxy = ["-proxy", results.proxy] + return results @@ -548,7 +552,7 @@ def startup(): logger('Attack platform\t\t: ' + platform.system(), kind='info') if not platform.system() == 'Windows': - em = WrappedEmulator(visible=True, delay=results.sleep) + em = WrappedEmulator(visible=True, delay=results.sleep, args=results.proxy) elif platform.system() == 'Windows': logger('x3270 not supported on Windows', kind='err') sys.exit(1) diff --git a/py3270wrapper.py b/py3270wrapper.py index 7c3760c..c49db17 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from py3270 import Emulator, CommandError, FieldTruncateError, X3270App, S3270App +from py3270 import Emulator, CommandError, FieldTruncateError, X3270App, S3270App, ExecutableApp import platform from time import sleep from sys import exit @@ -9,9 +9,9 @@ # Override some behaviour of py3270 library class EmulatorIntermediate(Emulator): - def __init__(self, visible=True, delay=0): + def __init__(self, visible=True, delay=0, args=None): try: - Emulator.__init__(self, visible) + Emulator.__init__(self, visible, args=args) self.delay = delay except OSError as e: print("Can't run x3270, are you sure it's in the right place? Actual error: " + str(e)) @@ -80,6 +80,16 @@ def get_hostinfo(self): return self.exec_command('Query(Host)').data[0].split(' ') +# Patching __init__ method to support correct args +def executable_app_init(instance, args): + if args: + instance.args = instance.args + args + instance.sp = None + instance.spawn_app() + + +ExecutableApp.__init__ = executable_app_init + # Set the emulator intelligently based on your platform if platform.system() == 'Darwin': class WrappedEmulator(EmulatorIntermediate): From c5760c35b7d3a6c2076a11613fb33aa711248f9d Mon Sep 17 00:00:00 2001 From: jacopodl Date: Fri, 5 Nov 2021 21:31:28 +0100 Subject: [PATCH 05/12] string to byte string --- birp.py | 30 +++++++++++++++--------------- py3270wrapper.py | 15 ++++++++------- tn3270.py | 14 +++++++------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/birp.py b/birp.py index 2cef2e2..55d7b3b 100755 --- a/birp.py +++ b/birp.py @@ -90,7 +90,7 @@ def logger(text, kind='clear', level=0): # Update a screen object with the latest x3270 screen def update_screen(em, screen): - screen = tn3270.Screen(em.exec_command('ReadBuffer(Ascii)').data) + screen = tn3270.Screen(em.exec_command(b'ReadBuffer(Ascii)').data) return screen @@ -101,8 +101,8 @@ def exec_trans(em, history, key='enter'): check = tn3270.Screen request = update_screen(em, request) keypress = '' - hostinfo = em.exec_command('Query(Host)').data[0].split(' ') - host = hostinfo[1] + ':' + hostinfo[2] + hostinfo = em.exec_command(b'Query(Host)').data[0].split(b' ') + host = hostinfo[1] + b':' + hostinfo[2] data = request.modified_fields if key == 'enter': em.send_enter() @@ -114,7 +114,7 @@ def exec_trans(em, history, key='enter'): elif 25 < key < 28: keypress = 'PA(' + str(key - 24) + ')' em.exec_command(keypress) - em.exec_command('Wait(1,3270Mode)') # Capture the whole 3270 screen + em.exec_command(b'Wait(1,3270Mode)') # Capture the whole 3270 screen response = update_screen(em, response) trans = tn3270.Transaction(request, response, data, keypress, host) history.append(trans) @@ -198,13 +198,13 @@ def interactive(em, history): key = getch() if key == getch.KEY_UP: # Up - em.exec_command('Up()') + em.exec_command(b'Up()') elif key == getch.KEY_DOWN: # Down - em.exec_command('Down()') + em.exec_command(b'Down()') elif key == getch.KEY_LEFT: # Left - em.exec_command('Left()') + em.exec_command(b'Left()') elif key == getch.KEY_RIGHT: # Right - em.exec_command('Right()') + em.exec_command(b'Right()') elif key == getch.KEY_ENTER: # Enter trans = exec_trans(em, history, 'enter') print(trans.response.colorbuffer) @@ -216,8 +216,8 @@ def interactive(em, history): elif key == getch.KEY_CTRLu: # Ctrl-u manually push transaction screen = update_screen(em, screen) data = screen.modified_fields - hostinfo = em.exec_command('Query(Host)').data[0].split(' ') - host = hostinfo[1] + ':' + hostinfo[2] + hostinfo = em.exec_command(b'Query(Host)').data[0].split(' ') + host = hostinfo[1] + b':' + hostinfo[2] trans = tn3270.Transaction(history.last().response, screen, data, 'manual', host) history.append(trans) print(screen.colorbuffer) @@ -232,13 +232,13 @@ def interactive(em, history): em.save_screen(str(trans.timestamp.date()) + '_' + str(trans.timestamp.time()) + '.html') logger('Screenshot saved', kind='info') elif key == getch.KEY_TAB: # Tab 9 - em.exec_command('Tab()') + em.exec_command(b'Tab()') elif key == getch.KEY_BACKSPACE: # Backspace - em.exec_command('BackSpace()') + em.exec_command(b'BackSpace()') elif key == getch.KEY_DELETE: # Delete - em.exec_command('Delete()') + em.exec_command(b'Delete()') elif key == getch.KEY_CTRLc: # Ctrl-c Clear - em.exec_command('Clear()') + em.exec_command(b'Clear()') elif key == getch.KEY_CTRLq: # Ctrl-q PA1 trans = exec_trans(em, history, 25) print(trans.response.colorbuffer) @@ -581,7 +581,7 @@ def startup(): sys.exit(1) hostinfo = em.get_hostinfo() - host = hostinfo[1] + ':' + hostinfo[2] + host = hostinfo[1] + b':' + hostinfo[2] menu(em, history) # And we're done. Close the connection diff --git a/py3270wrapper.py b/py3270wrapper.py index c49db17..bd027bc 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -18,12 +18,12 @@ def __init__(self, visible=True, delay=0, args=None): exit(1) def send_enter(self): # Allow a delay to be configured - self.exec_command('Enter') + self.exec_command(b'Enter') if self.delay > 0: sleep(self.delay) def screen_get(self): - response = self.exec_command('Ascii()') + response = self.exec_command(b'Ascii()') return response.data # Send text without triggering field protection @@ -71,16 +71,17 @@ def find_response(self, response): # Get the current x3270 cursor position def get_pos(self): - results = self.exec_command('Query(Cursor)') - row = int(results.data[0].split(' ')[0]) - col = int(results.data[0].split(' ')[1]) + results = self.exec_command(b'Query(Cursor)') + row = int(results.data[0].split(b' ')[0]) + col = int(results.data[0].split(b' ')[1]) return row, col def get_hostinfo(self): - return self.exec_command('Query(Host)').data[0].split(' ') + return self.exec_command(b'Query(Host)').data[0].split(b' ') -# Patching __init__ method to support correct args +# Patching __init__ method to support args +# this fix is required for the current version of py3270(0.3.5) def executable_app_init(instance, args): if args: instance.args = instance.args + args diff --git a/tn3270.py b/tn3270.py index 109fedd..683b544 100644 --- a/tn3270.py +++ b/tn3270.py @@ -55,13 +55,13 @@ def __init__(self, rawbuff): def plainbuffer(self): plnbuf = list() for line in self.rawbuffer: - splitline = line.split(' ') + splitline = line.split(b' ') plainline = [] for i in splitline: if len(i) == 2: # Not a field marker plainline.append(i) else: - plainline.append('00') # Use a NULL instead of a field marker + plainline.append(b'00') # Use a NULL instead of a field marker plnbuf.append(plainline) return plnbuf @@ -93,9 +93,9 @@ def colorbuffer(self): newline = list() newline.append('{:>2}'.format(counter) + ' ') # line no counter += 1 - for i in line.split(' '): + for i in line.split(b' '): # SF(c0=c8) is example of StartField markup - if len(i) > 3 and i.find('SF(') >= 0: + if len(i) > 3 and i.find(b'SF(') >= 0: attrib = int(i[3:5], 16) val = int(i[6:8], 16) @@ -143,7 +143,7 @@ def emubuffer(self): colbuf = list() for line in self.rawbuffer: newline = list() - for i in line.split(' '): + for i in line.split(b' '): # SF(c0=c8) is example of StartField markup if len(i) > 3 and i.find('SF(') >= 0: attrib = int(i[3:5], 16) @@ -181,9 +181,9 @@ def fields(self): row = 0 for line in self.rawbuffer: col = 0 - for i in line.split(' '): + for i in line.split(b' '): # SF(c0=c8) is example of StartField markup - if len(i) > 3 and i.find('SF(') >= 0: + if len(i) > 3 and i.find(b'SF(') >= 0: attrib = int(i[3:5], 16) val = int(i[6:8], 16) From 2846a4ba6c01487a23c93b424a2102ee5dcb60d3 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Fri, 5 Nov 2021 21:34:58 +0100 Subject: [PATCH 06/12] refactoring --- py3270wrapper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py3270wrapper.py b/py3270wrapper.py index bd027bc..5bb345e 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -63,7 +63,7 @@ def find_response(self, response): # increasing the delay works sleep(self.delay) self.delay += 1 - whine( + logger( 'Read error encountered, assuming host is slow, increasing delay by 1s to: ' + str(self.delay), kind='warn') return False @@ -108,6 +108,6 @@ class WrappedEmulator(EmulatorIntermediate): logger('Your Platform:', platform.system(), 'is not supported at this time.', kind='err') exit(1) if not path.isfile(X3270App.executable): - print(( - "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py")) + print( + "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py") exit(1) From aa674d79905efda77dbaa6a5c8672f17579457e9 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Mon, 8 Nov 2021 09:50:48 +0100 Subject: [PATCH 07/12] bugfix BrokenPipeError --- py3270wrapper.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/py3270wrapper.py b/py3270wrapper.py index 5bb345e..e24f391 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -79,6 +79,12 @@ def get_pos(self): def get_hostinfo(self): return self.exec_command(b'Query(Host)').data[0].split(b' ') + def is_connected(self): + try: + return Emulator.is_connected(self) + except BrokenPipeError: + return False + # Patching __init__ method to support args # this fix is required for the current version of py3270(0.3.5) @@ -109,5 +115,5 @@ class WrappedEmulator(EmulatorIntermediate): exit(1) if not path.isfile(X3270App.executable): print( - "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py") + "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py") exit(1) From 78490dcb2c2572c8a0c57223dfef6637bbe2eb31 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Mon, 8 Nov 2021 10:09:38 +0100 Subject: [PATCH 08/12] bugfix BrokenPipeError --- py3270wrapper.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/py3270wrapper.py b/py3270wrapper.py index e24f391..d1db54e 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from py3270 import Emulator, CommandError, FieldTruncateError, X3270App, S3270App, ExecutableApp +from py3270 import Emulator, Command, CommandError, FieldTruncateError, X3270App, S3270App, ExecutableApp import platform from time import sleep from sys import exit @@ -85,6 +85,12 @@ def is_connected(self): except BrokenPipeError: return False + def exec_command(self, cmdstr): + try: + return Emulator.exec_command(self, cmdstr) + except BrokenPipeError: + return Command(self.app, cmdstr) + # Patching __init__ method to support args # this fix is required for the current version of py3270(0.3.5) From 813ab4ef6b3c7795b89b3de69328386cfd52052a Mon Sep 17 00:00:00 2001 From: jacopodl Date: Mon, 8 Nov 2021 10:10:23 +0100 Subject: [PATCH 09/12] refactoring --- birp.py | 4 ++-- py3270wrapper.py | 20 +++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/birp.py b/birp.py index 55d7b3b..2dc64b5 100755 --- a/birp.py +++ b/birp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from py3270wrapper import WrappedEmulator +from py3270wrapper import EmulatorIntermediate import tn3270 import sys import argparse @@ -552,7 +552,7 @@ def startup(): logger('Attack platform\t\t: ' + platform.system(), kind='info') if not platform.system() == 'Windows': - em = WrappedEmulator(visible=True, delay=results.sleep, args=results.proxy) + em = EmulatorIntermediate(visible=True, delay=results.sleep, args=results.proxy) elif platform.system() == 'Windows': logger('x3270 not supported on Windows', kind='err') sys.exit(1) diff --git a/py3270wrapper.py b/py3270wrapper.py index d1db54e..b627cd7 100755 --- a/py3270wrapper.py +++ b/py3270wrapper.py @@ -104,22 +104,16 @@ def executable_app_init(instance, args): ExecutableApp.__init__ = executable_app_init # Set the emulator intelligently based on your platform -if platform.system() == 'Darwin': - class WrappedEmulator(EmulatorIntermediate): - X3270App.executable = './x3270' - S3270App.executable = 's3270' -elif platform.system() == 'Linux': - class WrappedEmulator(EmulatorIntermediate): - X3270App.executable = './x3270' - S3270App.executable = 's3270' +if platform.system() == 'Linux' or platform.system() == 'Darwin': + X3270App.executable = './x3270' + S3270App.executable = 's3270' elif platform.system() == 'Windows': - class WrappedEmulator(EmulatorIntermediate): - # x3270_executable = 'Windows_Binaries/wc3270.exe' - X3270App.executable = 'wc3270.exe' + # x3270_executable = 'Windows_Binaries/wc3270.exe' + X3270App.executable = 'wc3270.exe' else: logger('Your Platform:', platform.system(), 'is not supported at this time.', kind='err') exit(1) if not path.isfile(X3270App.executable): - print( - "Can't find the x3270 executable at " + X3270App.executable + " You can configure the location at the bottom of py3270wrapper.py") + print("Can't find the x3270 executable at %s." + "You can configure the location at the bottom of py3270wrapper.py" % X3270App.executable) exit(1) From 03dd94bce76a812f26815f038dcf8a0c7cb33ea5 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Mon, 8 Nov 2021 10:13:26 +0100 Subject: [PATCH 10/12] added support to passing arguments to x3270, refactoring --- birp.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/birp.py b/birp.py index 2dc64b5..ab68585 100755 --- a/birp.py +++ b/birp.py @@ -531,11 +531,17 @@ def prestartup(): type=str) parser.add_argument('-q', '--quiet', help="Ssssh! Don't print info text.", default=False, dest='quiet', action='store_true') - parser.add_argument('-p', '--proxy', help="Set proxy.", default=None, dest='proxy', action='store') + parser.add_argument('--proxy', help="Set proxy.", default=[], dest='proxy', action='store') + parser.add_argument('--args', help="Pass arguments to x3270 executable.", default=[], dest='args', action='store') results = parser.parse_args() - if results.proxy: - results.proxy = ["-proxy", results.proxy] + if results.args: + results.args = results.args.split() + + if results.proxy and "-proxy" not in results.args: + results.proxy = ["-proxy", results.proxy] + else: + results.proxy = [] return results @@ -552,7 +558,7 @@ def startup(): logger('Attack platform\t\t: ' + platform.system(), kind='info') if not platform.system() == 'Windows': - em = EmulatorIntermediate(visible=True, delay=results.sleep, args=results.proxy) + em = EmulatorIntermediate(visible=True, delay=results.sleep, args=results.args + results.proxy) elif platform.system() == 'Windows': logger('x3270 not supported on Windows', kind='err') sys.exit(1) From 681fc6b6a574fa26533bc8b83858ba13c8462eb5 Mon Sep 17 00:00:00 2001 From: jacopodl Date: Mon, 8 Nov 2021 10:27:14 +0100 Subject: [PATCH 11/12] bugfix --- birp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birp.py b/birp.py index ab68585..4d5f2a9 100755 --- a/birp.py +++ b/birp.py @@ -216,7 +216,7 @@ def interactive(em, history): elif key == getch.KEY_CTRLu: # Ctrl-u manually push transaction screen = update_screen(em, screen) data = screen.modified_fields - hostinfo = em.exec_command(b'Query(Host)').data[0].split(' ') + hostinfo = em.exec_command(b'Query(Host)').data[0].split(b' ') host = hostinfo[1] + b':' + hostinfo[2] trans = tn3270.Transaction(history.last().response, screen, data, 'manual', host) history.append(trans) From 21bb763c48618126fbbf5473fcf452ea4c803b3a Mon Sep 17 00:00:00 2001 From: Jacopo De Luca Date: Mon, 8 Nov 2021 10:34:26 +0100 Subject: [PATCH 12/12] Update Readme.md --- Readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Readme.md b/Readme.md index 633e5fb..0953c17 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +2,8 @@ Big Iron Recon & Pwnage (BIRP) ============================== by @singe (Dominic White @ SensePost) +**This version run on Python3!** + Overview -------- @@ -18,6 +20,8 @@ All you need is to specify a target with -t . Target specification can include a You can use -l to load a previously saved history file into the history. You must always specify a target and cannot just view history yet unfortunately. +You can use --args to push arguments to x3270 executable. Furthermore, a quick option(--proxy) has been added to specify the proxy to use. + Check the pre-requisites below for installing. Unfortunately, this will only run in Unix environments at the moment, no Windows support. Functionality