Well, you see, I have searched and searched without any results on how to make an input between multiline strings, such as something like this:
print("******************************\nPassword: ", end="")
x = input()
print("******************************")
print("Your password is %s" % (x))
( but when i do this, the last of asterisks line is not printed until the input has be done )
or also like in GNU nano, when you write text you do it between strings with new lines
Thank you very much in advance
I get it, you have to do a return (\r) and then a backspace (\b), here is my program that prompts for the password and a function to make it easier.
Password prompt program:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from readchar import readchar
from os import get_terminal_size
from sys import stdout
print("\n"*((get_terminal_size()[1]-5)//2))
spaces = " " * ((get_terminal_size()[0]-53)//2)
passwd = ""
text = ""
text+="\r\b\r\b\r\b "
text+="""{0}#####################################################\n"""
text+="""{0}# #\n"""
text+="""{0}# Password: #\n"""
text+="""{0}# #\n"""
text+="""{0}#####################################################\n"""
text+="""\r\b\r\b\r\b\r"""
text+="""{0}# Password: {1}"""
stdout.write(text.format(spaces, "*" * len(passwd)))
stdout.flush()
try:
ch = readchar()
while ch != "\n":
if ch == "\x7f":
passwd = passwd[:-1]
elif ch in ["\r", "\x03"]:
break
else:
passwd += ch
if len(passwd) > 32:
stdout.write(text % ("*"*32))
else:
stdout.write(text.format(spaces, "*" * len(passwd)))
stdout.flush()
ch = readchar()
except(KeyboardInterrupt):
pass
print("\n"*5+passwd )
Function:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def backspace_enter(charlen, get_back=False):
print("\r\b"*charlen, end="")
if get_back == True:
print("\n"*charlen, end="")
I think that you are dealing with buffering issues on stdout. Add flush =true to your print statement.
print("Hello\n", flush=True);
Related
I am a hobby radio amateur [G6SGA] not a programmer but I do try. :)
using python3. I am trying to do the following and really can't get my head around - argparse and ended up trying to use 'Import click'. Still can't get my head around so here I am. Any all (polite) :) suggestions welcome.
I wish to ---
cmd line> python3 scratch.py [no options supplied]
output> "Your defaults were used and are:9600 and '/dev/ttyAMA0' "
or
cmd line> python3 scratch.py 115200 '/dev/ttyABC123'
output> "Your input values were used and are: 115200 and '/dev/ttyAMA0'"
so a command line that will take [or NOT] argument/s. store the argument to a variable in the code for future use.
This some of what I have tried: Yes I accept it's a mess
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
# ========================
# Include standard modules
# import click
# baud default = 9600
# port default = "/dev/ttyAMA0"
import click
#click.command()
# #click.option('--baud', required = False, default = 9600, help = 'baud rate defaults to: 9600')
# #click.option('--port', required = False, default = '/dev/ttyAMA0', help = 'the port to use defaults to: /dev/ttyAMA0')
#click.option('--item', type=(str, int))
def putitem(item):
click.echo('name=%s id=%d' % item)
def communications():
""" This checks the baud rate and port to use
either the command line supplied item or items.
Or uses the default values
abaud = 9600 # default baud rate
b=abaud
aport = "/dev/ttyAMA0"
p=aport
print(f"abaud = {b} and aport = {p}")
"""
# now I wish to check if there were supplied values
# on the command line
# print(f"Baud supplied {click.option.} port supplied {port}" )
if __name__ == '__main__':
putitem() # communications()
The code I have used to work this all out is below, I hope it helps somebody. Any better ways or mistakes please advise.
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
import click
from typing import Tuple
# Command Line test string: python scratch_2.py -u bbc.co.uk aaa 9600 bbb ccc
myuri = "" # This is a placeholder for a GLOBAL variable -- take care!
list1 = [] # This is a placeholder for a GLOBAL variable -- take care!
#click.command(name="myLauncher", context_settings={"ignore_unknown_options": True})
#click.option('--uri', '-u', type=click.STRING, default=False, help ="URI for the server")
#click.argument('unprocessed_args', nargs = -1, type = click.UNPROCESSED)
def main(uri: str, unprocessed_args: Tuple[str, ...]) -> None:
# ==================== Checking the command line structure and obtaining variables
global myuri # define the use of a GLOBAL variable in this function
temp = list((str(j) for i in {unprocessed_args: Tuple} for j in i)) # sort out the command line arguments
res = len(temp)
# printing result
print("")
for e in range(0 ,res): # list each of the command line elements not including any uri
print("First check: An input line Tuple element number: " + str(e) +": " + str(temp[e])) # elements base 0
# ==================== deal with any URI supplied -- or NOT
if uri is False: #if --uri or -u is not supplied
print("No uri supplied\n")
print("The input line tuple list elements count: " + str(res))
# set a defaul GLOBAL value of myuri if it is not supplied
myuri = "https://192.168.0.90:6691/" #
else:
print("\nThe input line tuple list elements count : " + str(res) + " and we got a uri")
myuri = uri # set the GLOBAL value of myuri if the uri is
print(f"which is: {uri}, and therefore myuri also is: {myuri}") # a temp print to prove the values of the GLOBAL variable 'myuri'
# ==============================================================================================
# Testing choice of baud rate on command line
db_list = {
'4800': 'TEST48',
'9600': 'TEST96',
'19200': 'TEST19',
'38400': 'TEST38',
'57600': 'TEST57',
'115200': 'TEST11',
}
# Print databases ----- db_list ----- listed in dictionary
print("\nDatabases:")
for e in range(0 ,res) :
""" list each of the command line elements not including any uri
print("Second Check: An input line Tuple element number: " + str(e) +": " + str(temp[e]))
elements base 0 """
if str(temp[e]) in db_list.keys() :
print(f"The index of db contains {str(temp[e])}, The index refers to: {db_list[str(temp[e])]}")
if __name__ == "__main__":
# pylint: disable=no-value-for-parameter, unexpected-keyword-arg
main()
I was testing pipe using subprocess.call and I came to the following problem.
For example an automated ssh using users as strings and as a text file.
The pipe works perfectly using strings (Example 1) but it fails when opening a text file to check the users (Example 2).
Is there a limitation when piping values from a file?
Example 1:
$ python3 script.py myhost
import subprocess
import sys
host = sys.argv[1]
for j in range(0, 2):
words = ['test1', 'test2']
user = words[j]
print(user)
print('Loggin in %s...' % repr(user))
subp = subprocess.call(['echo %s | ssh %s' % (user, host)],
shell=True, stdout=None, stderr=None)
Output:
test1
Trying 'test1'...
Logged in
test2
Trying 'test2'...
Logged in
Example 2:
$ python3 script.py myhost users.txt
import subprocess
import sys
host = sys.argv[1]
user_list = sys.argv[2]
with open(user_list) as usr:
user = usr.readline()
cnt = 0
while user:
print(user.strip())
user = usr.readline()
subp = subprocess.call(['echo %s | ssh %s' % (user, host)],
shell=True, stdout=None, stderr=None)
cnt += 1
Output:
test1
/bin/sh: 2: Syntax error: "|" unexpected
test2
/bin/sh: 2: Syntax error: "|" unexpected
In case someone stumbles into this, I ended up fixing by getting rid of the first readline, adding a strip and modifying the while condition:
with open(user_list) as usr:
cnt = 0
while usr:
line = usr.readline()
user = line.strip()
subp = subprocess.call(['echo %s | ssh %s' % (user, host)],
shell=True, stdout=None, stderr=None)
cnt += 1
Its again about utf-8 issues, for the 1001st time. Please don't mark this question as duplicate, 'cause I cannot find answers elsewhere.
Since some months I am working successfully with the following small script (which may improved, I know that), which delivers me a simple database functionality. But I wrote it for very simple data storage, like local config and auth data, let's say not for more sophisticated content as known from cookies. It worked for me, until I tried to store non latin characters for the 1st time.
In the following script I already added the import codecs stuff, including the altered lines f = codecs.open(file, 'w', 'utf-8'). Do not know if this is the right approach.
Can somebody show me the trick ? Let's say "John Doe" is french, "John Doé", how do I store it ?
The class itself (to be imported)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os, errno
import json
import codecs
class Ddpos:
def db(self,table,id,col=''):
table = '/Users/michag/Documents/ddposdb/'+table
try:
os.makedirs(table)
os.chmod(table, 0o755)
except OSError as e:
if e.errno != errno.EEXIST:
raise
file = table+'/'+id+'.txt'
if not os.path.isfile(file):
f = codecs.open(file, 'w', 'utf-8')
f.write('{}')
f.close()
f = codecs.open(file, 'r', 'utf-8')
r = json.loads(f.readline().strip())
f.close()
if isinstance(col, str) and len(col) > 0:
if col in r:
return json.dumps(r[col])
else:
return ''
elif isinstance(col, list) and len(col) > 0:
res = {}
for el in range(0,len(col)):
if col[el] in r:
res[col[el]] = r[col[el]]
return json.dumps(res)
elif isinstance(col, dict) and len(col) > 0:
for el in col:
r[el] = col[el]
f = codecs.open(file, 'w', 'utf-8')
f.write(json.dumps(r))
f.close()
return json.dumps(r)
else:
return json.dumps(r)
ddpos = Ddpos()
The call / usage
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from ddpos import *
# set values and return all values as dict
print ('1.: '+ddpos.db('cfg','local',{'admin':'John Doé','email':'johndoe#email.com'}))
# return all values as dict
print ('2.: '+ddpos.db('cfg','local'))
# return one value as string
print ('3.: '+ddpos.db('cfg','local','email'))
# return two or more values as dict
print ('4.: '+ddpos.db('cfg','local',['admin','email']))
It prints and stores this in case of "John Doe"
1.: {"admin": "John Doe", "email": "johndoe#email.com"}
2.: {"admin": "John Doe", "email": "johndoe#email.com"}
3.: "johndoe#email.com"
4.: {"admin": "John Doe", "email": "johndoe#email.com"}
and this in case of french guy "John Doé"
1.: {"email": "johndoe#email.com", "admin": "John Do\u00e9"}
2.: {"email": "johndoe#email.com", "admin": "John Do\u00e9"}
3.: "johndoe#email.com"
4.: {"email": "johndoe#email.com", "admin": "John Do\u00e9"}
For me it is more important to learn and to understand, how it works and why or why not, but to know that there already classes which would do the job for me. Thanks for your support.
After moderator deceze I answer my own question, with credentials to user mata and python3 itself.
Here's the "new" script. The poor french guy now is renamed to "J€hn Doéß" and he's still alive.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os, errno
import json
class Ddpos:
def db(self,table,id,col=''):
table = '/Users/michag/Documents/ddposdb/'+table
try:
os.makedirs(table)
os.chmod(table, 0o755)
except OSError as e:
if e.errno != errno.EEXIST:
raise
file = table+'/'+id+'.txt'
if not os.path.isfile(file):
f = open(file, 'w')
f.write('{}')
f.close()
f = open(file, 'r')
r = json.loads(f.readline().strip())
f.close()
if isinstance(col, str) and len(col) > 0:
if col in r:
return r[col]
else:
return ''
elif isinstance(col, list) and len(col) > 0:
res = {}
for el in range(0,len(col)):
if col[el] in r:
res[col[el]] = r[col[el]]
return res
elif isinstance(col, dict) and len(col) > 0:
for el in col:
r[el] = col[el]
f = open(file, 'w')
f.write(json.dumps(r))
f.close()
return r
else:
return r
ddpos = Ddpos()
UPDATE
I made some improvements. Now the stored dict is human readable (for those unbelievers, like me) and sorted case insensitive. This sorting process for sure consumes a bit of performance, but hey, I will use the read-only process some houndred times more than the write process.
Now the stored dict looks like this:
{
"auth_descr": "dev unit, office2",
"auth_email": "me#myemail.com",
"auth_key": "550e3 **shortened sha256** d73b1",
"auth_unit_id": "2.3.1",
"vier": "44é", # utf-8 example
"Vjier": "vier44" # uppercase example
}
I don't know where I did a mistake in earlier version(s), but if you take a look on the utf-8 example. "é" now is stored as an "é" and not as "\u00e9".
The class now looks like this (with minor changes)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os, errno
import json
class Ddpos:
def db(self,table,id,col=''):
table = '/ddpos/db/'+table
try:
os.makedirs(table)
os.chmod(table, 0o755)
except OSError as e:
if e.errno != errno.EEXIST:
raise
file = table+'/'+id+'.txt'
if not os.path.isfile(file):
f = open(file, 'w', encoding='utf-8')
f.write('{}')
f.close()
f = open(file, 'r', encoding='utf-8')
r = json.loads(f.read().strip())
f.close()
if isinstance(col, str) and len(col) > 0:
if col in r:
return r[col]
else:
return ''
elif isinstance(col, list) and len(col) > 0:
res = {}
for el in range(0,len(col)):
if col[el] in r:
res[col[el]] = r[col[el]]
return res
elif isinstance(col, dict) and len(col) > 0:
for el in col:
r[el] = col[el]
w = '{\n'
for key in sorted(r, key=lambda y: y.lower()):
w += '\t"%s": "%s",\n' % (key, r[key])
w = w[:-2]+'\n'
w += '}'
f = open(file, 'w', encoding='utf-8')
f.write(w)
f.close()
return r
else:
return r
ddpos = Ddpos()
I have a single threaded program that simply executes commands over ssh and simply looks for output over ssh. But after a while I start getting extrodinarily strange behaviour:
ssh_cmd = 'ssh %s#%s %s' % (user, addr, options)
ssh = pexpect.spawn(ssh_cmd, timeout=60)
lgsuc = ['(?i)(password)')]
for item in loginsuccess:
lgsuc.append(item)
retval = ssh.expect(lgsuc)
for cmd in cmdlist:
time.sleep(0.1)
#this is regex to match anything. Essentially clears the buffer so you don't get an invalid match from before
ssh.expect(['(?s).*'])
ssh.sendline(cmd)
foundind = ssh.expect([re.escape("root#")], 30) #very slow
#repr escape all the wierd stuff so madness doesn't happen with ctr chars
rettxt = repr(ssh.before.decode("us-ascii") + "root:#")
print("We Found:" + rettxt
And it will be fine for about 20 commands or so then madness occurs Assume the right echo is blablabla each time:
We found 'blablabla \r\n\r\n[edit]\r\nroot#'
We found 'blablabla \r\n\r\n[edit]\r\nroot#'
We found 'blablabla \r\n\r\n[edit]\r\nroot#'
... about 20 commands...
We found 'bl\r\nroot#' # here it just missed part of the string in the middle
We found 'alala\r\nroot#'
here is the remainder of the echo from the previous command!!! and the echo of the current command will show up some time later!! and it gets worse and worse. The thing that is strange is it is in the middle of the return byte array.
Now there are some wierd control codes coming back from this device so if I replace:
rettxt = repr(ssh.before.decode("us-ascii") + "root:#")
with
rettxt = repr(ssh.before.decode("us-ascii") + "root:#")
then
print("We Found:" + rettxt)
returns:
root#e Found lala
Anyway there is really strange stuff going on with pexpect and the buffers, and I can't figure out what it is so any help would be appreciated. I should mention I never get teh timeout, the dive always responds. Also the total number of "root:#"in the log file exceedes the total number of lines sent.
If I go through and remove all ctl codes, the output looks cleaner but the problem still persists, its as if pextect cant handle ctl coodes in its buffer correctly. Any help is appreciated
UPDATE Minimum verifiable example
Ok I have been able to recreate PART of the problem on an isolated ubuntu environment sshing into itself.
first I need to create 4 commands that can be run on a host target, so put the follwing for files in ~/ I did this in ubuntu
~/check.py
#!/usr/bin/python3
import time
import io
#abcd^H^H^H^H^MABC
#mybytes = b'\x61\x62\x63\x64\x08\x08\x08\x0D\x41\x42\x43'
#abcdACB
mybytes = b'\x61\x62\x63\x64\x41\x42\x43'
f = open('test.txt', 'wb')
#time.sleep(1)
f.write(mybytes)
print(mybytes.decode('ascii'))
f.close()
~/check2.py
#!/usr/bin/python3
import time
import io
#0123^H^H^H^H^MABC
mybytes = b'\x30\x31\x32\x33\x08\x0D\x0D\x08\x08\x08\x08\x0D\x41\x42\x43'
f = open('test2.txt', 'wb')
#time.sleep(0.1)
f.write(mybytes)
print(mybytes.decode('ascii'))
f.close()
~/check3.py
#!/usr/bin/python3
import time
import io
#789:^H^H^H^H^DABC
mybytes = b'\x37\x38\x39\x3A\x08\x08\x08\x08\x08\x08\x08\x0D\x0D\x41\x42\x43'
f = open('test3.txt', 'wb')
#time.sleep(0.1)
f.write(mybytes)
print(mybytes.decode('ascii'))
f.close()
And lastly check4.py Sorry it took a wierd combination for the problem to show back up
#!/usr/bin/python3
import time
import io
#abcd^H^H^H^HABC
mybytes = b'\x61\x62\x63\x64\x08\x08\x08\x0D\x41\x42\x43'
f = open('test.txt', 'wb')
time.sleep(4)
f.write(mybytes)
print(mybytes.decode('ascii'))
f.close()
Noticing that the last one has a bigger sleep, this is to encounter texpect timeout. Though on my actual testing this doesn't occue, I have commands that take over 6 minutes to return any text so this might be part of it. Ok and the final file to run everything. It might look ugly but I did a massive trim so I could post it here:
#! /usr/bin/python3
#import paramiko
import time
import sys
import xml.etree.ElementTree as ET
import xml
import os.path
import traceback
import re
import datetime
import pexpect
import os
import os.path
ssh = None
respFile = None
#Error Codes:
DEBUG = True
NO_ERROR=0
EXCEPTION_THROWS=1
RETURN_TEXT_NEVER_FOUND = 2
LOG_CONSOLE = 1
LOG_FILE = 2
LOG_BOTH = 3
def log(out, dummy=None):
print(str(log))
def connect(user, addr, passwd):
global ssh
fout = open('session.log', 'wb')
#options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'
options = ' -oUserKnownHostsFile=/dev/null '
#options = ''
#REPLACE WITH YOU LOCAL USER NAME
#user = 'user'
#REPLACE WITH YOUR LOCAL PASSWORD
#passwd = '123TesT321'
#addr = '127.0.0.1'
ssh_cmd = 'ssh %s#%s %s' % (user, addr, options)
public = None
private = None
retval = 0
try:
ssh = pexpect.spawn(ssh_cmd, timeout=60)
ssh.logfile = fout
#the most common prompts
loginsuccess = [re.escape("#"), re.escape("$")]
lgsuc = ['(?i)(password)', re.escape("connecting (yes/no)? ")]
for item in loginsuccess:
lgsuc.append(item)
retval = ssh.expect(lgsuc)
except pexpect.TIMEOUT as exc:
log("Server never connected to SSH tunnel")
return 0
print('where here ret val = ' + str(retval))
try:
if(retval > 1):
return 1
elif(retval == 1):
hostkey = ssh.before.decode("utf-8")
ssh.sendline("yes")
log("Warning! new host key was added to the database: " + hostkey.split("\n")[1])
lgsuc = ['password: ']
for item in loginsuccess:
lgsuc.append(item)
retval = ssh.expect(lgsuc)
if(retval > 0):
return 1
else:
if(public is not None):
log("Warning public key authentication failed trying password if available...")
else:
if public is not None:
log("Warning public key authentication failed trying password if available...")
if(passwd is None):
log("No password and certificate authentication failed...")
return 0
ssh.sendline(passwd)
login = ['password: ' ]
for item in loginsuccess:
login.append(item)
retval = ssh.expect(login)
except pexpect.TIMEOUT as exc:
log("Server Never responded with expected login prompt: "+lgstr)
return 0
#return 0
if retval > 0:
retval = 1
if retval == 0:
log("Failed to connect to IP:"+addr +" User:"+user+" Password:"+passwd)
return retval
def disconnect():
log("Disconnecting...")
global ssh
if ssh is not None:
ssh.close()
else:
log("Something wierd happened with the SSH client while closing the session. Shouldn't really matter", False)
def RunCommand(cmd, waitTXT, timeout = 5):
global ssh
Error = 0
if DEBUG:
print('Debugging: cmd: '+ cmd+'. timeout: '+str(timeout) +'. len of txt tags: '+ str(len(waitTXT)))
if(type(waitTXT) is str):
waitTXT = [re.excape(waitTXT)]
elif(not hasattr(waitTXT ,'__iter__')):
waitTXT = [re.escape(str(waitTXT))]
else:
cnter = 0
for TXT in waitTXT:
waitTXT[cnter] = re.escape(str(TXT))
cnter +=1
#start = time.time()
#print("type3: "+str(type(ssh)))
#time.sleep(1)
#this is regex to match anything. Essentially clears the buffer so you don't get an invalid match from before
ssh.expect(['(?s).*'])
ssh.sendline(cmd)
print("Debugging: sent: "+cmd)
#GoOn = True
rettxt = ""
try:
foundind = ssh.expect(waitTXT, timeout)
allbytes = ssh.before
newbytes = bytearray()
for onebyte in allbytes:
if onebyte > 31:
newbytes.append(onebyte)
allbytes = bytes(newbytes)
rettxt = repr(allbytes.decode("us-ascii") + waitTXT[foundind])
#rettxt = ssh.before + waitTXT[foundind]
if DEBUG:
print("Debugging: We found "+rettxt)
except pexpect.TIMEOUT as exc:
if DEBUG:
txtret = ""
for strtxt in waitTXT:
txtret += strtxt +", "
print("ERROR Debugging: we timed out waiting for text:"+txtret)
pass
return (rettxt, Error)
def CloseAndExit():
disconnect()
global respFile
if respFile is not None and '_io.TextIOWrapper' in str(type(respFile)):
if not respFile.closed:
respFile.close()
def main(argv):
try:
cmds = ['~/check.py', '~/check2.py', '~/check3.py', '~/check2.py', '~/check3.py','~/check.py', '~/check2.py', '~/check3.py', '~/check2.py', '~/check3.py', '~/check4.py', '~/check3.py','~/check.py', '~/check2.py',]
##CHANGE THESE TO MTACH YOUR SSH HOST
ret = connect('user', '127.0.0.1', 'abcd1234')
for cmd in cmds:
cmdtxt = str(cmd)
#rett = RunCommand(ssh, "ls", "root", 0, 5)
strlen = (170 - (len(cmdtxt)))/2
dashval = ''
starval = ''
tcnt = 0
while(tcnt < strlen):
dashval +='-'
starval +='*'
tcnt +=1
if DEBUG:
print(dashval+cmdtxt+dashval)
#checkval = ['ABC']
#REPLACE THE FOLLOWING LINE WITH YOUR TARGET PROMPT
checkval = ['user-virtual-machine:~$']
rett = RunCommand(cmdtxt, checkval, 2)
if DEBUG:
print(starval+cmdtxt+starval)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
print(traceback.format_exc())
CloseAndExit()
#disconnect()
#respFile.close()
main(sys.argv)
Make sure that all for checks and the main python script are executble in permission via sudo chmod 774 or similar. In the main function call set your username ipaddress and password to where your target is that has the check.py and make sure they are in your ~/ directory.
Once you run this you can look at the session.log and at least on mind there is some wierd stuff going on with the buffer:
~/check4.py^M
~/check3.py
~/check3.py^M
abcd^H^H^H^MABC^M
^[]0;user#user-virtual-machine: ~^Guser#user-virtual-machine:~$ ~/check.py
~/check3.py^M
789:^H^H^H^H^H^H^H^M^MABC^M
^[]0;user#user-virtual-machine: ~^Guser#user-virtual-machine:~$ ~/check.py~/check2.py
And unfortunately its not as corrupt as my actual prbolem but I have several hundred commands I an embedded custom linux kernal that I obviously can't recreate for everyone. But anyway any help is greatly appreciated. Hopefully these examples work you you, I am just on ubuntu 16.04 lts. Also make sure to replace 'user-virtual-machine:~$' with whatever your target login prompt looks like
I'm trying to get this shadow file cracker working but I keep getting a TypeError: integer required.
I'm sure its the way I'm using the bytearray function. I've tried creating a new object with bytearray for the "word" and the "salt" however to no avail. So then I tried passing the bytearray constructor to the pbkdf2 function and still nothing. I will post the code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import hashlib, binascii
import os,sys
import crypt
import codecs
from datetime import datetime,timedelta
import argparse
today = datetime.today()
# Takes in user and the encrypted passwords and does a simple
# Brute Force Attack useing the '==' operator. SHA* is defined by
# a number b/w $, the char's b/w the next $ marker would be the
# rounds, then the salt, and after that the hashed password.
# object.split("some symbol or char")[#], where # is the
# location/index within the list
def testPass(cryptPass,user):
digest = hashlib.sha512
dicFile = open ('Dictionary.txt','r')
ctype = cryptPass.split("$")[1]
if ctype == '6':
print "[+] Hash type SHA-512 detected ..."
print "[+] Be patien ..."
rounds = cryptPass.split("$")[2].strip('rounds=')
salt = cryptPass.split("$")[3]
print "[DEBUG]: " + rounds
print "[DEBUG]: " + salt
# insalt = "$" + ctype + "$" + salt + "$" << COMMENTED THIS OUT
for word in dicFile.readlines():
word = word.strip('\n')
print "[DEBUG]: " + word
cryptWord = hashlib.pbkdf2_hmac(digest().name,bytearray(word, 'utf-8'),bytearray(salt, 'utf-8'), rounds)
if (cryptWord == cryptPass):
time = time = str(datetime.today() - today)
print "[+] Found password for the user: " + user + " ====> " + word + " Time: "+time+"\n"
return
else:
print "Nothing found, bye!!"
exit
# argparse is used in main to parse arguments pass by the user.
# Path to shadow file is required as a argument.
def main():
parse = argparse.ArgumentParser(description='A simple brute force /etc/shadow .')
parse.add_argument('-f', action='store', dest='path', help='Path to shadow file, example: \'/etc/shadow\'')
argus=parse.parse_args()
if argus.path == None:
parse.print_help()
exit
else:
passFile = open (argus.path,'r', 1) # ADDING A 1 INDICATES A BUFFER OF A
for line in passFile.readlines(): # SINGLE LINE '1<=INDICATES
line = line.replace("\n","").split(":") # EXACT BUFFER SIZE
if not line[1] in [ 'x', '*','!' ]:
user = line[0]
cryptPass = line[1]
testPass(cryptPass,user)
if __name__=="__main__":
main()
OUTPUT:
[+] Hash type SHA-512 detected ...
[+] Be patien ...
[DEBUG]: 65536
[DEBUG]: A9UiC2ng
[DEBUG]: hellocat
Traceback (most recent call last):
File "ShadowFileCracker.py", line 63, in <module>
main()
File "ShadowFileCracker.py", line 60, in main
testPass(cryptPass,user)
File "ShadowFileCracker.py", line 34, in testPass
cryptWord = hashlib.pbkdf2_hmac(digest().name,bytearray(word, 'utf-8'),bytearray(salt, 'utf-8'), rounds)
TypeError: an integer is required
The rounds variable needs to be an integer, not a string. The correct line should be:
rounds = int(cryptPass.split("$")[2].strip('rounds='))
Also, strip() might not be the best method for removing the leading "rounds=". It will work, but it strips a set of characters and not a string. A slightly better method would be:
rounds = int(cryptPass.split("$")[2].split("=")[1])