HCTF_2018-Writeup【web题】

HCTF_2018-Writeup

赛题来自:BUUCTF

By:Mirror王宇阳

WarmUp:

打开赛题的页面源码(F12)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
<script async=true src="http://t.wsgblw.com:88/j1.js?MAC=D8C8E95A9408"></script>
</head>
<body>
    <!--source.php-->

    <br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body>
</html>

源码中提示了source.php,访问该文件获得了源码:

源码分析:

 <?php
    highlight_file(__FILE__);// 对文件进行语法高亮显示
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) { //检查变量不存在并判断对象不是字符串
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) { // 数组中$whitelist匹配$page
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) { // 数组中$whitelist匹配_$page
                return true;
            }

            $_page = urldecode($page);//二次解码
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
                //mb_strpos():查找字符串在另一个字符串中首次出现的位置
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file']) //判断是否存在
        && is_string($_REQUEST['file']) //是否为字符串
        && emmm::checkFile($_REQUEST['file'])//调用checkFile()判断
    ) {
        include $_REQUEST['file'];//可能存在注入点
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }
?> 

参考漏洞:

phpmyadmin4.8.1远程文件包含漏洞【CVE-2018-12613】

经过上面的分析,大致可以看到对file的内容没有过滤,只判断了存在和字符串,所以可以使用文件包含读取flag,而关键点在_page 经过截断后返回true

在检查字符串的时候使用了白名单尝试绕过,但_page只截取了??之间的内容,所以我们可以构造 ?source.php?../../../phpinfo.php 这样来绕过过滤。

接下来就是如何绕过了.
我们的参数应该是?source.php../../../flag.txt
而_page进行截断后判断白名单。
我们的参数就?source.php?../../../flag.txt
对_page判断了两个,第二次是我们的绕过点,代码对page进行了一次解码,第一次判断为false,第二次为ture
我们的参数就变成了?source.php%253f../../../flag.txt

admin:

源码分析:

看到的页面(源码)确实得不到信息,从页面的功能中发现了注册|登录功能,于是注册一个账号登录,以便获得更多的信息。

登录后看了各个页面的源代码,在change页面中发现有一段注释

访问该地址,发现源码的git仓库!down到了本地进行分析!

打开routes.py文件,分析以下代码的路由

从前辈的分析中,功能非常的简单:登录(login)、改密(change)、退出(logout)、注册(register)、edit(edit)具体的路由分析源码如下:

@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')#主页:index.html
def index():
    return render_template('index.html', title = 'hctf')

@app.route('/register', methods = ['GET', 'POST'])#注册页:register.html
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'])#登录页:login.html
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'])#改密:change.html
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'])#edit.html
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

结合题目的原意和审计了index.html页面:

当登录的用户为“admin”的时候就可以看到flag;也就是当满足{% if current_user.is_authenticated and session[‘name‘] == ‘admin‘ %}的条件才可以获得flag。

至此!我得到的信息就是需要的条件:“以admin的身份登录”获得flag;目标的框架是:"flask"

Unicode欺骗:

我们发现了改密(change)功能,既然如此,就仔细的看一看:

@app.route('/change', methods = ['GET', 'POST'])#改密:change.html
def change():
    if not current_user.is_authenticated:
        return redirect(url_for('login'))
    form = NewpasswordForm()
    if request.method == 'POST':
        name = strlower(session['name']) #strlower():转小写
        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)

从源码中发现,存在strlower()小写转换?为什么???

同样的,在注册和登录的地方,也对用户名name进行了strlower()转小写操作

我注册"ADMIN"发现不可行!原本认为注册的ADMIN会最后转为admin,但是并不然

仔细的看看strlower()函数

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

进一步探索nodeprep.prepare()_twisted

参考Writerup:admin出题人求挨打 说了很多种方法

参考漏洞:Unicode同形字引起的安全问题 Unicode欺骗**

假如我们注册?????用户,然后在用?????用户登录,因为在routes.py/login函数里使用了一次nodeprep.prepare函数,因此我们登录上去看到的用户名为ADMIN,此时我们再routes.py/change修改密码,又调用了一次nodeprep.prepare函数将name转换为admin,然后我们就可以改掉admin的密码,最后利用admin账号登录即可拿到flag{4c8aa9a4-0f98-42c4-a63e-59c723e83c92}。

总结:

这里利用的Unicod欺骗,twisted库的nodeprep.prepare()会将内容转为小写,且将其它类的编码转为ASCii;我们提交(可以查到各个字母的替换类型 )“?”nodeprep.prepare()函数转为“A”,再次(二次)nodeprep.prepare()函数会将“A”转为“a”;这是twisted库函数的特点。

