Injection"주입". 변조된 입력을 주입해 의도하지 않은 행위를 발생시킴

 

ⓐ SQL Injection : SQL 문 사용 시 공격자의 입력 값이 정상적인 요청에 영향을 주는 취약점

ⓑ Command Injection : OS Command 사용 시 사용자의 입력 데이터에 의해 실행되는 Command를 변조 할 수 있는 취약점

ⓒ Server Side Template Injection(SSTI) : 템플릿 변환 도중 사용자의 입력 데이터가 템플릿으로 사용돼 발생하는 취약점

ⓓ Path Traversal : URL / File Path를 사용 시 사용자의 입력 데이터에 의해 임의의 경로에 접근하는 취약점

ⓔ Server Side Request Forgery(SSRF) : 공격자가 서버에서 변조된 요청을 보낼 수 있는 취약점

 

 

 

ⓐ-1 SQL Injection 

웹 어플리케이션에서 로그인/검색과 같이 사용자의 입력 데이터를 기반으로 DBMS에 저장된 정보를 조회하는 기능 등을 구현하기 위해 SQL 쿼리에 사용자의 입력 데이터를 추가하여 DBMS에 요청하는데, 그 과정에서 사용자의 입력이 SQL 쿼리에 삽입되어 SQL 구문으로 해석되거나 문법적으로 조작하게 되면 개발자가 의도하지 않은 임의의 쿼리가 실행될 수 있다.

 

즉, SQL 쿼리에 사용자의 입력 값이 삽입돼 사용자가 원하는 쿼리를 실행할 수 있는 취약점이다. 

 

대표적인 예시로, 로그인 시

SELECT * FROM users WHERE uid = '{uid}' and upw='{upw}'; 라는 쿼리가 실행될 때

 

'를 기준으로 문자열을 구분하고 있다는 점을 집중해서 보자.

만약 사용자가 입력에 ' 문자를 포함해 해당 문자열을 탈출하고 뒷 부분에 새로운 쿼리를 작성하여 전달하면 DBMS는 사용자가 직접 작성한 쿼리를 실행시키는 것이다.

 

'{uid}'admin을 , '{upw}'1'or'1 을 작성한다면, or 연산을 이용해 참의 조건이 만족되므로 admin의 데이터에 접근이 가능하게 된다.

+ (or 연산은 A or B와 같은 구조일 경우 A와 B 중 하나라도 참(True)인 경우 결과는 참이된다.)

 

ⓐ-2 SQL Injection 방어

SQL Injection을 막기 위해 권장하는 방법

:: ORM(Object Relational Mapper의 약자로써 SQL의 쿼리 작성을 돕기위한 라이브러리)과 같이 검증된 SQL 라이브러리 사용

 

이를 통해 개발자가 직접 쿼리를 작성하는 Raw 쿼리를 사용하지 않아도 기능 구현이 가능하여, SQL Injection으로부터 상대적으로 안전하다.

ORM은 생산성을 위해서도 사용하지만 사용자의 입력 값을 라이브러리 단에서 스스로 escape하고 쿼리에 매핑시키기 때문에 안전하게 SQL 쿼리를 실행한다.

 

 

ⓑ-1 Command Injection 

:: OS Command는 linux (ls, pwd, ping, zip..), windows (dir, pwd, ping..) 등의 OS에서 사용하는 명령어

:: 이러한 명령어를 실행하기 위해 PHP, NodeJS, Python과 같은 함수들이 존재한다.

 

OS Command는 내부적으로 셸(Shell)을 이용해 실행하는데, 셸은 사용자 편의성을 위해 한 줄에 여러 명령어를 실행하는 특수 문자가 여럿 존재한다.

따라서 이를 사용할 때 사용자의 입력 값을 검증하지 않고 함수의 인자로 전달한다면?

여러 특수 문자를 이용해 사용자가 원하는 명령어를 함께 실행할 수 있다.

` ` 명령어 치환 `` 안에 들어있는 명령어를 실행한 결과로 치환된다.
$( ) 명령어 치환 $( ) 안에 들어있는 명령어를 실행한 결과로 치환. 중복 가능
&& 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때.
앞 명령어에서 에러가 발생하지 않아야 뒷 명령어 실행 가능
|| 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때.
앞 명령어에서 에러가 발생해야 뒷 명령어 실행 가능
명령어 구분자 한 줄에 여러 명령어를 사용하고 싶을 때.
단순 구분자. 앞 명령어의 에러 유무 상관없이 뒷 명령어도 실행
| 파이프 앞 명령어의 결과가 뒷 명령어의 입력으로 들어감
ex) $echo id | /bin/sh

 

예를 들어, 사용자가 입력한 주소로 ping 명령어를 실행하는 코드가 있다고 가정해보자.

@app.route('/ping')
def ping():
	ip = request.args.get('ip')
	return os.system(f'ping -c 3 {ip}')

콘솔 환경에서 

ping -c 3 1.1.1.1; id 혹은 ping -c 3 1 && id 이런식으로 입력하게 되면 id 명령어도 실행이 된다.

 

 

ⓑ-2 Command Injection 방어

:: 사용자의 입력 데이터가 Command인자가 아닌 다른 값으로 해석되는 것을 방지해야 한다.

:: OS Command를 사용할 경우 해당 Command 내부에서 다른 취약점이 발생하는 등 잠재적 위협이 될 수 있으므로 OS Command를 되도록이면 사용하지 않는 것이 가장 좋은 방법이다.

 

그럼에도 불구하고 이를 사용해야 한다면, 필터링 과정을 거쳐야 한다.

 

→ 정규식을 통한 화이트리스트방식 필터링

#사용자가 입력한 IP가 정상적인 IP 형식인지 검증

