高校教务系统登录页面JS分析——安徽大学

高校教务系统密码加密逻辑及JS逆向

最近有粉丝说安徽大学的教务系统换了,之前用的是正方出品的系统,今天我来看看新版教务系统怎么模拟登录,总体来说,还是比较简单的,就是一个哈希加密了密码,其次就是一个滑块验证码,本文都会一一来介绍。

本文将介绍高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文,你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。

本文仅供交流学习,勿用于非法用途。

一、密码加密基本概念

密码加密是一种保护信息安全的技术手段,它通过将明文(原始信息)转换为密文(加密后的信息),以防止未经授权的访问和篡改。常见的密码加密算法有MD5、SHA-1、SHA-256等。

1.1 加密过程

加密过程通常包括以下步骤:

  1. 密钥扩展:将密钥扩展为多个轮值,每个轮值都与明文的一部分有关。
  2. 初始轮值生成:将扩展后的密钥与轮常数进行某种运算,生成第一轮加密的密文。
  3. 多轮迭代:对密文进行多轮迭代操作,每轮操作都包括非线性函数、模运算和轮常数的变换。
  4. 最终密文:经过多轮迭代后,得到最终的密文。

1.2 解密过程

解密过程与加密过程相反,通过反向操作来恢复原始明文。通常需要知道加密时使用的密钥和算法。

二、高校教务系统密码加密逻辑分析

2.1 抓包

我们首先打开教务系统的登录页面,我们可以看到,只有学号和密码,安徽大学是错误一次密码,会验证验证码,我们后面再说。

ps:这里系统有个小问题,有个测试账号估计安徽大学忘记删了。

密码错误一次后会触发滑块验证码,都没用极验验证码等主流的滑块验证码,都没加密,好搞。

我们打开开发者工具,尝试登录抓包,网页会返回这样的数据接口。我们用户名和密码都是默认输入123456,你也可以输入其他的。

2.2 分析加密参数

我们接下来,就是来分析这个密码是怎么加密的。我们全局搜索password。定位到加密的位置。

发现上面有一行字符串,我们仔细一看,就是加密方法。这里很简单,就是普通的哈希加密。

三、JS逆向分析方法

逆向分析是指从已知的加密文本或程序中还原出原始信息的过程。在本例中,我们将使用JavaScript编写一个简单的逆向分析工具,用于逆向高校教务系统的密码。

环境使用

  • python 3.9
  • pycharm
  • node

代码实现

我们就不去扣js代码了,直接用python实现。这里的salt就是服务器返回的值,也就是这个接口返回的密钥:https://jw.ahu.edu.cn/student/login-salt 

import hashlib

def sha1_hash(text):
    # 创建一个sha1 hash对象
    sha1 = hashlib.sha1()

    # 使用输入的文本更新hash对象
    sha1.update(text.encode('utf-8'))

    # 得到哈希摘要,并转换为十六进制字符串
    hash_output = sha1.hexdigest()

    return hash_output
new_password = salt + '-' + str("密码")
h_password = sha1_hash(new_password)

滑块验证码

我们今天来讲一下这个验证码,其实很简单,我们先看接口,总共有两个接口,一个是获取验证码图片的,一个是提交验证的。

login-captcha

我们先来看第一个接口,传入了两个参数,一个是ts,也就是时间戳,第二个是clientId。这个clientId是本地生成的,不难找到生成算法,我直接给大家了,原文算法是这样的:

uuid: function () {
                var s = []
                var hexDigits = '0123456789abcdef'
                for (var i = 0; i < 36; i++) {
                    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
                }
                s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010
                s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01
                s[8] = s[13] = s[18] = s[23] = '-'
                return s.join('')
            }

能用python实现,我们就不要用js,下面是我们的python代码:

def generate_uuid():
    hexDigits = '0123456789abcdef'
    s = [''] * 36

    for i in range(36):
        if i in [8, 13, 18, 23]:
            s[i] = '-'
        else:
            s[i] = hexDigits[random.randint(0, 0xf)]

    # 设置特定的位以匹配JavaScript代码
    s[14] = '4'  # 设置版本号为4(0100)
    # 设置时钟序列的变体部分
    variant = int(s[19], 16) & 0x3  # 获取当前s[19]的低两位
    s[19] = hexDigits[(variant | 0x8) & 0xf]  # 设置变体为RFC 4122(1000)

    return ''.join(s)

