'll Hacker

1주차 강의. 모의해킹 대비 OWASP top 10으로 뽀개기 심화스터디 본문

Hacking/EVI$ION(교내 해킹동아리)

1주차 강의. 모의해킹 대비 OWASP top 10으로 뽀개기 심화스터디

씨이오가 되자 2025. 5. 17. 20:58
Contents
728x90

OWASP top 10 리스트

웹 애플리케이션 취약점 중에서 빈도가 많이 발생하고, 보안상 영향을 크게 줄 수 있는 것들을 커뮤니티에서 연구하고 그 중 top 10을 발표한다

1️⃣ Broken Access Control (취약한 접근제어)

   💚인증을 우회하여 권한없는 리소스 접근 가능

 

2️⃣ Cryptographic Failures (암호화 실패)

   💚민감한 데이터 노출 위험, 암호화 설정 오류

 

3️⃣ Injection (인젝션)

   💚악의적 명령 삽입 (SQL, NOSQL. OS 등)

 

4️⃣ Insecure Design (불완전한 설계)

   💚보안이 고려되지 않은 시스템 설계

 

5️⃣ Security Misconfiguration (보안 설정 오류)

   💚잘못된 보안 설정, 디폴트 설정 유지 등

 

6️⃣ Vulnerable and Outdated Components (취약하거나 오래된 컴포넌트 사용)

   💚패치되지 않은 라이브러리 또는 구성요소 사용

 

7️⃣ Identification and Authentication Failures (식별 및 인증 실패)

   💚로그인 우회, 계정 탈취, MFA 미적용 등 

 

8️⃣ Software and Data Integrity Failures (소프트웨어 및 데이터 무결성 실패)

   💚배포 도구, 업데이트, CI/CD에서 무결성 검증 부족 

 

9️⃣ Security Logging and Monitoring Failures (로깅 및 모니터링 실패)

   💚침해 탐지 및 대응 불가 상태

 

🔟 Server-Side Request Forgery (SSRF) 

   💚서버가 공격자가 제어하는 URL로 요청을 보내도록 유도

 


A01️⃣: Broken Access Control

Access Control은 어떤 상황에서 행위를 허용하거나 거부할 것인지에 대한 내용을 나타낸다.

Broken은 말 그대로 통제가 깨진다는 뜻이니까 마음대로 공개하거나 수정가능함으로 이해할 수 있다.

이런 취약성은 URL, 내부 애플리케이션 상태 또는 HTML 페이지를 수정하거나 공격 도구를 사용하여 API 요청을 수정하고 액세스 제어 검사를 우회할 수 있다.

안전하지 않은 직접 객체 참조(=고유 식별자)를 제공하여 다른 사람의 계정을 보거나 편집을 할 수 있도록 허용한다.

POST, PUT, DELETE에 대한 액세스 제어가 누락되어서 API에 액세스가능하다.

 

직접 객체 참조란?⏬

더보기

사용자가 시스템 내부의 리소스 (예: 파일, 데이터베이스 레코드 등)에 접근할 수 있는 식별자(ID, 경로 등)를 URL이나 요청 파라미터로 직접 제고앋아 사용할 수 있는 상황을 말함.

보안적으로 문제가 되는 경우는 권한 검사를 하지 않고 이런 식별자만 가지고 접근이 가능할 때이다.

이 경우 공격자는 다른 사용자의 리소스에도 마음대로 접근할 수 있게 된다. 이를 취약한 접근 제어(Broken Access Control)유형 중 하나로 분류하며, 특히 IDOR(Insecure Direct Object Reference)라고 부른다.

 

예시1) 게시글 보기 URL에서 ID 조작

GET /post/view?id=123   ← 본인 글

사용자는 자신의 글 번호 123번을 조회한다.

근데 단순히  주소창에서 숫자를 바꾼다면?

GET /post/view?id=124   ← 다른 사람 글도 조회됨

 서버가 id=124에 대해 권한 확인없이 DB에서 꺼내 보여주면 직접 객체 참조 취약점 발생한다.

 

공격자는 다른 사용자 글, 주문내역, 개인정보를 열람할 수 있다.

 

예시2) 파일 다운로드

GET /download?file=report_2023.pdf

서버가 /files/report_2023.pdf 경로에서 파일을 읽어 내려준다.

 

하지만 악의적인 행위자가 이렇게 바꾸면?

