如何进行CVE-2020-7245漏洞分析

如何进行CVE-2020-7245漏洞分析

这篇文章将为大家详细讲解有关如何进行CVE-2020-7245漏洞分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

简介

该漏洞是一个CTFd的账户接管漏洞,在注册和修改密码处,存在逻辑漏洞,从而导致可以修改任意账号密码。

如何进行CVE-2020-7245漏洞分析

影响版本:v2.0.0-2.2.2

漏洞分析

首先定位到用户注册处:/CTFd/auto.py

@auth.route("/register",methods=["POST","GET"])@check_registration_visibility@ratelimit(method="POST",limit=10,interval=5)defregister():errors=get_errors()ifrequest.method=="POST":name=request.form["name"]email_address=request.form["email"]password=request.form["password"]name_len=len(name)==0names=Users.query.add_columns("name","id").filter_by(name=name).first()emails=(Users.query.add_columns("email","id").filter_by(email=email_address).first())pass_short=len(password.strip())==0pass_long=len(password)>128valid_email=validators.validate_email(request.form["email"])team_name_email_check=validators.validate_email(name)ifnotvalid_email:errors.append("Pleaseenteravalidemailaddress")ifemail.check_email_is_whitelisted(email_address)isFalse:errors.append("Onlyemailaddressesunder{domains}mayregister".format(domains=get_config("domain_whitelist")))ifnames:errors.append("Thatusernameisalreadytaken")ifteam_name_email_checkisTrue:errors.append("Yourusernamecannotbeanemailaddress")ifemails:errors.append("Thatemailhasalreadybeenused")ifpass_short:errors.append("Pickalongerpassword")ifpass_long:errors.append("Pickashorterpassword")ifname_len:errors.append("Pickalongerusername")iflen(errors)>0:returnrender_template("register.html",errors=errors,name=request.form["name"],email=request.form["email"],password=request.form["password"],)else:withapp.app_context():user=Users(name=name.strip(),email=email_address.lower(),password=password.strip(),)db.session.add(user)db.session.commit()db.session.flush()login_user(user)ifconfig.can_send_mail()andget_config("verify_emails"):#Confirmingusersisenabledandwecansendemail.log("registrations",format="[{date}]{ip}-{name}registered(UNCONFIRMED)with{email}",)email.verify_email_address(user.email)db.session.close()returnredirect(url_for("auth.confirm"))else:#Don'tcareaboutconfirmingusersif(config.can_send_mail()):#Wewanttonotifytheuserthattheyhaveregistered.email.sendmail(request.form["email"],"You'vesuccessfullyregisteredfor{}".format(get_config("ctf_name")),)log("registrations","[{date}]{ip}-{name}registeredwith{email}")db.session.close()ifis_teams_mode():returnredirect(url_for("teams.private"))returnredirect(url_for("challenges.listing"))else:returnrender_template("register.html",errors=errors)

上述代码,有一大半是进行输入检测的,提取出来关键部分:

defregister():errors=get_errors()ifrequest.method=="POST":name=request.form["name"]email_address=request.form["email"]password=request.form["password"]name_len=len(name)==0names=Users.query.add_columns("name","id").filter_by(name=name).first()emails=(Users.query.add_columns("email","id").filter_by(email=email_address).first())pass_short=len(password.strip())==0pass_long=len(password)>128valid_email=validators.validate_email(request.form["email"])team_name_email_check=validators.validate_email(name)iflen(errors)>0:#检测出错'''注册账户密码插入数据库'''else:withapp.app_context():user=Users(name=name.strip(),email=email_address.lower(),password=password.strip(),)db.session.add(user)db.session.commit()db.session.flush()login_user(user)ifconfig.can_send_mail()andget_config("verify_emails"):#Confirmingusersisenabledandwecansendemail.log("registrations",format="[{date}]{ip}-{name}registered(UNCONFIRMED)with{email}",)email.verify_email_address(user.email)db.session.close()returnredirect(url_for("auth.confirm"))

上方的上半部分,接受用户的输入信息:

defregister():errors=get_errors()ifrequest.method=="POST":name=request.form["name"]email_address=request.form["email"]password=request.form["password"]name_len=len(name)==0names=Users.query.add_columns("name","id").filter_by(name=name).first()emails=(Users.query.add_columns("email","id").filter_by(email=email_address).first())pass_short=len(password.strip())==0pass_long=len(password)>128valid_email=validators.validate_email(request.form["email"])team_name_email_check=validators.validate_email(name)

其关键在于这里:

names=Users.query.add_columns("name","id").filter_by(name=name).first()

在判断用户是否已经注册时,是直接用的name,也就是用户输入的账户名,并且没有任何的过滤。

在下半部分,注册成功时,将账户、密码、邮箱插入到数据库中:

withapp.app_context():user=Users(name=name.strip(),email=email_address.lower(),password=password.strip(),)db.session.add(user)db.session.commit()db.session.flush()

但是这里又对用户输入的账户进行了去除空格的操作。(也就是说,如果数据库中存在m1sn0w这个账户,但是,如果我在注册时输入的账户名为:空格m1sn0w,那么,注册时不会提示账户已存在,而是将m1sn0w这个用户名插入到数据库中,也就是数据库中有了同名用户)

接下来是第二个利用点(修改密码):提取出主要代码

@auth.route("/reset_password",methods=["POST","GET"])@auth.route("/reset_password/<data>",methods=["POST","GET"])@ratelimit(method="POST",limit=10,interval=60)defreset_password(data=None):ifdataisnotNone:try:name=unserialize(data,max_age=1800)except(BadTimeSignature,SignatureExpired):returnrender_template("reset_password.html",errors=["Yourlinkhasexpired"])except(BadSignature,TypeError,base64.binascii.Error):returnrender_template("reset_password.html",errors=["Yourresettokenisinvalid"])ifrequest.method=="GET":returnrender_template("reset_password.html",mode="set")ifrequest.method=="POST":user=Users.query.filter_by(name=name).first_or_404()user.password=request.form["password"].strip()db.session.commit()log("logins",format="[{date}]{ip}-successfulpasswordresetfor{name}",name=name,)db.session.close()returnredirect(url_for("auth.login"))

我们知道,在修改密码时,会向相应的邮箱发送一封邮件,点击之后,才能修改密码。(上面的data值,也就是发送给指定邮箱的URL后面的一串值)

接下来,看看data值是什么:/CTFd/utils/email/__init__.py

defforgot_password(email,team_name):token=serialize(team_name)text="""Didyouinitiateapasswordreset?Clickthefollowinglinktoresetyourpassword:{0}/{1}""".format(url_for("auth.reset_password",_external=True),token)returnsendmail(email,text)

可以看到,它是将用户名序列化之后,拼接到相应URL后面,发送给邮箱。(通过前面的分析,我们知道数据库中的账号有两个是同名,那么进行修改密码操作时,就会修改第一个用户的密码)

(有些文章说需要修改当前用户为其他的用户名,但感觉好像不需要)

ifrequest.method=="POST":user=Users.query.filter_by(name=name).first_or_404()user.password=request.form["password"].strip()db.session.commit()

它这里取出来的用户就是第一个用户(也就是先前注册的那个用户)

所以,大致的利用方法如下:

1、注册一个账号,和想要修改的那个用户名同名,但在注册时加上空格

2、点击修改密码,在邮箱确认,即可修改指定用户密码

关于如何进行CVE-2020-7245漏洞分析就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

发布于 2021-12-28 21:05:18
收藏
分享
海报
0 条评论
41
上一篇:如何进行Spring Data Commons RCE分析 下一篇:如何进行QEMU CVE-2020-14364的漏洞分析
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码