Business Logic 

:: 규칙에 따라 데이터를 생성. 표시. 저장. 변경하는 로직, 알고리즘

ex) 게시판 서비스는 회원 가입/로그인, 게시물 작성/수정/삭제 등 다양한 로직이 모여 하나의 서비스가 완성됨

 

ⓐ Business Logic Vulnerability

- 비즈니스 로직 취약점은 정상적인 비즈니스 로직을 악용하는 것

- 서비스의 기능에서 적용되어야 할 로직이 없거나 잘못 설계된 경우 발생

 

ex) 상품 후기를 작성시 포인트를 주는 이벤트가 있다. 

후기를 작성한 후, 100 포인트를 받았는데

글을 삭제한 후 다시 후기를 작성하니 100 포인트를 또 받을 수 있었다..

 

※ 비즈니스 로직 취약점을 방어하기 위해선?

- 비즈니스 로직을 확실하게 이해하고, 설계 및 개발 단계에서 어떤 위협이 발생할 수 있는지 위협을 파악하고 방어하는 것이 중요하다.

 

 

ⓑ IDOR (Insecure Direct Object Reference) Vulnerability

:: 안전하지 않은 객체 참조

:: 발생하는 주된 원인 : 사용자의 입력 데이터에 의해 참조하는 객체가 변하는 기능에서 사용자가 참조하고자 하는 객체에 대한 권한 검증이 올바르지 않아서

 

ex) 금액을 조회하고 송금할 수 있는 페이지에서 

사용자가 자신의 계좌번호를 다른 사용자의 것으로 바꿀 때 서버가 이를 검증하지 않는다면 조회, 송금이 가능하다.

 

※ IDOR 취약점을 방어하기 위해선?

- 사용자의 권한을 검증하는게 가장 중요

즉, 사용자가 의도한 권한을 벗어나서 행동할 수 없도록 권한 등을 분리해서 관리해야 한다.

 

- 사용자 인증을 거친 후 사용하는 서비스에서는 사용자가 요청 시 전달하는 세션을 통해 서버 내에서 처리하는 것이 안전

 

- 객체 참조 키를 단순한 숫자가 아닌 무작위 문자 생성 등을 통해 악의적 공격자가 이를 추측하기 어렵게 하는 방법도 있다.

 

 

 

ⓒ Race Condition

:: 공유 자원 처리 과정에서 해당 자원에 대한 동시 다발적인 접근으로 인해 발생하는 취약점

 

- 데이터베이스 또는 파일 시스템과 같이 웹 어플리케이션에서 공유하는 자원들에 대한 접근 과정에서 데이터를 참조하는 타이밍의 차이로 인해 취약점이 발생한다.

- 주로 검증 과정에서의 데이터와 수정 과정의 데이터의 차이로 인해 웹 어플리케이션에서 의도하지 않은 흐름으로 진행한다.

- 비즈니스 로직의 잘못된 순서로 인해 발생하기도 한다.

 

ex) 사용자의 잔액 확인 과정과 차감하는 과정 사이, 재고 확인 과정에서 시간 지연이 발생하며, 

잔액 확인 과정 이후에 잔액이 차감된다는 점을 이용하여 현재 잔액보다 더 많은 금액의 상품을 구매할 수 있다.

 

※ 레이스 컨디션 취약점을 방어하기 위해선?

- 하나의 접근이 끝난 후 다음 접근을 처리하도록 하는 쓰레드 락 등을 통해 동시 다발적 접근을 방지해야 한다.

- CSRF 토큰, 캡차 등을 통해 다량의 접근을 방지하는 방법도 있다.

File Vulnerability 

:: 파일을 업로드/다운로드 하는 기능에서 발생할 수 있는 취약점

 

ⓐ File Upload

:: 파일 업로드 기능은 사용자의 파일이 서버의 파일 시스템에 저장되어 처리된다는 이유로 인해 취약점이 발생할 수 있다.

이때 서버가 아무런 검증이 없다면 서버의 파일 시스템에 원하는 파일을 저장할 수 있다.

 

+) 웹 서버의 CGI(Common Gateway Interface) : 사용자의 요청을 받은 서버가 동적인 페이지를 구성하기 위해 엔진에 요청을 보내고 엔진이 처리한 결과를 서버에게 반환하는 기능

