跟进this.phases[i].doPhase
,这里会有循环遍历多个Phase
对象去调用doPhase方法

文章插图
继续跟进到
this.execute
public void doPhase(FacesContext context, Lifecycle lifecycle, ListIterator<PhaseListener> listeners) {context.setCurrentPhaseId(this.getId());PhaseEvent event = null;if (listeners.hasNext()) {event = new PhaseEvent(context, this.getId(), lifecycle);}Timer timer = Timer.getInstance();if (timer != null) {timer.startTiming();}try {this.handleBeforePhase(context, listeners, event);if (!this.shouldSkip(context)) {this.execute(context);}
在execute方法逻辑内,先通过facesContext.getExternalContext().getRequestMap();
拿到一个RequestMap其中的值为ExternalContextImpl
对象,该对象中包含了上下文、request、response等整体信息 。后续跟进 viewHandler.restoreView(facesContext, viewId);

文章插图
继续跟进
getstate

文章插图
下面是一处关键点 , 通过刚才我们提到的
ExternalContextImpl
,从中对应的requestParameterMap
中的key取出我们传入的payload,默认情况下是javax.faces.Viewstate
,之后该值作为形参带入doGetState
方法内
文章插图
下面是漏洞出发点的反序列化逻辑部分
先Base64解码,解码后通过
this.guard
的值是否为null判断是否有加密,有加密的话会去调用this.guard.decrypt
进行解密 , 之后ungzip解压
文章插图
之后将该流转换为ApplicationObjectInputStream并有一个timeout的判断逻辑,最后直接反序列化

文章插图
存在加密的情况的话可能会有以下的配置
<context-param><param-name>javax.faces.STATE_SAVING_METHOD</param-name><param-value>client</param-value></context-param><env-entry><env-entry-name>com.sun.faces.ClientStateSavingPassword</env-entry-name><env-entry-type>java.lang.String</env-entry-type><env-entry-value>[some secret password]</env-entry-value></env-entry>
或<context-param><param-name>com.sun.faces.ClientSideSecretKey</param-name><param-value>[some secret password]</param-value></context-param>
在ClientSideStateHelper#doGetState
中有如下代码其中
guard
来标识是否启用加密,有加密时会调用this.guard.decrypt
进行解密if ("stateless".equals(stateString)) {return null;} else {ObjectInputStream ois = null;InputStream bis = new Base64InputStream(stateString);try {if (this.guard != null) {byte[] bytes = stateString.getBytes("UTF-8");int numRead = ((InputStream)bis).read(bytes, 0, bytes.length);byte[] decodedBytes = new byte[numRead];((InputStream)bis).reset();((InputStream)bis).read(decodedBytes, 0, decodedBytes.length);bytes = this.guard.decrypt(decodedBytes);if (bytes == null) {return null;}bis = new ByteArrayInputStream(bytes);}
加解密逻辑均在ByteArrayGuard
类中,需要时扣代码即可public byte[] decrypt(byte[] bytes) {try {byte[] macBytes = new byte[32];System.arraycopy(bytes, 0, macBytes, 0, macBytes.length);byte[] iv = new byte[16];System.arraycopy(bytes, macBytes.length, iv, 0, iv.length);byte[] encdata = https://www.huyubaike.com/biancheng/new byte[bytes.length - macBytes.length - iv.length];System.arraycopy(bytes, macBytes.length + iv.length, encdata, 0, encdata.length);IvParameterSpec ivspec = new IvParameterSpec(iv);Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");decryptCipher.init(2, this.sk, ivspec);Mac decryptMac = Mac.getInstance("HmacSHA256");decryptMac.init(this.sk);decryptMac.update(iv);decryptMac.update(encdata);byte[] macBytesCalculated = decryptMac.doFinal();if (this.areArrayEqualsConstantTime(macBytes, macBytesCalculated)) {byte[] plaindata = https://www.huyubaike.com/biancheng/decryptCipher.doFinal(encdata);return plaindata;} else {System.err.println("ERROR: MAC did not verify!");return null;}} catch (Exception var10) {System.err.println("ERROR: Decrypting:" + var10.getCause());return null;}}
整体逻辑为,其中看lib版本和配置来判断走不走加解密 * Generate Payload: *writeObject ==> Gzip ==> Encrpt ==> Base64Encode * * Recive Payload: *Base64Decode ==> Decrpt ==> UnGzip ==> readObject
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- elasticsearch聚合之bucket terms聚合
- 赛尔号破解破解幽契之门通关符文位置图示
- “黑绷带的力量” 首先,它有一个奇怪的名字,叫“黑绷带” 其次,在看产品介绍之初,它是一款晚霜。
- 云原生之旅 - 11)基于 Kubernetes 动态伸缩 Jenkins Build Agents
- C#多线程之线程基础篇
- 我的世界漏斗与漏斗之间怎么相连(我的世界漏斗上怎么放东西)
- 洛谷 P4135 作诗 题解
- Java 【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK 输出日志并以文件形式保存
- Java安全之CC3
- 云顶之弈冒险迭嘉阵容搭配推荐攻略