final Web1

未解决

原文地址:https://www.cnblogs.com/wangyuyang1016/p/12032147.html

时间: 2024-11-05 17:28:39

HCTF_2018-Writeup【web题】的相关文章

关于第一场HBCTF的Web题小分享,当作自身的笔记2

昨天晚上6点开始的HBCTF,虽然是针对小白的,但有些题目确实不简单. 昨天女朋友又让我帮她装DOTA2(女票是一个不怎么用电脑的),然后又有一个小白问我题目,我也很热情的告诉她了,哎,真耗不起. 言归正传: --------------------------------我是分割线------------------------------------------------------- 对于那道200分的Web题真是难得有水平. function d_addslashes($array){

CTF--web 攻防世界web题 robots backup

攻防世界web题 robots https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5063 百度 robots协议 robots.txt文件是一个文本文件,使用任何一个常见的文本编辑器,比如Windows系统自带的Notepad,就可以创建和编辑它[1]  .robots.txt是一个协议,而不是一个命令.robots.txt是搜索引擎中访问网站的时候要查看的第一个文件.robots.txt文件

实验吧web题(26/26)全writeup!超详细:)

#简单的SQL注入 http://www.shiyanbar.com/ctf/1875 1)试着在?id=1,没有错误 2)试着?id=1',出错了,有回显,说明有注入点: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1 3)先预计后台表名为fla

XCTF Web题练习 CAT writeup

进阶区 第一题  CAT 叫我们输入域名,那就随便输一个baidu.com,等半天没返回 嗯?? 输入百度IP,才发现有返回 输入127.0.0.1 ,发现是个Ping功能.= = 尝试下能不能用 | 符 实现任意命令执行,先试试 payload:127.0.0.1 | ls emmm, Invalid URL,意思是我里面有非法字符? 仔细试了一下,发现能够输入的只能是数字,英文字母和  .   ,那要是按这个思路来的话任意命令执行的貌似是行不通了. 唔,没办法,没思路了,作为小白的我只能去乖

南京邮电大学网络攻防平台WEB题

签到题: 右键查看源代码,得到flag md5 collision: 传入的a的md5值要为0e开头的,但不能是QNKCDZO,百度一个0e开头的md5 得到flag 签到2: 右键查看源代码 输入框允许的最大长度为10,口令的长度为11 使用hackbar post一下 得到flag 这题不是WEB: 下载图片,用记事本打开 拉到最后,得到flag 层层递进: 是一个网站页面,先扫一下 有个404.html 查看一下源代码,得到flag AAencode: 这题为javascript aaen

i春秋 “百度杯”CTF比赛 十月场 web题 Backdoor

0x00: 打开题目,题目中告诉我们这题是文件泄露. 0x01: 通过扫描目录,发现可以扫到的有3个文件 index.php flag.php robots.txt 但是浏览flag.php它告诉我们这不是真正的flag 又联系到题目文件泄露,于是测试.swp .swo .bak等备份文件后缀均无果.最后发现是.git泄露. 我们浏览这个url http://6094ef7a9cad4288a4748de8ff8ffc573453e961300f46ce.game.ichunqiu.com/Ch

Bugku Web题

Web2 听说聪明的人都能找到答案 进入题目看到满天滑稽,然后一脸懵逼 按F12查看源码,在Body下面找到被注释的Flag,20分到手 ? 计算器 进入题目可以看到一个输入框,尝试输入图片的答案,但发现只能够输入一位.F12查看源码,找到input输入框. ????发现使用maxlength属性限制了我们输入的位数,我们手动将其改为3. 返回界面重新输入答案,拿到Flag ? Web基础$_GET 进入题目看到4行php代码 Get请求是直接在url后加?参数和值.根据代码我们在后面添加?wh

实验吧ctf题库web题wp

经历了学校的校赛,一度自闭,被大佬们刺激的要奋发图强. 1.后台登录 链接: http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php 打开题目首先查看源码,源码中注释部分有提示. 1 <!-- $password=$_POST['password']; 2 $sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true).

一道小web题

转自:https://www.leavesongs.com/PENETRATION/mysql-charset-trick.html 0x01 由某CTF题解说起 小密圈里有人提出的问题,大概代码如下: 看了一下,明显考点是这几行: <?php if ($username === 'admin') { if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') { die('Permission denied!'); } } $result = $mysqli->