ex) Apache 웹 서버, php 웹 어플리케이션 사용하는 서버에 사용자가 요청을 보내면

Apache는 사용자의 요청을 해석하고,

사용자가 요청하는 리소스의 확장자가 .php와 같이 php 엔진을 사용하기로 설정되어 있는 확장자라면

mod_php(CGI)를 통해 사용자의 요청을 php 엔진이 처리 및 실행하도록 요청한다.

 

 

웹 서비스가 동작하는 경로에 사용자가 원하는 파일 내용과 파일 명을 업로드할 수 있다면

서버가 엔진에 요청하는 확장자를 업로드하여 서버의 웹 어플리케이션에 원하는 코드를 실행할 수 있다.

 

웹 어플리케이션이 실행하는 코드를 악의적 공격자가 조작할 수 있다면

웹 어플리케이션 언어에 내장된 OS 명령어 등을 사용할 수 있으며, 해당 서버의 쉘을 웹을 통해 사용한다고 하여

WebShell(웹쉘)이라는 악성코드가 등장하게 되었다.

 

<?php
if(!empty($_FILES['file'])){
  $filename = generateRandomString(); // custom function
  $ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
  $path = "./uploads/" . $filename . "." . $ext;
  if(move_uploaded_file($_FILES['file']['tmp_name'], $path)) {
    return true; // upload success
  } else {
    return false; // upload fail
  }
}
?>

이러한 코드를 가지는 업로드 페이지가 있다면,

php 파일을 업로드하여 php를 실행시키거나 html 파일 등을 업로드하여 Stored XSS 취약점을 발생시킬 수 있다.

 

 

이런식으로 .php, .php3/4/5/7, .pht, .phtml 등의 파일 확장자를 업로드하여 php 엔진이 처리하도록 유도할 수 있다.

 

 

 

ⓑ File Download

파일 다운로드 기능을 구현할 때 발생하는 취약점의 형태는 사용자가 입력한 파일이름을 검증하지 않은 채 그대로 다운로드를 제공하는 형태이다.

 

...
@app.route("/download")
def download():
    filename = request.args.get("filename", "")
    return open("uploads/" + filename, "rb").read()
...

위와 같은 코드를 가지는 다운로드 페이지가 있다고 하면

Path Traversal과 같은 Injection 공격을 통해 uploads 경로보다 더 상위 경로에 존재하는 시스템 파일, 설정 파일과 같은 중요한 정보들을 다운로드 할 수 있다.

 

※파일 다운로드 취약점을 막기 위해선?

- 기본적으로 인자에 다운로드 받으려는 파일의 경로나 이름을 넘기지 않은 것이 좋다.

- 반드시 이름을 넘기는 방식으로 구현해야 한다면 상대경로로 접근하는데 사용될 수 있는 ../를 적절하게 필터링 해야한다.

- 또 다른 방법으로, 데이터베이스에 다운로드 될 파일의 경로와 그에 해당하는 랜덤키를 생성해 1대 1로 매칭해서 저장해두고 해당 랜던 값이 인자로 넘어왔을 때 데이터베이스에 존재하는 파일인지를 먼저 식별하고 다운로드 하는 방법이 있다.

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

'웹 서비스를 제공하는 서버'를 대상으로 공격할 때 발생하는 웹 취약점

 

:: 주 목적 = 서버 내에 존재하는 사용자들의 정보 탈취, 서버 권한 획득

:: 종류

1. Injection(인젝션) - 서버의 처리 과정 중 사용자가 입력한 데이터가 처리 과정의 구조나 문법으로 사용되어 발생

2. File vulnerability - 서버의 파일 시스템에 사용자가 원하는 행위를 할 때 발생

3. Business Logic Vulnerability - 정상적인 흐름을 악용할 때 발생

4. Language specific Vulnerability(PHP, Python, NodeJS 등) - 언어의 특성으로 인해 발생

5. Misconfiguration - 잘못된 설정으로 인해 발생

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

Server - side Vulnerability ② File  (0) 2021.03.09
Server - side Vulnerability ① Injection  (0) 2021.03.08
Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24

그림 1 첫 화면
그림 2 csrf 페이지

xss 공격이 막혀 있는 것 같다.

@app.route('/csrf')
def csrf():
    csrf = request.args.get('csrf', '').lower()
    xss_filter = ['frame', 'script', 'on']
    for _ in xss_filter:
        csrf = csrf.replace(_, '*')
    return csrf

