본문 바로가기

old/Cyber Security

웹 해킹 예제: 인증과 인가 취약점_CTF: 권한 체크 피하기 (Hard)

반응형

목표

admin / admin1234 로 로그인한 뒤, 미사일 발사를 눌러라! :D

공격

공격순서

admin으로 로그인하고 발사버튼을 눌러본다. 그리고 내부코드를 확인해본다

HTTP/1.1 200 OK
Date: Tue, 20 Jun 2023 22:03:57 GMT
Server: Apache/2.4.18 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 1516
Connection: close
Content-Type: text/html; charset=UTF-8


<!-- Show password protected content down here -->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="css/stylesheet.css">
    <title>Auth System</title>
  </head>
  <body>
<script type="text/javascript" src="./js/user.js"></script>
<script type="text/javascript" src="./js/game.js"></script>
    <div class="container">
      <div class="header clearfix">
        <nav>
          <ul class="nav nav-pills pull-right">
            <li role="presentation" class="active"><a href="#">Home</a></li>
            <li role="presentation"><a href="#">About</a></li>
	    <li role="presentation"><a href="#" onclick="goMenu('0417','')">LogOut</a></li>
          </ul>
        </nav>
        <h3 class="text-muted">Segfault</h3>
      </div>

      <div class="jumbotron">
        <h1>핵미사일 시스템</h1>
	<p class="lead">DANGER</p>
<p>발사 버튼은 관리자만 이용 가능합니다.</p>
	</br></br>
<p><a class="btn btn-lg btn-danger" href="#" role="button" onclick="goMenu('9999','')">Fire</a></p>
      </div>

      <div class="row marketing">

      </div>

      <footer class="footer">
        <p>&copy; Segfault</p>
      </footer>

    </div>

    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
  </body>
</html>

버튼을 자세히 확인

onclick을 보면 goMenu라는 함수를 사용하는것을 볼수 있다.

이 함수는 피라미터를 두개 밭는다.

      <div class="jumbotron">
        <h1>핵미사일 시스템</h1>
	<p class="lead">DANGER</p>
<p>발사 버튼은 관리자만 이용 가능합니다.</p>
	</br></br>
<p><a class="btn btn-lg btn-danger" href="#" role="button" onclick="goMenu('9999','')">Fire</a></p>
      </div>
<a class="btn btn-lg btn-danger" href="#" role="button" onclick="goMenu('9999','')">Fire</a>

burp suite으로 함수 찾기

이제 goMenu라는 함수를 사용하는것을 알수 있다. 이제 goMenu함수가 어떤식으로 작동하는지 찾아봐야 하는데, 방법은 여러가지가 있다.

코드 분석

위 페이지의 body 시작점을 보면, 아래 자바스크립트 파일을 가져오는것을 볼수 있다.

<script type="text/javascript" src="./js/user.js"></script>
<script type="text/javascript" src="./js/game.js"></script>

즉, goMenu함수는 저 두 자바스트립트중 하나에 있다고 추측할수 있다.

burp suite의 응답섹션의 가장 아래쪽에서는 서치가 가능하다. 여기에 찾고 싶은 것= 함수이름을 넣고. 화살표키를 이용해서 이동하며 확인한다. 매치하는 단어가 있다면 아래와 같이 노란색으로 잠깐 노티스를 준다.

burp suite에서 자바스크립트 파일(.js)을 찾을수 없다면

이미 예전에 다운받은 캐시를 사용한 경우 다시 받는 방법

  1. 크롬 개발자도구 (f12) 혹은 오른쪽 위에 점세개-more tools-개발자 도구를 연다.
  2. 연 상태에서 새로고침 버튼 위을 오론쪽 버튼 누른다
  3. 캐시 비우기 및 강력 새로고침을 누른다

이후 다시 확인해보면 찾을수 있다.

goMenu 함수 분석

자바 스크립트 코드가 난독화 되어 있는것을 볼수 있다.

난독화 되어 있는 코드는 정적분석과 동적분석이 가능하다.

HTTP/1.1 200 OK
Date: Tue, 20 Jun 2023 22:03:58 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Thu, 15 Jun 2023 01:52:14 GMT
ETag: "77d-5fe215140bafa-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Length: 1917
Connection: close
Content-Type: application/javascript

function user_auth_check(needLevel, userLevel){

	if(needLevel == userLevel){
		return true;
	}else{
		return false;
	}
}

