首页 > 其他分享 >咕噜校园项目总结

咕噜校园项目总结

时间:2022-11-25 11:57:35浏览次数:35  
标签:总结 咕噜 String 校园 ret header static new ba

咕噜校园项目功能解刨

技术分析

校园后台:正方软件后台系统

  1. 抓包登录:
    1. 抓取账号密码,看看加密各方面
    2. 查看请求参数
    3. 成功 和 失败 动作
  2. 课表查询
    1. 抓取URL
    2. 查看请求参数
    3. 解析返回数据
  3. 同学汇:
    1. emmmm Mysql一些多表查询就能写

登录

模拟登录:

解析到登录URL:String url = "https://ijw.xxxxx.edu.cn/xxxxxxxxx/login_slogin.html?time=";

解析到这里做了 Csrf 攻击防护,所以要获取:Csrftoken

image-20221125111233761

每次刷新都会改变。

解析到这里的账号密码提交做了一个加密,可以跟进去看到加密的方式:

image-20221125111654740

OK 很清楚了:

  1. 密码RSA加密,
  2. 要获取 modulus 和 exponent,加密换取 rsaKey
  3. 然后rsaKey 和 密码二次加密,换取加密的密码
  4. 提交加密的密码 和 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:

image-20221125112412893

//获取 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, "抱歉,您的登录已过期,请重新登录!");
}
// 解析课表这里省略

完成

效果图:

image-20221125113551214

image-20221125113613163

image-20221125113708961

image-20221125113716855

image-20221125113732196

image-20221125113756005

image-20221125113842664

image-20221125113934013

完成展示,不足之处请指正,学习交流OK!?

转载请声明,请尊重原创,谢谢。

标签:总结,咕噜,String,校园,ret,header,static,new,ba
From: https://www.cnblogs.com/bi-hu/p/16924661.html

相关文章

  • 二分查找总结
    二分查找二分查找也常被称为二分法或者折半查找(BinarySearch),每次查找时通过将待查找区间分成两部分并只取一部分继续查找,将查找的复杂度大大减少。对于一个长度为O(n) ......
  • Java对象值传递和对象传递的总结
    值传递和对象传递的问题总结下。   先看基本类型作为参数传递的例子:publicclassTest1{publicstaticvoidmain(String[]args){intn=3;System.......
  • 第九章运行存储分配常考大题总结(二)一些题
    题一 解题思路:先画出整体的活动树 (1)题干指出当前执行过程为quicksort(2,3),意为q(5,9)一侧不需要考虑,因为q(1,3)先执行完才能执行q(5,9),本题轮不到q(5,9)main()-......
  • Oracle中字符串截取最全方法总结
    substr函数:截取字符串语法:SUBSTR(string,start, [length])string:表示源字符串,即要截取的字符串。start:开始位置,从1开始查找。如果start是负数,则从string字符串末......
  • java23种设计模式概述总结
    软件设计模式的意义:它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠......
  • Docker总结整合(一)
    1、简介Docker是一个开源的应用容器引擎;是一个轻量级容器技术;Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像......
  • 总结Vue父子组件相互传值和路由传值的两种方式【后续更新】
    1、父到子思路总结:   1、定义子组件接收父组件的变量在props['child'],的单独的属性中,与data()平行;   2、在父组件中给子组件中定义的变量赋值==> :child="pare......
  • Flink与Hive集成错误总结
    1.Causedby:java.lang.ClassNotFoundException:org.apache.hive.common.util.HiveVersionInfo原因:flink缺少hive-exec-3.1.2.jar包解决方法:cp/usr/local/hive/lib/......
  • Java 集合 - 总结
    介绍Java集合类是数据结构的实现,这些类用来存储和操作对象。常见接口1、Collection:最基本的集合接口,存储一组不唯一,无序的对象。2、List:继承Collection接口,存储一组......
  • Struts2学习总结
    struts2其实主要充当MVC模式的View层,主要是为了代替Servlet获取请求参数那些繁琐的操作。它提供的功能主要有如下2点:1.通过属性绑定和模型绑定来简化传统servlet需要使用req......