[SVATTT2020] TSULOTT3

    

    Bài cho 1 đường dẫn đến đề và source code main.py. Tải source về, nhưng trước hết vào link đề bài coi ra sao đã. Đầu tiên sẽ phải nhập name vào sau đó đoán 6 số random nào đó nếu đúng thì sẽ làm gì đó tiếp khả năng là in ra flag. Xong đã hiểu luồng bài này ta tiến hành đọc source code, dưới đây là source main.py:

from flask import Flask, session, request, render_template, render_template_string
 from flask_session import Session
 from random import randint as ri
 app = Flask(name)
 SESSION_TYPE = 'filesystem'
 app.config.from_object(name)
 Session(app)
 cheat = "Pls Don't cheat! "
 def check_session(input):
     if session.get(input) == None:
         return ""
     return session.get(input)
 @app.route("/", methods=["GET","POST"])
 def index():
     try:
         session.pop("name")
         session.pop("jackpot")
     except:
         pass
     if request.method == "POST":
         ok = request.form['ok']
         session["name"] = request.form['name']
         if ok == "Go":
             session["check"] = "access"
             jackpot = " ".join(str(x) for x in [ri(10,99), ri(10,99), ri(10,99), ri(10,99), ri(10,99), ri(10,99)]).strip()
             session["jackpot"] = jackpot
             return render_template_string("Generating jackpot…setInterval(function(){ window.location='/guess'; }, 500);
")
     return render_template("start.html")
 @app.route('/guess', methods=["GET","POST"])
 def guess():
     try:
         if check_session("check") == "":
             return render_template_string(cheat+check_session("name"))
         else:
             if request.method == "POST":
                 jackpot_input = request.form['jackpot']
                 if jackpot_input == check_session("jackpot"):
                     mess = "Really? GG "+check_session("name")+", here your flag: ASCIS{xxxxxxxxxxxxxxxxxxxxxxxxx}"
                 elif jackpot_input != check_session("jackpot"):
                     mess = "May the Luck be with you next time!setInterval(function(){ window.location='/reset_access'; }, 1200);
"
                 return render_template_string(mess)
             return render_template("guess.html")
     except:
         pass
     return render_template_string(cheat+check_session("name"))
 @app.route('/reset_access')
 def reset():
     try:
         session.pop("check")
         return render_template_string("Reseting…setInterval(function(){ window.location='/'; }, 500);
")
     except:
         pass
     return render_template_string(cheat+check_session("name"))
 if name == "main":
     app.secret_key = 'xxxxxxxxxxxxxxxxxxxxx'
     app.run()

    Đến đây mình thấy vùng random nhỏ chỉ từ 10 đến 99 cộng với ngồi soi một lúc 1 em cùng team bảo thử brute force thành ra code luôn 1 cái brute force, chạy 2 tiếng không ra bắt đầu quay ra đọc lại. Mình bắt đầu để ý trường name trong session, đây là trường duy nhất được in ra thay vì mess ở đoạn check jackpot. Tiếp tục soi đoạn code sau:

try:
         if check_session("check") == "":
             return render_template_string(cheat+check_session("name"))
         else:
             if request.method == "POST":
                 jackpot_input = request.form['jackpot']
                 if jackpot_input == check_session("jackpot"):
                     mess = "Really? GG "+check_session("name")+", here your flag: ASCIS{xxxxxxxxxxxxxxxxxxxxxxxxx}"
                 elif jackpot_input != check_session("jackpot"):
                     mess = "May the Luck be with you next time!setInterval(function(){ window.location='/reset_access'; }, 1200);
"
                 return render_template_string(mess)
             return render_template("guess.html")
except:
         pass
return render_template_string(cheat+check_session("name"))

    Đoạn này có xử lý exception, mà như đã biết nếu trong khối try mà có exception thì sẽ lập tức nhảy qua khối except rồi thực hiện tiếp từ đó. Hmm, exception ở đây bây giờ? Để ý đoạn lấy jackpot từ request nếu trong request không có jackpot thì sẽ auto đẩy ra exception, mình thử và in ra name thật. Cảm thấy đã gãi đúng chỗ ngứa, chỉ là chưa biết gãi sao cho ra cờ, mình google tìm xem cái này có lỗi gì inject name được không.

    Search google các kiểu đến lúc search từ khóa “flask request.form vulnerability” thì OMG ra 1 trang:

https://blog.nvisium.com/injecting-flask

    Kinh thư đây rồi, thử search cái SSTI này thì ra vài payload check. Cái mình đã sử dụng để test lỗi là chèn {{7*7}} vào name và bing cmn go in ra “Pls Don’t cheat! 49”. Hô, ngon, tay trái có lỗi, tay phải có cách in ra lỗi, đọc main.py nữa là xong. Search google các kiểu, riêng đoạn search này mình search kém mãi mới ra 1 payload chạy được:

{{config.class.init.globals[‘os’].popen(‘cat main.py’).read()}}

Quăng nó vào name -> flag: ASCIS{yo___SSTI___R0ck_} 

Post a Comment

Previous Post Next Post