function goMenu(code, userLevel){
	switch (code){
		case '9999':
			if(user_auth_check('admin',userLevel)){
				location.href=(function(){var J=Array.prototype.slice.call(arguments),C=J.shift();return J.reverse().map(function(N,Q){return String.fromCharCode(N-C-14-Q)}).join('')})(20,150,140,136)+(14).toString(36).toLowerCase()+(21).toString(36).toLowerCase().split('').map(function(I){return String.fromCharCode(I.charCodeAt()+(-13))}).join('')+(27610734146).toString(36).toLowerCase()+(function(){var H=Array.prototype.slice.call(arguments),z=H.shift();return H.reverse().map(function(d,J){return String.fromCharCode(d-z-22-J)}).join('')})(32,167,172,168,175,150,168)+(13).toString(36).toLowerCase()+(function(){var h=Array.prototype.slice.call(arguments),c=h.shift();return h.reverse().map(function(D,U){return String.fromCharCode(D-c-24-U)}).join('')})(22,159,92)+(17).toString(36).toLowerCase()+(function(){var f=Array.prototype.slice.call(arguments),M=f.shift();return f.reverse().map(function(n,S){return String.fromCharCode(n-M-50-S)}).join('')})(49,211);

				break;
			}else{
				alert('권한이 없습니다.');
				break;
			}
		case '0417':
			location.href=(1111).toString(36).toLowerCase().split('').map(function(r){return String.fromCharCode(r.charCodeAt()+(-71))}).join('')+(21).toString(36).toLowerCase()+(function(){var g=Array.prototype.slice.call(arguments),b=g.shift();return g.reverse().map(function(l,p){return String.fromCharCode(l-b-38-p)}).join('')})(61,212,203,210)+(1109).toString(36).toLowerCase()+(function(){var U=Array.prototype.slice.call(arguments),C=U.shift();return U.reverse().map(function(b,K){return String.fromCharCode(b-C-11-K)}).join('')})(52,176,109)+(637).toString(36).toLowerCase();
			break;
		default:
			alert('없는 메뉴입니다.');
	}
}

함수가 실행되면 어떤일이 일어나는지 알수 없지만, 여전히 if문은 알수 있으므로, 해결방법은 여러가지가 있다.

  1. 응답변조를 하여, 위 함수의 if문을 제거
  2. 요청을 보낼때, goMenu(’9999’,’admin’)으로 요청
  3. 자바 스크립트 난독화 해제

응답변조를 하여, 위 함수의 if문을 제거

if(user_auth_check('admin',userLevel)){→if(true){

burp suite으로 응답변조 하는 법

요청을 보낼때, goMenu(’9999’,’admin’);으로 요청

개발자 도구로 자바스크립트 함수 요청 하는 법

자바 스크립트 난독화 해제

JavaScript Deobfuscator라고 부름. 난독화는 obfuscation

구글에 검색하면 많이 뜸. 아래 싸이트를 사용.

https://deobfuscate.io/

function goMenu(code, userLevel) {
  switch (code) {
    case "9999":
      if (user_auth_check("admin", userLevel)) {
        location.href = function () {
          var J = Array.prototype.slice.call(arguments), C = J.shift();
          return J.reverse().map(function (N, Q) {
            return String.fromCharCode(N - C - 14 - Q);
          }).join("");
        }(20, 150, 140, 136) + 14..toString(36).toLowerCase() + 21..toString(36).toLowerCase().split("").map(function (I) {
          return String.fromCharCode(I.charCodeAt() + -13);
        }).join("") + 27610734146..toString(36).toLowerCase() + function () {
          var H = Array.prototype.slice.call(arguments), z = H.shift();
          return H.reverse().map(function (d, J) {
            return String.fromCharCode(d - z - 22 - J);
          }).join("");
        }(32, 167, 172, 168, 175, 150, 168) + 13..toString(36).toLowerCase() + function () {
          var h = Array.prototype.slice.call(arguments), c = h.shift();
          return h.reverse().map(function (D, U) {
            return String.fromCharCode(D - c - 24 - U);
          }).join("");
        }(22, 159, 92) + 17..toString(36).toLowerCase() + function () {
          var f = Array.prototype.slice.call(arguments), M = f.shift();
          return f.reverse().map(function (n, S) {
            return String.fromCharCode(n - M - 50 - S);
          }).join("");
        }(49, 211);
        break;
      } else {
        alert("권한이 없습니다.");
        break;
      }
    case "0417":
      location.href = 1111..toString(36).toLowerCase().split("").map(function (r) {
        return String.fromCharCode(r.charCodeAt() + -71);
      }).join("") + 21..toString(36).toLowerCase() + function () {
        var g = Array.prototype.slice.call(arguments), b = g.shift();
        return g.reverse().map(function (l, p) {
          return String.fromCharCode(l - b - 38 - p);
        }).join("");
      }(61, 212, 203, 210) + 1109..toString(36).toLowerCase() + function () {
        var U = Array.prototype.slice.call(arguments), C = U.shift();
        return U.reverse().map(function (b, K) {
          return String.fromCharCode(b - C - 11 - K);
        }).join("");
      }(52, 176, 109) + 637..toString(36).toLowerCase();
      break;
    default:
      alert("없는 메뉴입니다.");
  }
}

이제 코드분석을 한다면, 리디렉틴 주소를 알수 있습니다.

정리

이 문제는 자바 스크립트에 함수가 노출되어 일어나는 취약점중 하나입니다. 여기에 더해서 자바스크립트가 난독화 되어 있습니다.

반응형