๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • Welcome.
:: DreamHack ๐Ÿšฉ/wargame - web

[ dreamhack ] - [ web | login-1 ]

by EunBird 2022. 4. 25.

https://dreamhack.io/wargame/challenges/47/

 

login-1

python์œผ๋กœ ์ž‘์„ฑ๋œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. "admin" ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ํš๋“ํ•˜์„ธ์š”. Reference Server-side Basic

dreamhack.io

#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for, session, g
import sqlite3
import hashlib
import os
import time, random

app = Flask(__name__)
app.secret_key = os.urandom(32)

DATABASE = "database.db"

userLevel = {
    0 : 'guest',
    1 : 'admin'
}
MAXRESETCOUNT = 5

try:
    FLAG = open('./flag.txt', 'r').read()
except:
    FLAG = '[**FLAG**]'

def makeBackupcode():
    return random.randrange(100)

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    db.row_factory = sqlite3.Row
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()



@app.route('/')
def index():
    return render_template('index.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        userid = request.form.get("userid")
        password = request.form.get("password")

        conn = get_db()
            # mysql connection ์—ฐ๊ฒฐ.
        cur = conn.cursor()
            # connection ์œผ๋กœ ๋ถ€ํ„ฐ Dictionary cursor ์ƒ์„ฑ.
        user = cur.execute( 'SELECT * FROM user WHERE id = ? and pw = ?', ( userid, hashlib.sha256( password.encode() ).hexdigest() ) ).fetchone()
            #  excute : sql๋ฌธ ์‹คํ–‰.(์ธ์ž๋Š” userid / password(sha256์œผ๋กœ ์•”ํ˜ธํ™”๋œ.))

        if user:
            session['idx'] = user['idx']
            session['userid'] = user['id']
            session['name'] = user['name']
            session['level'] = userLevel[ user['level'] ]
            return redirect(url_for('index'))

        return "<script>alert('Wrong id/pw');history.back(-1);</script>";

@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html')
    else:
        userid = request.form.get("userid")
        password = request.form.get("password")
        name = request.form.get("name")

        conn = get_db()
        cur = conn.cursor()
        user = cur.execute('SELECT * FROM user WHERE id = ?', (userid,)).fetchone()
        if user:
            return "<script>alert('Already Exists userid.');history.back(-1);</script>";

        backupCode = makeBackupcode()
        sql = "INSERT INTO user(id, pw, name, level, backupCode) VALUES (?, ?, ?, ?, ?)"
        cur.execute(sql, (userid, hashlib.sha256(password.encode()).hexdigest(), name, 0, backupCode))
        conn.commit()
        return render_template("index.html", msg=f"<b>Register Success.</b><br/>Your BackupCode : {backupCode}")
ใ… 
@app.route('/forgot_password', methods=['GET', 'POST'])
def forgot_password():
    if request.method == 'GET':
        return render_template('forgot.html')
    else:
        userid = request.form.get("userid")
        newpassword = request.form.get("newpassword")
        backupCode = request.form.get("backupCode", type=int)

        conn = get_db()
        cur = conn.cursor()
        user = cur.execute('SELECT * FROM user WHERE id = ?', (userid,) ).fetchone()
        if user:
            # security for brute force Attack.
            time.sleep(1)

            if user['resetCount'] == MAXRESETCOUNT:
                return "<script>alert('reset Count Exceed.');history.back(-1);</script>"
            
            if user['backupCode'] == backupCode:
                newbackupCode = makeBackupcode()
                updateSQL = "UPDATE user set pw = ?, backupCode = ?, resetCount = 0 where idx = ?"
                cur.execute(updateSQL, (hashlib.sha256(newpassword.encode()).hexdigest(), newbackupCode, str(user['idx'])))
                msg = f"<b>Password Change Success.</b><br/>New BackupCode : {newbackupCode}"

            else:
                updateSQL = "UPDATE user set resetCount = resetCount+1 where idx = ?"
                cur.execute(updateSQL, (str(user['idx'])))
                msg = f"Wrong BackupCode !<br/><b>Left Count : </b> {(MAXRESETCOUNT-1)-user['resetCount']}"
            
            conn.commit()
            return render_template("index.html", msg=msg)

        return "<script>alert('User Not Found.');history.back(-1);</script>";


@app.route('/user/<int:useridx>')
def users(useridx):
    conn = get_db()
    cur = conn.cursor()
    user = cur.execute('SELECT * FROM user WHERE idx = ?;', [str(useridx)]).fetchone()
    if user:
        return render_template('user.html', user=user)

    return "<script>alert('User Not Found.');history.back(-1);</script>";


@app.route('/admin')
def admin():
    if session and (session['level'] == userLevel[1]):
        # session๋ณ€์ˆ˜์— ๊ฐ’์ด ์กด์žฌ and (session['level'] == userLevel[1]) ์ธ ๊ฒฝ์šฐ์— FLAG ๋ฐ˜ํ™˜.
        return FLAG

    return "Only Admin !"


app.run(host='0.0.0.0', port=8000)

 

 

 

 

  • /login
    • GET method ์ด๋ฉด 
      • ๋‹ค์‹œ login.html ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ….
    • POST method ์ด๋ฉด 
      • ๋ณ€์ˆ˜  userid , password ์— ๊ฐ๊ฐ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ์ €์žฅ.
      • SQL ๋ฌธ 'SELECT * FROM user WHERE id = ? and pw = ?'์˜ ์ธ์ž ? ์— ๊ฐ๊ฐ userid ์™€ password์˜ ์•”ํ˜ธํ™” ๊ฐ’์„ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•˜์—ฌ ์ถœ๋ ฅ๊ฐ’์„ ๋ณ€์ˆ˜ user ์— ์ €์žฅ.
      • user ๊ฐ’์ด ์กด์žฌํ•œ๋‹ค๋ฉด 
        • session['idx'] = user['idx']             
        • session['userid'] = user['id']             
        • session['name'] = user['name']             
        • session['level'] = userLevel[ user['level'] ]
        • ๊ทธ ํ›„ index  url๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ….
      • user ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๋‹ค๋ฉด
        • "Wrong id/pw"๋ผ๋Š” ๋ง๊ณผ ํ•จ๊ป˜ ๊ฒฝ๊ณ ์ฐฝ์„ ์ถœ๋ ฅํ•˜๊ณ  ์ด์ „ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ….

 

  • /logout
    • session์„ ๋น„์šฐ๊ณ  index url ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ….

 

  • /register
    • GET method ์ด๋ฉด
      • ๋‹ค์‹œ redirect
    • POST method ์ด๋ฉด
      • ๋ณ€์ˆ˜ userid, password, name ์— ๊ฐ๊ฐ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’๋“ค์„ ์ €์žฅ.
      • user ๋ณ€์ˆ˜์— SQL๋ฌธ "SELCET * FROM  user WHERE id = ?"์˜  ์ธ์ž๊ฐ’ ? ์— userid ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•œ ๊ฐ’์„ ์ €์žฅ.
      • user ๋ณ€์ˆ˜์— ๊ฐ’์ด ์žˆ๋‹ค๋ฉด (์ค‘๋ณต๋œ userid ์ธ ๊ฒฝ์šฐ)
        • "Already exists userid."๋ผ๋Š” ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ๊ฒฝ๊ณ ์ฐฝ์„ ์ถœ๋ ฅํ•˜๊ณ  ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ… ์‹œํ‚ด.
      • user ๋ณ€์ˆ˜์— ๊ฐ’์ด ์—†๋‹ค๋ฉด (์ค‘๋ณต๋œ userid ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ)
        • backupCode ์— makebackupCode() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋žœ๋ค ๋ฐฑ์—…์ฝ”๋“œ๋ฅผ ์ €์žฅ.
        • sql ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— "INSERT INTO user(id, pw, name, level, backupCode) Values( ?, ?, ?, ?, ?)" ๋ผ๋Š” ๋ฌธ์ž์—ด ์ €์žฅ.
        • sql ๋ณ€์ˆ˜์— ๋‹ด๊ธด SQL๋ฌธ์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ, ๊ฐ ์ธ์ž ? ์— ์ฐจ๋ก€๋Œ€๋กœ [userid , ์•”ํ˜ธํ™”ํ•œ password , name, 0 , backupCode] ๊ฐ’๋“ค์„ ๋„ฃ์–ด์„œ ์‹คํ–‰.
        • "Register Success .  Your backupCode : {backupCode}"๋ผ๋Š” ๋ฌธ์ž์—ด๊ณผ ํ•จ๊ป˜ ๊ฒฝ๊ณ ์ฐฝ์„ ์ถœ๋ ฅํ•˜๊ณ  backupCode๋„ ๊ฐ™์ด ์ถœ๋ ฅ.

 

  • /forgot_password
    • method ๊ฐ€ get ์ด๋ฉด
      • ๋‹ค์‹œ redirect
    • method ๊ฐ€ post์ด๋ฉด 
      • ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’ 3๊ฐœ(userid , newpassword , backupCode)๋ฅผ ๋ฐ›์Œ.
      • db์˜ user ํ…Œ์ด๋ธ”์˜ id ์†์„ฑ ์ค‘ ์ž…๋ ฅ๊ฐ’ userid์˜ ๊ฐ’๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ์กด์žฌํ•˜๋ฉด
        • time.sleep(1)  
        • user['resetCount'] == MAXRESETCOUNT ๊ฐ€ True ์ด๋ฉด 
          • reset Count Exceed ๋ผ๋Š” ๋ง์ด ๋‹ด๊ธด ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šฐ๊ณ  ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŒ….
        • user['backupCode'] == backupCode ๊ฐ€ True ์ด๋ฉด
          • newbackupCode ์— makeBackupcode() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋žœ๋ค๋ฌธ์ž๋“ค์„ ์ €์žฅ.
          • updateSQL ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— "UPDATE user set pw = ?, backupCode = ?, resetCount = 0 where idx = ? " ์ด๋ผ๋Š” ๋ฌธ์ž์—ด ์ €์žฅ.
          • updateSQL์— ๋‹ด๊ธด ๋ฌธ์ž์—ด์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ, ์ฒซ๋ฒˆ์งธ ? ์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ newpassword  ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•˜๊ณ ,
          • ๋‘๋ฒˆ์งธ ? ์—๋Š” newbackupCode์— ๋‹ด๊ธด ๋ฌธ์ž๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•˜๊ณ , 
          • ์„ธ๋ฒˆ์งธ ? ์—๋Š” str(user['idx'])๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•œ๋‹ค.
          • msg ๋ผ๋Š” ๋ณ€์ˆ˜์— "Password change success , New backupCode : {newbackupCode}"๋ฅผ ์ €์žฅ.
        • user['backupCode'] == backupCode ๊ฐ€ False ์ด๋ฉด
          • updateSQL ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— "Update user set resetCount = resetCount + 1 where idx = ? " ์ €์žฅ.
          • updateSQL  ๋ณ€์ˆ˜์— ๋‹ด๊ธด ๋ฌธ์ž์—ด์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ, ์ฒซ๋ฒˆ์งธ ์ธ์ž ? ์— str(usr['idx']) ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰.
          • msg ๋ผ๋Š” ๋ณ€์ˆ˜์— " Wrong backupCode ! Left Count : {MAXRESETCOUNT - 1 } - user['resetcount'] " ์ €์žฅ.
        • msg ๋ณ€์ˆ˜์— ๋‹ด๊ธด ์ฝ”๋“œ๋ฅผ ์ถœ๋ ฅ.
      • db์˜ user ํ…Œ์ด๋ธ”์˜ id ์†์„ฑ ์ค‘ ์ž…๋ ฅ๊ฐ’ userid์˜ ๊ฐ’๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด
        • "User Not Found ๋ผ๋Š” ๋ง๊ณผ ํ•จ๊ป˜ ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šฐ๊ณ  ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚ด."
 
 
 
 
  • /user/<int:useridx>
    • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ useridx์— ๋Œ€ํ•ด db์˜ user ํ…Œ์ด๋ธ”์˜ idx ์†์„ฑ์— ํ•ด๋‹น ์ž…๋ ฅ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด
      • ํ•ด๋‹น user์— ๋Œ€ํ•œ user.html์„ ๋ฆฌํ„ด
    • ์ž…๋ ฅ์— ํ•ด๋‹นํ•˜๋Š” user๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด
      • "User not found"๋ผ๋Š” ๋ง์ด ๋‹ด๊ธด ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์›€.
  • /admin
    • session and (session['level'] == userLevel[1]): ์ธ ์กฐ๊ฑด์ด ์ฐธ์ธ ๊ฒฝ์šฐ(userLevel[1]์€ admin ์ด๋‹ค.)
      • FLAG๋ฆฌํ„ด.
    • session and (session['level'] == userLevel[1]): ์ธ ์กฐ๊ฑด์ด ๊ฑฐ์ง“์ธ ๊ฒฝ์šฐ
      • " Only admin! " ์ถœ๋ ฅ.
 

 

 


 

์ด ๋ฌธ์ œ์˜ ํŠน์ง•์„ ์–˜๊ธฐํ•ด๋ณด์ž๋ฉด,

 

- /admin ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค๋ฉด level = userLevel[1] ์ด์–ด์•ผ ํ•œ๋‹ค.

 

- userLevel ์€ 1 ๊ณผ 0 ์ด ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š”๋ฐ, 1 ์€ admin ์ด๊ณ  0 ์€ ์ผ๋ฐ˜์‚ฌ์šฉ์ž๋กœ ๋ณด์ธ๋‹ค.

   ์™œ๋ƒ๋ฉด ๋‚ด๊ฐ€ /register ์„ ํ†ตํ•ด ๊ณ„์ •์„ ์ƒ์„ฑํ•˜๊ณ  ๋กœ๊ทธ์ธ ํ•˜๋ฉด, userLevel ์ด 0 ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

- /user/์ˆซ์ž    ๋ฅผ get ๋ฉ”์†Œ๋“œ๋กœ ๋ณด๋‚ด๋ฉด ํ•ด๋‹น ์ˆซ์ž์˜ useridx ๋ฅผ ๊ฐ€์ง„ user์˜ [UserID , UserName, UserLevel]์„ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

/user/1

์ด๋ฅผ ํ†ตํ•ด UserLevel์ด 0์ธ ๊ณ„์ •๊ณผ 1์ธ ๊ณ„์ •์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

 

- /forgot_password ํŽ˜์ด์ง€์—๋Š” [userid , newPassword , backupCode]๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, 

์ด๋•Œ, Submit ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋ณด๋‚ด๊ณ  1์ดˆ ๋™์•ˆ time.sleep(1) ๊ตฌ๊ฐ„ ์ด ์กด์žฌํ•œ๋‹ค.

/forgot_password

 

Left Count : 4&nbsp; &nbsp;--> 4๋ฒˆ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ๊ธฐํšŒ๊ฐ€ ๋‚จ์•„์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

- ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด , backupCode๋Š” makebackupCode() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•˜๋Š”๋ฐ, 

random.randrange(100--> 1~100 ๊นŒ์ง€์˜ ์ˆซ์ž์ค‘ ํ•œ๊ฐœ๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
 
 
 

๋”ฐ๋ผ์„œ ์ด์ œ ์šฐ๋ฆฌ๋Š” /user/{์ˆซ์ž} 

ํŽ˜์ด์ง€์—์„œ UserLevel ์ด 1 ์ธ ๊ณ„์ •์„ ์ฐพ์•„๋‚ธ ํ›„, 

 

/forgot_password ํŽ˜์ด์ง€์—์„œ 

userid , newPassword , backupCode ๋ฅผ ์ž…๋ ฅํ•  ๋•Œ, 

ํ•ด๋‹น ๊ณ„์ •์˜ backupCode๋งŒ ์•Œ์•„๋‚ด์„œ 

๋‚ด ๋งˆ์Œ๋Œ€๋กœ newPassword ๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ”๊ฟ”๋ฒ„๋ฆฐ ๋‹ค์Œ์—, 

 

์ด ๊ณ„์ •์œผ๋กœ /login ์—์„œ ๋กœ๊ทธ์ธํ•˜์—ฌ FLAG ๋ฅผ ์–ป์–ด๋‚ด๋ฉด ๋˜๋Š”๋ฐ, !! 

 

backupCode ๋Š” 1~100 ๊นŒ์ง€์˜ ์ˆซ์ž ๋ผ์„œ  ํ•œ๋ฒˆ์— ์•Œ์•„๋‚ด๊ธฐ ์‰ฝ์ง€์•Š๋‹ค . 

5๋ฒˆ์˜ /forgot_password ํŽ˜์ด์ง€์˜ ๋ณด์•ˆ์กฐ์น˜๊ฐ€ ์—†์—ˆ๋‹ค๋ฉด 

1๋ถ€ํ„ฐ 100๊นŒ์ง€ ๋Œ€์ž…ํ•ด๋ณด๋ฉด ๋˜๋Š”๋ฐ 

๊ทธ๋ ‡์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ์ง์ ‘ ๋Œ€์ž…ํ•ด๋ณด๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 
 
๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” /forgot_password ํŽ˜์ด์ง€์—์„œ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋ณด๋ƒˆ์„ ๋•Œ, 
1์ดˆ ๋™์•ˆ ๋ฉˆ์ท„๋‹ค๊ฐ€ ์ง„ํ–‰๋˜๋Š” ๋ถ€๋ถ„ ์‚ฌ์ด ๋™์•ˆ์— 
backupCode ์— 1~100์„ ๋ชจ๋‘ ๋ณด๋‚ด์„œ 
backupCode ๊ฐ€ ๋ฌด์—‡์ธ์ง€๋Š” ๋ชฐ๋ผ๋„ password ๋ฅผ ๋ฐ”๊พธ๋Š”๋ฐ ์„ฑ๊ณต ์‹œํ‚จ ํ›„,
๋ฐ”๊พผ password ๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธํ•˜์—ฌ FLAG ๋ฅผ ์–ป์–ด๋‚ผ ๊ฒƒ์ด๋‹ค.
 
 

 

 

๋”ฐ๋กœ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ•ด๊ฒฐํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค. ..

 

 

 

728x90

':: DreamHack ๐Ÿšฉ > wargame - web' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[ dreamhack ] - [ web | csrf-2 ]  (0) 2022.04.05
[ dreamhack ] - [ web | csrf -1 ]  (0) 2022.03.29
[ dreamhack ] - [ web | image-storage ]  (0) 2022.03.17
[ dreamhack ] - [ web | proxy-1 ]  (0) 2022.03.17
[ dreamhack ] - [ web | command-injection-1 ]  (0) 2022.03.16

๋Œ“๊ธ€