CyKor 동기 취약점 찾기

김성진·2022년 11월 21일
0

📒 neoqp/first_web

run.py를 확인해보자.

📖 app.py

from flask import *
import pymysql

app= Flask(__name__)
app.secret_key=b'230&6^240)'
host = '0.0.0.0'
port = '8080'

db = pymysql.Connect(host='localhost',user='root',password='eodus6450', database='web_db')
cursor = db.cursor()

@app.route('/')
def root():
    return redirect('/home')

@app.route('/home')
def home():
    query = "SELECT * FROM user"
    cursor.execute(query)
    result = cursor.fetchall()
    if 'id' in session:
        return render_template('/home.html',id=session['id'],reg=result)
    else:
        return render_template('/home.html',id='X',reg=result)

@app.route('/register', methods=['GET','POST'])
def register():
    if request.method == 'POST':
        id = request.form['id']
        pw = request.form['pw']
        query = "INSERT INTO user (id, pw) VALUES (%s, %s)"
        data = (id,pw)
        try:
            cursor.execute(query,data)
            return redirect('/home')
        except:
            return redirect('/')

    else:
        return render_template('/register.html')

@app.route('/login', methods=['GET','POST'])
def login():
    if request.method == 'POST':
        id = request.form['id']
        pw = request.form['pw']
        query = "SELECT id, pw FROM user WHERE id=%s and pw=%s"
        data = (id,pw)
        try:
            cursor.execute(query,data)
        except:
            return redirect('/')
        result = cursor.fetchall()
        if len(result)==0:
            return redirect('/home')
        else:
            session['id']=request.form['id']
            return redirect('/home')
    else:
        return render_template('/login.html')

@app.route('/pwchange',methods=['GET','POST'])
def pwchange():
    if request.method=='POST':
        id = request.form['id']
        bpw = request.form['bpw']
        apw = request.form['apw']
        query = "SELECT id FROM user WHERE id=%s and pw=%s"
        data = (id,bpw)
        try:
            cursor.execute(query,data)
        except:
            return redirect('/')
        result = cursor.fetchall()
        if len(result)==0:
            return render_template('pwchange.html')
        else:
            query = "UPDATE user SET id=%s, pw=%s"
            data = (id,apw)
            try:
                cursor.execute(query,data)
                return redirect('/home')
            except:
                return redirect('/')
    else:
        return render_template('/pwchange.html')

@app.route('/delete',methods=['GET','POST'])
def delete():
    if request.method=='POST':
        id = request.form['id']
        pw = request.form['pw']
        query = "SELECT id FROM user WHERE id=%s and pw=%s"
        data = (id,pw)
        try:
            cursor.execute(query,data)
        except:
            return redirect('/')
        result = cursor.fetchall()
        if len(result)==0:
            return render_template('/delete.html', alert=1)
        else:
            query = "DELETE FROM user where id=%s and pw=%s"
            data = (id,pw)
            try:
                cursor.execute(query,data)
                return redirect('/logout')
            except:
                return redirect('/')
    else:
        return render_template('/delete.html')

@app.route('/logout')
def logout():
    session.pop('id',None)
    return redirect('/home')

if __name__ == '__main__':
    app.run(debug=True, host=host, port=port)
    session.clear()

음 우선 로그인 할 때 취약점이 확실히 보인다.
id에 admin#을 넣는다 생각해보자. (또는 admin--) 이후 비밀번호에 아무거나 넣는다면 쿼리는

SELECT id FROM user WHERE id=admin# and pw=asdfsdafsdkfkj

이 되어버린다. 그렇다면 id는 admin인데 sqli로 인해 로그인이 되어버린다.
하지만 ! 개발자가 너무한게 cursor.execute가 자체적으로 필터링이 된다고 한다. 힝

다른 취약점을 보자. 별 거 아니긴 한데 중복검사를 하지 않는다. 뭐 이정도 ...


📒 namicad

만약 로그인을 하고 글을 POST한다면 왼쪽과 같은 형식으로 글이 넘어가진다. 하지만 로그아웃을 하고, req 패킷을 복사하여 repeater에서 send 해도 글이 작성된다.
위는 로그아웃을 하고도 작성된 글의 예시이다. 로그아웃을 하더라도 세션이 살아있기에 이처럼 되는 것 같다. 이게 취약점은 아닌 것 같은데 ...


📒 comibear.kr(정말 찾음)

admin의 비밀번호를 수정할 수 있다.
우선 mmtest/mmtest로 계정을 만들어준다.
이후 비밀번호를 수정한다고 생각해보자.

$change = "UPDATE member SET password = '{$_POST['new_pw']}' WHERE id = '{$id}'";

이런 쿼리가 있다.
여기서 new_pw 부분을 iammm0ck3r' WHERE id='admin'# 이렇게 준다면 어떻게 될까.

UPDATE member SET password = 'iammm0ck3r' WHERE id='admin'#' WHERE id = '{$id}'

이렇게 변하게 된다. 따라서 admin의 비밀번호는 iammm0ck3r이 되어버리는 것이다.
실제로 값을 바꾸고 로그인 하면
위처럼 모든 계정들의 정보가 뜨는 것이 확인된다.


📒 결론

너무 빈약하다.
너무 빈약하다.
너무 빈약하다.
시간을 가지고 좀 더 찾아본 다음 본 포스팅을 업데이트 하도록 해야겠다.
나도 얼른 도박 기능 만들고 배포해야지 ㅎㅎ

profile
Today I Learned

0개의 댓글