HCTF2018-admin

注册账号登录,打开f12我们能够看到github的提示,我们把源码下载下来进行分析。

查看初始化模块
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
login = LoginManager(app)

from app import routes, models  

查看routes文件

修改password模块
@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)
register登记注册模块
@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)
查看渲染的index页面
{% 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') %}  

发现判断逻辑: {% if current_user.is_authenticated and session['name'] == 'admin' %} 证明要使用admin账号才能登陆。

config.py
import 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  

flask的session是存储在客户端cookie中的,而且flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。
利用脚本我们将session解密,之后修改用户名为admin,然后再加密,burp截包替换session即可。

{'_fresh': True, '_id': b'121de14bca66edf6cc98e254ab460d68f9122c75e64747a997410a84049d9295b53192aebf5c2b93641e5c58cc1596ed3850da7a17a5f3f6415ac0743afe3dc4', 'csrf_token': b'd2495789467d55d9e38c2ffd63e9c578ee1b267a', 'image': b'BUXE', 'name': 'admin', 'user_id': '10'}
unicode欺骗

无论是在register,changepassword模块他们都加了strlower()进行小写转换,右键转到函数的实现。

def strlower(username):
    username = nodeprep.prepare(username)
    return username

使用到nodeprep.prepare函数,该函数专函大小写字符如下:
ᴬᴰᴹᴵᴺ -> ADMIN -> admin
我们注册ᴬDMIN用户,在registr中这个函数没被使用不被转义,在login进行第一次的编码转换,在changepassword又进行第二次,此时我们用户名就由ᴬDMIN变为了admin,修改了admin的password。
转换形式如下:
ᴬᴰᴹᴵᴺ -> ADMIN -> admin

条件竞争

这个在刚入学时候极客大挑战已经碰见过了,我们利用burpsuit的intruder模块就能利用,要设置两个线程同时进行,一个是不行的。

猜你喜欢

转载自www.cnblogs.com/ophxc/p/12887959.html