코드를 보니 아니나 다를까,

클라이언트가 전달한 csrf의 값 중에서 frame, script, on 이라는 문자열이 있다면 

해당 문자열을 *로 바꾸고 있다.

 

따라서 xss 공격을 위해선 다른 태그를 사용해야 할 것이라고 생각했다.

 

그림 3 memo 페이지

memo_text = ''
@app.route('/memo')
def memo():
    global memo_text
    text = request.args.get('memo', None)
    if text:
        memo_text += text.replace('<', '&lt;') + '\n'
    return render_template('memo.html', memo=memo_text)

memo 페이지는 앞서 xss 문제(2021/01/23 - [Study/WEB Hacking] - Dreamhack | 워게임 | 문제)에서 풀었던 것과 똑같이 구성되어 있다.

 

그림 4 notice_flag 페이지

아무것도 안 했는데 Access Denied가 뜬다.

@app.route('/admin/notice_flag')
def admin_notice_flag():
    global memo_text
    if request.remote_addr != '127.0.0.1':
        return 'Access Denied'
    if request.args.get('userid', '') != 'admin':
        return 'Your not admin'
    memo_text += f'[Notice] flag is {FLAG}\n'
    return 'Ok'

해당 페이지 코드를 보니 고려해야 할 if 문이 두 개나 있다.

① request.remote_addr != '127.0.0.1' : 접속한(클라이언트의) IP 주소가 127.0.0.1이 아니라면~

② request.args.get('userid',' ') != 'admin' : userid에 해당하는 값이 admin이 아니라면~

 

접속한 IP 주소가 127.0.0.1이 아니었기 때문에 Access Denied가 뜬 것이다.

그렇다면 접속 IP주소를 127.0.0.1로, userid 값을 admin으로 설정해준다면

global 변수인 memo_text에 flag 값이 들어가 memo 페이지에 써져 있을 것이라고 생각했다.

 

 

그림 5 flag 페이지

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if request.method == 'GET':
        return render_template('flag.html')
    elif request.method == 'POST':
        csrf = request.form.get('csrf', '')
        if not read_url(csrf):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

그림 6 app.py 일부. read_url( )

flag 페이지에선 'csrf'의 값을 알아낸 후 read_url() 함수에 넣어 실행시키고 있다.

 

마지막 부분인

driver.get(f'http://127.0.0.1:8000/csrf?csrf={urllib.parse.quote(url)}') 에 의해 해당 페이지가 불러와지므로

csrf 페이지 내에서 공격을 하기로 했다.

 

csrf 페이지에서 공격할 때 frame, script, on 태그는 사용하지 못하므로

img 태그를 사용했다.

 

<img src="http://127.0.0.1:8000/admin/notice_flag?userid=admin"> 입력

 

그림 7 memo 페이지

그리고 나서 memo 페이지를 가면 빨간 표시한 두 줄이 뜬다.

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

Server - side Vulnerability ① Injection  (0) 2021.03.08
Server - side Vulnerability  (0) 2021.03.06
Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23

Client-side Attack. 앞서 설명했듯이 서비스 사용자에 대한 공격이다.

 

공격자의 주 목적은 무엇일까?

:: 사용자로부터 본인을 식별하기 위한 정보, 즉 쿠키나 세션에 저장된 세션 아이디 정보를 탈취해 사용자 권한을 얻거나

사용자의 브라우저에서 자바스크립트 등을 실행하는 등의 특별한 행위를 수행

사용자가 요청을 보낸 것처럼 하는 것이다.

 

 

그렇다면 클라이언트 사이드 취약점이 발생하는 이유는 무엇일까?

① 웹 브라우저는 Stateful한 상태를 유지하기 위해 모든 HTTP 요청에 쿠키를 함께 보낸다.

   (stateful : server side에 client와 server의 동작, 상태정보를 저장하는 형태)

:: 웹 브라우저는 HTTP 요청을 생성할 때 시작 주소(Referer)와 상관없이 대상 호스트가 발급한 쿠키를 삽입한다.

 

② 자바스크립트를 이용해 페이지 내의 요소들을 관리한다.