# 生成UUID
uuid = generate_uuid()
# print(uuid)

我们可以看到返回了验证码图片,这里是以base64数据返回的,我们保存到本地就可以。

 下面是保存验证图片的代码,以便于我们后续比较:


import base64

def save_base64_image(base64_string, file_path):
    """
    将 Base64 编码的图片保存到本地文件

    :param base64_string: Base64 编码的图片字符串
    :param file_path: 保存图片的文件路径
    """

    # 将 Base64 字符串解码为二进制数据
    image_data = base64.b64decode(base64_string)

    # 将二进制数据写入文件
    with open(file_path, "wb") as file:
        file.write(image_data)

    print(f"图片已保存到 {file_path}")


# 调用函数保存图片
save_base64_image(jigsawImageBase64, "jsgsaw.jpg")
save_base64_image(originalImageBase64, "originalImage.jpg")

login-captcha-check

我们看看第二个接口,这里传入了四个参数,一个是ts,一个是clientid,前面提及到过,token的值是上一个接口返回的,都不需要出,第四个参数,也就是我们要处理的值,首先,我们知道X是我们移动的距离,Y是0~100的随机值,其次,这些数据都没有加密,那就很简单了,我们直接算出X移动的距离就好了,简而言之,就是计算缺口图片缺口的位置。

 我们这里用cv2库,直接实现,直接调用,没啥难度。


from PIL import Image
import cv2
import numpy as np

def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
    return cv2.cvtColor(np.asarray(img), flag)



def getDistance(imgpath, sliceimgpath):
    img = Image.open(imgpath)
    slice = Image.open(sliceimgpath)
    # 通过 pilImgToCv2 将图片置灰
    # 背景图和滑块图都需要做相同处理
    grayImg = pilImgToCv2(img, cv2.COLOR_BGR2GRAY)
    # img.show(grayImg)
    # showImg(grayImg) # 可以通过它来看处理后的图片效果
    graySlice = pilImgToCv2(slice, cv2.COLOR_BGR2GRAY)
    # 做边缘检测进一步降低干扰,阈值可以自行调整
    grayImg = cv2.Canny(grayImg, 255, 255)
    # showImg(grayImg) # 可以通过它来看处理后的图片效果
    graySlice = cv2.Canny(graySlice, 255, 255)
    # 通过模板匹配两张图片,找出缺口的位置
    result = cv2.matchTemplate(grayImg, graySlice, cv2.TM_CCOEFF_NORMED)
    maxLoc = cv2.minMaxLoc(result)[3]
    # 匹配出来的滑动距离
    distance = maxLoc[0]
    # print(distance)
    return distance
sliceimgpath = 'jsgsaw.jpg'
imgpath = 'originalImage.jpg'
x_dis= getDistance(imgpath, sliceimgpath)

 验证码通过验证之后,会返回这样的结果:

{
    "code": "0000",
    "message": "成功",
    "originalImageBase64": null,
    "jigsawImageBase64": null,
    "token": null,
    "originalImageWidth": 0,
    "success": true
}

全部代码 

下面是这个模拟登录的全部代码,不排除后期这个系统维护升级导致代码失效。

#!/usr/bin/python3.9.6
# _*_ coding: utf-8 _*_
#
# Copyright (C) 2022 - 2024 BROKEN, Inc. All Rights Reserved 
#
# @Time    : 2025/1/5 16:34
# @Author  : 爱吃饼干的小白鼠
# @File    : 安徽大学教务系统(新).py
# @IDE     : PyCharm
# @Blog    :https://broken.blog.csdn.net/

import requests
import json
import time
import random
import hashlib
import base64
from PIL import Image
import cv2
import numpy as np

def sha1_hash(text):
    # 创建一个sha1 hash对象
    sha1 = hashlib.sha1()
    # 使用输入的文本更新hash对象
    sha1.update(text.encode('utf-8'))
    # 得到哈希摘要,并转换为十六进制字符串
    hash_output = sha1.hexdigest()
    return hash_output

