Username: natas11
URL: http://natas11.natas.labs.overthewire.org
접속했을 때 화면:

쿠키값이 XOR 암호화에 의해 보호된다고 한다.
입력받은 값에 따라 백그라운드 색 바뀐다. bgcolor라는 파라미터에 입력한 색 코드가 붙는다. 색이 예뻐졌다!

소스 코드를 보면,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
<?
$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>
|
cs |
step1) 코드 해석해서 풀이 생각하기~
꽤 까다롭다. (거의 두 달만에 올리는데... 한달은 바빠서 문제 구경도 못했고 한달은 틈틈이 생각해봤는데...어려웠다...ㅜ)
핵심은 58~60번째 줄이다. $data 배열의 "showpassword"의 값이 "yes"이면 패스워드를 출력한다.
이 $data는 38번째 줄에서
loadData함수에 $defaultdata를 넣은 값임을 알 수 있다.
$defaultdata는 4번째 줄에서
array( "showpassword"=>"no", "bgcolor"=>"#ffffff");이고, (이 showpassword의 값을 yes로 바꿔야할 것이다)
loadData함수는 19~32번째 줄에서
base64디코딩 > XOR암호화 > json디코딩 과정을 거치는 복호화 함수이다.
즉, 현재 웹 페이지 data쿠키의 값을 loadData를 통해 복호화하였을 때 "showpassword"의 값이 "no"이므로 패스워드가 출력되지 않는 상태이다.
따라서 array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");를 json인코딩 > XOR암호화 > base64인코딩 순으로 암호화한 값을 data쿠키로 변조하면 서버에서 패스워드를 출력해줄 것이다.
step2) XOR 키 구하기~
이제 암호화만 하면 되는데, json인코딩이나 base64인코딩은 문제 없지만 XOR암호화를 하려면 키가 필요하다.
6~17번 줄이 XOR 암호화 코드인데, 키가 가려져있다.
키를 구하기 위해서는 XOR 알고리즘을 알고 있어야 한다.
XOR연산은 두 개의 입력이 다를 때에만 참(True)을 반환하고, 두 입력이 같을 때에는 거짓(False)을 반환한다.
0^0=0
0^1=1
1^0=1
1^1=0
대수적으로 설명하면 이항 연산으로, 닫혀있는 데다 교환법칙/결합법칙이 성립하고, 항등원/역원이 존재한다.
따라서 XOR연산으로 아벨군도 만들 수 있다(아벨군 진짜 오랜만에 보네 좀 반갑다...)
즉 A^B=C 에 대하여 양변에 A를 XOR연산하면 A^A^B=A^C이 되고, A^A는 0이므로 0^B=A^C가 되어 B=A^C가 된다.
결론은,
A^B=C에 대하여 B=A^C이 성립한다는 것이다.
A가 XOR암호화 전 데이터, B가 XOR 키, C가 XOR 암호화 후 데이터라고 생각하면
XOR 암호화 전 데이터와 암호화 후 데이터를 XOR연산하면 키가 나온다.
따라서
array( "showpassword"=>"no", "bgcolor"=>"#ffffff")를 json인코딩한 값과
data 쿠키의 값을 base64디코딩한 값을
XOR연산해서 키를 구하자.
현재 data 쿠키의 값은 "MGw7JCQ5OC04PT8jOSpqdmkgJ25nbCorKCEkIzlscm5oKC4qLSgubjY%3D" 이다.
%3D는 url인코딩된 것으로, "="을 뜻한다.

이 data 쿠키값과 array( "showpassword"=>"no", "bgcolor"=>"#ffffff")를 이용하여 다음과 같이 XOR키를 구하는 코드를 작성했다.

XOR 연산을 하려면 $base64_decode_data와 $json_encode_defaultdata의 길이가 동일해야 한다. 따라서 두 문자열 중 길이가 더 짧은 쪽으로 맞춰준 후 연산을 해야 한다.

step3) 패스워드 구하기~
XOR키가 "KNHL"임을 알았으니 이제 array( "showpassword"=>"yes", "bgcolor"=>"#ffffff")를 차례로
json인코딩 > XOR암호화 > base64인코딩하자.


이제 이걸 패스워드...가 아니라 data 쿠키값으로 변조하면 진짜 패스워드가 나온다.

'Wargame > natas' 카테고리의 다른 글
Natas Level 13 풀이 (0) | 2023.07.22 |
---|---|
Natas Level 12 풀이 (0) | 2023.07.15 |
Natas Level 10 풀이 (0) | 2023.05.09 |
Natas Level 9 풀이 (0) | 2023.05.04 |
Natas Level 8 풀이 (0) | 2023.04.27 |