GET /download?file=../../etc/passwd

 서버가 경로 검증없이 파일 읽어주면 심각한 디렉터리 리버설+직접 객체 참조 취약점이 발생하게 된다.

 

예시3) API 호출에서 사용자 ID 노출

GET /api/users/1001/profile   ← 본인

1001번이 내 사용자 ID이다.

GET /api/users/1002/profile   ← 다른 사용자 프로필도 조회 가능

 이렇게 한다면 서버에서 인증된 사용자라고 해도, 이 요청이 해당 자원에 대한 권한을 갖는지 확인하지 않으면 심각한 보안 사고로 이어질 수 있다.

 

해결방법:

  • 클라이언트가 제공한 식별자(ID, 파일명 등)에 대해 항상 서버 측에서 권한 확인을 수행해야한다.
  • 가능한 경우에는 사용자에게 간접 참조 키를 부여하거나 UUID나 토큰 등을 사용하여 추측을 어렵게 만들어야한다.
GET /post/view?ref=adkj13h2k13l4kl2l4kl    ← 추측 어려움

 

따라서 Broken Access Control에 대한 공격은 다음과 같다:

 

▶️ 인증없이도 로그인된 사용자처럼 행동할 수 있다. 

일반 사용자로 로그인했지만, 추가 조작을 통해 관리자처럼 행동할 수 있다.

 

예시:

# 로그인하지 않았지만 이 URL로 접속했더니 정보가 나옴
GET /user/profile?id=1234

# 일반 사용자로 로그인했지만 URL을 바꾸니 관리자 페이지에 접근됨
GET /admin/dashboard

서버가 로그인 여부, 권한 레벨 (사용자/관리자 등)을 제대로 확인하지 않아서 발생했다.

권한이 없는 사람이 다른 역할로 행동할 수 있는 상태를 "수직적 권한 상승" 또는 "수평적 권한 상승"이라고 한다.

 

▶️ JWT나 쿠키, 숨겨진 필드 등을 직접 조작해서 권한을 얻거나 세션을 속일 수 있다.

 

예시1: JWT 변조

{
  "user": "normal_user",
  "role": "admin"
}

JWT나 서명없이 사용되거나 HMAC 키가 노출된 경우, 위처럼 payload를 바꿔서 권한 상승 가능하다.

 

예시2: 조작된 쿠키

Cookie: role=admin

서버가 쿠키에 있는 role 값을 신뢰하면 공격자는 쿠키를 조작해서 관리자처럼 행동 가능하다.

 

예시3: 숨겨진 필드

<input type="hidden" name="user_role" value="admin">

이런 필드는 클라이언트에서 쉽게 조작 가능하다.

 

▶️CORS 설정이 잘못되면 외부 웹사이트에서도 내부 API에 요청을 보낼 수 있다.

 

예시:

Access-Control-Allow-Origin: *

이런 설정이면 누구나 브라우저에서 내부 API에 요청할 수 있음 

민감 데이터 노출 가능하다.

 

▶️로그인하지 않은 사람이 인증된 사용자 전용 페이지에 접근하거나, 일반 사용자가 관리자만 접근 가능한 페이지로 강제 이동해서 열람가능하다.

GET /dashboard ← 로그인 필요
GET /admin/delete_user?id=100 ← 관리자만 가능

서버가 이런 요청에 대해 사용자 상태를 검사하지 않으면, 누구나 URL만 알면 접근 가능하다.

 

broken access control은 통계적으로 다음과 같은 결과를 나타난다.

매핑된 CWE 최대 발생률 평균 발생률 평균 가중 익스플로잇 평균 가중영향 최대범위 평균범위 총 발생 횟수 총 CVE
34 55.97% 3.81% 6.92 5.93 94.55% 47.72% 318,487 19,013

 

CVE (Common Vulnerabilities and Exposures)

컴퓨터 하드웨어 또는 소프트웨어 결함이나 체계, 설계 상의 허점.

* 취약점 리스트

 

CWE (Common Weakness Enumeration)

커뮤니티에서 개발한 일반적인 소프트웨어 및 하드웨어 취약점 목록

* 보안 약점 리스트

여기서 말하는 Weakness은 특정 상황에서 취약점 도입에 기여할 수 있는 소프트웨어, 펌웨어, 하드웨어 또는 서비스 구성요소의 조건. 다양한 소프트웨어 언어 및 아키텍처, 디자인 설계, 코딩 등의 개발 단계에서 발생 가능한 취약점.

