AES链接加密逆向

本文分析http://ggzy.zwfwb.tj.gov.cn/网站

展示的是url加密(列表页源码中对应的url和详情页对应的url不同)
在这里插入图片描述
对应的详情页url是http://ggzy.zwfwb.tj.gov.cn/jyxxcggg/Dn+BswYsE55CV9r1AJrIgg.jhtml

梳理本案例中的反爬策略:
1.列表页响应的源码包含详情页的地址。
2.点击详情页链接,转跳加密,出现新的地址。
3.原地址直接报403访问问题。
4.用简单的静态搜索没有找到有用的生成逻辑,通过Initiator堆栈调式也没有找到有用的生成逻辑。
解决方法:
跳转加密逻辑,不是请求逻辑,所以它的加密逻辑一定是在前端 JS 文件中实现的(经验问题),此时我们可以基于网页元素事件绑定,跟踪加密逻辑。
新手可以先观察DOM事件监听是怎样的。
(在开发者工具中,直接检查 DOM 元素的所有事件,其中重点关注的是单击操作(因为基于上文分析,是单击之后跳转地址发生了变化。)
观察下面几张图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

点击 第一张图中对应的VM 之后,直接跳转到 JS 代码页面,将源码格式化之后,发现非常短小。
发现加密是AES
在这里插入图片描述
通过断点调试知道密钥是s
在这里插入图片描述

修改对应的js

// npm install crypto-js

var CryptoJS = require("crypto-js");

function lx(hh) {
    var aa = hh.split("/");
    var aaa = aa.length;
    var bbb = aa[aaa - 1].split('.');
    var ccc = bbb[0];
    var cccc = bbb[1];
    var r = /^\+?[1-9][0-9]*$/;

    var srcs = CryptoJS.enc.Utf8.parse(ccc);
    var s = "qnbyzzwmdgghmcnm";
    var k = CryptoJS.enc.Utf8.parse(s);
    var en = CryptoJS.AES.encrypt(srcs, k, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    var ddd = en.toString();
    ddd = ddd.replace(/\//g, "^");
    ddd = ddd.substring(0, ddd.length - 2);
    var bbbb = ddd + '.' + bbb[1];
    aa[aaa - 1] = bbbb;
    var uuu = '';
    for (i = 0; i < aaa; i++) {
        uuu += aa[i] + '/'
    }
    uuu = uuu.substring(0, uuu.length - 1);
    return uuu;
}

python调用js

import execjs

js = '''
// npm install crypto-js

var CryptoJS = require("crypto-js");

function lx(hh) {
    var aa = hh.split("/");
    var aaa = aa.length;
    var bbb = aa[aaa - 1].split('.');
    var ccc = bbb[0];
    var cccc = bbb[1];
    var r = /^\+?[1-9][0-9]*$/;

    var srcs = CryptoJS.enc.Utf8.parse(ccc);
    var s = "qnbyzzwmdgghmcnm";
    var k = CryptoJS.enc.Utf8.parse(s);
    var en = CryptoJS.AES.encrypt(srcs, k, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });
    var ddd = en.toString();
    ddd = ddd.replace(/\//g, "^");
    ddd = ddd.substring(0, ddd.length - 2);
    var bbbb = ddd + '.' + bbb[1];
    aa[aaa - 1] = bbbb;
    var uuu = '';
    for (i = 0; i < aaa; i++) {
        uuu += aa[i] + '/'
    }
    uuu = uuu.substring(0, uuu.length - 1);
    return uuu;
}
'''

hh="http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/970369.jhtml"
url = execjs.compile(js).call('lx',hh)
print(url)

可以将对应的js修改成python

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

import base64

def encrypt_text(text, key):
    aes = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    encrypt_str = aes.encrypt(pad(text.encode('utf-8'), AES.block_size, style='pkcs7'))
    encrypt_str = str(base64.encodebytes(encrypt_str), encoding='utf-8')
    return encrypt_str

if __name__ == '__main__':
    key = 'qnbyzzwmdgghmcnm'

    es = encrypt_text("1013331", key)
    es.replace("\n", "")  # 去掉后面的换行
    es = es.replace('/', '^')[:-2]  # 去掉最后的 ==
    print(es)

完整代码
完整获取url,加密url,获取详情页数据

import requests,re
from bs4 import BeautifulSoup
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64

def get_urlid():

    list_urls = []
    for i in range(1,2):
        list_url=[]
        if i==1:
            url = 'http://ggzy.zwfwb.tj.gov.cn/jyxx/index.jhtml'
        else:
            url = 'http://ggzy.zwfwb.tj.gov.cn/jyxx/index_{}.jhtml'.format(i)
        r = requests.get(url).text
        soup = BeautifulSoup(r, 'lxml')
        books = soup.find_all(class_='article-list3-t')
        # print(books)

        for book in books:
            url_list = book.find(name='a')['url']
            list_url.append(url_list)
        list_urls.append(list_url)
    return list_urls


def encrypt_text(text, key):
    aes = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    encrypt_str = aes.encrypt(pad(text.encode('utf-8'), AES.block_size, style='pkcs7'))
    encrypt_str = str(base64.encodebytes(encrypt_str), encoding='utf-8')
    return encrypt_str

def get_content(url,url_id):
    r = requests.get(url).text
    soup = BeautifulSoup(r, 'lxml')
    books = soup.find(class_='content-article')
    # print(books)
    contents = books.find(id='content').find_all(name='p')
    s=''
    for content in contents:
        con = content.text
        s=s+'\n'+con
        print(con)


    with open('{}.txt'.format(url_id),'w',encoding='utf-8') as f:
        f.write(s)


if __name__ == '__main__':
    key = 'qnbyzzwmdgghmcnm'

    urlids=get_urlid()
    id_lists = []
    for urlid in urlids:
        for id_url in urlid:
            id_es = []
            list_id = id_url.split('/')[-1].split('.')[0]
            id_es.append(list_id)
            es = encrypt_text(list_id, key)
            es=es.replace("\n", "")  # 去掉后面的换行
            es = es.replace('/', '^')[:-2]  # 去掉最后的 ==
            es = es.replace("^", "%5E")
            id_es.append(es)
            url=id_url.replace(list_id, es)
            print(id_url,url)
            get_content(url,list_id)

<think>好的,用户想了解CTF比赛中关于AES加密逆向分析方法。首先,我需要回忆一下AES的基本原理和常见模式,因为在逆向分析中,识别加密算法是关键。AES有多个步骤,比如字节代替、行位移、列混淆和轮密钥加,这些步骤在代码中可能会有特定的特征。 接下来,用户提到的参考资料里提到了一些关键点,比如S盒和密钥扩展。逆向分析时,查找S盒的使用可能有助于识别AES的存在。S盒是固定的置换表,如果在反汇编代码中看到大量固定的256字节数组,那可能是S盒或逆S盒。此外,密钥扩展过程生成轮密钥,这也是一个特征点。 然后,考虑加密模式。比如ECB模式每个块独立加密,而CBC需要IV。在逆向时,查找IV的存储位置或生成方式很重要。例如,IV可能硬编码在程序中,或者通过某种算法生成,这会影响如何构造解密脚本。 还要注意反调试和SMC(自修改代码)技术,这些在CTF题中常用来保护AES的实现。例如,程序可能在运行时解密关键代码,干扰静态分析。这时候需要动态调试,或者识别出SMC的触发点,手动提取解密后的代码。 另外,密钥的存储方式也很重要。密钥可能被分成多个部分,隐藏在代码的不同位置,或者通过某种运算动态生成。逆向时需要跟踪密钥的生成过程,可能需要将各个部分拼接起来,或者逆向生成算法。 还有,如果题目使用了自定义的S盒或修改了AES的某些步骤,比如改变行位移的方向,这就需要分析具体的实现细节。这时候对比标准AES的流程,找出差异点,才能正确解密。 最后,编写解密脚本时,可能需要利用现有的加密库,如PyCryptodome,但要确保模式、填充方式、密钥和IV都正确匹配。如果遇到问题,需要检查每一步的参数是否正确,特别是字节序和填充的处理。 总结一下,逆向AES的步骤大致是:识别算法特征,确定模式和密钥,处理反调试/SMC,分析密钥生成,编写解密脚本。同时结合动态分析和静态分析,逐步拆解保护措施,最终提取关键参数进行解密。</think>### CTF中AES加密逆向分析技巧 #### 1. **识别AES算法特征** - **S盒与逆S盒**:AES的核心组件是固定的$256$字节S盒(SubBytes)和逆S盒。在逆向分析中,若发现程序代码中存在固定的$256$字节数组(例如`0x63, 0x7c, 0x77...`),极可能是S盒或逆S盒[^3]。 - **密钥扩展**:AES需要生成轮密钥(Round Keys),密钥扩展过程包含循环左移、S盒置换等操作。逆向时需关注密钥生成逻辑,尤其是对初始密钥的多次变换。 - **加密轮数**:根据密钥长度(如AES-128为$10$轮),可通过循环结构或轮密钥数量判断具体类型。 #### 2. **分析加密模式与参数** - **模式识别**:AES常见模式包括ECB、CBC、CTR等。例如,CBC模式需要初始向量(IV),逆向时需查找IV存储位置或生成方式(如硬编码、动态计算)[^1]。 - **填充方式**:PKCS#7填充是常见方案,需在解密后验证填充合法性。若程序包含填充校验逻辑(如检查最后一个字节的值),可辅助确认填充类型。 #### 3. **定位关键数据** - **密钥与IV提取**:密钥可能被分割存储或动态生成。例如,密钥可能由多个字符串拼接后经过哈希处理生成,需跟踪内存操作或调试提取。 - **密文定位**:密文通常以字节数组形式存储在数据段,或通过文件/网络输入。若程序包含加密函数调用,可通过参数传递路径定位密文[^4]。 #### 4. **对抗反调试与SMC** - **反调试绕过**:部分题目会通过`except_handler`或`IsDebuggerPresent`检测调试器,需使用插件(如ScyllaHide)或修改标志位绕过[^1]。 - **SMC处理**:自修改代码(Self-Modifying Code)会动态解密关键函数。可通过动态调试在解密后DUMP内存,或静态分析解密算法还原代码。 #### 5. **编写解密脚本** ```python from Crypto.Cipher import AES from Crypto.Util.Padding import unpad key = b'ctf_race_key123' # 提取的密钥 iv = b'initial_vector_iv' # 提取的IV ciphertext = open('encrypted.bin', 'rb').read() cipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) print(plaintext.decode()) ``` - **注意事项**:需确保模式、填充方式与目标程序一致,否则解密可能失败。 #### 6. **实战案例** - **案例1**:某CTF题通过修改S盒实现自定义AES,需对比标准S盒差异后逆向置换逻辑[^4]。 - **案例2**:程序使用CBC模式但IV由时间戳生成,需在内存中捕获IV或通过漏洞预测。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值