:: 외부 리소스를 불러오는 엘리먼트(iframe, img, video 등)를 자바스크립트로 관리하면 사용자의 동의없이 해당 내용을 읽거나 변조할 수 있게 된다.

 

이러한 공격을 막기 위해 Same Origin Policy(SOP) 정책이 탄생한다.

(*SOP : 서로 다른 오리진의 문서 또는 스크립트의 상호작용을 금한다)

(*오리진 : 프로토콜(protocol,scheme), 포트(port), 호스트(host)로 구성되며 구성요소가 모두 일치해야 같은 오리진이다)

 

일반적으로 SOP의 영향으로 서로 다른 리소스와 공유하지 못하지만 공유해야 하는 상황이 있을 수 있다.

따라서 SOP가 적용된 상태에서도 리소스를 공유하는 법인 Cross Origin Resource Sharing(CORS)가 등장한다.

(이는 나중에 따로 다뤄보기로 한다.)

 


이제 클라이언트 사이드 취약점을 알아보자

ⓐ Cross Site Scripting(XSS)

:: 공격자의 입력값이 크로스 사이트의 자바스크립트 일부로 웹 브라우저에서 실행되는 취약점이다.

:: 실행된 스크립트는 해당 사이트의 일부가 되어 SOP의 제약없이 사이트의 구조를 변경하거나, 임의의 HTTP 요청 등을 실행할 수 있다.

 

-- 성공적 공격을 위한 조건

   1. 입력 데이터에 대한 충분한 검증 과정이 없어야 한다.

   2. 서버의 응답 데이터가 웹 브라우저 내 페이지 출력 시 충분한 검증 과정이 없어야 한다.

 

-- 자바스크립트를 이용한 공격

    (ex; 화면 구성 바꾸기, 사용자 권한으로 정보 조회하기, 웹 브라우저 위치 바꾸기 등)

    :: 대표적 방법은 script 태그를 이용하는 방식 (script 태그 : 다른 프로그래밍 언어 연결시 사용하는 태그)

    공격자가 입력 데이터로 script 태그를 전송해 다른 사용자의 응답에 포함되면 공격자의 자바스크립트가 실행된다.

    :: on* 이벤트를 사용하는 방식

 

(1) Stored XSS

:: 악성 스크립트가 서버 내에 존재하는 데이터베이스 또는 파일형태로 저장되어 있다가

사용자가 이를 조회하는 순간 발생하는 형태

(ex; 게시판 조회)

 

(2) Reflected XSS 

:: 악성 스크립트가 사용자의 요청과 함께 전송되는 형태

:: 사용자가 요청한 데이터가 서버의 응답에 포함되어 HTML 등의 악성 스크립트가 그대로 출력된다.

(ex; 특정 링크 유도)

+ Click Jacking, Open Redirect 취약점과 연계되어 발생하는 경우도 있다.

 

-- 방어기술

ⓐ Server-side Mitigations(방어)

:: XSS를 유발할 수 있는 태그삽입 방지를 위해 서버 단에서 검증하는 방식

- 사용자의 입력값이 HTML 태그가 될 일이 없다면 특수문자를 HTML Entity Encoding을 이용해 태그로 인식되지 않도록 함

- 현재 IP 주소와 로그인했던 IP주소로 비교하는 방법 (요즘은 Wifi의 사용으로 동일 IP 검사가 아닌 동일 국가인지 탐지하는 것으로 변경)

 

ⓑ HTTPOnly Flag

:: 서버 측에서 응답 헤더에 Set-Cookie 헤더를 전송(Set-Cookie: session=sbdh1vjwvq; HttpOnly)해 자바스크립트로 해당 쿠키에 접근하는 것을 금지

- HTTPOnly로 설정한 쿠키는 document.cookie API를 통해 접근할 수 없다.

 

ⓒ Content Security Policy(CSP)

:: 응답 헤더(Content-Security-Policy: <지시어>; ...)나 meta 태그(<meta http-equiv="Content-Security-Policy" content="지시어")를 통해 선언 

:: 각각의 지시어를 적용하여 사이트에서 로드하는 리소스들의 출처를 제한

 

ⓓ X-XSS-Protection Header

:: 응답 헤더에 선언 X-XSS-Protection: <값>

:: 웹 브라우저에 내장된 XSS Filter의 활성화 여부를 판단

 

ⓑ Cross Site Request Forgery(CSRF 또는 XSRF)