취약성을 초래하는 약점을 아는 것은 소프트웨어 개발자, 하드웨어 설계자 및 보안 설계자가 배포 전에 이를 제거할 수 있음을 의미한다▶️배포하기 전에 제거하는 것이 훨씬 쉽고 저렴함, 효과적임.

 

CVE vs CWE

CVE의 V는 취약점(Vulnerabilities)을 의미하고, CWE의 W는 보안약점(Weakness)를 의미한다.

보안약점 ⊃ 취약점 → 보안약점은 소프트웨어 취약점으로 이어질 수 있는 오류를 의미하고, 취약점은 해커가 시스템이나 네트워크에 액세스하기 위해 직접 사용할 수 있는 소프트웨어의 실수.

 

주목할 만한 공통적 CWE

CWE-200 : Exposure of Sensitive Information to an Unauthorized Actor.

= 권한이 없는 행위자에게 민감한 정보 노출

CWE-201 : Insertion of Sensitive Information Into Sent Data

= 전송된 데이터에 민감한 정보 삽입

CWE-352 : Cross-Site Request Forgery

= 사이트 간 요청 위조

CWE-200 : Exposure of Sensitive Information to an Unauthorized Actor.

민감한 정보의 종류

1. 개인메시지, 재무 데이터, 건강 기록, 지리적 위치 또는 연락처 정보

2. 운영체제 및 설치된 패키지와 같은 시스템 상태 및 환경

3. 사업 비밀과 지적 재산권

4. 네트워크 상태 및 구성

5. 제품 자체의 코드 또는 내부 상태

6. 메타데이터 (예: 연결 또는 메시지 헤더 로깅)

7. 외부인이 관찰할 수 있는 두 가지 내부 작업 간의 불일치와 같은 간접 정보

 

이런 민감한 정보가 왜 노출될 수 있는가?

프로그램의 전체 시스템 경로가 드러나는 웹 스크립트 오류와 같이 민감한 정보가 간접적으로 리소스에 삽입되는 경우에 해당된다.

 

ex1. 제공된 사용자 이름과 비밀번호의 유효성을 검사하고 사용자에게 로그인의 성공 또는 실패를 알리는 코드 구현.

my $username=param('username');
my $password=param('password');

if (IsValidUsername($username) == 1)
{
	if (IsValidPassword($username, $password) == 1)
	{
		print "Login Successful";
	}
	else
	{
		print "Login Failed - incorrect password";
	}
}
else
{
	print "Login Failed - unknown username";
}

잘못된 사용자 이름이 제공될 때 사용자 이름은 올바르지만 비밀번호가 틀릴 때의 메시지의 차이점을 통해 Attacker는 로그인 기능의 상태를 파악해서 브루트포스나 딕셔너리 공격으로 잘못된 비밀번호 메시지가 반환될 때까지 공격할 수 있음.(사용자 이름 파악)

따라서 필요한 인증 정보의 증명은 거의 얻게 됨.

else
{
	print "Login Failed - unknown username or incorrect password"
}

ID나 비밀번호가 틀렸다고 알림을 주면 된다. 그러면 ID가 틀렸는지 비밀번호가 틀렸는지 알 수 없기 때문이다.

 

ex2-1. 

try {
	openDbConnection();
}
//print exception message that includes exception message and configuration file location
catch (Exception $e) {
	echo 'Caught exception: ', $e->getMessage(), '\n';
	echo 'Check credentials in config file at: ', $Mysql_config_location, '\n';
}

이 코드는 예외가 발생하면 구성 파일 위치를 포함하는 예외 메시지를 출력하게 된다. Attacker는 이 정보를 사용하여 구성 파일을 path traversal 공격을 가능하게 된다. 이때, 파일에 접근가능할 경우 DB에 접근하기 위한 정보들을 얻게 된다. 

 

ex2-2