import re, os, ...
...
chk_ip = re.compile('^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if bool(chk_ip.match(ip)):
    return run_system(f'ping -c 3 {ip}')
else:
    return 'ip format error'

→ OS Command에서 Meta 문자로 사용되는 값을 필터링 하고 따옴표로 감싸기

if '\'' in ip:
    return 'not allowed character'
return run_system(f'ping -c 3 \'{ip}\'')

→ execve args 인자로 사용

#shell meta 문자로 해석되지 않도록 입력 값을 넣음
subprocess.Popen(['ping', '-c', '3', ip]) # B

기능에 해당하는 라이브러리 사용

# 사용하고자하는 기능을 OS 커맨드가 아닌 구현한 라이브러리로 대체 사용
#! pip install ping3 
# https://github.com/kyan001/ping3/blob/master/ping3.py
import ping3
ping3.ping(ip)

 

ⓒ Server Side Templete Injection(SSTI)

:: 웹 어플리케이션에서 동적인 내용을 HTML로 출력할 때 미리 정의한 templete에 동적인 값을 넣어 출력하는 Templete Engine을 사용할 때 발생하는 취약점

※ 따라서, 사용자가 입력한 데이터가 templete에 직접 사용될 경우 templete Engine이 이를 해석하여 실행하는 과정에서 예상치 못한 공격을 당할 수 있다.

 

- 대부분의 Templete Engine은 {{user.uid}}, ${user.uid}와 같은 문법을 지원한다.

더보기

<각 언어별 많이 사용되는 Templete Engine>

Python : Jinja2, Mako, Tornado..

PHP : Smarty, Twig..

JavaScript : Pug, Marko, EJS... 

...
class Secret(object):
    def __init__(self, username, password):
        self.username = username
        self.password = password
secret = Secret('admin', secret_password)
...
@app.route('/board')
def board():
    title = request.form['title']
    content = request.form['content']
    template = '''<html>
    <body>
        <h3 id="title">{{title}}</h3>
        <h3 id="content">%s</h3>
    </body>
</html>''' % content
    return render_template_string(template, title=title, secret=secret)

사용자가 페이지에서 content 부분을 입력하면 %s 바로 저 부분에 들어가게 되는데,

이때 {{secret.password}} 와 같은 문자열을 입력하여 templete Engine이 해석하는 {{Data}} 형태를 이용, 공격에 사용할 수 있다.

 

 

ⓓ Path Traversal

:: 사용자의 입력 데이터가 적절한 검증 없이 URL/File Path에 직접적으로 사용될 경우 설계 및 개발 당시에 의도하지 않은 임의의 경로에 접근할 수 있는 취약점이 발생

 

- URL 필터링 또는 인코딩이 부재하면 ../ 와 같은 구분 문자를 통해 의도한 경로가 아닌 상위 경로에 접근해 다른 API를 호출할 수 있다.

 

/ 경로 구분자
..  부모 디렉토리
? 쿼리 구분자 (? 뒤는 query로 해석됨)
# 프래그먼트 구분자 (# 뒤는 Server로 전달되지 않음)
& 파라미터 구분자 (여러 정보를 함께 전달할 때 사용)

 

 

ⓔ Server-side Request Forgery(SSRF)

URL을 통해 사용자가 입력한 사진을 업로드하는 기능을 구현하면 사용자가 입력한 URL을 웹 어플리케이션에서 접근해야 하는 경우처럼, 웹 어플리케이션에서 사용자가 입력한 URL에 요청을 보내는 기능이 구현되어야 하는 경우가 있다.

 

:: SSRF는 웹 어플리케이션에서 요청을 보내는 것

(웹 어플리케이션이 작동하고 있는 서버 내부의 포트, 서버와 연결된 내부망에 요청을 보냄)

 

:: Server-side에서 변조된 요청/의도하지 않은 서버로 요청을 보내는 공격

 

- 웹 인프라를 구성할 시 외부망/내부망을 나누어 설계하고 "내부망에서는 인증된 서버/사용자만이 요청을 보낼 수 있다"고 가정해 별도의 인증 없이 기능을 구현하는 경우가 많다.

- 클라우드 플랫폼들에서도 내부망에서 작동하는 기능들이 있어 SSRF 공격의 대상이 될 수 있다.

 

※ 취약점 방지를 위해선?

- URL HOST 화이트리스트 방식 필터링 : 미리 신뢰할 수 있는 Domain Name, IP Address 등을 리스트에 등록하고 사용자가 입력한 URL에서 HOST 부분을 파싱해 화이트리스트에 있는지 확인하여 사용

 

<SSRF 예시>

이미지 URL을 입력받아 Externel Server에서 Internal Server로 접근하는 예시

 URL 주소 입력 부분에 HOST를 127.0.0.1로, 그리고 외부 서버의 코드를 확인하여 코드 속의 config 함수를 활용하면

이런 식으로 내부 서버로 들어갈 수 있는 URL을 얻을 수 있다. 

내부 서버로 들어간 후, 코드를 확인해 여러 함수를 악용하면 특정한 사용자의 권한을 높인다던지 등의 악위적 행위를 할 수 있게 된다.

 

SSRF 공격에 대한 자세한 설명은 여기에서..

https://medium.com/naver-cloud-platform/ssrf-%EA%B3%B5%EA%B2%A9%EC%9D%98-%ED%94%BC%ED%95%B4-%EC%82%AC%EB%A1%80%EC%99%80-%EB%8C%80%EC%9D%91-1-d0be4b12d10a

'WEB > WEB Hacking' 카테고리의 다른 글

Server - side Vulnerability ③ Business Logic  (0) 2021.03.09
Server - side Vulnerability ② File  (0) 2021.03.09
Server - side Vulnerability  (0) 2021.03.06
Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25

+ Recent posts