天天看点

*CTF WEB题lotto复现

题目要你去玩这个乐透,虽然没接触过,但不影响

进去先要写脚本爆破一下这个MD5

*CTF WEB题lotto复现
import hashlib
from string import ascii_letters, digits
from itertools import product
table = ascii_letters + digits
def crash():
    hash = "xxxxxx"
    #product()函数可用于生成笛卡尔积(就是排列组合),参数repeat为组几位
    for i in product(table, repeat=5):
        t = hashlib.md5(('').join(i).encode()).hexdigest()
        #print(t[:6])
        if t[:6] == hash:
            print(''.join(i))
            break
if __name__ == '__main__':
    crash()           

复制

题目还给了带Docker的源码,可以自己本地搭建环境测试。重点代码:

app目录下的

from flask import Flask,render_template, request
import os

app = Flask(__name__, static_url_path='')

def safe_check(s):
    if 'LD' in s or 'HTTP' in s or 'BASH' in s or 'ENV' in s or 'PROXY' in s or 'PS' in s: 
        return False
    return True

@app.route("/", methods=['GET', 'POST'])
def index():
    return render_template('index.html')

@app.route("/lotto", methods=['GET', 'POST'])
def lotto():
    message = ''

    if request.method == 'GET':
        return render_template('lotto.html')

    elif request.method == 'POST':
        flag = os.getenv('flag')
        lotto_key = request.form.get('lotto_key') or ''
        lotto_value = request.form.get('lotto_value') or ''
        try:
            lotto_key = lotto_key.upper()
        except Exception as e:
            print(e)
            message = 'Lotto Error!'
            return render_template('lotto.html', message=message)
        
        if safe_check(lotto_key):
            os.environ[lotto_key] = lotto_value
            try:
                os.system('wget --content-disposition -N lotto')

                if os.path.exists("/app/lotto_result.txt"):
                    lotto_result = open("/app/lotto_result.txt", 'rb').read()
                else:
                    lotto_result = 'result'
                if os.path.exists("/app/guess/forecast.txt"):
                    forecast = open("/app/guess/forecast.txt", 'rb').read()
                else:
                    forecast = 'forecast'

                if forecast == lotto_result:
                    return flag
                else:
                    message = 'Sorry forecast fxxxxxxxxxxxx!' + result
                    return render_template('lotto.html', message=message)
            except Exception as e:
                message = 'Lotto Error!'
                return render_template('lotto.html', message=message)
                
        else:
            message = 'NO NO NO, JUST LOTTO!'
            return render_template('lotto.html', message=message)
            
@app.route("/forecast", methods=['GET', 'POST'])
def forecast():

    message = ''
    if request.method == 'GET':
        return render_template('forecast.html')
    elif request.method == 'POST':
        if 'file' not in request.files:
            message = 'Where is your forecast?'
            
        file = request.files['file']
        file.save('/app/guess/forecast.txt')
        message = "OK, I get your forecast. Let's Lotto!"
        return render_template('forecast.html', message=message)

@app.route("/result", methods=['GET'])
def result():

    if os.path.exists("/app/lotto_result.txt"):
        lotto_result = open("/app/lotto_result.txt", 'rb').read().decode()
    else:
        lotto_result = ''
    
    return render_template('result.html', message=lotto_result)
        

if __name__ == "__main__":
    app.run(debug=True,host='0.0.0.0', port=8080)           

复制

lotto目录下的

from flask import Flask, make_response
import secrets

app = Flask(__name__)

@app.route("/")
def index():
    lotto = []
    for i in range(1, 20):
        n = str(secrets.randbelow(40))
        lotto.append(n)
    
    r = '\n'.join(lotto)
    response = make_response(r)
    response.headers['Content-Type'] = 'text/plain'
    response.headers['Content-Disposition'] = 'attachment; filename=lotto_result.txt'
    return response

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)           

复制

乐透这个游戏是要我们去猜彩票的号码,要求我们去上传一个

forecast.txt

的文件,文件里是我们预测的数字,同时其使用 wget 这个命令去下载生成随机数的文件

lotoo_result.txt

(20个0-40的随机数)。题目说我们可以作弊,就是可以上传key,vale来更改环境变量

*CTF WEB题lotto复现

可以改变环境变量,那么可以让

PATH

这个环境变量为空,就会导致当前这个 os 的shell的 wget 失效(测试过也不会报错),从而使生成的随机数不会再改变,再去上传这个随机数就可以了,说到这个那就讲讲这个Linux环境变量

系统中有环境变量 PATH ,看看这个PATH是什么

*CTF WEB题lotto复现

是几个含有各种系统命令的路径,每次在bash中输入各种命令就会在这些路径去寻找

现在使

PATH=

看看

*CTF WEB题lotto复现

ls

命令直接没了(这里export可以省略)echo命令可以正常使用

*CTF WEB题lotto复现

echo一下,PATH为空了,看看wget命令也没了

*CTF WEB题lotto复现

当然,这些改变都是临时的,退出终端在进去一切正常,同一设备的不同的终端也不会相互影响

好了,回到正题,在本地用docker搭建下环境

打开docker,直接在vscode的终端输入

docker-compose up

docker-compose up -d

( -d 代表在后台运行)

*CTF WEB题lotto复现

随便输点拿到随机数

*CTF WEB题lotto复现

在KEY中输入 PATH 配置环境变量为空使wget失效

*CTF WEB题lotto复现

这下 随机数是个定值了

上传文件使用 bp 抓包(这里由于是在本地搭建的环境,不好设置代理让 bp抓包,就直接用bp自带的浏览器了)其实bp自带的浏览器还是可以的

这里注意要将 \r 给去掉,应为题目给的随机数之间是以

\n

分割的

*CTF WEB题lotto复现

,而两者之间又是比较的它们的 二进制值 是否相同,所以要完全一致才行,改完保存好发送

*CTF WEB题lotto复现

回到lotto页面点击lotto按钮就可以拿到flag了

*CTF WEB题lotto复现

这里的方法应该是非预期解,后面又给了个revenge版,是预期解,这个lotto2 以后再说………….