[모의해킹 실습] 불충분한 인가 페이지 구현 및 공격 실습

불충분한 인가

중요 기능 또는 데이터에 접근 사용자 권한에 따른 접근 통제를 두지 않은 취약점입니다. 접근 권한에 대한 인증 프로세스 올바른 접근 통제 로직이 구현되지 않아 다른 사용자의 민감한 정보나 인가되지 않은 페이지에 접근할 있습니다.

1. 공격 실습

No.

실습 위치

비고

1

http://localhost/freeboard/index

게시판 목록 기능

 2. 게시판 php 코드

<?php 
error_reporting(E_ALL);

ini_set("display_errors", 1);

  session_start();
  $session_username = $_SESSION['username'];
  if( is_null($session_username)) {
    header( 'Location: ../login.php' );
  }
  header('Content-Type: text/html; charset=utf-8'); // utf-8인코딩

  $db = new mysqli("DB주소","DB사용자ID","DB패스워드","테이블명"); 
  $db->set_charset("utf8");

  function mq($sql)
  {
    global $db;
    return $db->query($sql);
  }
?>
<!doctype html>
<head>
    <meta charset="utf-8">
    <title>HOME</title>
    <link rel="stylesheet" href="/css/loginstyle.css">
    <link rel="stylesheet" type="text/css" href="/css/style.css"/>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="/css/gallery.css">
  </head>
  <body class="loggedin">
  <!-- Nav Bar -->
    <nav class="navtop">
      <div>
        <h1>My Website</h1>
                <a href="../home"><i class="fas fa-home"></i>Home</a>
        <a href="../profile.php"><i class="fas fa-user-circle"></i>Profile</a>
        <a href="/member/logout.php"><i class="fas fa-sign-out-alt"></i>Logout</a>
      </div>
    </nav>
    <div class="container mt-3">
      <div class="row">
        <div class="col-sm-12 col-md-3 col-lg-2 p-2">
        <!-- Sidebar  -->
          <nav id="sidebar" class="border-top border-secondary">
            <div class="list-group">
              <a class="rounded-0 list-group-item list-group-item-action list-group-item-light " href="/freeboard/index">자유게시판</a>
              <a class="rounded-0 list-group-item list-group-item-action list-group-item-light " href="/login/report">버그및건의</a>
            </div>
          </nav>
        </div>
        <div class="col-sm-12 col-md-9 col-lg-10 p-2">
          <div class="content">

<div id="board_area"> 
  <h2>자유게시판</h2>
