百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

如何测试加密站点(如何测试加密站点是否正确)

toyiye 2024-09-03 22:28 3 浏览 0 评论

0x1 前言

在对一次小程序的测试过程中,发现返回的数据部分是加密的,目前一般通过burpsuite的插件和mitmproxy模块来对数据进行加密解密。今天就来介绍一下这两种方法,当然这两种方法都需要用到python,不得不说python是世界上最好的语言(php:? 你小子在说什么)

0x2 burpy

咋们进入正题,在对小程序的某个接口进行测试时,发现会返回当前用户的个人信息,通过将电话号码置空,返回了所有用户的信息,可惜的是关键敏感信息如姓名、电话号码、身份证号等信息都是加密的

得尽量解密数据将它升级为高危漏洞

通过逆向小程序找到了加密算法和key,就差解密了,解密使用的是github上的一个项目burpy

地址:https://github.com/mr-m0nst3r/Burpy

这个插件可以很方便地对通过bp的数据进行加密和解密,项目也给出了示例脚本,我们一般情况下只需要编写encrytp和decrypt两个函数就可以。

对于全数据包加密的数据处理起来更方便一点,而这种局部加密的数据就得多加几行代码。

因为这里我只需解密返回数据,只编写decrypt函数就可以

def decrypt(self, header, body):
        '''
        Auto Enc/Dec feature require this function
        '''

方法传递的header和body就是burp拦截到的原始header和body,包括请求包和响应包,脚本拿到这些数据包,处理好return一下就行了。

完整代码

import json
from Crypto.Cipher import AES
import base64
class Burpy:
    '''
    header is dict
    body is string
    '''
    def __init__(self):
        '''
        here goes some code that will be kept since "start server" clicked, for example, webdriver, which usually takes long time to init
        '''
        pass

    def encrypt(self, header, body):
        '''
        Auto Enc/Dec feature require this function
        '''
        header["Cookie"] = "admin=1"
        return header,body

    def decrypt(self, header, body):
        new_data = json.loads(body)       
        for i in new_data['data']['records']:
            i["visitorName"] = str(aesd(i['visitorName']))
            i["visitorTelephone"] = str(aesd(i['visitorTelephone']))
            i["visitorIdentityNumber"] = str(aesd(i['visitorIdentityNumber']))
            i["personName"] = str(aesd(i['personName']))
            i["personTelephone"] = str(aesd(i['personTelephone']))
        data = json.dumps(new_data,indent=4,ensure_ascii=False)
        return header,data