session = requests.Session()
headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Pragma": "no-cache",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62",
}
url = "https://jw.ahu.edu.cn/student/login"
response = session.get(url, headers=headers)
url = "http://jw.ahu.edu.cn/student/login-salt"
salt = session.get(url, headers=headers).text
new_password = salt + '-' + str("123456")
h_password = sha1_hash(new_password)


def generate_uuid():
    hexDigits = '0123456789abcdef'
    s = [''] * 36

    for i in range(36):
        if i in [8, 13, 18, 23]:
            s[i] = '-'
        else:
            s[i] = hexDigits[random.randint(0, 0xf)]

    # 设置特定的位以匹配JavaScript代码
    s[14] = '4'  # 设置版本号为4(0100)
    # 设置时钟序列的变体部分
    variant = int(s[19], 16) & 0x3  # 获取当前s[19]的低两位
    s[19] = hexDigits[(variant | 0x8) & 0xf]  # 设置变体为RFC 4122(1000)

    return ''.join(s)

# 生成UUID
uuid = generate_uuid()

timetemp = int(time.time()*1000)

url = "https://jw.ahu.edu.cn/student/login-captcha"
data = {
    "ts": timetemp,
    "clientId": uuid
}
response = session.post(url, json=data)

jigsawImageBase64 = response.json()['jigsawImageBase64']
originalImageBase64 = response.json()['originalImageBase64']
token = response.json()['token']

def save_base64_image(base64_string, file_path):
    """
    将 Base64 编码的图片保存到本地文件
    :param base64_string: Base64 编码的图片字符串
    :param file_path: 保存图片的文件路径
    """
    # 将 Base64 字符串解码为二进制数据
    image_data = base64.b64decode(base64_string)

    # 将二进制数据写入文件
    with open(file_path, "wb") as file:
        file.write(image_data)

# 调用函数保存图片
save_base64_image(jigsawImageBase64, "jsgsaw.jpg")
save_base64_image(originalImageBase64, "originalImage.jpg")

def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
    return cv2.cvtColor(np.asarray(img), flag)

def getDistance(imgpath, sliceimgpath):
    img = Image.open(imgpath)
    slice = Image.open(sliceimgpath)
    # 通过 pilImgToCv2 将图片置灰
    # 背景图和滑块图都需要做相同处理
    grayImg = pilImgToCv2(img, cv2.COLOR_BGR2GRAY)
    # img.show(grayImg)
    # showImg(grayImg) # 可以通过它来看处理后的图片效果
    graySlice = pilImgToCv2(slice, cv2.COLOR_BGR2GRAY)
    # 做边缘检测进一步降低干扰,阈值可以自行调整
    grayImg = cv2.Canny(grayImg, 255, 255)
    # showImg(grayImg) # 可以通过它来看处理后的图片效果
    graySlice = cv2.Canny(graySlice, 255, 255)
    # 通过模板匹配两张图片,找出缺口的位置
    # 通过模板匹配两张图片,找出缺口的位置
    result = cv2.matchTemplate(grayImg, graySlice, cv2.TM_CCOEFF_NORMED)
    maxLoc = cv2.minMaxLoc(result)[3]
    # 匹配出来的滑动距离
    distance = maxLoc[0]
    return distance
sliceimgpath = 'jsgsaw.jpg'
imgpath = 'originalImage.jpg'
x_dis= getDistance(imgpath, sliceimgpath)

url = "https://jw.ahu.edu.cn/student/login-captcha-check"
data = {
    "point": {
        "x": x_dis,
        "y": random.randint(0, 99)# 生成一个0到99之间的随机整数

    },
    "token": token,
    "ts": timetemp+23253,
    "clientId": uuid
}
response = session.post(url, json=data)

print(response.text)

url = "https://jw.ahu.edu.cn/student/login"
data = {
    "username": "123456",
    "password": h_password,
    "captchaToken": token
}

response = session.post(url,headers=headers, json=data)

print(response.text)

由于我们账号和密码是错误的(大家也可以用测试账号12345模拟登录,密码也是12345,看看效果吧),所以返回密码错误,但是会提示验证码正确("needCaptcha":true),就说明我们滑块验证码破解成功了,下面是运行结果:
 

四、总结

本文介绍了高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的方法。通过学习这些知识,你可以更好地理解密码加密技术的原理,并掌握一定的逆向分析技巧。请注意,逆向分析可能涉及到法律问题,请在合法范围内进行研究和实践。