public BankAccount getUserBankAccount(String username, String accountNumber) {
	BankAccount userAccount = null;
	String query = null;
	try {
		if (isAuthorizedUser(username)) {
			query = "SELECT * FROM accounts WHERE owner = "+ username + " AND accountID = " + accountNumber;
			DatabaseManager dbManager = new DatabaseManager();
			Connection conn = dbManager.getConnection();
			Statement stmt = conn.createStatement();
			ResultSet queryResult = stmt.executeQuery(query);
			userAccount = (BankAccount)queryResult.getObject(accountNumber);
		}
	} catch (SQLException ex) {
        String logMessage = "Unable to retrieve account information from database,\nquery: " + query;
        Logger.getLogger(BankManager.class.getName()).log(Level.SEVERE, logMessage, ex);
    }
	return userAccount;
}

생성된 오류 메시지에는 DB 또는 쿼리 로직에 대한 민감한 정보(데이터베이스에서 사용된 테이블 이름과 열 이름 노출)를 포함할 수 있는 데이터베이스 쿼리에 대한 정보가 포함된다. SQL injection attack에 사용될 수 있다.

 

CWE-200의 대표 CVE는 CVE-2002-1725, CVE-2001-1528, CVE-2005-1205, CVE-2003-0190 등이 있다.

  1. CVE-2002-1725 : 스크립트는 phpinfo()를 호출하여 웹 사용자에게 시스템 구성을 공개
  2. CVE-2001-1528 : AmTote International 홈벳 프로그램은 잘못된 계좌 번호와 PIN 코드가 제공되면 다양한 오류 메시지를 반환하는데, 이를 통해 원격 공격자는 무차별 대입 공격을 통해 유효한 계좌 번호가 존재하는지 확인할 수 있다.
  3. CVE-2003-0190 : PAM 지원이 활성화된 OpenSSH-portable(OpenSSH) 3.6.1p1 및 이전 버전은 사용자가 존재하지 않을 때 즉시 오류 메시지를 보내므로 원격 공격자가 타이밍 공격을 통해 유효한 사용자 이름을 확인할 수 있다.
  4. CVE-2005-1205 : Microsoft Windows XP, Windows Server 2003 및 UNIX용 Windows 서비스용 Telnet 클라이언트를 사용하면 원격 공격자가 SEND ENV_USERVAR 명령과 함께 NEW-ENVIRON 옵션을 사용하여 중요한 환경 변수를 읽을 수 있다.

CWE-201 : Insertion of Sensitive Information Into Sent Data

다른 행위자에게 데이터를 전송할 때, 데이터의 해당 행위자가 접근해서는 안되는 민감한 데이터가 포함되어있음.

ex1.

Warning: mysql_pconnect(): Access denied for user: 'root@localhost' (Using password: N1nj4) 
in /usr/local/www/wi-data/includes/database.inc on line 4

 

대표 CVE는 CVE-2022-0708은 팀 생성자의 이메일주소는 API 중 하나를 통해 팀 구성원에게 공개한다.

  1. CVE-2022-0708 : Mattermost 6.3.0 및 이전 버전은 API 중 하나를 통해 팀 생성자의 이메일 주소를 보호하지 못하여 인증된 팀 구성원이 이 정보에 접근하여 민감하고 개인적인 정보가 공개되는 문제가 있습니다.

CWE-352 : Cross-Site Request Forgery (사이트 간 요청 위조)

사용자가 의도하지 않은 요청을 공격자가 유도하여 수행하는 웹 보안 취약점이다. 기본적으로 공격자는 사용자의 인증된 세션을 악용해 서버에서 원하지 않는 작업을 수행한다. 웹서버가 의도적으로 전송되었는지 확인할 검증없이 클라이언트로부터 요청을 받도록 설계된 경우 Attacker가 클라이언트를 속여 웹 서버에 의도하지 않은 요청을 하도록 만들 수 있으며, real request로 처리됨.

URL, 이미지 로드, XMLHTTPRequest 등을 통해 수행될 수 있으며, 데이터 노출이나 의도치 않은 코드 실행으로 가능하다.

 

피해자를 속여서 악성 요청을 제출하게 하는 공격이다. 사용자가 모르게 공격자가 의도한 행동을 하게 만드는 공격 방식이다. 피해자의 신원과 권한을 가로채서 원치 않는 기능 수행한다. 대부분 사이트의 경우 브라우저 요청에는 사용자의 세션 쿠키, IP 주소, Windows 도메인 자격 증명 등과 같이 사이트와 관련된 모든 자격 증명이 자동으로 포함되어 사용자가 현재 사이트에 인증된 경우 사이트는 피해자가 보낸 위조된 요청과 피해자가 보낸 합법적인 요청는 구별 불가능하다.

 