:: 비정상적으로 사용자의 의도와 무관하게 HTTP 요청을 보내는 것(사용자 권한 이용). Forgery = '위조'

-- 기본

   : 웹 브라우저는 SOP에 위반되지 않는 모든 요청에 쿠키를 포함해 전송한다.

 

-- 공격자가 취할 수 있는 이득

   : 해당 세션 쿠키를 가진 사람만 사용할 수 있는 기능을 요청할 수 있다. 

   (ex; 금액 송금, 패스워드 변경)

 

-- 성공적 공격을 위한 조건

   1. 해당 웹 사이트가 쿠키를 이용한 인증방식을 사용해야 한다.

   2. 공격자가 사전에 알 수 없는 파라미터가 존재하면 안된다.

      (ex; 자동 입력 방지 문자, 기존 패스워드 등)

 

-- 방어기술

ⓐ 세션 쿠키 대신 커스텀 헤더를 사용하여 사용자 인증

:: 사용자 인증만을 위한 헤더를 추가 (e.g. Authorization)

 

ⓑ 공격자가 예측할 수 없는 파라미터 추가 및 검증

:: 같은 오리진에서만 접근 가능한 데이터 삽입 (CSRF Token)

:: CAPTCHA

:: 정상적 사용자만 알고있는 값 검증(ex; 현재 비밀번호)

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

Server - side Vulnerability  (0) 2021.03.06
Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23

웹 해킹 문제를 푸는데 Flask 사용법을 몰라 문제를 풀 때 한참 헤멨다.

Flask 사용법을 점차 익혀야겠다.

 

 

 

문제 페이지 소스코드

Flask 에서 처리하기 전에 먼저 html 소스에서 <form><input> 에 보면 name 이라는 속성이 있다.

이 name의 속성 값이 중요하다.

클라이언트에서 서버로 데이터를 전송할 때 이름과 값의 쌍이 전송이 되는데 이 형태는 key 와 value로 표현이 될 수 있다.

그래서 <input type="text" name="xss"> 에서 xss 이라고 하는 것이 key가 되고  이 텍스트 박스에서 입력된 내용은 value가 된다.

 

 

app.py

@라고 되어있는 부분은 파이썬에서 데코레이터(decorator)라고 부르며, 이를 사용하여 app의 객체의 route 함수에 request 인자를 넘기면서 HTTP 요청을 처리한다.

request는 보통 get, post 방식으로 넘어온 데이터를 처리할 때 필요하다.

사실 "request"는 서버 측에서 요청한다는 의미. 즉, 사용자가 서버로 보내오는 요청이나 데이터를 얻어내는 역할을 하는 것이 이 request 객체의 역할이다.

GET 방식으로 요청 파라미터를 가져오려면 request 객체의 args 함수를 호출하면 된다.

POST 방식으로 요청 파라미터를 가져오려면 request 객체의 form 함수를 호출하면 된다.

+ get 함수의 첫 번째 인자는 요청 파라미터명, 두 번째 인자는 해당 요청 파라미터가 없을 시의 초기값이다.

 

밑의 함수는 @app.route 데코레이터 URL과 자신을 연결한다.

 