五、累计更新

争取到到底早日更新30所高校,大家可以在评论区留言。前期更的可能会多一点,有的学校教务系统都没有加密,我这里就不写了,还有,部分学校的教务系统已经和我之前写的是一样的,我也不重复赘述了。

往期作品可以查看专栏👇👇👇

全国高校教务系统登录页面JS分析_爱吃饼干的小白鼠的博客-CSDN博客

6adf31c8c5dd4e6a83314f4805b30bc1.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949161.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示

在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示 参考文章源码下载地址一、SDL2的创建、初始化、退出二、系统基本Tick、彩屏刷新、按键事件三、彩屏获取与设置颜色四、彩屏填充颜色及清屏五、彩屏显示中文和英文字符串六、彩屏显示数字七、彩屏初始化八、主函数测…

Speech Recognition vs. Voice Recognition | 语音识别工作原理 | 模型训练 | 应用

注&#xff1a;机翻&#xff0c;未校。 Speech Recognition 与 Voice Recognition 剑桥词典 speech recognition&#xff0c;语音识别 voice recognition&#xff0c;声音识别 Speech vs. Voice - What’s the Difference? | This vs. That https://thisvsthat.io/speech-vs…

《Vue3实战教程》35:Vue3测试

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 测试​ 为什么需要测试​ 自动化测试能够预防无意引入的 bug&#xff0c;并鼓励开发者将应用分解为可测试、可维护的函数、模块、类和组件。这能够帮助你和你的团队更快速、自信地构建复杂的 Vue 应用。与任何应用一…

【MySQL 保姆级教学】用户管理和数据库权限(16)

数据库账户管理是指对数据库用户进行创建、修改和删除等操作&#xff0c;以控制用户对数据库的访问权限。通过账户管理&#xff0c;可以设置用户名、密码、主机地址等信息&#xff0c;确保数据库的安全性和可控性。例如&#xff0c;使用 CREATE USER 创建用户&#xff0c;ALTER…

【复盘】2024年终总结

工作 重构风控系统 今年上半年其实就是整体重构系统&#xff0c;经历了多次加班的&#xff0c;其中的辛酸苦辣只有自己知道&#xff0c;现在来看的话&#xff0c;其实对自己还有一定的成长&#xff0c;从这件事情上也明白 绩效能不能拿到A&#xff0c;在分配的任务的时候就决…

美食烹饪互动平台

本文结尾处获取源码。 一、相关技术 后端&#xff1a;Java、JavaWeb / Springboot。前端&#xff1a;Vue、HTML / CSS / Javascript 等。数据库&#xff1a;MySQL 二、相关软件&#xff08;列出的软件其一均可运行&#xff09; IDEAEclipseVisual Studio Code(VScode)Navica…

linux-centos-安装miniconda3

参考&#xff1a; 最新保姆级Linux下安装与使用conda&#xff1a;从下载配置到使用全流程_linux conda-CSDN博客 https://blog.csdn.net/qq_51566832/article/details/144113661 Linux上删除Anaconda或Miniconda的步骤_linux 删除anaconda-CSDN博客 https://blog.csdn.net/m0_…

[读书日志]从零开始学习Chisel 第一篇:书籍介绍,Scala与Chisel概述,Scala安装运行(敏捷硬件开发语言Chisel与数字系统设计)

简介&#xff1a;从20世纪90年代开始&#xff0c;利用硬件描述语言和综合技术设计实现复杂数字系统的方法已经在集成电路设计领域得到普及。随着集成电路集成度的不断提高&#xff0c;传统硬件描述语言和设计方法的开发效率低下的问题越来越明显。近年来逐渐崭露头角的敏捷化设…

工厂模式与抽象工厂模式在Unity中的实际应用案例

一、实验目的 实践工厂模式和抽象工厂模式的实际应用。 创建一个小型的游戏场景&#xff0c;通过应用这些设计模式提升游戏的趣味性和可扩展性。 掌握在复杂场景中管理和使用不同类型的对象。 比较在实际游戏开发中不同设计模式的实际效果和应用场景。 学习如何进行简单的性…

vue3+Echarts+ts实现甘特图

项目场景&#xff1a; vue3Echartsts实现甘特图;发布任务 代码实现 封装ganttEcharts.vue <template><!-- Echarts 甘特图 --><div ref"progressChart" class"w100 h100"></div> </template> <script lang"ts&qu…