<?php
echo "<p>{$_SESSION['username']} 님 환영합니다.</p>";
?>
  <p>자유롭게 글을 쓸 수 있는 게시판입니다.</p>
     <form method ="post" action="order.php">
     <input style='float:right;' type="submit" value="선택"/>
      <select style='float:right;' name="order" >
	<option value="">정렬 방법 선택</option>
	<option value="title">제목 (가나다 순)</option>
	<option value="name">글쓴이 (가나다 순)</option>
	<option value="date">작성일 (최신 순)</option>
	<option value="hit">조회수 (높은 순)</option>
      </select>
    </form>
    <table class="table table-hover" style="border: 1px solid;">
      <thead class="thead-dark">
          <tr>
              <th scope="col" width="70">번호</th>
                <th width="500">제목</th>
                <th width="120">글쓴이</th>
                <th width="100">작성일</th>
                <th width="100">조회수</th>
            </tr>
        </thead>
	<?php
	if(isset($_GET['page'])){
              $page = $_GET['page'];
	                  
	}else{
                  $page = 1;
		              
	}
  	$sql = mq("select * from freeboard");
	$row_num = mysqli_num_rows($sql);
	$list = 10; //한 페이지에 보여줄 개수
	$block_ct = 5; //블록당 보여줄 페이지 개수

	$block_num = ceil($page/$block_ct); // 현재 페이지 블록 구하기
	$block_start = (($block_num - 1) * $block_ct) + 1; // 블록의 시작번호
	$block_end = $block_start + $block_ct - 1; //블록 마지막 번호

	$total_page = ceil($row_num / $list); // 페이징한 페이지 수 구하기
	if($block_end > $total_page) {
	    $block_end = $total_page; //만약 블록의 마지박 번호가 페이지수보다 많다면 마지박번호는 페이지 수
	}
	$total_block = ceil($total_page/$block_ct); //블럭 총 개수
	$start_num = ($page-1) * $list; //시작번호 (page-1)에서 $list를 곱한다.

	$sql2 = mq("select * from freeboard order by idx desc limit $start_num, $list");
    	
	
        // board테이블에서 idx를 기준으로 내림차순해서 5개까지 표시
          $sql3 = mq("select * from freeboard order by idx desc limit $start_num, $list"); 
            while($board = $sql3->fetch_array())
            {
              //title변수에 DB에서 가져온 title을 선택
              $title=$board["title"]; 
              if(strlen($title)>30)
              { 
                //title이 30을 넘어서면 ...표시
                $title=str_replace($board["title"],mb_substr($board["title"],0,30,"utf-8")."...",$board["title"]);
              }
        ?>
      <tbody>
        <tr>
          <td width="70"><?php echo $board['idx']; ?></td>
          <td width="500"><a href="/freeboard/read?idx=<?php echo $board["idx"];?>"><?php echo $title;?></a></td>
          <td width="120"><?php echo $board['name']?></td>
          <td width="100"><?php echo $board['date']?></td>
          <td width="100"><?php echo $board['hit']; ?></td>
        </tr>
      </tbody>
      <?php } ?>
    </table>
    <div id="page_num">	
      <ul>
	<?php
	      if($page <= 1)
	      {
		  echo "<li class='fo_re'>처음</li>";
	      }else{
		  echo "<li><a href='?page=1'>처음</a></li>";
	      }
	      if($page <= 1)
	      {

	      }
	      else{
		   $pre = $page-1;
		   echo "<li><a href='?page=$pre'>이전</a></li>";
	      }
	      for($i=$block_start; $i<=$block_end; $i++){
		  if($page == $i){
		      echo "<li class='fo_re'>[$i]</li>";
		  }else{
		      echo "<li><a href='?page=$i'>[$i]</a></li>";
		  }
	      }
	      if($page >= $total_page){
		  
	      }else{
		  $next = $page + 1;
		  echo "<li><a href='?page=$next'>다음</a></li>";
	      }
	      if($page >= $total_page){
		  echo "<li class='fo_re'>마지막</li>";
	      }else{
		  echo "<li><a href='?page=$total_page'>마지막</a><li>";
	      }
	?>
      </ul>
    </div>
    <hr>
   <body>
   <br>
    <div id="search_box">
    <form action="search.php" method="get">
      <select name="menu">
        <option value="title">제목</option>
        <option value="name">글쓴이</option>
      </select>
      <input type="text" name="search" size="40" required="required" /> <button>검색</button>
    </form>
    </div>
    <div id="write_btn">
      <a href="/freeboard/write.html" class="btn btn-outline-info float-right">글쓰기</a>
    </div>
  </div>
    <footer class="footer">
    <div class="container mt-3">
        <span class="text-muted">©2021 • ParkDohyeon</span>
        <div class="float-right small"><a href=#>개인정보취급방침</a></div>
    </div>
</footer>
<script src="/js/jquery-3.4.1.min.js"></script>
<script src="/js/bootstrap.min.js"></script>

</html>
</body>
</html>

3. 공격 실습

Step1:게시판 기능은 로그인 이후에 사용할 수 있는 기능입니다. 하지만 회원 정보 없이 URL로 직접 게시판에 접근이 가능합니다.

정상 접근 과정

login – home - freeboard

비 정상 접근 과정

freeboard/index

URL입력으로 세션 정보 없이 게시판 직접 접근

중요 기능 또는 데이터 접근 시 2차 인증 프로세스를 구현하고, 사용자 접근 통제 로직이 구현되지 않았다면 세션 관리 로직을 통해 사용자 권한을 식별하고 인가된 사용자 요청을 관리합니다. 페이지 별 권한 메트릭스를 작성하여, 페이지에 부여된 권한의 타당성을 체크 후에 권한 매트릭스를 기준으로 하여 전 페이지에서 권한 체크가 이루어지도록 구현해야 합니다.

반응형