最新要闻
- 环球头条:周鸿祎:打造中国版ChatGPT难度比研发光刻机低很多
- 快看点丨中国打造全球首艘大容量电池混合动力客滚船:能充8800度电
- 全球最大3D内容生态!努比亚推出首款裸眼3D平板nubia Pad 3D
- 视讯!爽脆有嚼劲/便携小包装 鱼泉榨菜7.9元 1.2斤大促
- 环球新消息丨魅族20系列首发Flyme 10无界生态系统 支持全链路防诈技术
- 【快播报】李瑞峰回答长城:我们究竟遇到了什么问题
- 12.98万起 新款长城欧拉好猫上市:小姐姐最爱
- 世界百事通!马斯克做出重大决定:特斯拉车主可能要难受了
- 代表建议春节假期至9天:取消调休制度 法定3天变5天
- 贵州一公司设立“临时哭泣点”引热议:you cry I cry no bb
- 焦点快看:早安!出行气象来了(2023年3月1日)
- 全球动态:能否破40亿?《流浪地球2》成2月票房冠军 力压《满江红》
- 代表建议春节假期延至9天 取消调休!网友期待
- 天天快看:兼容友商Mesh组网!中兴小方糖路由器今日开售:到手仅99元
- 当前头条:《流浪地球3》何时出?导演郭帆:估计还要等四年
- 环球微速讯:3月24日公测!暴雪《暗黑破坏神4》PC配置要求公布
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
java反射机制
JAVA反射机制
-----copy自p牛的java安全漫谈
反射是⼤多数语⾔⾥都必不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有⽅法(包括私有),拿到的⽅法可以调⽤,总之通过“反射”,我们可以将Java这种静态语⾔附加上动态特性。
【资料图】
PHP本身拥有很多动态特性,所以可以通过“⼀句话⽊⻢”来执⾏各种功能;Java虽不像PHP那么灵活,但其提供的“反射”功能,也是可以提供⼀些动态特性。⽐如,这样⼀段代码,在你不知道传⼊的参数值的时候,你是不知道他的作⽤是什么的:
public void execute(String className, String methodName) throws Exception { Class clazz = Class.forName(className); clazz.getMethod(methodName).invoke(clazz.newInstance());}
上⾯的例⼦中,演示了⼏个在反射⾥极为重要的⽅法:
- 获取类的⽅法: forName
- 实例化类对象的⽅法: newInstance
- 获取函数的⽅法: getMethod
- 执⾏函数的⽅法: invoke
基本上,这⼏个⽅法包揽了Java安全⾥各种和反射有关的Payload。
forName 不是获取“类”的唯⼀途径,通常来说我们有如下三种⽅式获取⼀个“类”,也就是 java.lang.Class 对象:
- obj.getClass() 如果上下⽂中存在某个类的实例 obj ,那么我们可以直接通过obj.getClass() 来获取它的类
- Test.class 如果你已经加载了某个类,只是想获取到它的 java.lang.Class 对象,那么就直接拿它的 class 属性即可。这个⽅法其实不属于反射。
- Class.forName 如果你知道某个类的名字,想获取到这个类,就可以使⽤ forName 来获取
forName有两个函数重载:
- Class> forName(String name)
- Class> forName(String name, booleaninitialize, ClassLoader loader)
第⼀个就是我们最常⻅的获取class的⽅式,其实可以理解为第⼆种⽅式的⼀个封装:
Class.forName(className)// 等于Class.forName(className, true, currentLoader)
默认情况下, forName 的第⼀个参数是类名;第⼆个参数表示是否初始化(“类初始化”);第三个参数就是 ClassLoader
ClassLoader 是什么呢?它就是⼀个“加载器”,告诉Java虚拟机如何加载这个类。关于这个点,后⾯还有很多有趣的漏洞利⽤⽅法,这⾥先不展开说了。Java默认的 ClassLoader 就是根据类名来加载类,这个类名是类完整路径,如 java.lang.Runtime 。
什么是初始化?
public class TrainPrint { { System.out.printf("Empty block initial %s\n", this.getClass()); } static { System.out.printf("Static initial %s\n", TrainPrint.class); } public TrainPrint() { System.out.printf("Initial %s\n", this.getClass()); }}
上述的代码执行后⾸先调⽤的是 static {} ,其次是 {} ,最后是构造函数。
其中, static {} 就是在“类初始化”的时候调⽤的,⽽ {} 中的代码会放在构造函数的 super() 后⾯,但在当前构造函数内容的前⾯。所以说, forName 中的 initialize=true 其实就是告诉Java虚拟机是否执⾏”类初始化“
$的作用就是查找内部类。Java的普通类 C1 中支持编写内部类 C2 ,而在编译的时候,会生成两个文件: C1.class 和C1$C2.class ,我们可以把他们看作两个无关的类,通过 Class.forName("C1$C2") 即可加载这个内部类。
获得类以后,我们可以继续使用反射来获取这个类中的属性、方法,也可以实例化这个类,并调用方法。
class.newInstance() 的作用就是调用这个类的无参构造函数,这个比较好理解。不过,我们有时候在写漏洞利用方法的时候,会发现使用 newInstance 总是不成功,这时候原因可能是:
- 你使用的类没有无参构造函数
- 你使用的类构造函数是私有的
最最最常见的情况就是 java.lang.Runtime ,这个类在我们构造命令执行Payload的时候很常见,但我们不能直接这样来执行命令:
Class clazz = Class.forName("java.lang.Runtime");clazz.getMethod("exec", String.class).invoke(clazz.newInstance(), "id");
然后就会得到如下异常
原因是 Runtime 类的构造方法是私有的。
有同学就比较好奇,为什么会有类的构造方法是私有的,难道他不想让用户使用这个类吗?这其实涉及到很常见的设计模式:“单例模式”。(有时候工厂模式也会写成类似)比如,对于Web应用来说,数据库连接只需要建立一次,而不是每次用到数据库的时候再新建立一个连接,此时作为开发者你就可以将数据库连接使用的类的构造函数设置为私有,然后编写一个静态方法来获取:
public class TrainDB {private static TrainDB instance = new TrainDB();public static TrainDB getInstance() {return instance;}private TrainDB() {// 建立连接的代码...}}
这样,只有类初始化的时候会执行一次构造函数,后面只能通过 getInstance 获取这个对象,避免建立多个数据库连接。回到正题,Runtime类就是单例模式,我们只能通过 Runtime.getRuntime() 来获取到 Runtime 对象。我们将上述Payload进行修改即可正常执行命令了:
Class clazz = Class.forName("java.lang.Runtime");clazz.getMethod("exec",String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"calc.exe");
这里用到了 getMethod 和 invoke 方法。
getMethod 的作用是通过反射获取一个类的某个特定的公有方法。而学过Java的同学应该清楚,Java中支持类的重载,我们不能仅通过函数名来确定一个函数。所以,在调用 getMethod 的时候,我们需要传给他你需要获取的函数的参数类型列表。
比如exec里面就有6个重载
这里我们使用第一个,最简单的进行命令执行
它只有一个参数,类型是String,所以我们使用getMethod("exec", String.class) 来获取 Runtime.exec 方法。
invoke 的作用是执行方法,它的第一个参数是:
- 如果这个方法是一个普通方法,那么第一个参数是类对象
- 如果这个方法是一个静态方法,那么第一个参数是类
这也比较好理解了,我们正常执行方法是 [1].method([2], [3], [4]...) ,其实在反射里就是method.invoke([1], [2], [3], [4]...) 。
所以我们的Payload分解一下就是:
Class clazz = Class.forName("java.lang.Runtime");Method execMethod = clazz.getMethod("exec", String.class);Method getRuntimeMethod = clazz.getMethod("getRuntime");Object runtime = getRuntimeMethod.invoke(clazz);execMethod.invoke(runtime, "calc.exe");
那么又会产生几个问题:
- 如果一个类没有无参构造方法,也没有类似单例模式里的静态方法,我们怎样通过反射实例化该类呢?
- 如果一个方法或(有参或无参都行)构造方法是私有方法,我们是否能执行它呢?
对于第一个问题,我们需要一个新的反射方法getConstructor。
和 getMethod 类似, getConstructor 接收的参数是构造函数列表类型,因为构造函数也支持重载,所以必须用参数列表类型才能唯一确定一个构造函数。获取到构造函数后,我们使用 newInstance 来执行。
比如,我们常用的另一种执行命令的方式ProcessBuilder,我们使用反射来获取其构造函数,然后调用start() 来执行命令:
Class clazz = Class.forName("java.lang.ProcessBuilder");((ProcessBuilder)clazz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))).start();
ProcessBuilder有两个构造函数:
- public ProcessBuilder(List
command) - public ProcessBuilder(String... command)
我上面用到了第一个形式的构造函数,所以我在 getConstructor 的时候传入的是 List.class 。但是,我们看到,前面这个Payload用到了Java里的强制类型转换,有时候我们利用漏洞的时候(在表达式上下文中)是没有这种语法的。所以,我们仍需利用反射来完成这一步。
Class clazz = Class.forName("java.lang.ProcessBuilder");clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));
通过 getMethod("start") 获取到start方法,然后 invoke 执行, invoke 的第一个参数就是ProcessBuilder Object了。
那么,如果我们要使用 public ProcessBuilder(String... command) 这个构造函数,需要怎样用反射执行呢?这又涉及到Java里的可变长参数(varargs)了。正如其他语言一样,Java也支持可变长参数,就是当你定义函数的时候不确定参数数量的时候,可以使用 ... 这样的语法来表示“这个函数的参数个数是可变的”。对于可变长参数,Java其实在编译的时候会编译成一个数组,也就是说,如下这两种写法在底层是等价的(也就不能重载):
public void hello(String[] names) {}public void hello(String...names) {}
也由此,如果我们有一个数组,想传给hello函数,只需直接传即可:
String[] names = {"hello", "world"};hello(names);
那么对于反射来说,如果要获取的目标函数里包含可变长参数,其实我们认为它是数组就行了。所以,我们将字符串数组的类 String[].class 传给 getConstructor ,获取 ProcessBuilder 的第二种构造函数:
Class clazz = Class.forName("java.lang.ProcessBuilder");clazz.getConstructor(String[].class)
在调用 newInstance 的时候,因为这个函数本身接收的是一个可变长参数,我们传给ProcessBuilder 的也是一个可变长参数,二者叠加为一个二维数组,所以整个Payload如下:
Class clazz = Class.forName("java.lang.ProcessBuilder");((ProcessBuilder)clazz.getConstructor(String[].class).newInstance(newString[][]{{"calc.exe"}})).start();
所以改成完整反射的payload就是:
Class clazz = Class.forName("java.lang.ProcessBuilder");clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc.exe"}}));
再说到第二个问题,如果一个方法或构造方法是私有方法,我们是否能执行它呢?
这就涉及到 getDeclared 系列的反射了,与普通的 getMethod 、 getConstructor 区别是:
- getMethod 系列方法获取的是当前类中所有公共方法,包括从父类继承的方法
- getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了
getDeclaredMethod 的具体用法和 getMethod 类似, getDeclaredConstructor 的具体用法和getConstructor 类似
举个例子,前文我们说过Runtime这个类的构造函数是私有的,我们需要用 Runtime.getRuntime() 来获取对象。其实现在我们也可以直接用 getDeclaredConstructor 来获取这个私有的构造方法来实例化对象,进而执行命令:
Class clazz = Class.forName("java.lang.Runtime");Constructor m = clazz.getDeclaredConstructor();m.setAccessible(true);clazz.getMethod("exec", String.class).invoke(m.newInstance(), "calc.exe");
可见,这里使用了一个方法 setAccessible ,这个是必须的。我们在获取到一个私有方法后,必须用setAccessible 修改它的作用域,否则仍然不能调用。
java反射机制
世界讯息:HTML+JSP+CSS实现表格布局的例子
环球头条:周鸿祎:打造中国版ChatGPT难度比研发光刻机低很多
快看点丨中国打造全球首艘大容量电池混合动力客滚船:能充8800度电
全球最大3D内容生态!努比亚推出首款裸眼3D平板nubia Pad 3D
视讯!爽脆有嚼劲/便携小包装 鱼泉榨菜7.9元 1.2斤大促
环球新消息丨魅族20系列首发Flyme 10无界生态系统 支持全链路防诈技术
推荐系统[四]:精排-详解排序算法LTR (Learning to Rank)_ poitwise, pairwise, listwise相关评价指标,超详细知
全球热资讯!使用unplugin-auto-import自动导入插件优化vite开发vue3应用
全球视讯!移动计算入门教程_编程入门自学教程_菜鸟教程-免费教程分享
【快播报】李瑞峰回答长城:我们究竟遇到了什么问题
12.98万起 新款长城欧拉好猫上市:小姐姐最爱
世界百事通!马斯克做出重大决定:特斯拉车主可能要难受了
代表建议春节假期至9天:取消调休制度 法定3天变5天
贵州一公司设立“临时哭泣点”引热议:you cry I cry no bb
焦点快看:早安!出行气象来了(2023年3月1日)
当前短讯!读Java性能权威指南(第2版)笔记05_数据库性能JDBC
korean doll likeness模型|Japanese-doll-likeness模型获取及使用
天天微速讯:一招搞定孩子不吃饭问题
实时焦点:python通过轮子安装第三方库(以Wordcloud为例)
全球动态:能否破40亿?《流浪地球2》成2月票房冠军 力压《满江红》
代表建议春节假期延至9天 取消调休!网友期待
天天快看:兼容友商Mesh组网!中兴小方糖路由器今日开售:到手仅99元
当前头条:《流浪地球3》何时出?导演郭帆:估计还要等四年
环球微速讯:3月24日公测!暴雪《暗黑破坏神4》PC配置要求公布
每日报道:MySQL的RR和RC事务隔离级别加锁类型验证
全球今热点:白马非马是什么学派_白马非马是哪家的学说
最完美iPhone要来了!消息称iPhone 16 Pro将采用屏下Face ID
焦点速看:《白夜追凶2》要来了!优酷独家悬疑剧:前作口碑爆火
每日热文:高三女生因百日誓师热血发言表情被网暴 官方回应已心里辅导:女孩未受影响
《暗黑破坏神4》Beta测试系统需求
世界今热点:TVB小花新剧牺牲大!遭五花大绑太重口味,脚踏两只船遭雪藏半年
【全球新要闻】记一次 CesiumJS 中非 4326/3857 WMTS 数据的加载
百度预告3月16日召开发布会:主题围绕文心一言
全球信息:“假苍耳”入侵中国!剧毒杀死牛羊、改变土壤、减产60%
和AI谈恋爱之后 她忘掉了相恋5年的前男友:结局心酸
环球快看:苹果供应商印度工厂突发大火:损失超8300万!一半机器烧毁
全球关注:“春天一把豆,胜过吃猪肉”,常吃4豆,高营养高蛋白,增强免疫
快资讯丨Spring IOC官方文档学习笔记(十三)之环境概要
我国累计落实补偿补助资金近270亿元用于长江禁渔退捕渔民安置
NVIDIA RTX VSR脑补网络视频:标清秒变4K超高清!
每日资讯:离谱!男子邮政寄房产证71天仍未送达
今日热门!AMD锐龙9 7000X3D正式开卖!价格、性能、功耗三杀13900KS
热讯:restaurants怎么读英语发音_restaurants怎么读
【天天播资讯】SpringBoot项目多层级多环境yml设计
天天热头条丨Kubernetes(K8S)应用案例
当前要闻:90后女孩奋斗14年从服务员到博士生 要释放所有潜力:网友感慨太强
热门看点:地铁告示牌提醒“严禁黑车及马自达占用停放”引争议 南京官方解释尴尬
日本女歌手黑崎真音因病去世 年仅35岁
世界时讯:04if分支语句
每日关注!沙特土豪要造巨型科幻建筑了:这次是世界最大立方体
当前信息:搭载全新12代酷睿N200处理器轻薄本仅 2599元!攀升笔记本开学季促销
Rust 知识积累(2)
环球观速讯丨Luffy项目:3、前端调整(全局css、全局配置、全局axios...),后端主页轮播图表设计,接口部分代码编写
世界热消息:pycharm破解版
环球精选!变量处理中的标准化方法
数学家的小故事五十字_50 100字数学家的小故事
焦点播报:曾致2死3伤 特斯拉潮州事故鉴定结果已出:目前不会进行公布
微软与谷歌正面扳手腕:计划推出自家移动应用商店
【世界时快讯】放生大鱼游回岸边“致谢”放生者?别自作多情了 800万粉大V科普
焦点热议:卷死燃油车!新能源价格战打起来了:“迪王”都已坐不住
长安控诉银河之光抄袭背后 两家车企的设计师都是陈政
高并发场景下常见的限流算法及方案介绍
组合数学笔记-计数原理
索尼WF-1000XM4降噪豆发布新固件:可同时连接2台设备
全球报道:女子帮网友表白:单日收入过万
享36个月超长质保!魅族20系列1元超前预订开启:立省699元
《福星小子》新动画角色公开 3月2日最新话登场
身材抢眼!75岁“终结者”施瓦辛格首演电视剧:经典台词“我回来了”
记录--如何优雅地校验后端接口数据
世界今亮点!New Bing怼人、说谎、PUA,ChatGPT已经开始胡言乱语了
要闻:全新起亚K3开启预售 新款起亚K3怎么样?
今热点:只要78元!《元能失控》登陆任天堂国行Switch:支持多人联机 太罕见
今日热闻!累计订单已超5万!比亚迪豪华MPV腾势D9 EV官宣涨价6000元
送女神绝佳好礼 好吃还能发圈!榴芒一刻礼盒大促:立减179元
环球速讯:恐怖!男子酒后吃布洛芬致皮肤大面积剥脱 医生:重度药疹
焦点滚动:另起炉灶?马斯克怒批ChatGPT 欲开发替代品
全球播报:Rust 知识积累(1)
世界百事通!让WPF中的DataGrid像Excel一样可以筛选
全球头条:Codeforces Round #854 by cybercats (Div. 1+2) 1799 A~G 题解
全球报道:2363. 合并相似的物品
【天天速看料】c语言运算符优先级实例解析
资讯:建设银行e路通不用了直接扔了吗_建设银行e路通
恐怕人类永远也搞不定真正的AI!
环球时讯:黄仁勋带着NVIDIA新品发布会来了!RTX 4070梦碎
大量年轻人成为“果粉” :苹果连三星大本营都快攻陷了
精选!AGM G2 Guardian发布:全球首款500米范围热成像手机
全球时讯:不怕停电了?董明珠:格力开始研究将储能技术应用冰箱上
新消息丨.NET MAUI
外敷仙人掌的禁忌和副作用_外敷仙人掌的禁忌
环球热文:官宣定档3月6日 领创科技旗舰荣耀Magic5系列即将国内亮相
需要去看医生的呼噜声什么样?这三种情况要特别注意:有危险
蔚来:阿尔卑斯全系车型采用800V方案 还将共享使用三代换电站
【全球新视野】男子反复发烧20多天被诊出黑热病:发病率仅0.0108/10万
环球快报:一加Buds Pro 2轻享版上架:48dB深度降噪
今热点:11 款顶级 MySQL 图形化工具汇总,总有一款适合你!(建议收藏)
【速看料】Python实战项目3-前后端连接/首页轮播图表设计
热头条丨剑指 Offer 55 - II. 平衡二叉树(java解题)
焦点速讯:安装node并创建vue项目
报告称每天工作超8小时心脏病风险增8成:很多公司拒绝996、启用四天工作制