/etc/passwd及/etc/shadow
在写 UNIX Password Cracker之前我们首先要了解UNIX系统是如何保存用户密码的。
/etc/passwd内容如下:
/etc/shadow内容如下(密码域结构:$指示加密方式$干扰串$密码hash值):
etc/passwd、/etc/shadow文件权限如下:
各域解释如下:
(仅上图转载自https://blog.csdn.net/zhuoya_/article/details/77418413)
为此可以看出**/etc/passwd文件所有用户都可以读,而/etc/shadow仅有root及shadow**组用户可以读。
UNIX Password Cracker
UNIX Password Cracker实现思路:
- 拿到**/etc/shadow**文件然后提取其中的密码域
- 分析密码域的结构确定salt(即hash算法及干扰串)
- 逐条计算字典中的条目的hash值并与密码域的hash值进行比对
比如:
>>> import crypt
>>> dir(crypt)
['__doc__', '__file__', '__name__', '__package__', 'crypt']
>>> crypt.crypt('root','$6$.XjiYlU6$')
'$6$.XjiYlU6$X7ux./bZdhR9.iVRy8UE10Wlk4oD3TxQsw6QymbsNTfreg/2n1Fhj3Ug1qqc.Wkp7/Gb7YcIyotOKYunJhbMV/'
- 如果相同则对应的密码字典中的词既是密码
完整代码如下:
import crypt
import re
r = re.compile('(\$\d\$.*\$)')
def testPass(cryptPass):
if cryptPass:
print "[+] No Password"
return
salt = r.findall(cryptPass)
if not salt:
print '[-] Password Has Expired or Been Locked'
return
dictFile = open('dictionary.txt','r')
for word in dictFile.readlines():
word = word.strip('\n')
cryptWord = crypt.crypt(word,salt[0])
if (cryptWord == cryptPass):
print "[+] Found Password: "+word+"\n"
return
print "[-] Password Not Found.\n"
return
def main():
passFile = open('passwords.txt')
for line in passFile.readlines():
if ":" in line:
user = line.split(':')[0]
cryptPass = line.split(':')[1].strip(' ')
print "[*] Cracking Password For: "+user
testPass(cryptPass)
if __name__ == "__main__":
main()
Zipfile Password Cracker
关键点:zipfile.ZipFile类实例化后的extactall方法在提取文件内容时通过pwd参数可以指定密码。
Zipfile Password Cracker实现思路:
- 使用文件名初始化zipfile.ZipFile得到zFile
- 调用zFile的extracall方法并指定pwd参数
- 出现异常则可判断密码不正确
- 否则密码正确
完整代码如下:
import zipfile
import optparse
from threading import Thread
def extractFile(zFile, password):
try:
zFile.extractall(pwd=password)
print '[+] Found password ' + password + '\n'
except:
pass
def main():
parser = optparse.OptionParser("usage%prog "+\
"-f <zipfile> -d <dictionary>")
parser.add_option('-f', dest='zname', type='string',\
help='specify zip file')
parser.add_option('-d', dest='dname', type='string',\
help='specify dictionary file')
(options, args) = parser.parse_args()
if (options.zname == None) | (options.dname == None):
print parser.usage
exit(0)
else:
zname = options.zname
dname = options.dname
zFile = zipfile.ZipFile(zname)
passFile = open(dname)
for line in passFile.readlines():
password = line.strip('\n')
t = Thread(target=extractFile, args=(zFile, password))
t.start()
if __name__ == '__main__':
main()
在上述代码中optparse模块已经过期,推荐使用argparse模块,其次是没必要对每一条密码记录开启一个线程,使一个线程处理多条字典密码。改进后代码如下。
import zipfile
import argparse
import sys
import threading
import Queue
word_list = Queue.Queue()
flag = threading.Event()
def extractFile(zFile):
while not (word_list.empty() or flag.is_set()):
try:
zFile.extractall(pwd=word_list.get())
print '[+] Found password ' + password + '\n'
flag.set()
except:
pass
def main():
parser = argparse.ArgumentParser(prog=sys.argv[0], usage="-f <zipfile> -d <dictionary>")
parser.add_argument('-f', dest='zname', action='store',help='specify zip file')
parser.add_argument('-d', dest='dname', action='store',help='specify dictionary file')
options = parser.parse_args()
if (options.zname == None) | (options.dname == None):
print parser.usage
exit(0)
zname = options.zname
dname = options.dname
zFile = zipfile.ZipFile(zname)
passFile = open(dname)
for line in passFile.readlines():
word_list.put(line.strip('\n'))
for i in range(20):
t = threading.Thread(target=extractFile, args=(zFile,))
t.start()
if __name__ == '__main__':
main()