KMACTF và nỗi buồn éo làm được gì cả T__T

hế lô ae, lại là mình đây :<

Một lần nữa trong năm mình vẫn ăn hại khi solve rất ít chall trong giải của kma và cũng thx bạn X đã hỗ trợ đề cho mình

Tranh thủ đợi download các bài for các thì bắt đầu với for1 :/

Đề bài như sau

Mình được cho 1 file pcap :v vậy sài "cá mập trắng" để xem gói tin.
chú ý và chỗ mình khoanh vùng
Sắp xếp tăng dần là được, 
Đọc và lọc từng kí tự thôi :/ bài này đánh giá dễ làm

Web1:
Mình được cho source như thế này :v
Hãy cùng đi phân tích 1 chút :v
Chúng ta có 2 route cần chú ý là /login và /register
Các giá trị nhận đầu vào đều được tham số hóa nên sẽ không thể inject code được.

Tại route /login nó sẽ kiểm tra user có === 'admin' không :v
cái này thì bypass khá dễ :/ Dễ thấy nếu là Admin sẽ bypass thành công :/
Vậy chỉ còn password thôi :/

Lục lại ctf hồi trước, mọi người có thể đọc tại đây.

khi ta truyền một obj
password={"username":false}
tức là
select * from users from user where password= `username` = false
mysql sẽ tự động so sánh password với giá trị tại column username sau đó so sánh tiếp với false :v
Payload của mình
{'user':'Admin','pass':{'username':false}}
-> select * from user = 'Admin' and pass = `username` = false

Web 3: Flag Holder
Mình được tác giải cho source như sau


Điểm đáng chú ý là route /render.
có các biến template và variable nhận giá trị đầu vào của người dùng. If đầu tiên sẽ check length, nếu độ dài một trong hai biến bằng không thì render ra missing parameter .
If thứ 2 sẽ được vượt qua nếu length nhỏ hơn 20 :v
If thứ 3 sẽ đi qua hàm waf để check xem có các kí tự bị filter không.
Việc sử dụng render_template_string() dẫn đến việc bị khai thác lỗi ssti :/
Tóm tắt ý tưởng là thế, payload mình không được lớn hơn 20 kí tự là được.
Tại hàm waf mình thấy các kí tự không được phép, ý tưởng đầu tiên là dùng {% aaa%} nhưng payload mình khá dài cộng với đó set đã bị filter T__T 
Chú ý đến string.lower()[:MAX_LENGTH], mình nảy ra ý tưởng nếu một kí tự nào đó từ 1 byte khi đi qua hàm lower() lại thành nhiều byte thì sao, nó sẽ bypass được. Yeah đã có :/
Bây giờ chỉ cần lấy kí tự đó nhân 10 là sẽ bypass được waf :/
Tải trong phía sau sẽ do mình kiểm soát. nhưng payload chỉ có 10 :/
{FLAG} sẽ được replace thành giá trị flag, thêm nó vô phần template :/ vậy là xong.


Code để mn build lại ở local

from flask import Flask, request, Response, render_template_string
app = Flask(__name__)
FLAG="this_is_FLAG"
MAX_LENGTH=20

def waf(string):
    blacklist = ["{{", "_", "'", "\"", "[", "]", "|", "eval", "os", "system",
                  "env", "import", "builtins", "class", "flag", "mro", "base",
                    "config", "query", "request", "attr", "set", "glob", "py"]
    for word in blacklist:
        if word in string.lower()[:MAX_LENGTH]:
            return False
    return True

@app.route("/",methods=['POST','GET'])
def index():
    template = request.args.get("template")
    variable = request.args.get("variable")
    if not waf(template) or not waf(variable):
        return "Try harder broooo =)))"
    if len(template) == 0 or len(variable) == 0:
        return "Missing parameter required"
    if len(template) > MAX_LENGTH or len(variable) > MAX_LENGTH:
        return "Input too long"
    data = template.replace("{FLAG}", FLAG).replace("{variable}", variable)
    return render_template_string(f"""
    <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>cc</title>
        </head>
        <body>
            <p1> {data} </p1>
        </body>
        </html>
        """,data=data)
if __name__=="__main__":
    app.run(port=1234)


lmao hehe







Nhận xét

Bài đăng phổ biến từ blog này