咕噜校园项目功能解刨
技术分析
校园后台:正方软件后台系统
- 抓包登录:
- 抓取账号密码,看看加密各方面
- 查看请求参数
- 成功 和 失败 动作
- 课表查询
- 抓取URL
- 查看请求参数
- 解析返回数据
- 同学汇:
- emmmm Mysql一些多表查询就能写
登录
模拟登录:
解析到登录URL:String url = "https://ijw.xxxxx.edu.cn/xxxxxxxxx/login_slogin.html?time=";
解析到这里做了 Csrf 攻击防护,所以要获取:Csrftoken
每次刷新都会改变。
解析到这里的账号密码提交做了一个加密,可以跟进去看到加密的方式:
OK 很清楚了:
- 密码RSA加密,
- 要获取 modulus 和 exponent,加密换取 rsaKey
- 然后rsaKey 和 密码二次加密,换取加密的密码
- 提交加密的密码 和 scrftoken 值
SpringBoot登录:
用HTTPClient + Jsoup 请求和解析获取scrftoken
按照上面写:
//获取Csrftoken
public static String getCsrftoken() throws Exception {
String url = "https://ijw.xxxx.edu.cn/xxxxxx/login_slogin.html?time=" + new Date().getTime();
HttpClientResp httpClientResp = HttpClientUtil.requestGet(url + new Date().getTime(), null);
String res = Jsoup.parse(httpClientResp.getEntity()).getElementById("csrftoken").attr("value");
return res;
}
抓取 modulus 和 exponent:
//获取 exponent modulus 生成公钥
public static HttpClientResp getExponentAndModulus() throws Exception {
String url = "https://ijw.xxxx.edu.cn/xxxx/login_getPublicKey.html?time="; // 为了安全 这里没给出全链接
HttpClientResp httpClientResp = HttpClientUtil.requestGet(url + new Date().getTime(), null);
return httpClientResp;
}
密码加密:
//密码加密
String en_password = RSAEncoder.RSAEncrypt(loginReq.getMm(), B64.b64tohex(jsonObject.get("modulus").toString()), B64.b64tohex(jsonObject.get("exponent").toString()));
en_password = B64.hex2b64(en_password);
B64:
package com.bihu.glxy.utils;
import static java.lang.Integer.parseInt;
public class B64 {
public static String b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
private static char b64pad = '=';
private static String hexCode = "0123456789abcdef";
// 获取对应16进制字符
public static char int2char(int a) {
return hexCode.charAt(a);
}
// Base64转16进制
public static String b64tohex(String s) {
String ret = "";
int k = 0;
int slop = 0;
for (int i = 0; i < s.length(); ++i) {
if (s.charAt(i) == b64pad) break;
int v = b64map.indexOf(s.charAt(i));
if (v < 0) continue;
if (k == 0) {
ret += int2char(v >> 2);
slop = v & 3;
k = 1;
} else if (k == 1) {
ret += int2char((slop << 2) | (v >> 4));
slop = v & 0xf;
k = 2;
} else if (k == 2) {
ret += int2char(slop);
ret += int2char(v >> 2);
slop = v & 3;
k = 3;
} else {
ret += int2char((slop << 2) | (v >> 4));
ret += int2char(v & 0xf);
k = 0;
}
}
if (k == 1)
ret += int2char(slop << 2);
return ret;
}
// 16进制转Base64
public static String hex2b64(String h) {
int i, c;
StringBuilder ret = new StringBuilder();
for (i = 0; i + 3 <= h.length(); i += 3) {
c = parseInt(h.substring(i, i + 3), 16);
ret.append(b64map.charAt(c >> 6));
ret.append(b64map.charAt(c & 63));
}
if (i + 1 == h.length()) {
c = parseInt(h.substring(i, i + 1), 16);
ret.append(b64map.charAt(c << 2));
} else if (i + 2 == h.length()) {
c = parseInt(h.substring(i, i + 2), 16);
ret.append(b64map.charAt(c >> 2));
ret.append(b64map.charAt((c & 3) << 4));
}
while ((ret.length() & 3) > 0) ret.append(b64pad);
return ret.toString();
}
}
RSA:
package com.bihu.glxy.utils;
import java.math.BigInteger;
import java.util.Random;
public class RSAEncoder {
private static BigInteger n = null;
private static BigInteger e = null;
public static String RSAEncrypt(String pwd, String nStr, String eStr) {
n = new BigInteger(nStr, 16);
e = new BigInteger(eStr, 16);
BigInteger r = RSADoPublic(pkcs1pad2(pwd, (n.bitLength() + 7) >> 3));
String sp = r.toString(16);
if ((sp.length() & 1) != 0)
sp = "0" + sp;
return sp;
}
private static BigInteger RSADoPublic(BigInteger x) {
return x.modPow(e, n);
}
private static BigInteger pkcs1pad2(String s, int n) {
if (n < s.length() + 11) { // TODO: fix for utf-8
System.err.println("Message too long for RSAEncoder");
return null;
}
byte[] ba = new byte[n];
int i = s.length() - 1;
while (i >= 0 && n > 0) {
int c = s.codePointAt(i--);
if (c < 128) { // encode using utf-8
ba[--n] = new Byte(String.valueOf(c));
} else if ((c > 127) && (c < 2048)) {
ba[--n] = new Byte(String.valueOf((c & 63) | 128));
ba[--n] = new Byte(String.valueOf((c >> 6) | 192));
} else {
ba[--n] = new Byte(String.valueOf((c & 63) | 128));
ba[--n] = new Byte(String.valueOf(((c >> 6) & 63) | 128));
ba[--n] = new Byte(String.valueOf((c >> 12) | 224));
}
}
ba[--n] = new Byte("0");
byte[] temp = new byte[1];
Random rdm = new Random(47L);
while (n > 2) { // random non-zero pad
temp[0] = new Byte("0");
while (temp[0] == 0)
rdm.nextBytes(temp);
ba[--n] = temp[0];
}
ba[--n] = 2;
ba[--n] = 0;
return new BigInteger(ba);
}
}
登录:
// 登录
HttpResponse loginResponse = HttpRequest.post(url + new Date().getTime())
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
.header("Accept-Encoding", "gzip, deflate")
.header("Accept-Language", "zh-CN,zh;q=0.9")
.header("Cache-Control", "max-age=0")
.header("Connection", "keep-alive")
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Host", "ijw.zspt.edu.cn")
.header("Origin", "https://ijw.zspt.edu.cn")
.header("Upgrade-Insecure-Requests", "1")
.header("UserInfo-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36")
.cookie("JSESSIONID=" + exponentAndModulus.getCookie()) //这个是一定要携带的,不然模拟会失败,这个携带的是获取exponentAndModulus时候返回的Cookie
.form("csrftoken", Utils.getCsrftoken())
.form("language", "zh_CN")
.form("yhm", loginReq.getXh()) //学号
.form("mm", en_password) //加密过的密码
.form("mm", en_password) //加密过的密码
.execute();
如果成功登录会跳转,所以我们getEntry为空
登录失败跳转到登录页[全部数据没了]
然后我们只需要获取到它返回的Cookie即可
查询课表
就抓到看些提交什么 携带Cookie去即可:
HttpResponse kbResponse = HttpRequest.post(url + kb.getXh()) //模擬瀏覽器
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
.header("Accept-Encoding", "gzip, deflate")
.header("Accept-Language", "zh-CN,zh;q=0.9")
.header("Cache-Control", "max-age=0")
.header("Connection", "keep-alive")
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Host", "ijw.zspt.edu.cn")
.header("Origin", "https://ijw.zspt.edu.cn")
.header("Upgrade-Insecure-Requests", "1")
.header("UserInfo-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36")
.cookie("JSESSIONID=" + kb.getCookie())
.form("xnm", 2022)//固定
.form("xqm", 3)//固定
.form("kzlx", "ck")//固定
.execute();
if (Strings.isEmpty(kbResponse.body())) {
return R.error(401, "抱歉,您的登录已过期,请重新登录!");
}
// 解析课表这里省略
完成
效果图:
完成展示,不足之处请指正,学习交流OK!?
转载请声明,请尊重原创,谢谢。
标签:总结,咕噜,String,校园,ret,header,static,new,ba From: https://www.cnblogs.com/bi-hu/p/16924661.html