def aesd(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"xxxxxxxxxxxxxxxx"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()

通过设置好插件的python路径和脚本路径,启动插件,就可以邮件解密数据了,原谅我码较厚。

通过右键解密会弹出一个窗口来显示解密数据,如果想在bp的原始窗口显示解密数据你可以开启自动加密解密功能

0x3 mitmproxy

还有一种便是通过python的mitmproxy来编写代理拦截脚本,对数据进行加密和解密。

想必这也是大家的老朋友了,中间人攻击的居家旅行必备良药。

3.1 响应包解密

这里拿有道翻译举个例子

有道翻译的返回数据都是经过加密的,如图

通过分析加密代码发现加密方式为aes加密,找到了加密的key和IV就可以编写脚本了

这里只处理返回数据,编写response函数即可

我们可以编写一个类,通过类方法来处理加密数据,使用flow.response.get_text函数可获取响应包,然后将响应包进行解密,通过response.set_text函数将解密后的数据替换掉响应数据

完整代码

from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
# import json
import base64

class Mimit():


    def response(self,flow):
        resp = flow.response.get_text()
        rep = AES_Decrypt(resp)
        flow.response.set_text(rep)


def AES_Decrypt(data):
    key=b'\x08\x14\x9d\xa7\x3c\x59\xce\x62\x55\x5b\x01\xe9\x2f\x34\xe8\x38'
    iv=b'\xd2\xbb\x1b\xfd\xe8\x3b\x38\xc3\x44\x36\x63\x57\xb7\x9c\xae\x1c'
    aes = AES.new(key,AES.MODE_CBC,iv)
    rep = aes.decrypt(base64.urlsafe_b64decode(data)).decode('utf-8')
    return rep



addons = [Mimit(),]

启动mitm

mitmdump -p 9090 -s .\test.py --ssl-insecure

我们再将burpsuite的上游代理设置为9090端口,这样就能看到明文数据了

3.2 请求体和响应体解密

网上找了几个没发现请求体和响应体都同时加密的站,索性简单的写了一个测试站

可以看到数据都是加密过的

想要在bp里看到明文的请求数据和响应数据,就需要结合bp的上游代理和下游代理了

加密数据发送到下游代理,再解密数据发送到bp,bp便能看到明文的请求数据

同样的,服务器返回的数据到bp的上游代理,再解密数据,bp便能看到明文的返回数据

这其中有个小问题

从请求方向看,下游代理解密数据后,数据一直以明文的形式发送到服务器,服务器肯定要按照设定的程序对数据进行解密,解密必定是失败的,所以无法返回正常数据。

从响应方向看,响应数据在上游代理被解密为明文后,数据一直以明文的形式返回到浏览器,前端代码对数据解密也必然是失败的,也会报错。

所以我们需要在上游代理对明文数据进行加密后发送给服务器,在下游代理将数据加密发送给浏览器客户端,如下图

这样就可以正常查看明文数据了,同样的可以结合xray来使用这种方法。

另外,遇到的一种情况有些接口是明文发送,不用加密,为了防止二次加密,编写一个函数来识别数据是否需要解密和加密,由于本站是使用json来传输数据,可以使用json.loads()来识别数据是否是明文和密文。

下游代理代码

from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
# import json
import base64

class Mimit():

    def request(self,flow):
        if flow.request.host=="127.0.0.1":
            req = flow.request.get_text()
            ctx.log.info("请求数据 => "+req)
            if IsJson(req):
                flow.request.set_text(req)
            else:
                data = AesDecrypt(req)
                flow.request.set_text(data)


    def response(self,flow):
        rep = flow.response.get_text()       
        ctx.log.info("响应数据 => "+flow.response.get_text())
        if IsJson(rep):
            rep = Encrypt_data(rep,"aa834085ebd67a24")
            flow.response.set_text(rep)
        else:
            flow.response.set_text(rep)

def AesDecrypt(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"aa834085ebd67a24"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()

def Encrypt_data(data, key):
    aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
    pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
    # 加密函数,使用pkcs7补全
    res = aes.encrypt(pad_pkcs7)
    # 转换为base64
    msg = str(base64.b64encode(res), encoding="utf-8")
    return msg

def IsJson(data):
    try:
        data = json.loads(data) 
        return True
    except: 
        return False


addons = [Mimit(),]

上游代理代码

from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
# import json
import base64

class Mimit():

    def request(self,flow):
        if flow.request.host=="127.0.0.1":
            req = flow.request.get_text()
            ctx.log.info("请求数据 => "+req)
            #如果使用bp的repeater模式,判断是否为明文
            if IsJson(req):
                data = Encrypt_data(req,"aa834085ebd67a24")
                flow.request.set_text(data)

            else:
                flow.request.set_text(req)


    def response(self,flow):
        resp = flow.response.get_text()
        ctx.log.info("返回数据 => "+resp)
        if IsJson(resp):
            flow.response.set_text(resp)
        else:
            resp = AesDecrypt(resp)
            flow.response.set_text(resp)



def AesDecrypt(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"aa834085ebd67a24"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()

def Encrypt_data(data, key):
    aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
    pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
    # 加密函数,使用pkcs7补全
    res = aes.encrypt(pad_pkcs7)
    # 转换为base64
    msg = str(base64.b64encode(res), encoding="utf-8")
    return msg

def IsJson(data):
    try:
        data = json.loads(data) 
        return True
    except: 
        return False


addons = [Mimit(),]

启动下游代理,将数据发送到bp的8080端口

mitmdump -p 7070 -s .\test.py --mode upstream:https://127.0.0.1:8080 --ssl-insecure

启动上游代理

mitmdump -p 9090 -s .\test.py --ssl-insecure

bp设置上游代理到9090端口,这样就可以查看请求和响应的明文了

0x4 工具结合

4.1 sqlmap

在使用sqlmap配合加密数据时,只需要设置一层上游代理即可,代码可以上面的bp上游代码共用,但前提是你需要将解密好的playload给sqlmap,sqlmap将数据发送给上游代理,上游代理加密后发送给服务器,服务器返回数据给上游代理,解密后明文还给sqlmap。但如果你要将原始密文数据给sqlmap,就需要再来一层下游代理了,后面讲xray的时候会将。

代码

from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow

import base64
from urllib.parse import unquote

class Mimit():

    def request(self,flow):
        if flow.request.host=="127.0.0.1":
            req = flow.request.get_text()
            ctx.log.info("请求数据 => "+unquote(req))
            #如果使用bp的repeater模式,判断是否为明文
            if IsJson(req):
                data = Encrypt_data(req,"aa834085ebd67a24")
                flow.request.set_text(data)

            else:
                flow.request.set_text(req)


    def response(self,flow):
        resp = flow.response.get_text()
        ctx.log.info("返回数据 => "+resp)
        if IsJson(resp):
            flow.response.set_text(resp)
        else:
            resp = AesDecrypt(resp)
            flow.response.set_text(resp)



def AesDecrypt(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"aa834085ebd67a24"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()

def Encrypt_data(data, key):
    aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
    pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
    # 加密函数,使用pkcs7补全
    res = aes.encrypt(pad_pkcs7)
    # 转换为base64
    msg = str(base64.b64encode(res), encoding="utf-8")
    return msg

def IsJson(data):
    try:
        data = json.loads(data) 
        return True
    except: 
        return False


addons = [Mimit(),]

启动代理

mitmdump -p 9090 -s .\test.py --ssl-insecure

sqlmap

sqlmap -r sql.txt -proxy http://192.168.1.5:9090

4.2 xray

xray的话还是需要设置2层代理,我们在浏览器点击一个链接时发送的数据是密文的,需要经过一次解密再发送给xray。

但这个第一层代理就只管解密一次,可以简单点

from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow

import base64
from urllib.parse import unquote

class Mimit():

    def request(self,flow):
        if flow.request.host=="127.0.0.1":
            req = flow.request.get_text()
            ctx.log.info("请求数据 => "+unquote(req))
            #如果使用bp的repeater模式,判断是否为明文
            if IsJson(req):
                flow.request.set_text(req)

            else:
                data = AesDecrypt(req)
                flow.request.set_text(data)


    def response(self,flow):
        pass


def AesDecrypt(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"aa834085ebd67a24"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()


def IsJson(data):
    try:
        data = json.loads(data) 
        return True
    except: 
        return False


addons = [Mimit(),]

上游代理

from mitmproxy import flowfilter,ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES 
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow

import base64
from urllib.parse import unquote

class Mimit():

    def request(self,flow):
        if flow.request.host=="127.0.0.1":
            req = flow.request.get_text()
            ctx.log.info("请求数据 => "+unquote(req))
            #如果使用bp的repeater模式,判断是否为明文
            if IsJson(req):
                data = Encrypt_data(req,"aa834085ebd67a24")
                flow.request.set_text(data)

            else:
                flow.request.set_text(req)


    def response(self,flow):
        resp = flow.response.get_text()
 #       ctx.log.info("返回数据 => "+resp)
        if IsJson(resp):
            flow.response.set_text(resp)
        else:
            resp = AesDecrypt(resp)
            flow.response.set_text(resp)



def AesDecrypt(s):
    BS = AES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
    unpad = lambda s : s[0:-s[-1]]
    key = b"aa834085ebd67a24"
    ciphertext_b64 = s

    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = base64.b64decode(ciphertext_b64)
    plaintext_padded = cipher.decrypt(ciphertext)
    plaintext = unpad(plaintext_padded)
    return plaintext.decode()

def Encrypt_data(data, key):
    aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
    pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
    # 加密函数,使用pkcs7补全
    res = aes.encrypt(pad_pkcs7)
    # 转换为base64
    msg = str(base64.b64encode(res), encoding="utf-8")
    return msg

def IsJson(data):
    try:
        data = json.loads(data) 
        return True
    except: 
        return False


addons = [Mimit(),]

启动下游代理,将数据转发到xray的端口

mitmdump -p 7070 -s .\test.py --mode upstream:https://127.0.0.1:8090 --ssl-insecure

启动上游代理

mitmdump -p 9090 -s .\test.py --ssl-insecure

配置xray的代理,修改config文件

启动xray

xray.exe -ws --listen 127.0.0.1:8090

接下来配置浏览器代理端口为7777即可

但xray这里没能跑出来sql注入,应该是xray对json的解析有问题,无法解析json的值,将payload直接拼接在了后面,不是json传输的站点应该没问题。

测试代码

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户查询</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

</head>
<body>


    <script>
function decryptAES(data, key) {  
    var key  = CryptoJS.enc.Utf8.parse(key);
    var decrypt = CryptoJS.AES.decrypt(data, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
    return CryptoJS.enc.Utf8.stringify(decrypt).toString();

};


        function sendNumber() {
          // 获取输入框中的数字
          var num = $('#numberInput').val();

          // 创建一个包含数字的 JSON 对象
          var data = {
            number: num
          };
          var datas = JSON.stringify(data);

           const aesKey = CryptoJS.enc.Utf8.parse("aa834085ebd67a24");
           var encrypted = CryptoJS.AES.encrypt(datas, aesKey, { 
  mode: CryptoJS.mode.ECB,
  padding: CryptoJS.pad.Pkcs7
}).toString();;
console.log(encrypted);
          // 发送 AJAX 请求
          $.ajax({
            url: 'query.php', // 替换为你的 PHP 文件路径
            type: 'POST',
            data: encrypted,

            success: function(response) {
              // 请求成功后的处理逻辑
              var result =  decryptAES(response, "aa834085ebd67a24");


              document.getElementById("result").innerHTML = result;

            },
            error: function(xhr, status, error) {
              // 请求失败后的处理逻辑
              console.log(error);
            }
          });
        }
        </script>


<input type="text" id="numberInput">
<button onclick="sendNumber()">发送</button>

<div id="result">结果:</div>>

</body>
</html>

query.php

<?php
function aes_encrypt($data, $key) {
    $cipher = "aes-128-ecb"; // 使用 AES 128位 ECB模式
    $options = OPENSSL_RAW_DATA; // 使用原始数据输出

    // 对密钥进行处理
    $key = substr($key, 0, 16); // 只使用前16字节作为密钥

    // 加密数据并返回结果
    $result = openssl_encrypt($data, $cipher, $key, $options);

    return base64_encode($result);
}

function aes_decrypt($data, $key) {
    $cipher = "aes-128-ecb"; // 使用 AES 128位 ECB模式
    $options = OPENSSL_RAW_DATA; // 使用原始数据输出

    // 对密钥进行处理
    $key = substr($key, 0, 16); // 只使用前16字节作为密钥

    // 解密数据并返回结果
    $result = openssl_decrypt(base64_decode($data), $cipher, $key, $options);
    return $result;
}


// 获取发送的 JSON 数据
$data = file_get_contents('php://input');
$number = aes_decrypt($data,"aa834085ebd67a24");


// 提取数字

$num = json_decode($number,true)['number'];


// 进行处理(这里只是一个示例)

// 返回响应



$con=mysqli_connect("localhost","root","123456","db_name");
// 检测连接
if (mysqli_connect_errno())
{
    echo "连接失败: " . mysqli_connect_error();
}

$result = mysqli_query($con,"SELECT * FROM v9_admin WHERE userid={$num}");

while($row = mysqli_fetch_array($result))
{
    $str = array('username' =>  $row['username'],   'password' => $row['password'],'lastloginip' => $row['lastloginip'],'email' => $row['email'] );

}
//$results = aes_decrypt(json_decode(json_encode($str)),"aa834085ebd67a24");
$a = json_encode($str);
$results = aes_encrypt($a,"aa834085ebd67a24");
echo $results;

?>

0x4 总结

其实对于数据全加密的站点还好,要是部分接口加密,部分接口又不加密,这种就比较恼火,还要判断数据是否为明文,json格式传输的站点还好判断,其他的貌似就不好判断是否是明文还是密文了。另外就是要对算法的逆向和调试了,只有先找到了算法和相关信息,才能编写解密脚本。


from: https://xz.aliyun.com/t/12652

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码