[WEB] pollute-me

 

signup 페이지에서 회원가입을 할 수 있다. 이름, 나이, 학교 이름, 학교번호를 넣을 수 있다.

@app.route('/signup', methods=['GET', 'POST'])
def signup():
    if request.method == 'POST':
        name = request.form['name']
        age = request.form['age']
        school_type = request.form['school_type']
        number = request.form['number']

        if not is_alpha(name):
            return redirect(url_for('login'))
        if not is_alpha(age):
            return redirect(url_for('login'))
        if not is_alpha(school_type):
            return redirect(url_for('login'))
        if not is_alpha(number):
            return redirect(url_for('login'))

        cykor_mem = CYKOR()
        input_list = {}
        input_list[school_type] = number
        input_list["name"] = name
        input_list['age'] = age
        input_list["making"] = {'name' : 'saneo'}
        #input_list={'KOREA':123123,'name':jin,'age':19,'making':{'name':'saneo'}}
        list2mem(input_list, cykor_mem)

        user = User(name=name, age=age, school_type=school_type, number=number, output_str=str(vars(cykor_mem)))
        db.session.add(user)
        db.session.commit()

        return redirect(url_for('login'))
    return render_template('signup.html')

 

위는 회원가입 페이지에서 post 요청을 다루는 코드이다. input_list를 만드는데, {school_type: 학교 번호, name: 이름, age: 나이, making: {name: saneo}}로 list를 만든다.

burp suite으로 확인해보았다. name, age, school_type, number를 데이터로 보내고 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>flag</title>
</head>
<body>
    cykor{fake}
</body>
</html>

 

error.html이다. 딱 봐돠 error.html을 발생시키면 flag를 얻을 수 있을 것 같다.

아까 회원가입한 정보로 로그인해보았다. 위와 같이 이름, 나이, 학교이름, 학교번호를 보여주고, 추가된 리스트까지 보여주고 있다.

 

이 문제를 해결하기 위해서는 에러를 발생시켜야 한다.

@app.errorhandler(AttributeError)
def handle_attribute_error(e):
    return render_template('error.html'), 500

 

위의 코드는 AttributeError가 발생했을 때 실행하는 코드이다. 따라서 우리는 AttributeError를 발생시켜야 한다.

def list2mem(src, dst):
    for k, v in src.items():
        print(k,v, vars(dst))
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                list2mem(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            list2mem(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

 

위의 list2mem 함수에서 취약점을 확인할 수 있었다. 이 함수는 내가 입력한 것을 바탕으로 리스트를 만들어서 이를 메모리에 추가해주는 함수인 것 같다.

위의 블로그를 참고하여 hasattr, getattr 함수 등에 대해 공부하였다. hasattr 함수는 객체에 해당 키가 존재하는지, 그리고 getattr 함수는 객체에서 해당 키에 해당하는 value를 가져오는 함수이다.

 

위의 if hasattr(dst, ‘__getitem__’)을 통과하면 dst.get()함수를 실행시킨다. 그런데 dst에는 get 함수가 존재하지 않는다!! 따라서 여기서 AttributeError가 발생하고 , 그러면 flag를 확인할 수 있다.

 

그러면 어떻게 hasattr(dst, ‘__getitem__’)를 통과할 수 있을까? 이것을 통과하기 위해서는 dst에서 key값으로 ‘__getitem__’을 가지고 있어야 하는데 우리가 입력할 수 있는 이름, 나이, 학교번호는 모두 key가 아닌 value로 들어간다.

 

그런데 한 가지 다른 것이 있다. 바로 school_type이다! 실제 회원가입 페이지에서는 KOREA와 y만 고를 수 있게 되어있지만, 이것이 결국 list의 key로 들어가기에 burp suite를 사용하면 내가 원하는 값으로 바꿔서 넣을 수 있다.

따라서 위와 같이 school_type을 ‘__getitem__’으로 바꿔주었다. 이렇게 되면 list에 ‘__getitem__’:123이라는 key, value 쌍이 하나 생기고, if문을 통과하고 dst에 없는 get 함수를 실행시키려 해서 AttributeError를 발생시킬 수 있다. 보면 Response에서 error.html이 로딩되어 flag를 보이고 있는 것을 확인할 수 있다!

🚩 cykor{d0_y0u_kn0w_cla5s_p011ution??}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