해킹&보안/웹해킹

[웹 해킹 : 나타스(Natas 워게임] Level 10 -> 11(웹 해킹 / 보안)

yamaeking 2025. 4. 7. 11:11

Natas wargame Level 10 -> 11 로그인 정보와 URL 은 아래와 같다.

 

OverTheWire

We're hackers, and we are good-looking. We are the 1%. <!-- Please read and accept the Rules! --> Username: natas1 URL: http://natas1.natas.labs.overthewire.org

overthewire.org

 

 

1. 문제 풀이

 > Natas URL로 접속하면 아래 화면이 나온다

 

> 쿠키는 XOR 암호화 되어 있다고 하며, Background color 에 이것저것 넣어서 setColor 해보면 바탕 색깔이 바뀐다. view source를 눌러보자.

 

<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas11", "pass": "<censored>" };</script></head>
<?

$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");

function xor_encrypt($in) {
    $key = '<censored>';
    $text = $in;
    $outText = '';

    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }

    return $outText;
}

function loadData($def) {
    global $_COOKIE;
    $mydata = $def;
    if(array_key_exists("data", $_COOKIE)) {
    $tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
    if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
        if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
        $mydata['showpassword'] = $tempdata['showpassword'];
        $mydata['bgcolor'] = $tempdata['bgcolor'];
        }
    }
    }
    return $mydata;
}

function saveData($d) {
    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

$data = loadData($defaultdata);

if(array_key_exists("bgcolor",$_REQUEST)) {
    if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
        $data['bgcolor'] = $_REQUEST['bgcolor'];
    }
}

saveData($data);



?>

<h1>natas11</h1>
<div id="content">
<body style="background: <?=$data['bgcolor']?>;">
Cookies are protected with XOR encryption<br/><br/>

<?
if($data["showpassword"] == "yes") {
    print "The password for natas12 is <censored><br>";
}

?>

<form>
Background color: <input name=bgcolor value="<?=$data['bgcolor']?>">
<input type=submit value="Set color">
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

 

 

위 코드에서 입력값을 key값과 XOR 연산을 하여 암호화 한 뒤 return 하고 있다. 그리고 key 값은 censored되 어있어서 안 보이는데, 이걸 찾아야 한다!

 

 

-> saveData는 인자로 받은 값을 json_encode 하고, 이를 xor_encrypt를 하고 , 다시 base64로 인코딩하여 data라는 이름의 쿠키로 저장을 하고 있다.

 

> data라는 이름의 쿠키가 있으면, 이를 base64로 디코딩하고 , xor_encrypt 를 통해 다시 복호화하고(XOR는 암호화 할 때나 복호화 할 때나 프로세스가 똑같음.) , 그리고 이를 다시 json_decode 를 하고 있다.

 

 

그리고 html 이 body 에 있는 코드를 보면 ["showpassword"] == "yes" 라면 비밀번호를 보여주는데 이 부분이 핵심이라고 볼 수 있겠다.


data인 쿠키값을 변조해서 showpassword를 yes로 바꾸어 전달한다면 비밀번호를 얻을 수 있다라는 것이다. 쿠키값은 F12 -> Application -> Cookies 에서 확인할 수 있다.  ( HmYkBwozJw4WNyAAFyB1VUcqOE1JZjUIBis7ABdmbU1GJTUMASExTRg%3D )

 

 

우선 키값이 뭔지 아래의 php code 를 실행해보자. (아래 드래그 한 부분에는 쿠키에서 확인한 값을 넣어야 한다!)

<?php
function xor_encrypt() {
    $defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
    $text = base64_decode("HmYkBwozJw4WNyAAFyB1VUcqOE1JZjUIBis7ABdmbU1GIjEJAyIxTRg%3D");
    $outText = json_encode($defaultdata);
    $key = '';

    for($i=0;$i<strlen($text);$i++) {
    $key .= $outText[$i] ^ $text[$i % strlen($text)];
    }

    return $key;
}

echo "key : ". xor_encrypt();
?>

 

 

 구한 쿠키값을 base64로 디코딩하고, outText는 json_encode 한다.

그리고 outText의 문자열과 $text의 문자열을 순회하면서 하나하나 XOR 연산을 해주게 되면 원래의 키를 알 수가 있는데, 이는 XOR 특성상   평문 XOR 키  = 암호문,   이라고 한다면 암호문 XOR 평문 = 키 가 나오게 되기 때문이다. 

 

  • 암호문 XOR 평문 = key
  • 평문 $outText와 암호문 $text를 문자 단위로 XOR해서 key 생성

 

 

키값은 반복되는 문자인 " eDWo" 이라고 볼 수 있으며, 그럼 이 키를 가지고 "showpassword" = "yes" 일 때의 쿠키값을 구해보도록 하자.

 

<?php
 function xor_encrypt() {
    $defaultdata = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
    $text = json_encode($defaultdata);
    $outText = '';
    $key = 'eDWo';

    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }

    return base64_encode($outText);
}

echo  xor_encrypt();
?>

 

 

 'showpassword' = "yes"일 때의 쿠키값은 HmYkBwozJw4WNyAAFyB1VUc9MhxHaHUNAic4Awo2dVVHZzEJAyIxCUc5 라고 볼 수 있다. 자 그럼 이 값을 쿠키에 덮어씌우고 난 뒤에 새로고침을 해보면 비밀번호를 얻을 수 있다

( yZdkjAYZRd3R7tq7T5kXMjMJlOIkzDeB  )

 

2. 요약

☞ 암호화 된 쿠키를 복호화 시켜서 키를 찾아낸 뒤 쿠키값을 변조하여 비밀번호를 획득한다