CSRF 공격은 사용자의 비밀번호 변경, 이메일 주소 수정, 상품 구매, 게시글 작성 등 서버의 데이터나 설정이 실제로 바뀌는 요청을 노린다. 예: 사용자가 로그인된 상태에서 공격자가 만든 악성 웹사이트를 방문하면, 그 웹사이트가 사용자의 의지와 상관없이 은행 계좌 이체를 요청하게 만드는 식이다.

 

하지만 GET 요청은 CSRF로 해도 소용없다.

ex1. 로그인 상태에서 사용자가 프로필을 업데이트할 수 있도록 하기 위한 화면 구성(HTML 구현)◀️상태 변경 요청 대상

<form action="/url/profile.php" method="post">
<input type="text" name="firstname"/>
<input type="text" name="lastname"/>
<br/>
<input type="text" name="email"/>
<input type="submit" name="submit" value="업데이트"/>
</form>

 

// 세션을 검증하기 위해 세션을 초기화합니다.

session_start();

// 세션이 유효한 사용자에게 등록되어 있으면 업데이트를 허용합니다.

if (!session_is_registered("username")) {

    echo "잘못된 세션이 감지되었습니다!";

    // 사용자를 로그인 페이지로 리디렉션
    [...]

    종료;
}

// 사용자 세션이 유효하므로 요청을 처리하고 정보를 업데이트합니다. //

update_profile();

function update_profile {
    // $POST에서 데이터를 읽고

    데이터베이스에
    업데이트를 보냅니다 . SendUpdateToDatabase($_SESSION['username'], $_POST['email']);
    [...]
    echo "프로필이 성공적으로 업데이트되었습니다.";
}

 

세션이 존재하는 사용자만 프로필을 업데이트할 수 있도록 하려는 의도가 있다 즉, 세션 기반 인증으로 보호하고자 한 것이다.

사용자가 이미 로그인된 상태 = 세션이 존재하는 상태에서 공격자는 사용자의 브라우저가 자동으로 이 폼을 제출하게 만들어서 공격자의 의도대로 사용자의 프로필 정보를 바꿀 수 있다. 

즉, 세션이 있기만 하면 요청을 처리하기 때문에, CSRF 공격에 취약하다.

따라서 공격자가 다음과 같은 코드로 익스플로잇할 수 있다.

<SCRIPT>
함수 SendAttack() {
form.email = "attacker@example.com";
// profile.php로 전송
form.submit();
}
</SCRIPT>

<BODY onload="javascript:SendAttack();">

<form action="http://victim.example.com/profile.php" id="form" method="post">
<input type="hidden" name="firstname" value="웃긴">
<input type="hidden" name="lastname" value="농담">
<br/>
<input type="hidden" name="이메일">
</form>

<form> 태그는 피해자 사이트인 http://victim.example.com/profile.php 데이터를 를 전송하도록 설정한다.

<input type="hidden"> 는 사용자가 화면에서 볼 수 없음. <script> 부분의 SendAttack함수는 form.email="attacker@example.com"으로 이메일 값을 조작하고, form.submit()으로 자동 제출된다. <body onload="SendAttack()">는 페이지가 열리자마자 공격 코드가 자동 실행되게 만든다.

 

그래서 이 코드는 피해자가 모르게 로그인된 상태를 이용해서 서버에 요청을 보낸다. 서버는 이 요청을 신뢰하고, 피해자의 정보를 공격자가 원하는 값으로 바꾼다. 화면에 아무것도 표시되지 않기 때문에 피해자는 바뀐 사실을 모를 수 있다.

요청이 진짜 사용자가 보낸 것인자 확인하는 것이 필요하다.

 

관련 CVE는 10가지가 되는데 그 중 몇 가지를 말해보자면

  1. CVE-2004-1703 : img 태그의 URL을 통해 사용자계정 추가
  2. CVE-2004-1967 : 제작된 img 태그나 URL에 코드를 지정하여 임의의 코드 실행
  3. CVE-2004-1842 : img 태그의 URL을 통해 관리자 권한 얻기
  4. CVE-2009-3520 : 관리자의 비밀번호를 수정
  5. CVE-2009-3759 : 웹 인터페이스는 CSRF를 통해 암호 변경 또는 가상 머신 중지를 허용시킴

 

728x90