生成pkcs(填充明文)

输入str类型的data,返回byte型data

padding(data,key_len)

def padding(data,key_len): #传参是str类型的data和密钥长度key_len
    data=data.encode() #先把它这个str转成byte~
    missing_padding=key_len-len(data)%key_len #计算需要填充几个字符 假设data长33,密钥长16,那么取模得1,要填充15位保证data填充后长度是密钥长度的整数倍 但是……要是刚好整除,取模为0,那不就是要填充一个密钥长度了……好像不太合理
    if missing_padding:
        data+=(chr(missing_padding)*missing_padding).encode() #如果需要填充,那么就填充上missing_padding这么多位数的missing_padding,这种设计主要是为了之后去掉填充会很巧妙,注意不要漏掉encode(),因为data已经是byte类型了
    return data #返回byte形式的、已经填充的data

去掉填充

输入是上面的那个byte形式的、已经填充的data,返回的是去掉填充的str形式的data

unpadding(data_e)

def unpadding(data_e): #参数data_e是byte形式的、已经填充的data
    data_e=data_e[:-data_e[-1]] #去掉填充,这里直接去掉data_e的最后一位的值对应的长度,因为之前填充的填充位就是填充长度的数字(读起来太绕的话建议直接执行一下试试看效果,但要注意这里是【byte类型】才可以实现这种操作!)
    return data_e.decode() #byte转str

DES加密(ECB模式)

需要自己写一部分,然后调用两个模块,DES和base64:
记得要先在代码开头写上
from Crypto.Cipher import DES

import base64
传参是str,在函数内部先转换密钥key为byte,对明文data填充并转byte,之后再调用DES模块,new一个des对象,des对象调用encrypt加密函数,加密完再base64编码一下,最后转str类型返回

des_encrypt(data,key)

def des_encrypt(data,key): #明文data和密钥key均为str类型
    key_len=len(key) #拿到密钥长度,后续作为padding函数的传参
    key=key.encode() #密钥需要转成byte
    data=padding(data,key_len) #调用上面的padding函数得到byte形式的、已经填充的data
    '''------↓下面重点来了↓------'''
    des=DES.new(key,DES.MODE_ECB) #调用DES.new创建了一个des对象!指定了密钥和模式为ECB
    result=des.encrypt(data) #由des对象调用DES模块的encrypt函数进行des加密
    '''注意上面这两个DES模块的函数,参数都需要是byte类型,返回的result也是byte,然后下一步直接传给base64编码函数'''
    result=base64.b64encode(result) #加密结果做base64编码
    return result.decode() #返回str类型的base64编码结果

DES解密(ECB模式)

类比加密,传参data是上面des_encrypt函数返回的那种str类型的密文,key也是str类型,进入函数先转key为byte,并将data做base64解码(b64decode函数的参数可以是str,解码后返回的结果是byte,但b64encode函数的参数只能是byte,编码后返回的也是byte)。调用DES.new创建des对象,des对象调用解密函数decrypt对密文data解密,解密结果去掉填充,得到str类型的明文。

des_decrypt(data,key)

def des_decrypt(data,key):
    key=key.encode()
    data=base64.b64decode(data) #b64decode传入参数可以是str,返回的是byte,所以这里执行后,data也是byte了
    des=DES.new(key,DES.MODE_ECB)
    data=des.decrypt(data) #解密得到的是明文经填充了的结果,byte类型
    result=unpadding(data) #去掉填充,str类型
    return result

总结上面的函数,在加解密方面,我们自定义的函数传参都是str,返回也是str;但Python的DES模块提供的函数传入参数和返回参数都是byte。对于填充函数padding,传入str,返回byte;对于去填充函数unpadding,传入byte,返回str。

请求包加密

对HTTPS请求包的内容进行加密。body就是请求包中body的内容,是str类型,进入函数首先要调用json.loads(body)将str转成dict。
调用json模块的函数要先
import json
加密后要对body做url编码,调用parse.quote(body)也要先
from urllib import parse

req_encrypt(body)