[Linux]redis5.0.x升级至7.x完整操作流程

1. 从官网下载最新版redis&#xff1a; 官网地址&#xff1a;https://redis.io/download 注&#xff1a;下载需要的登录&#xff0c;如果选择使用github账号登录&#xff0c;那么需要提前在github账号中取消勾选“Keep my email addresses private”&#xff08;隐藏我的邮箱…

android 外挂modem模块实现Telephony相关功能(上网,发短信,打电话)

一.背景 当前模块不支持Telephony相关的功能,例如上网、发短信等功能,就需要外挂另一个模块实现此功能,这就是外挂modem模块实现Telephony功能,此篇主要就是说实现外挂modem模块功能中的Framework层实现逻辑,如下流程是在Android 13中实现的外挂pcie模块的流程 二.ril库相…

倍思氮化镓充电器分享:Super GaN伸缩线快充35W

快节奏的时代,在旅游、办公等场景下,一款高效、便捷的充电器可以让我们的生活更便捷、高效。今天就给大家推荐一款倍思氮化镓充电器——Super GaN伸缩线快充35W。它具备多重亮点,可以满足我们在许多场景下的充电需求,成为我们的得力助手。 倍思氮化镓Super GaN伸缩线快充35W的亮…

若依前后端分离项目部署(使用docker)

文章目录 一、搭建后端1.1 搭建流程&#xff1a;1.2 后端零件:1.2.1 mysql容器创建&#xff1a;1.2.2 redis容器创建&#xff1a;1.2.3 Dockerfile内容&#xff1a;1.2.4 构建项目镜像&#xff1a;1.2.5 创建后端容器&#xff1a; 二、前端搭建&#xff1a;2.1 搭建流程&#x…

STM32驱动NRF24L01

一、NRF24L01的相关介绍 1.2 引脚的介绍 关于SPI的引脚就不再说了&#xff0c;这里介绍其余的两个引脚&#xff1a; CE 模块控制引脚&#xff1a;芯片开启信号&#xff0c;激活RX或TX模式 IRQ 模块中断信号输出引脚&#xff1a;其低电平有效&#xff0c;也就是中断时变为低电平…

OneOS操作系统入门-驱动-03:I2C总线及驱动

一、I2C总线 1.1、I2C总线简介 IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的两线式串行总线&#xff0c;用于连接微控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线&#xff0c;可发送和接收数据&#xff0c;在 CPU 与被控 IC…

【可实战】Bug的判定标准、分类、优先级、定位方法、提交Bug(包含常见面试题)

一、Bug相关概念 &#xff08;一&#xff09;bug判定标准 &#xff08;二&#xff09;常见 Bug 分类 &#xff08;三&#xff09;bug优先级 1.bug严重程度与优先级的关系 有些很严重的Bug&#xff0c;只在极端的条件下才出现&#xff0c;用户碰到的概率很低&#xff0c;这种情…

nginx学习之路-nginx配置https服务器

文章目录 1. 生成证书2. 配置证书1. 拷贝证书文件2. 修改conf/nginx.conf文件内容 3. 查看效果1. 重载配置2. 访问 1. 生成证书 在linux系统下执行&#xff0c;使用openssl命令。&#xff08;windows环境也可以使用cmder&#xff09; # 1. 生成私钥 server2025.key(无密码保护…

【mybatis】Mybatis整体架构解析

从本篇开始我们开始学习mybatis的系列源码&#xff0c;主要的主题可能就是四个方面 从整体把握mybatis系统架构通过一个查询SQL 源码解析核心流程mybatis的缓存机制-源码级别mybatis的插件机制-源码级别spring是如何整合的mybatis框架的 1.整体架构 上述是mybatis的源码&…

DDcGAN_多分辨率图像融合的双鉴别条件生成对抗网络_y译文马佳义

摘要&#xff1a; 在本文中&#xff0c;我们提出了一种新的端到端模型&#xff0c;称为双鉴别条件生成对抗网络&#xff08;DDcGAN&#xff09;&#xff0c;用于融合不同分辨率的红外和可见光图像。我们的方法建立了一个生成器和两个鉴别器之间的对抗博弈。生成器的目的是基于特…