본문 바로가기

InfoSec Log/WEB Hacking

OWASP Top 10 - 2021

Source: https://owasp.org/Top10/

 

OWASP Top 10은 개발자와 웹 애플리케이션 보안을 위해 Open Web Application Security Project에 의해 작성된 문서이다. 해당 문서에서는 웹 애플리케이션과 관련하여 가장 중요한 보안 위협 상위 10가지에 대해 다룬다.

 

주로 3~4년 간격으로 OWASP Top 10의 업데이트 이루어지고, 2024년 기준 현재 가장 최신 버전은 2021년에 발간된 버전이다.

 

 

A01: Broken Access Control

접근 제어는 사용자가 개발자의 의도된 권한을 벗어난 행동을 수행 할 수 없도록 기능에 제한을 두는 것을 말한다. 하지만 이러한 접근 제어가 약하게 설정되어 있거나 실패하면 일반적으로 접근이 불가능한 리소스 혹은 데이터에 대해 무단 접근이 가능하여 해당 데이터에 대한 무단 유출, 수정 및 삭제 등의 보안 위협이 우려된다.

 

 

포함되는 취약점들

 

IDOR 취약점

IDOR(Insecure Direct Object Reference) 취약점은 직접 객체 참조인 파라미터를 변조하는 행위로 허용되지 않은 자원에 접근 및 변조 권한을 가질 수 있는 취약점을 말한다.

 

 

만약 유저 정보를 관리하는 마이페이지가 mypage.php?user_id=1과 같이 user_id를 직접 참조하여 유저 정보를 관리하면 user_id=2를 통해 다른 사용자의 정보를 무단 열람 할 수 있다.

 

예방 방법

  • 모든 리소스에 대해 요청 시 현재 사용자의 권한을 검증한다.
  • 데이터베이스에 저장된 고유한 id 값을 직접적으로 참조하는 것이 아닌, uuid와 같이 고유성이 보장되면서 랜덤으로 생성되어 추측하기 어려운 값을 id와 매핑 시켜 사용한다.

 

Forced Browsing

애플리케이션에서 개발자가 인덱싱 하지 않은 페이지(리소스)에 대해 인증되지 않은 사용자 및 인증된 사용자의 권한을 넘어선 요청을 수행할 때, 접근 제어 로직이 적절히 구현되어 있지 않아, URL 주소창을 통해 해당 리소스에 직접 접근이 가능한 경우를 말한다.

 

 

만약 관리자의 대시보드가 /admin/dashboard.php의 경로일 때, 접근 권한이 없는 사용자가, URL 주소창을 통해 직접 경로를 입력하여 접근을 시도할 때, 접근이 가능한 경우를 말한다.

 

예방 방법

  • 리소스에 대한 요청 시, 현재 사용자의 권한을 검증하여 해당 사용자의 권한을 넘어선 행위를 하지 못하도록 로직을 구현한다.

 

Method Tampering