저기에서 '/'로 요청(request)을 하면 (즉 http://127.0.0.1/(생략가능) 여기로 접속하면) index() 함수가 실행된다는 것이다.

 

** HTTP 요청 방식

클라이언트에서 웹 서버로 요청할 때 어떤 방식으로 데이터를 전달할 것인지를 정한다. 

GET 서버로부터 정보를 조회 또는 요청(데이터를 Body에 담지 않고 URL에 쿼리스트링을 통해 전송)
가장 일반적인 요청 방식
* 쿼리스트링: URL의 끝에 ?와 함께 이름과 값으로 쌍을 이루는 요청 파라미터 (파라미터가 여러 개이면 &로 연결)
HEAD GET 요청으로 반환될 데이터 중 헤더 부분에 해당하는 데이터만 요청
POST 클라이언트에서 서버로 처리할 수 있는 데이터를 보냄(데이터를 HTTP 메세지의 Body에 담아서 전송)
보통 HTML 폼을 통해 데이터를 전송
PUT 클라이언트가 서버에게 지정한 URL에 지정한 데이터를 저장할 것을 요청. POST와 유사
DELETE 클라이언트가 서버에게 지정한 URL의 정보를 제거할 것을 요청
OPTIONS 해당 URL에서 지원하는 request method를 알려줌

 

 

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

Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19

 

처음 화면

xss, memo, flag 각각의 페이지가 있다.

 


분석

xss 클릭시 나오는 화면

자세히 보면 xss 값에 <script>alert(1)</script>가 들어가 있다.

그리고 이에 대해 그대로 그 결과를 보여주었다는 것은

웹 페이지 내에서 XSS 공격이 가능하다는 의미이다.

 

 

 

memo 클릭시 나오는 화면

memo를 클릭했을 때는 memo안에 hello 값이 들어가있고,

이를 화면에 출력하고 있다.

 

 

 

flag 클릭시 나오는 화면
flag.html의 소스코드 확인

 

이 부분이 중요해 보였다.

'xss라는 이름으로 POST 방식으로 넘겨지는 요 부분'이 우리가 채울 부분이다.

 

 

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

@app.route('/xss') 
def xss():
    xss = request.args.get('xss', '') 
    return xss 

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if request.method == 'GET':
        return render_template('flag.html')
    elif request.method == 'POST': 
        xss = request.form.get('xss') 
        if not read_url(xss, {'name': 'flag', 'value': FLAG}):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

memo_text = ''
@app.route('/memo')
def memo():
    global memo_text
    text = request.args.get('memo', None)
    if text:
        memo_text += text.replace('<', '&lt;') + '\n'
    return render_template('memo.html', memo=memo_text)

↑app.py 코드 일부

 

[GET] /xss 에서는 xss 파라미터가 그대로 출력되고,

[GET] /memo에서는 'memo' 파라미터를 저장(text)하고 저장된 값(memo_text)들을 보여준다.

[POST] /flag 에선 read_url 로 'xss' 파라미터와 'flag' 쌍을 넘겨준다.

 

 

아무리 고민해도,, 어디부터 봐야할지 감이 안 잡혀 힌트를 봤는데, 먼저 /memo가 왜 있는지 생각해보라고 했다.

나중에 알아냈지만 /memo의 역할은 get 방식으로 'memo' 파라미터 값으로 쿠키값(document.cookie)을 전달받으면

이 페이지에 나타내도록 하는 것이다.

 

/memo에서 궁금한게 있었다. 왜 replace 함수를 사용해서 < 부등호를 &lt;로 변환을 할까?

자바스크립트를 이용한 공격을 막기 위해서?

 

 

def read_url(url, cookie={'name': 'name', 'value': 'value'}):
    cookie.update({'domain':'127.0.0.1'})
    try:
        options = webdriver.ChromeOptions()
        for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
            options.add_argument(_)
        driver = webdriver.Chrome('/chromedriver', options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.get('http://127.0.0.1:8000/') #URL에 접근
        driver.add_cookie(cookie)
        driver.get(f'http://127.0.0.1:8000/xss?xss={urllib.parse.quote(url)}')
        #urllib.parse.quote(string, safe='/', encoding='utf-8', errors='strict'): 인자로 주어진 문자열에서 특수문자를 문자열로 변환해서 반환
    except:
        driver.quit()
        return False
    driver.quit()
    return True

그 후, 핵심 코드인 read_url을 이해하려 하였다.

 

/flag 페이지에서 'xss'의 데이터를 POST 방식으로 보내면 read_url 함수가 동작하는데,

read_url에선 flag 쌍을 'cookie'로 설정하고,

FLAG 변수의 내용이 담긴 flag 쿠키가 생성(add_cookie(cookie))된다

 

그 후, /xss?xss={입력한 부분} 으로 get request를 보낸다.

따라서 'xss' 값을 아래와 같이 적으면 document.cookie를 memo에 입력할 수 있게 된다.

 

 

처음에 이해가 안 갔던 것은 driver.get(f'http://127.0.0.1:8000/xss?xss={입력한 부분}') 이 코드가 왜 필요한가,, 였는데

이게 진짜 핵심이었던 것..

접속하는 호스트에 서버를 연결시켜 XSS 공격을 유발하도록 하는 부분이었다.

(이 문제에서 공격자는 로컬(나)이기 때문에 주소를 http://127.0.0.1/로 설정하는 것임)

 

 

 

빈칸 입력

빈칸에 <script>location.href="/memo?memo="+document.cookie;</script>를 입력.

location.href를 통해 지정한 위치(해커 사이트, memo)로 리다이렉션되고, document.cookie 정보를 함께 입력시켜

사용자의 쿠키가 지정한 위치(해커 사이트, memo)에 출력된다.

 

 

 

memo 페이지

즉, /xss페이지에 'xss'값이 전달되고 실행되어 '잠깐 동안 존재했던 flag 쿠키'가 /memo 페이지에 기록된다.

 

더보기

Flask에서 GET,POST 사용하는 방법 조금씩 익히기

# render_template : html 파일 불러옴

# GET과 POST는 둘 다 서버로 요청하는 방식
# GET 방식 : 모든 파라미터를 url로 보내는 것(눈에 보임) => Flask에서 제공하는 request객체의 args 함수 호출

# get 함수의 첫 번째 인자는 요청 파라미터명, 두 번째 인자는 초기값, 그 다음은 타입

# POST 방식 :전달하려는 정보가 HTTP Body에 포함되어 전달되는 것(눈에 안보임) => request 객체의 form 함수 사용

 

더보기

꼭 알아둘 웹 사이트에서 정보 탈취나 위치 이동&변조가 가능한 코드들!

<script>

alert("hi"); <!--메시지 출력-->

document.cookie; <!--쿠키값-->

location.href=""; <!--""내의 링크로 위치 이동-->

document.location=""; <!--""링크로 이동-->

</script>

 


주절주절 썼지만

계속 풀면서 들었던 생각은

'탄탄한 기본기 갖추기'라는 것이다. 

까먹거나 모르는 부분을 쬐금씩 찾으면서 하니까 너무 오래걸렸다.

다시 공부하러,, 고고╭(๑•̀ㅂ•́)و

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

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

웹 

:: 월드 와이드 웹(World Wide Web) 또는 웹(Web) 

:: 거미줄(Web)에서 따온 이름으로, 서로 연결되어 정보를 공유한다는 의미에서 사용

 

인터넷 상의 서비스 중 HTTP를 이용하여 정보를 공유하는 통신 서비스가 웹(Web)이며

서비스를 제공하는 대상을 웹 서버(Web Server), 서비스를 받는 사용자를 웹 클라이언트(Web Client)라고 부른다.

 

초기 웹은 단지 페이지 상에서 문자를 출력해주는 역할이 컸지만 ,

오프라인 상의 물리적이었던 정보들이 웹 안으로 들어오게 되면서 

보안의 중요성이 커지게 된다.

 

 

웹 해킹 개요

크게 Client-side Attack, Server-side Attack으로 나뉜다.

 

ⓐ Client-side Attack

:: 서비스 사용자에 대한 공격

웹을 이용하는 사용자는 웹 브라우저를 통해 서비스를 제공받는데, 웹 서버가 제공해주는 데이터가 공격자에 의해 변조되었을 경우 웹 브라우저에서 렌더되는 과정에서 취약점이 발생하는 경우가 대표적

 

ⓑ Server-side Attack

:: 서버에 대한 공격

운영되는 서비스의 구조와 특징에 따라 다양한 공격 형태가 존재하며, 공격자가 공격에 성공하게 되면 서버의 어플리케이션 코드 또는 다른 사용자의 정보 유출, 서버 탈취 등으로 이어질 수 있음

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

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

1단계, simple_sqli 문제풀이

처음 들어갔을 때 나온 화면

 

 

로그인 화면
guest 입력 화면

아이디, 비밀번호에 guest를 입력하면 

 

 

hello guest가 alert로 뜨는 것 확인할 수 있다.

 

 

쿼리 문장(select * from users where userid="{userid}" and userpassword="{userpassword}")이 항상 참이 되게 하는 값을 넣어보았다. 

 

userid에는 admin" or "1

password 에는 1을 입력할 시 

쿼리문이

select * from users where userid="admin" or "1" and userpassword="1"

가 되어 userid가 admin인 경우가 항상 참(1)이된다.

 

위의 것으로 로그인 한 후의 화면

uid가 admin인 경우가 참(Truid가 admin인 경우가 참(True)이 되도록 설정합니다.ue)이 되도록 설정합니다

flag 입력

 

 

simple_sqli 문제 해결!

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

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

+ Recent posts