def req_encrypt(body):
    body_dict=json.loads(body) #body传入时是str,这里先转str为dict
    data=body_dict['data'] #取字典中的data【键】对应的【值】,ps:因为这里是要加密明文,而明文中的data值又是字典类型,所以下面要将dict转str
    data=json.dumps(data,ensure_ascii=False) #dict转str
    data=des_encrypt(data,key) #调用上面的des_encrypt加密函数,输入参数为str,返回值也为str,所以这里得到的密文data是str
    body_dict['data']=data #加密结果赋值给data键对应的值
    body=json.dumps(body_dict) #将dict转回str得到已经加密的body
    body='CONTENT_DATA='+parse.quote(body) #连接字符串,quote是用url编码body
    return body

请求包解密

req_decrypt(body)

def req_decrypt(body):
    body=parse.unquote(body)[13:] #从body的'CONTENT_DATA='后面开始取,调用parse.unquote()将url编码做解码,即%xx替换成单个字符,这里body是str类型
    body_dict=json.loads(body) #str转dict
    data=body_dict['data']  #取dict中的'data'【键】对应的【值】,这里data是密文是str
    data=des_decrypt(data,key) #调用上面自定义的des_decrypt函数做DES解密,解密后得到str类型的data明文
    data=json.loads(data) #str转dict
    body_dict['data']=data #解密后的data赋给body中的'data'键,作为值
    body=json.dumps(body_dict) #dict转回str
    return body
    

总结以上函数,https的请求包中的body是str且body在加密前、加密后都是str在加密和解密时,因为要取出’data’键对应的值,所以都是先将body做str到dict的转换
加密时,data的明文是dict加密处理前还要转一次str,加密后将密文重新赋给data,再把body转回str。
解密时,data的密文是str,可以直接去调解密函数,解密后要先将明文data转成dict类型再重新赋给data,最后再把body转回str。

响应包解密

和请求包解密一个道理,就是body先转dict,取出data密文,解密得到data明文先转dict再重新赋给data,最后将body转回str。

def rsp_decrypt(body):
    body_dict=json.loads(body)
    data=body_dict['data']  #body_dict是dict,但'data'【键】的值是密文、是str
    data=des_decrypt(data,key)
    body_dict['data']=json.loads(data)  #解密结果先转dict再赋回data
    body=json.dumps(body_dict,ensure_ascii=False)  #body_dict整体转str
    return body

响应包加密

之前觉得响应包加密是服务端干的事儿,不用关心,但是后来意识到,我忽略了拦截响应包再修改响应包后放包的渗透测试常用操作……
响应包加密函数里执行的步骤几乎完全可以参考请求包加密。

def rsp_encrypt(body):
    body_dict=json.loads(body)
    data=body_dict['data']  #data是dict类型
    data=json.dumps(data,ensure_ascii=False)  #加密前先转str
    data=des_encrypt(data,key)
    body_dict['data']=data  #加密后的data赋给'data'
    body=json.dumps(body_dict,ensure_ascii=False)  #body_dict整体转str
    return body

class Burpy

最后顺便贴上想要调用burpy插件中Python加解密脚本的固定代码
记得要先在代码开头写上import traceback

class Burpy:
    def __init__(self):
        print('-----------')
        pass

    def _getmethod(self, header):
        if "POST" in header['first_line']:
            return 0
        else:
            return 1
    def decrypt(self,header,body):
        try:
            meth = self._getmethod(header)
            if meth==0:
                body=req_decrypt(body)
            if meth==1:
                body=rsp_decrypt(body)
        except  Exception as err:
            print(err)
            traceback.print_exc() #import traceback            
            pass
        return header,body
    def encrypt(self,header,body):
        try:
            meth = self._getmethod(header)
            if meth==0:
                body=req_encrypt(body)
            if meth==1:
                body=rsp_encrypt(body)
        except  Exception as err:
            print(err)
            traceback.print_exc() 
            pass
        return header,body

备注

对密文解密后得到的明文再加密,得到的密文和原始密文不同,这是因为原始密文解密后得到的明文会多些空格啥的,导致再次加密后得到的密文和原始密文不一致了,但不用担心这个事情,因为经试验发现,再对该密文(原始密文解密再加密得到的那个密文)解密,还是可以得到关键内容一致的明文,只是空格的区别(我知道我在说废话哈哈哈
具体如下:
原始密文解密:原始密文解密
解密后的明文再加密后,再解密:
解密再加密再解密
可见密文不同但得到的明文只是在换行或者空格的位置上有点区别,所展现的关键内容是一致的。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