클라이언트와 서버가 통신 할 때, 클라이언트 측에서는 HTTP Method를 요청 메시지에 포함하여 서버 측에 요청을 보낸다. 이때  HTTP Method에 대한 접근 제어(역할 기반 접근 제어(RBAC)가 적절히 구현되어 있지 않을 경우 공격자는 Burp Suite과 같은 프록시 도구를 이용하여 요청 메시지를 가로채어 HTTP Method를 조작하여 서비스의 기밀성, 무결성, 가용성을 훼손할 수 있다.

 

 

특정 게시글을 요청 할 때, 보통 GET 메서드를 사용한다. 그런데 만약 해당 게시글에 대한 요청에 DELETE 메서드가 활성화 되어 있고, 접근 제어가 적절히 구현되어 있지 않으면 공격자는 GET 메서드를 DELETE 메서드로 변조된 요청을 보내 해당 게시글을 삭제할 수 있다. 더 나아가 /account/user123 이라는 리소스의 GET 요청이 user123이라는 사용자의 계정 정보를 보여주는 페이지에 대한 요청 일때, DELETE 메서드의 활성화 및 접근 제어 부재 시 특정 사용자의 계정 정보를 삭제할 수 있다.

 

예방 방법

  • 불필요한 HTTP Method 비활성화 및 각 메서드에 대해 Role based Access Control 을 구현하여 적용한다.

 

권한 상승 취약점

권한 상승 취약점이란 사용자가 자신의 권한 보다 더 높은 권한을 획득하거나 다른 사용자의 권한을 획득하여, 애플리케이션에서 자신에게 인가되지 않은 리소스에 대한 열람 및 기능을 수행하는 취약점을 말한다.

 

권한 상승에는 두 가지의 경우가 존재한다. 즉 수평적 권한 상승수직적 권한 상승이다. 수평적 권한 상승의 경우 사용자 본인인 사용자 A가 다른 사용자인 사용자 B가 소유하고 있는 권한을 사용할 수 있는 경우를 말하고 수직적 권한 상승의 경우 일반 사용자가 관리자의 권한을 획득한 경우를 말한다.

 

  • 수평적 권한 상승의 경우, 사용자 A가 사용자 B가 가진 권한인 사용자 B에 대한 정보 열람, 수정, 삭제 등이 가능할 때를 말한다.
  • 수직적 권한 상승의 경우 일반 사용자 A가 관리자만이 접근할 수 있어야 하는 관리자의 대시보드 열람, 쇼핑몰 사이트에서의 물품 관리(수정, 삭제) 등이 가능할 때를 말한다.

예방 방법

  • 리소스 요청 시에 현재 사용자의 권한을 지속적으로 검증한다.
  • 최소 권한 원칙을 적용한다. 즉 일반 사용자에게 꼭 필요한 최소한의 권한만 부여한다. 예를 들어 일반 사용자의 경우에는 관리에 관한 기능이 필요하지 않음으로 해당 기능과 관련된 기능에 대해서는 접근 권한을 부여하지 않아야 한다.

 

A02: Cryptographic Failures

Cryptographic Failures(암호화 실패)란 민감한 데이터(카드 정보, 계좌번호, 전화번호 등)를 보호하기 위해 사용해야하는 암호화가 제대로 구현되지 않았거나 잘못 사용되어 데이터가 유출되거나 조작될 수 있는 취약점을 말한다.

 

 

포함되는 취약점들

  • 비밀번호, 카드 정보 등 민감한 정보를 암호화하지 않고 평문으로 저장 혹은 전송하는 경우
  • MD5, SHA-1과같이 서로 다른 입력값에 대해 같은 해시 값이 생성되는 충돌 취약성이 존재하고 각 160비트, 128비트라는 길이가 짧은 키를 사용하여 현대의 컴퓨팅 파워로 쉽게 크랙될 수 있는 안전하지 않은 암호화 알고리즘(해시 함수)을 사용하는 경우 
  • 소스코드 혹은 설정 파일에 암호화 키를 하드코딩 하는 경우
  • SSL/TLS 인증서를 잘못 관리하여 만료되거나 잘못된 인증서를 사용하는 경우. 이러한 경우에는 공격자가 중간자 공격(Man-in-the-Middle-Attack)을 통해 데이터의 탈취가 가능하다.

 

예방 방법

  • 충돌 가능성이 낮고 암호화의 길이가 상대적으로 긴 SHA-2 계열 이상의 256비트의 길이를 가진 SHA256, 512비트의 길이를 가진 SHA512를 사용하여 데이터의 무결성을 검증하고 비밀번호를 해싱한다.
  • 이미 해시화된 목록과 매핑되는 평문 값들이 체인으로 엮어 있는 레인보우 테이블 공격을 무효화시키기 위해 비밀번호 해싱 시 평문에 솔트를 적용하도록 한다.
  • 소스코드 혹은 설정 파일에 키를 하드코딩 하지 않고 안전한 키 관리 시스템(HSM(Hardware Security Module))을 사용하거나 클라우드 기반 키 관리 서비스를 이용하여 암호화 키의 생성 및 관리를 하고 또한 주기적으로 키를 변경하고 불필요한 키는 제거한다.
  • 민감한 데이터의 경우에는 전송 및 저장 시에는 항상 SHA-2 계열 이상의 암호화 알고리즘을 사용하여 데이터를 암호화 해야 한다.
  • 인증서는 정기적으로 갱신하고 취소 혹은 만료된 인증서를 제거하여 배포된 인증서를 잘 관리해야 하며, TLS 1.2이상의 최신 버전을 사용하고 HSTS 헤더를 활성화하여 HTTP가 아닌 HTTPS로의 접속을 강제하여 중간자 공격의 방지와 같이 클라이언트와 서버간의 통신을 보호해야 한다.

 

A03: Injection

인젝션(Injection)은 애플리케이션에서 사용자 입력값에 대한 검증이 미흡하여 공격자가 악의적인 코드를 삽입할 때, 애플리케이션의 명령어 실행에 영향을 미쳐, 개발자가 본래 의도하지 않은 명령어가 실행되는 취약점을 말한다. 이러한 인젝션 공격의 종류로는 SQL Injection, XSS, Command Injection, LDAP Injection 등이 포함되며, 해당 취약점으로 인해 개인정보와 같은 민감한 데이터의 유출, 권한 상승, 시스템 조작 등의 보안 위협을 초래할 수 있다.

 

 

포함되는 취약점들

 

SQL Injection

source:  https://www.arkoselabs.com/explained/sql-injection/

 

SQL Injection은 애플리케이션과 연동된 DB 서버가 SQL 쿼리를 통해 통신하는 RDBMS(MySQL, PostgreSQL, MSSQL, etc.)를 사용할 때, 사용자 입력값에 대한 검증이 미흡할 경우 공격자가 주입한 악의적인 SQL 쿼리가 실행되는 취약점을 말한다. 해당 취약점으로 인해 DB에 저장된 사용자의 계정 정보, 카드 정보 등과 같은 민감한 정보의 탈취가 가능하다.

 

SQL Injection에는 크게 두 가지의 공격 방식이 존재한다. 즉 공격자가 삽입한 SQL 쿼리의 처리 결과가 브라우저의 에러 메시지가 출력되는 화면에 반환되는 경우인 Error Based SQLi와 공격자가 삽입한 SQL 쿼리의 처리 결과가 화면에 출력되지 않는 경우인 Blind SQLi가 존재한다.

 

Error Based SQLi의 경우 UNION 절을 이용하여 후속 공격을 진행한다. 즉 UNION SELECT 절을 이용하여 원래 쿼리의 출력 결과에 새로운 행을 추가하여 해당 레코드에 원하는 데이터를 가져오도록 만든다. 그러기 위해서는 먼저 원래 쿼리의 필드 수와 데이터 유형을 일치시켜야 할 필요가 있다.

 

SELECT 절에 해당하는 원래 쿼리의 필드 수를 알아낼 때 사용하는 기법은 ORDER BY를 이용한 기법이다. 즉 ORDER BY 1과 같이 인덱스 1을 기준으로 오름차순 정렬시키는 SQL 쿼리를 삽입하여, 만약 해당 SQL 쿼리의 출력 결과가 에러가 발생할 경우, 해당 숫자는 원래 쿼리에 존재하는 필드 수를 초과하였다는 것을 알아, 원래 쿼리의 필드 수는 해당 에러 메시지가 발생하기 전까지인 것을 알 수 있게 된다.

 

데이터 유형의 경우 보통 정수와 문자열로 이루어져 있는데 공격자가 원하는 데이터의 경우 보통 문자열이므로, 문자열의 데이터를 저장하는 필드를 알아내기 위해 UNION SELECT ‘a’와 같이 필드에 문자열을 주입하여 에러가 발생하는지 확인하고, 만약 에러가 발생하지 않을 경우 해당 필드는 문자열로 저장되는 필드임을 알 수 있다.

 

그 후 공격자는 UNION SELECT절을 이용하여 RDBMS에 기본적으로 존재하는 information_schema를 통해 데이터베이스의 목록 및 테이블의 목록, 필드 목록, 필드의 값들을 획득해나간다.

 

Blind SQLi의 경우에는 사용자가 삽입한 SQL 쿼리가 DB 서버에서 처리가 되지만, 클라이언트 측인 웹 브라우저에서는 해당 처리 결과가 보이지 않는다. 따라서 이와 같은 경우에는 조건부 연산(True or False)을 사용하여 조건이 참일 때의 응답 페이지와 조건이 거짓일 때의 응답 페이지를 비교하여 차이가 있는지 확인하고, 만약 없다면 sleep(1)과 같이 sleep 함수를 적용하여 조건이 참일 때 의도적으로 응답 페이지의 반환을 1초 지연시키는 방식으로 정보를 하나 하나 획득해나간다.

 

즉 Blind SQLi의 경우, 정보를 하나 하나 획득해 나가다 보니, 수작업으로 하기에는 시간이 굉장히 많이 걸린다. 따라서 거의 대부분의 경우 자동화 스크립트를 사용하여 Blind SQLi 취약점을 악용한다. 즉 만약 DB에 저장된 사용자의 비밀번호를 알아내기 위해서는 먼저 DB의 이름을 알아내고, 그 후 테이블의 이름을 알아내고, 테이블의 필드 수까지 알아낸 후, 페이로드와 성공조건을 적용한 스크립트를 통해 사용자의 비밀번호를 알아내게 된다.

 

예방 방법

  • Prepared Statements를 사용하여 사용자의 입력이 직접 SQL 쿼리로 작용하는 것이 아닌 별도의 매개변수로 처리되도록 만들어 사용자의 SQL 쿼리가 단순한 데이터로 처리되도록 한다. 즉 매개변수화된 쿼리를 사용한다.
Node.js에서 Prepared Statements 적용
// Node.js with MySQL
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
connection.query(query, [username, password], function (error, results, fields) {
if (error) throw error;
 // Handle results
});
  • 사용자의 입력이 애플리케이션의 처리 구조에 오류를 일으킬 때 생성되는 에러 메시지를 브라우저에 출력하지 않도록 서버 설정을 변경한다.
  • 사용자의 입력 값이 개발자가 의도한 입력 값인지 검증하는 로직 구축. 즉 사용자가 입력한 값이 개발자가 정의한 허용된 패턴에 속하는지 화이트리스트 기반 검증을 진행하고 악의적인 영향을 끼칠 수 있는 문자열 목록에 대해 필터링을 진행한다. 
필터링 문자열 목록
/*, –, ‘, “, ?, #, (, ), ;, @, =, *, +, union, select, drop, update, from, where, join, substr, user_tables, user_table_columns, information_schema, sysobject, table_schema, declare, dual,…
사용자 입력값인 inputId가 정수인지 검증하는 로직
if (!/^\d+$/.test(inputId)) {
    throw new Error('Invalid input');
}
  • 최소 권한 원칙을 적용하여 관리자 권한이 아닌 특정 작업에 필요한 권한만을 가진 계정을 사용하여 SQL Injection 공격이 성공하더라도 해당 취약점을 악용하여 사용할 수 있는 기능에 제한을 두어 시스템 피해 영향을 최소화 한다.
  • 데이터베이스의 테이블을 프로그래밍 언어의 객체로 매핑하여 데이터베이스 작업을 처리하는 ORM(Object-Relational Mapping)을 사용한다. 예를 들어 Modelclass를 생성하고 메서드에 쿼리문을 정의해두었을 때 Model과 연결된 Controller에서 인스턴스화를 통해 객체를 생성하고 메서드에 인수를 입력하여 Model에 전달해주는 방식이 존재한다. ORM의 경우, SQL 쿼리를 미리 처리하고, 사용자로부터 입력받은 값을 매개변수로 처리하기 때문에, 즉 SQL 쿼리에 직접 삽입되는 것이 아닌 매개변수를 통해 쿼리에 바인딩 되기 때문에 해당 방식의 경우 Prepared Statements가 적용된 방식과 동일하여 SQL Injection 공격에 대응이 가능하다.
ORM 적용 로직 - user.controller.js
// 로그인 시
const bcrypt = require('bcrypt');
const User = require('../models/User');

const login = async (req, res) => {
    const { username, password } = req.body;

    const user = await User.findOne({
        where: { username }
    });

    if (user) {
        const isMatch = await bcrypt.compare(password, user.password);
        if (isMatch) {
            res.send('Login successful');
        } else {
            res.send('Invalid password');
        }
    } else {
        res.send('User not found');
    }
};




NoSQL Injection

source:  https://portswigger.net/web-security/nosql-injection

 

NoSQL Injection이란 애플리케이션과 연동된 DB 서버가 MongoDB와 같이 SQL 쿼리를 사용하여 통신하지 않는 DBMS를 사용할 때, 사용자 입력값 검증 미흡으로 인해 공격자가 삽입한 NoSQL 쿼리가 실행되는 취약점을 말한다.

 

예방 방법

  • express-mongo-sanitize와 같은 보안 라이브러리 사용
  • ODM(Object-Document Mapping) 사용
  • 필터링을 통한 입력값 검증
  • 웹 애플리케이션과 연동된 DB에 쿼리 시, 최소 권한이 적용된 계정 사용

 

XSS(Cross-Site Scripting)

source:  https://bit.ly/4dy9qvn

 

XSS란 URL 파라미터, 글 생성 입력 폼 등 사용자의 입력이 가능한 곳에 공격자가 Javascript 구문을 실행시킬 수 있는 클라이언트 측 스크립트를 삽입하였을 때, 서버 측 스크립트에서 해당 입력값 검증이 미흡하여 공격자가 삽입한 스크립트가 브라우저에서 실행되는 취약점을 말한다. 

 

해당 취약점의 주 목적으로는 document.cookie와 같은 스크립트를 삽입하여, 사용자 인증에 사용되는 세션 ID가 담긴 쿠키를 탈취하여, 인증된 사용자의 계정을 탈취하는 것이다.

 

XSS 공격의 종류로는 Stored XSS, Reflected XSS, DOM based XSS가 존재한다.

 

Stored XSS공격자가 주입한 악성 스크립트가 데이터베이스에 저장되는 경우를 말한다. 예를 들어 공격자가 글 생성 입력 폼에 악성 스크립트를 삽입하여 글을 생성하였을 때, 해당 글을 조회하는 모든 사용자에게 공격자가 삽입한 스크립트가 브라우저를 통해 실행되어 영향을 끼치게 된다.

 

해당 취약점이 존재하고, httpOnly 플래그가 설정되어 있지 않을 때, 공격자는 document.cookie와 같은 자바스크립트 구문을 통해 사용자를 인증하는데 쓰이는 세션 ID가 담긴 쿠키값을 탈취하여, 사용자의 계정 혹은 더 나아가 관리자의 계정을 탈취할 수 있다.

 

그리고 만약 CSRF에 대한 대응 로직이 존재하지 않을 경우, Stored XSS 공격과 CSRF 공격을 합쳐, 사용자가 악성 스크립트가 삽입된 글을 열람하려고 시도했을 때, 사용자의 아이디와 비밀번호를 공격자가 원하는 값으로 바꿔, 사용자의 계정을 탈취할 수 있다.

 

또한 만약 가짜 로그인 페이지로 리다이렉션이 되는 악성 스크립트가 삽입되어 있을 때, 사용자가 해당 글을 클릭하여 열람을 시도한 경우, 삽입된 악성 스크립트가 브라우저를 통해 실행되어, 사용자는 해당 사이트의 로그인 페이지와 동일한 외형을 갖춘 페이지로 리다이렉션이 되고, 만약 사용자가 자신이 사용 중인 웹사이트의 로그인 페이지와 동일하여 의심하지 않고 로그인을 진행하는 경우에는 사용자가 입력한 로그인 정보는 공격자의 서버로 전송되어 해당 사용자의 계정 탈취로 이어질 수 있다.

 

Reflected XSS공격자가 주입한 스크립트가 데이터베이스에 저장되는 것이 아닌 그대로 서버에서 반사되어 사용자에게 돌아와 브라우저에서 실행되는 경우를 말한다. 따라서 공격의 영향이 지속적이지 않은 일회성 공격으로, 주로 링크에 악성 스크립트를 주입하여 이메일, 문자등을 이용하여 사용자에게 전송해 클릭을 유도하는 방식이 주로 쓰인다. 즉 문자, 이메일과 같은 피싱을 통해 링크 클릭을 유도하는 방식이 주를 이룬다.

 

Reflected XSS의 공격 시나리오로 생각해 볼 수 있는 것은 구글 로그인 페이지와 같이 신뢰할 수 있는 페이지와 동일한 외형을 갖춘 피싱 페이지와 링크 자체에 악성 스크립트를 삽입한 후, 만약 사용자가 해당 링크를 클릭하여, 해당 로그인 페이지에서 계정 정보를 입력하면, 비밀번호 필드에 삽입된 oninput과 같은 이벤트핸들러가 트리거되어, 공격자 서버로 사용자가 입력한 정보가 전송되게 된다. 따라서 결국에는 사용자의 아이디와 비밀번호의 탈취로 이어질 수 있다. 

 

DOM based XSS는 DOM(Document Object Model)을 조작하는 과정에서 발생하는 XSS를 말한다. DOM의 경우 HTML로 표시되는 웹 문서가 트리 구조와 같이 계층적 구조로 나타나 있는 인터페이스를 말하는데, 이러한 DOM은 자바스크립트를 통해 조작이 가능하다.

 

만약 <input name="password">라는 HTML 태그가 존재할 때, document.getElementByName('password')라는 자바스크립트 구문을 통해 DOM 내의 해당 Input 태그를 제어할 수 있다. 이러한 DOM XSS는 주로 공격자가 입력값을 제어할 수 있는 Source가 HTML 페이지에 출력되도록하는 Sink에 전달될 때 발생한다.

 

예를 들어, 만약 특정 웹 사이트에 현재 보여주고 있는 페이지가 몇 페이지인지 나타낼 때,

 

const pageParam = new URLSearchParams(window.location.search).get('page');

document.write(pageParam);

 

위 로직에서 보듯이, page 파라미터의 값을 window.location.search를 통해 가져오고 있는데, 해당 부분이, 공격자가 제어 가능한 Source가 되며, 해당 값이 전달되어, HTML 코드에 출력되게 만드는 document.write이 Sink가 되어, pageParam에 대한 적절한 이스케이프 처리가 없을 경우, XSS 취약점이 발생하게 되고, 해당 XSS 케이스가 DOM XSS에 해당한다.

 

해당 취약점은 자바스크립트를 통해 DOM을 조작하는 과정에서 발생하므로, 오로지 서버 측을 거치지 않고 클라이언트 측에서 발생하는 취약점이다. 

 

 

예방 방법

  • 악성 HTML 태그, Javascript 코드가 실행되지 않도록 화이트리스트 기반 사용자 입력값 검증 시행
  • 악성 스크립트를 삽입할 때 사용되는 <, >, ‘, “와 같은 특수 문자를 HTML Entity(&lt; &gt; &quot; &apos;)로 변환 하는 작업을 거쳐, 사용자의 스크립트 삽입이 스크립트 코드로써 실행되는 것이 아닌 일반 문자열로 실행되도록 이스케이프 처리
  • 쿠키에 HttpOnlySecure 속성을 적용하여 Javascript로 쿠키에 접근할 수 없도록 하거나 HTTPS를 통해서만 쿠키가 전송 되도록 한다.
  • DOM을 직접 조작하는 것이 아닌, XSS 방지 기능이 포함된 라이브러리 혹은 프레임워크를 사용한다.

 

Command Injection

source:  https://www.indusface.com/learning/what-is-command-injection/

 

Command Injection이란 웹 애플리케이션에서 사용자가 입력한 시스템 명령어가 서버에서의 입력값 검증 미흡으로 인해 시스템 명령어로 실행되는 취약점을 말한다.

 

만약 PHP로 구성된 웹 애플리케이션에서 shell_exec() 함수를 사용하여 서버에서 시스템 명령어를 실행할 경우, shell_exec() 함수의 인자로 사용자의 입력값을 받을 때, 적절한 서버 측 입력값 검증 로직이 존재하지 않을 경우, 공격자는 해당 입력에 메타 문자와 시스템 명령어를 삽입하여, 공격자가 의도한 시스템 명령이 서버 측에서 실행되게 만들 수 있다.

 

예를 들어 PHP에서 shell_exec(‘cat ’ . $fileName)을 통해 파일 이름을 사용자의 입력으로 받을 때 /etc/passwd; rm -rf / 와 같이 입력하면 /etc/passwd 파일을 읽어온 후 시스템 내 모든 파일을 삭제하는 시스템 명령어가 실행된다.

 

아래는 사용자의 입력이 시스템 명령으로 실행되는 곳에 사용할 수 있는 메타 문자의 목록이다. 예를 들어 PHP에서 shell_exec(‘ping -c 8.8.8.8’ . $userInput)함수가 사용자의 입력($userInput)을 받아 시스템 명령을 실행 할 때, 앞 선 명령(ping -c 8.8.8.8) 실행 후 사용자가 입력한 시스템 명령이 실행되게 하기 위해서는 아래의 메타 문자 중 하나를 사용하여 ping 시스템 명령 실행 후, 사용자가 삽입한 시스템 명령이 실행되게 만들 수 있다.

메타 문자 설명
; 여러 명령어를 순차적으로 실행. 즉 앞의 명령어의 성공 여부와 관계 없이 뒤에 오는 명령어 실행
&& 앞의 명령어가 성공적으로 실행될 경우에만 뒤의 명령어 실행
|| 앞의 명령어가 실패할 경우에만 뒤의 명령어 실행
| 앞 명령어의 출력이 뒷 명령어의 입력으로 들어감
& 명령어 백그라운드 실행

 

예방 방법

  • 사용자의 입력 값 검증 및 필터링을 수행한다. 즉 화이트리스트 기반으로 사용자의 입력값을 검증하고 특수 문자인 메타 문자(;, &&, ||, |, >, <, $, `, (), \, 등)를 차단한다.
  • 애플리케이션에서 시스템 명령어 사용 시, system() 혹은 exec() 함수 대신, escapeshellcmd() 혹은 escapeshellarg() 함수를 사용하여 사용자의 입력에 대해 이스케이프 처리 수행
  • 시스템 명령어가 실행되는 시스템 계정에는 최소 권한만 부여하여, 루트 권한이 필요한 민감한 파일의 정보를 열람 및 변조하지 못하도록 하여 공격으로 인한 피해를 최소화한다.

 

LDAP Injection

 

LDAP(Lightweight Directory Access Protocol) Injection디렉토리 서비스(DS)에 접근하고 관리하기 위해 사용되는 프로토콜인 LDAP에 공격자가 SQLi에서와 같이 LDAP 쿼리를 애플리케이션에 삽입할 때, 서버 측에서 해당 입력값에 대한 Sanitize 및 이스케이프 처리가 이루어지지 않아 발생하는 취약점이다. 

 

해당 취약점의 주 공격 벡터는 비밀번호 없이 다른 사용자로 로그인하는 로그인 우회, 공격자에게 인가되지 않은 민감한 데이터에 접근 시도 및 LDAP 디렉토리의 데이터를 변조하는 것이다.

 

 

LDAP데이터를 계층적으로 저장하는 디렉토리 서비스에 접근하는 방법을 표준화한 프로토콜로, 해당 계층 구조는 트리 구조로 표현되며 이는 파일 시스템의 디렉토리 구조와 유사하다. 트리의 각 노드는 특정 개체(사용자, 조직, 장치 등)에 대한 정보를 나타낸다.

 

디렉토리 서비스는 네트워크 내의 리소스(사용자, 그룹, 장치 등)에 대한 정보를 계층적인 구조로 저장하고, 해당 정보를 효율적으로 검색 및 관리 할 수 있도록 하는 시스템이다.

 

LDAP는 애플리케이션에서 사용자 인증, 권한 부여, 주소록 관리, 이메일 시스템 등에서 널리 사용되는데, 주로 회사 내부의 사용자 인증 시스템에서 LDAP 서버를 사용하여 사용자의 로그인 자격 증명을 확인하고 사용자의 속성(이름, 이메일 주소 등)을 검색하는데 사용된다.

 

LDAP 쿼리는 계층적 디렉토리 구조에서 데이터를 검색하거나 수정하기 위해 사용되고, 기본적으로 필터 표현식을 사용하여 특정 기준에 맞는 데이터를 검색한다. 필터는 일반적으로 &(AND), |(OR), !(NOT) 연산자와 속성 조건으로 구성된다. 만약 user 객체 클래스를 가진 guanjoer라는 사용자를 검색하는 쿼리는 아래와 같다.

(&(objectClass=user)(uid=guanjoer))

 

사용자 ID가 guanjoer이거나 이름이 GuanJoer인 사용자를 검색하는 쿼리는 아래와 같다.

(|(uid=guanjoer)(cn=GuanJoer))

 

 

Example

 

만약 로그인 시 사용하는 LDAP 쿼리가 아래와 같고,

(&(uid={userInput})(userPassword={passwordInput}))

 

{userInput}{passwordInput}에 사용자 입력값을 직접적으로 전달할 경우,

 

{userInput}에 *)(|(& 을 삽입하고, {passwordInput}에 pwd) 를 삽입할 경우, 전체 쿼리는 아래와 같다.

(&(uid=*)(|(&)(userPassword=pwd)))

 

즉 사용자의 아이디 값으로 *인 와일드 카드를 사용하여 모든 사용자와 매칭되도록 하고, 빈 AND 연산자는 항상 결과가 참이므로, |(OR) 연산자를 통한 (|(&)(userPassword=pwd) 해당 쿼리의 결과는 참이되고 따라서 전체 LDAP 쿼리의 결과가 참이 되어, 디렉토리 서비스의 로그인 인증을 우회하여 쿼리 결과의 첫번째 사용자로 디렉토리 서비스에 로그인하게 된다. 다른 사용자로 로그인하기 위해서는 f로 시작하는 모든 유저를 뜻하는 f*와 같이 와일드 카드 앞에 특정 단어를 붙여주어야 한다.

 

예방 방법

  • 모든 Injection 취약점은 서버 측에서의 사용자 입력값 검증 미흡으로부터 발생하므로, 사용자의 입력값을 적절히 검증하고 JAVA에서 escapeLDAPSearchFilter()와 같은 함수를 사용하거나 LDAP에서 쿼리에 영향을 주는 특수문자(&, |, *, etc.)들을 필터링하여 이스케이프 처리를 한다. 
  • SQL 쿼리에서 Prepared Statements를 적용한 것과 유사하게 매개변수화된(Parameterized) 쿼리를 사용하여 사용자의 입력값을 직접 LDAP 쿼리에 포함하는 것이 아닌, 변수로 바인딩 하도록 한다.
  • 최소 권한 원칙을 적용하여, LDAP 서버에 대한 접근 권한을 최소화 하여 피해의 영향을 최소화시킨다.

 

XML External Entity (XXE)

source: https://www.acunetix.com/blog/articles/xml-external-entity-xxe-vulnerabilities/

 

XXE(XML External Entity)란 XML 데이터를 파싱하여 사용하는 웹 서비스 중, 외부 엔티티를 참조하는 경우 공격자가 악의적인 외부 엔티티를 XML 문서에 삽입하여 서버 파일 시스템의 민감한 데이터에 접근하거나 HTTP 요청을 통해 SSRF(Server-Side Request Forgery) 공격으로 이어질 수 있는 취약점이다.

 

여기서 XML은 데이터를 구조화하여 저장하고 전달하기 위한 마크업(Markup) 언어HTML과 같이 태그(Tag)로 데이터들을 구분하며, 하지만 HTML 보다 더 큰 유연성을 가지고 사용자 정의가 가능하다.



DTD (Document Type Definition)

 

DTDXML 문서의 구조를 정의하는데 사용된다. 즉 XML 문서에서 사용할 수 있는 요소, 속성, 데이터 타입 등을 규정한다.

 

XML 문서에 DTD를 포함시키면, XML 파서는 해당 DTD를 참조하여 문서가 올바르게 구성되어있는지 검사할 수 있다.

 

DTD에는 XML 문서 내부에 정의된 내부 DTD, URL을 통해 외부에서 참조하는 외부 DTD가 있다.

<!DOCTYPE test [
    <!ELEMENT test (this, is, test)>
    <!ELEMENT this (#PCDATA)>
    <!ELEMENT is (#PCDATA)>
]>

엔티티XML 문서에서 일종의 변수처럼 사용되고, 특정 값을 재사용하거나 텍스트를 줄여서 사용할 수 있게 한다.(& == &amp;).

 

외부 엔티티(External Entity)XML 문서 외부의 데이터를 참조할 수 있는 엔티티를 말한다. 이는 파일 시스템 혹은 URL을 통해 외부 리소스에 대한 참조가 가능하다.

<!DOCTYPE test [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<test>
    <this>&xxe;</this>
    <is>test</is>
 </test>

위 XML 문서는 &xxe;를 통해 서버의 /etc/passwd 파일을 참조한다. 만약 서버가 이러한 XML 구문을 처리한다면 /etc/passwd 파일의 내용이 노출되게 된다.

 

예방 방법

  • DTD 및 외부 엔티티 비활성화
  • XInclude 기능 비활성화
  • 데이터 처리에 XML이 아닌, JSON 데이터 형식으로 기능을 구현한다.

 

A04: Insecure Design

Insecure Design(불완전한 설계) 취약점은 웹 애플리케이션의 초기 설계 단계에서부터 보안 관점이 충분히 고려되지 않은 상태에서 설계된 경우 발생할 수 있는 취약점이다.

 

해당 취약점은 잘못된 설계로 인해 보안 기능이 충분하지 않거나, 아예 설계되지 않았을 때 발생할 수 있다. 이를 테면, 사용자의 입력값 검증이 불충분하거나 권한 관리가 올바르게 이루어지지 않는 경우가 포함된다.

 

 

포함되는 주요 요소

  • 보안 요구 사항의 부재: 설계 단계에서 보안 요구 사항이 정의되지 않았거나, 불충분하게 정의된 경우 취약점이 발생할 수 있다. 사용자 인증 및 권한 부여가 제대로 설계되지 않은 경우가 이에 포함된다.
  • 잘못된 위험 모델링: 웹 애플리케이션의 잠재적 위협에 대한 충분한 이해 없이 설계가 이루어진 경우, 공격자는 시스템의 설계 결함을 이용하여 중요한 데이터를 탈취하거나 시스템을 손상시킬 수 있다.
  • 취약한 인터페이스 설계: 외부 시스템과의 통신 인터페이스가 안전하지 않게 설계되면, 해당 인터페이스를 통해 공격자가 시스템에 침투할 수 있게 된다. 예를 들어, API가 접근에 대한 인증 없이 외부에 공개되어 있으면 누구나 시스템 자원에 접근할 수 있다.

 

예방 방법

  • 웹 애플리케이션 설계 초기 단계에서부터 명확한 보안 요구 사항을 정의하고 이를 설계에 반영해야 한다. 이에는 인증, 권한 관리, 데이터 보호 등의 요소가 포함된다.
  • 위협 모델링을 통해 설계 단계에서 잠재적 위협을 식별하고, 이에 대한 대응방안을 마련한다.
  • 설계가 완료된 후 이를 보안 전문가에게 검토 및 모의 침투 테스트를 통해 취약점을 발견하고 개선해나가는 과정이 필요하다.
  •  OWASP의 보안 가이드라인을 참고하여 설계를 진행한다. 즉 보안 지침을 준수하여 이를 설계에 반영하다.

 

A05: Security Misconfiguration

Security Misconfiguration(보안 설정 오류)는 시스템 혹은 웹 애플리케이션의 보안 설정이 제대로 구성되지 않아서 발생하는 취약점을 의미한다. 이는 보안 패치가 적용되지 않거나, 불필요한 기능이 활성화되어 있거나, 기본값으로 설정된 보안 설정을 변경하지 않고 그대로 사용하는 경우에 자주 발생한다.

 

 

Examples

  • 기본 관리자 계정 사용: 웹 애플리케이션을 설치한 후, 기본으로 제공된 관리자 계정(admin/admin)을 그대로 사용하고 있는 경우 공격자는 쉽게 추측을 통해 관리자 권한을 획득할 수 있다.
  • 디렉토리 인덱싱 활성화: 웹 서버에서 디렉토리 인덱싱이 활성화되어 있어 디렉토리 내의 모든 파일이 나열되는 경우 공격자는 해당 웹 애플리케이션의 디렉토리 구조를 파악하고 민감한 파일을 발견할 수 있으며 더 나아가 웹쉘을 이용한 공격(해당 공격의 조건으로 웹쉘이 올라간 경로를 알아야만 한다)이 이루어질 수 있다.
  •  디버그 모드 활성화: 프로덕션 환경에서 애플리케이션의 디버그 모드가 활성화되어 있어, 발생하는 오류와 관련된 상세한 정보(DB 쿼리, 파일 경로 등)가 사용자가 노출되는 경우, 공격자는 해당 정보를 통해 시스템의 구조와 weakpoint를 파악할 수 있다.
  • 파일 및 디렉토리의 잘못된 권한 설정: 서버의 중요한 설정 파일에 대해 모든 사용자가 읽기 권한 및 수정, 실행 권한(chmod 777)을 가지고 있는 경우
  • 잘못된 CORS(Cross-Origin Resource Sharing) 설정: 웹 애플리케이션에서 모든 도메인에 대해 CORS 요청을 허용하도록 설정한 경우(Access-Control-Allow-Origin: *).

 

예방 방법

  • 기본 계정과 비밀번호(admin/admin)를 변경하고 불필요한 기능(httpd.conf파일의 Options Indexes)이나 서비스는 비활성화한다. 
  • 애플리케이션이 오류를 발생시킬 때, 사용자가 시스템의 내부 정보를 알 수 없도록 에러 메시지를 간단하게 표시하고, 구체적인 오류 내용은 서버 로그에만 기록되도록 설정한다.
  • 보안 헤더를 설정한다. 즉 클릭재킹을 방지하기 위해 X-Frame-Options 헤더를 설정하거나, 스크립트 실행을 제한하는 Content-Security-Policy 헤더를 추가한다.
  • 파일, 디렉토리, 데이터베이스, 사용자 계정 등 시스템 내 모든 요소에 대해 최소한의 권한만 부여한다.
  • 소프트웨어 혹은 시스템의 보안 패치를 정기적으로 확인하고, 최신 상태로 유지해야 한다.
  • CORS 설정을 신뢰할 수 있는 특정 도메인에 대해서만 허용하도록 제한한다.



A06: Vulnerable and Outdated Components

Vulnerable and Outdated Components(취약하거나 오래된 구성 요소) 취약점은 시스템이나 애플리케이션에서 사용되는 라이브러리, 프레임워크, 소프트웨어가 최신 상태로 유지되지 않거나, 이미 알려진 보안 취약점이 존재하는 경우를 의미한다. 

 

현대의 많은 애플리케이션이 여러 오픈 소스 또는 서드파티 구성 요소를 포함하고 있는데, 이러한 구성 요소들이 적시에 업데이트되지 않으면 공격자에 의한 큰 보안 위협으로 이어 질 수 있다. 일례로, Apache StrutsRCE(Remote Code Execution)가 가능한 CVE-2017-5638 취약점의 경우 패치가 제공된 후에도 많은 시스템이 이를 적용하지 않아 Equifax의 데이터 유출 사건과 같은 심각한 보안 사고로 이어졌다. Equifax의 경우 보안 패치를 적시에 적용하지 않음으로 인해 탈취 당한 데이터의 수는 미국인 1억 4400만 명으로, 1억 4400만명의 개인 식별 정보(이름, 주소, 생년월일, 사회보장번호, 운전면허번호 등) 및 약 20만 건의 신용카드 번호가 탈취당했다. 이러한 공격으로 인한 피해의 크기는 미국 인구의 40% 이상이 영향을 받았다.

 

 

해당 취약점에 포함되는 경우

  • 더 이상 지원되지 않는(EOL; End-of-Life) 소프트웨어 사용
  • 알려진 취약점이 있는 라이브러리나 프레임워크 사용
  • 보안 패치가 적용되지 않은 소프트웨어 사용
  • 안전하지 않은 서드파티 라이브러리 사용

예방 방법

  • 정기적인 소프트웨어 업데이트를 통해 사용 중인 라이브러리, 프레임워크, 서드파티 소프트웨어의 최신 버전을 항상 유지한다. 가능한 경우, 구성 요소의 자동 업데이트를 활성화하여 패치를 놓치지 않도록 한다.
  • NVD(National Vulnerability Database)나 각 라이브러리의 CVE(Common Vulnerabilities and Exposures) 목록을 정기적으로 확인하여 사용 중인 구성요소의 취약점을 모니터링 한다.
  • Snyk, WhiteSource, Dependabot과 같은 SCA(Software Composition Analysis)도구를 활용하여 애플리케이션이 사용하는 오픈 소스 라이브러리의 취약점을 자동으로 식별하도록 한다.

 

A07: Identification and Authentication Failures

Identification and Authentication Failures(식별 및 인증 실패)는 사용자의 신원을 확인하고 권한을 부여하는 과정에서 발생할 수 있는 취약점이다.

 

 

해당 취약점에 포함되는 경우

  • 약한 패스워드 정책(짧은 길이, 특수문자 조합 미사용, 쉽게 추측이 가능한 단어 등)을 사용하는 경우
  • 사용자를 인증하는데 쓰이는 세션 ID가 예측 가능하거나 변하지 않는 경우
  • 다중 인증(MFA) 혹은 2차 인증의 부재로 Brute Forcing, Credential Stuffing 공격(대량의 유출된 계정을 사용하는 무차별 대입 공격) 등에 노출되는 경우
  • URL에 사용자를 인증하는데 쓰이는 세션 ID가 노출되는 경우

 

예방 방법

  • 강력한 비밀번호 정책(특수 문자가 포함된 조합 및 긴 문자, 자신과 연관성이 없고 추측이 어려운 단어) 사용 및 인증 실패 횟수에 대한 제한 적용
  • 다중 인증(OTP, 생체 인식 등) 사용
  • 로그인 시 새로운 세션 ID 발급 및 로그아웃 시 세션 파기
  • 세션 ID는 암호화된 채널(HTTPS)에서 헤더를 통해 전송

 

A08: Software and Data Integrity Failures

Software and Data Integrity Failures(소프트웨어 및 데이터 무결성 실패)는 소프트웨어와 데이터의 무결성을 보장하지 못하는 경우에 발생하는 취약점으로, 즉 소프트웨어의 무결성 검증 실패로 인해 발생하는 취약점이다.

 

 

해당 취약점에 포함되는 경우

  • 신뢰할 수 없는 소스로부터 소프트웨어나 라이브러리를 다운로드 한 경우
  • 다운로드 및 업데이트 한 소프트웨어에 대해 코드 서명 및 무결성 검증이 이루어지지 않은 경우(업데이트 서버가 공격자에 의해 장악된 경우 업데이트 코드에 악성 코드의 주입이 가능하다)
  • CI/CD(Continuous Integration/Deployment) 파이프라인에서 코드나 구성 요소가 제대로 검증되지 않은 경우
  • 직렬화된 데이터에 대해 무결성 검증이 수행되지 않은 경우

 

CASE

 

해당 취약점의 대표적인 사건으로는 2018년 경, Node.js 환경에서 스트림을 처리하는데 사용되는 npm 패키지 중 하나인 event-stream에서 발생한 사건이 존재한다. 해당 패키지의 경우, 그 당시 일주일 당 2M인 2백만의 다운로드 수를 기록할정도로 많은 개발자가 사용하던 패키지였다. 

 

취약점이 발생한 원인으로는 2018년 9월 경 event-stream 패키지의 기존 관리자가 더 이상 유지 보수할 시간이 없다는 이유로 해당 패키지의 권한을 다른 사용자에게 넘겨주었고, 이때, 새로운 관리자는 기존 소스코드에 악성 코드가 포함된 패키지인 flatmap-stream 패키지를 추가함으로 인해 발생하였다.

 

해당 코드는 암호화된 형태로 포함되어 있어, 발견하기가 쉽지 않았으며,. 해당 악성 코드의 타겟은 copay라는 암호화폐 지갑 애플리케이션이며, 해당 애플리케이션의 사용자들의 자격 증명을 탈취하는 것이 주목적이었다.

 

https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident

 

npm Blog Archive: Details about the event-stream incident

The npm blog has been discontinued. Updates from the npm team are now published on the GitHub Blog and the GitHub Changelog. This is an analysis of the event-stream incident of which many of you became aware earlier this week. npm acts immediately to addre

blog.npmjs.org

 

https://www.theregister.com/2018/11/26/npm_repo_bitcoin_stealer/

 

Check your repos... Crypto-coin-stealing code sneaks into fairly popular NPM lib (2m downloads per week)

Node.js package tried to plunder Bitcoin wallets

www.theregister.com

 

 

예방 방법

  • 신뢰 할 수 있는 소스에서 서명된 패키지와 라이브러리를 사용하고, 서명 검증 절차를 구축한다.
  • 다운로드한 파일에 대해, 개발자가 파일에 디지털 서명을 포함한 경우, 사용자는 디지털 서명을 개발자가 배포한 공개키로 복호화하여 해당 해시값과 파일을 동일한 해시 함수를 사용하여 생성한 해시 값과 비교하여 무결성 검증을 수행하거나, 개발자가 처음부터 파일의 해시값을 제공하는 경우, 해당 파일에 대해 개발자가 사용한 동일한 해시 함수로 해시값을 생성하여 무결성 검증을 수행한다.
  • CI/CD 도구에 대한 접근 권한을 엄격히 관리하고, 파이프라인의 모든 단계에서 무결성 검증을 실시한다.
  • 직렬화된 데이터에 대해 무결성 검증을 수행한다.

 

A09: Security Logging and Monitoring Failures

Security Logging and Monitoring Failures(보안 로깅 및 모니터링 실패)는 보안 이벤트(비정상적인 로그인 시도, 데이터베이스에 대한 비정상적인 접근 등)에 대해 제대로 기록하거나 모니터링하지 않아, 보안 사고가 발생했을 때 이를 탐지하지 못하거나 적절히 대응하지 못하는 상황을 의미한다.

 

로깅과 모니터링은 보안 사고를 탐지하고, 원인을 분석하고, 향후 유사한 보안 사고를 방지하는데 필수적이다.

 

예방 방법

  • 로그인 시도, 권한 상승, 중요한 파일이나 데이터베이스에 대한 접근 등 보안과 관련된 중요한 이벤트를 모두 로깅(기록)하도록 하고 정기적인 백업을 통해 보관한다.
  • 실시간으로 시스템에서 발생하는 로그를 모니터링하고, 비정상적인 활동이 발생하면 알림을 받을 수 있도록 설정한다. SIEM(Security Information and Event Management) 시스템을 통해 자동화된 모니터링과 알림을 설정할 수 있다.
  • 정기적으로 로그를 분석하여 이상 징후를 탐지한다.
  • 로그 저장소에 대한 접근을 제한하여 로그 파일에 대한 무단 변조 및 삭제되지 않도록 보호한다.

 

A10: Server-Side Request Forgery (SSRF)

 

source:  https://cyberhub.sa/posts/3268

 

Server-Side Request Forgery(SSRF)CSRF와 다르게 서버 측에서 발생하는 취약점으로, 서버가 사용자의 입력으로 URL을 입력 받는다면, 즉 서버가 사용자의 입력을 통해 외부 리소스 요청 및 내부 리소스 요청을 수행할 경우 발생할 수 있는 취약점이다.

 

만약 쇼핑몰 사이트에서 사용자가 물품을 검색할 때, 서버는 해당 물품에 대한 정보가 내부 네트워크의 다른 서버에 존재하여 URL 요청 시에 다른 서버의 URL을 지정하여 물품에 대한 정보를 받아온다면, 공격자는 이를 수정하여 해당 서버에 존재하는 다른 파일들을 요청하여 응답 받을 수 있게 된다. 즉 원래 사용자는 DMZ 구간에 존재하는 웹 서버와의 통신 밖에 가능하지 않지만, SSRF 취약점을 이용하면, 웹서버를 이용하여 내부 네트워크와의 통신이 가능해져, 내부 네트워크 대역에 존재하는 시스템에 접근 할 수 있게 된다.

 

예방 방법

  • 적절한 입력값 검증을 시행한다. 즉 만약 외부 리소스에 대한 요청이 필요할 경우, 사용자로부터 전달받은 URL 혹은 IP 주소를 철저히 검증하고, 내부 IP(Private IP) 주소(127.0.0.1, 192.168.0.1) 및 내부 도메인으로의 요청을 차단한다.
  • 원천적으로 차단하기 위해서는 화이트리스트 기반 방식을 사용하여, 요청 가능한 도메인 혹은 IP 주소에 대해서만 요청 및 접근을 허용한다.
  • 서버가 외부로 요청을 보낼 때 최소한의 권한(Least Privilege)으로 실행되도록 하여, 침해 시 공격자의 행동에 제한을 두어 피해 영향을 최소화한다.

 

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

[WEB Hacking] XXE (XML External Entity) 취약점  (2) 2024.10.10
[WEB Hacking] CSRF Attack  (1) 2024.09.03