1) URL 접근 제한 미흡 취약점이란 무엇인가?
URL 접근 제한 미흡 취약점(Failure to Restrict URL Access Vulnerability)
인증 또는 인가된 사용자가 접근이 가능한 페이지(관리자 페이지, 회원 전용 페이지)에 대해서 접근 제한이 존재하지 않거나, 접근 제한이 존재하지만 우회하여 접근할 수 있는 취약점
→ 관리자 페이지에 일반 사용자가 접근, 인증하지 않은 사용자가 접근하는 경우
실무에서 자주 발생하는 취약점
- SQL Injection, XSS, 파라미터 변조, URL 접근 제한 미흡 취약점
어플리케이션 기능 개발을 우선으로 하다보니 보안이 최우선이 아닌 경우 어쩔수 없이 취약점이 발생함.
2) 인증과 인가에 대한 이해
Authentication(인증) vs Authorization(인가)
인증
→ 로그인 유무 확인
인가
→ 권한 확인(관리자, 일반 회원)
인증: 로그인되지 않은 사용자가 회원 전용 페이지에 접근 불가
인가: 일반 회원이 관리자 페이지에 접근 불가
인증: 회사 내부로 들어가기 위해서 사원증이 필요
인가: 사장실, 전무실, 상무실 등 임원 사무실로 들어가기 위해서는 해당 임원의 사원증이 필요
3) 공격 원리
URL 접근 제한 미흡 취약점은 파라미터 변조 취약점과 유사하게 해킹인지 인식하지 못할정도로 간단하면서도 공격 페이로드가 명확하지 않다.
사용자는 admin 페이지에 권한이 있어 로그인 후 접근하지만, 공격자는 admin 페이지에 권한이 없지만 유추해서 접근한다. → 접근 시도 후 실제 접근 여부 확인
hxxp://www.victim.co.kr/admin
공격자는 어떤 페이지에 접속하는지 유추하여 접근한다.
수동적 유추 - admin, adm, manager 등 관리자명으로 사용하는 페이지 요청
자동화 유추 - 사전 대입(자주 사용하는 디렉터리명 또는 페이지명 요청)
네이밍 패턴 파악하기
게시판 목록이 다음과 같다면 → board List.do
게시판 작성은 이렇게 유추 가능 → board Write.do, board Create.do, board Insert.do
공지사항 게시글 번호 파라미터 유추→ board View.do?idx, board View.do?seq, board View.do?num, board View.do?no
실습10-1 URL 접근 제한 미흡 취약점 공격 실습
URL 접근 제한 미흡 취약점을 실습하기 위해서는 웹 사이트의 페이지명을 알아야한다.
관리자 계정으로 접속 후 메인페이지를 확인하면 우측에 Write 버튼이 확인된다.
로그아웃 후 확인해보면 우측에 Write 버튼은 존재하지 않는다.
로그인 창을 확인해보면 상단 URL에 page=login 이 확인된다.
회원가입 페이지는 상단 URL 에 page=join 으로 확인된다.
이를 통해 특정 기능을 하는 페이지는 page 라는 파라미터를 사용한다는 것을 알 수 있다.
여기서 게시글 작성 페이지를 유추해본다.
URL 에 page=insert 를 입력해본다.
정상적인 값이 아니라는 에러메시지가 발생한다.
URL 에 page=create 를 입력해본다.
정상적인 값이 아니라는 에러메시지가 발생한다.
URL 에 page=write 를 입력해본다.
다음과 같이 로그인하지 않아도 게시글 작성 페이지로 접속되었다.
게시글을 작성해본다.
게시글 작성 전 CSRF Token 검증 로직을 주석 처리한다.
< action.php 에 CSRF Token 검증 로직 주석 처리 >
@session_start();
header("Content-Type: text/html; charset=UTF-8");
include ( './common.php' );
# CSRF Token 검증 로직
/*
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
unset($_SESSION["csrf_token"]);
if(empty($csrf_token_session) && empty($csrf_token_param)) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
} else {
if($csrf_token_param != $csrf_token_session) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
}
}
*/
page=write 에서 게시글을 작성한다.
다음과 같이 로그인을 하지 않고도 게시글 작성이 된 것을 확인할 수 있다.
회원 아이디가 없는 상태로 게시글이 작성된 것이다.
Form 페이지에 접근이 되는 것은 괜찮지만, Form 페이지에서 작성 시 실제로 게시글이 작성되는 것이 문제다.
( action 페이지에서 회원 유무에 대한 인증 검증 절차가 필요하다. )
또한 관리자만 접근이 가능했던 페이지들도 로그인을 하지 않은 상태로 접근이 가능하다.
http://192.168.56.1/insecure_website/index.php?page=pingcheck
http://192.168.56.1/insecure_website/index.php?page=xmlparser
로그인하지 않은 상태로 해당 페이지들에 접근해본다. ( pingcheck, xmlparser )
위와 같이 비회원인 상태로 관리자만 접근 가능한 페이지에 접근이 가능한 것을 확인할 수 있다. (인증 부분 취약)
test 라는 임의의 계정을 생성하고 해당 페이지들에 접근을 시도해본다.
다음과 같이 비회원과 동일하게 해당 페이지에 접근 가능한 것을 확인할 수 있다. (인가 부분 취약)
위 페이지들은 인증, 인가 둘다 취약하므로 해당 페이지들은 관리자만 아니면 아예 접근할 수 없도록 검증이 필요하다.
* 취약한 기능
- 게시글 작성
- pingcheck
- xmlparser
실제 취약점 진단 시 게시판을 많이 타겟으로 한다. (공지사항, 관리자 페이지 등)
공지사항은 인가 부분에 해당
→ 로그인 상태에서 관리자가 아니면 작성 버튼이 없다. - 관리자가 아닌데 공지사항을 작성 하는 부분을 노린다.
실무에서는 공지사항 진단 시 담당자와 협의하에 진행할 필요가 있다. (공지사항 작성 시 모바일로 전체 공지 알람이 발생할 수 있기 때문에)
웹 사이트마다 성격이 다르기 때문에 각각 상황에 따라 알맞게 취약점 진단이 필요
4) 대응 방안
URL 인증 및 인가가 필요한 페이지에 대해서 접근 제한에 대한 로직이 필요하다.
→ 회원 전용 페이지, 관리자 페이지
회원 전용 페이지
→ 비회원 접근 불가
관리자 페이지
→ 관리자 외 접근 불가
로그인 할 때 세션에 ID 값을 부여하게 되는데, 세션 ID 가 없으면 비회원이라는 의미이다.
세션 ID 를 받아서 빈 값이면 비정상으로 판단.
특정 페이지에 권한이 없으면 접근 불가하도록 소스코드 작성 (특정 권한이 여러 개 있는 경우)
→ 일반 사용자, 관리자
실습10-2 취약 환경 시큐어 코딩 적용 실습
action.php / pingcheck.php / xmlparser.php / write.php
* 취약한 기능
- 게시글 작성 (action.php, write.php) → 인증
- pingcheck (pingcheck.php) → 인증, 인가
- xmlparser (xmlparser.php) → 인증, 인가
게시글 작성 부분에 시큐어 코딩을 적용한다.
< action.php 에 인증 로직 및 CSRF Token 검증 로직 추가 >
@session_start();
header("Content-Type: text/html; charset=UTF-8");
include ( './common.php' );
# 인증 기능
if(empty($_SESSION["id"])) {
echo "<script>alert('정상적인 접근이 아닙니다.');location.href='index.php?page=login';</script>";
exit();
}
# CSRF Token 검증 로직
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
unset($_SESSION["csrf_token"]);
if(empty($csrf_token_session) && empty($csrf_token_param)) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
} else {
if($csrf_token_param != $csrf_token_session) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
}
}
보통 인증 기능은 각 페이지에 따로따로 넣는 것이 아니라, 공통된 페이지(common.php 등)에 한번에 적용하는 경우가 많다.
action 페이지에 권한이 없는 사용자가 접근하게 된다면 로그인 페이지로 리다이렉트되는 코드이다.
소스코드 적용 후 비회원으로 게시글 작성을 시도해본다.
게시글 작성 페이지에 접근하여 Write 를 클릭하여 게시글 작성을 시도하지만, 정상적인 접근이 아니라는 메시지와 함께 로그인 페이지로 리다이렉트 된다.
만약 비회원이 Write Page 에 접근을 못하게 조치하고 싶다면 write.php 에 인증 기능 로직을 추가해준다.
< write.php 에 인증 기능 추가 >
<?
# 인증 기능
if(empty($_SESSION["id"])) {
echo "<script>alert('정상적인 접근이 아닙니다.');location.href='index.php?page=login';</script>";
exit();
}
?>
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">Write Page</h1>
<hr>
</div>
<div class="container">
<form action="action.php" method="POST" enctype="multipart/form-data">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="title" placeholder="Title Input">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" name="password" placeholder="Password Input">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Contents</label>
<textarea class="form-control" name="content" rows="5" placeholder="Contents Input"></textarea>
</div>
<div class="form-group">
<label for="exampleInputPassword1">File</label>
<input type="file" class="form-control" name="userfile">
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customCheck1" name="secret">
<label class="custom-control-label" for="customCheck1">Secret Post</label>
</div>
<div class="text-right">
<input type="hidden" name="csrf_token" value="<?=$csrf_token?>">
<input type="hidden" name="mode" value="write">
<button type="submit" class="btn btn-outline-secondary">Write</button>
<button type="button" class="btn btn-outline-danger" onclick="history.back(-1);">Back</button>
</div>
</form>
</div>
소스코드 적용 후 비회원으로 게시글 작성 페이지에 접근 시 다음과 같이 접근이 불가한 것을 확인할 수 있다.
pingcheck 부분에는 인증 부분(회원 유무)도 중요하지만 인가 부분(관리자 여부)가 더 중요하다.
→ 관리자만 접근하는 페이지에 권한이 없는 사용자가 접근이 가능
현재 웹 사이트는 관리자 권한을 확인하는 방법은 id 뿐이다.
id 가 admin 인지 아닌지 검증하는 코드를 추가한다.
< pingcheck.php 에 인증 및 인가 검증 코드 추가 >
include_once("./common.php");
$ip = $_POST["ip"];
$page = $_SERVER['REQUEST_URI'];
if(empty($_SESSION["id"])) {
echo "<script>alert('정상적인 접근이 아닙니다.');location.href='index.php?page=login';</script>";
exit();
} else {
if($_SESSION["id"] != "admin") {
echo "<script>alert('접근 권한이 없습니다.');history.back(-1);</script>";
exit();
}
}
세션이 비어있는 경우(비회원)에는 로그인 페이지로 리다이렉트되며, 관리자가 아닌 경우에는 로직을 종료하는 코드이다.
중요한 것은 exit(); 를 꼭 사용해줘야 한다는 것이다. 간혹 exit(); 를 사용하지 않아 에러 메시지만 발생하고 로직이 여전히 진행되므로 exit(); 로 로직을 종료해줘야 한다. (실무에서 이런 경우가 다수 발생함)
→ 접근 제한 미흡
→ exit() 함수를 사용하지 않으면 웹 프록시 도구(버프스위트)로 우회가 가능하다.
버프스위트에서 pingcheck 로 요청하는 패킷을 잡고 해당 에러 메시지를 삭제 후 Intercept Off 하면
다음과 같이 접근이 가능하다.
간혹 기능이 다 실행되고 마지막에 검증하는 코드도 종종 있지만 이런 경우에는 검증이 되지 않으므로 꼭 기능 실행 전에 검증하는 코드를 작성해야 한다.
exit() 함수 적용 후에 관리자가 아닌 상태로 접근하게 되면 다음과 같이 에러메시지가 발생하면서 접근이 불가능해진다.
xmlparser.php 에도 동일하게 인증 및 인가 검증 코드를 적용해준다.
인증, 인가 검증 코드 적용 시, 기능 수행 전에 검증하도록 상단에 작성해준다.
< xmlparser.php 에 인증 및 인가 검증 코드 적용 >
<?
include_once("./common.php");
$xml = $_POST["xml"];
if(empty($_SESSION["id"])) {
echo "<script>alert('정상적인 접근이 아닙니다.');location.href='index.php?page=login';</script>";
exit();
} else {
if($_SESSION["id"] != "admin") {
echo "<script>alert('접근 권한이 없습니다.');history.back(-1);</script>";
exit();
}
}
libxml_disable_entity_loader(true);
if(!empty($xml)){
$result = simplexml_load_string($xml);
}
?>
소스코드 적용 후 xmlparser 접근 시 다음과 같이 에러 메시지가 발생한다.
비회원인 경우 다음과 같이 에러 메시지 발생 후 로그인 페이지로 리다이렉트 된다.
참고
'웹 해킹 > 웹 해킹 및 시큐어 코딩 기초' 카테고리의 다른 글
파라미터 변조 취약점 (0) | 2025.02.26 |
---|---|
파일 업로드 취약점 (0) | 2025.02.25 |
파일 다운로드 취약점 (1) | 2025.02.10 |
CSRF(Cross-Site Request Forgery) (0) | 2025.02.08 |
XSS (Cross-Site Scripting) (0) | 2025.01.24 |