[Writeup] [OverTheWire] [Natas] Level 11

Standard

Lời nói đầu

Nội dung chính

18-08-2013 03-09-57

Xem source:

<?

$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);

?>

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

?>

Ok, chúng ta cần có $data[“showpassword”] == “yes”.

Trước đó, $data được lấy giá trị thông qua hàm loadData():

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;
}

Hiểu tổng quát, $data được lấy từ biến data của cookie (không có thì lấy từ biến mặc định), với các thao tác xử lý lần lượt là:

base64_decode → xor_encrypt → json_decode

Quá trình này dễ thấy là đối xứng với các thao tác trong hàm saveData():

json_encode → xor_encrypt → base64_encode

Do json_encode, json_decode, base64_encode, base64_decode là các hàm có sẵn của PHP, nên cái ta cần bây giờ là hiểu được hàm xor_encrypt.

Nhưng… khoan đã, nãy giờ chúng ta cứ lan man về vấn đề mã hóa cookie, vậy nó có ý nghĩa gì đối với task này? emo_popo_angry

Hãy nhớ lại rằng, chúng ta phải có $data[“showpassword”] == “yes”, nhưng biến showpassword được mặc định là “no” (trong khai báo $defaultdata), còn cái mà chúng ta có thể thay đổi chỉ là mỗi bgcolor. Vậy thì chỉ còn cách đọc hiểu cơ chế xử lý cookie của task, và chỉnh sửa nó thủ công mà thôi.

Trở về với hàm xor_encrypt:

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;
}

Rất dễ hiểu, là phép XOR với một dãy byte. Và do biến $key đã bị ẩn, nên ta cần tìm nó. Tìm bằng cách nào?

Chúng ta có input, dựa trên $data = $defaultdata. Chúng ta cũng có output, dựa trên giá trị cookie. Tóm tắt lại một chút:

$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
cookie['data'] = ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D
saveData() = setcookie("data", base64_encode(xor_encrypt(json_encode($d))));

Thực thi câu lệnh PHP sau để tìm được input của hàm xor_encrypt:

echo json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
{"showpassword":"no","bgcolor":"#ffffff"}

Tương tự như vậy, thực thi câu lệnh PHP sau để xác định output của hàm xor_encrypt:

echo base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=');

Ra xấu quá emo_popo_beat_brickThôi kệ nó đi >.<

Như vậy, ta đã có input và ouput. Kết hợp với tính chất kinh điển của phép toán XOR (mà mình đã từng nhắc đến trong một writeup trước đây), chúng ta coi như có đủ dữ kiện cần thiết. Đoạn code dưới đây sẽ cho ta biết các byte lần lượt được dùng để XOR input thành output là gì:

import base64
plain = '{"showpassword":"no","bgcolor":"#ffffff"}'
xored = base64.b64decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=')

for i in range(len(xored)):
	print hex(ord(xored[i]) ^ ord(plain[i]))
0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
0x38
0x4a
0x71
0x77
...

Dễ thấy $key = ‘\x71\x77\x38\x4a’. Giờ thì ta đã có thể thay đổi giá trị cookie theo ý muốn được rồi emo_popo_beauty

Đoạn code sau sẽ sinh cho ta một cookie với biến data[“showpassword”] = “yes”:

import base64
def xor(plain):
	xor_key = '\x71\x77\x38\x4a'
	encoded = ''
	for i in range(len(plain)):
		encoded += chr(ord(xor_key[i % len(xor_key)]) ^ ord(plain[i]))

	return encoded

print base64.b64encode(xor('{"showpassword":"yes","bgcolor":"#ffffff"}'))
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK

Thay thế cookie bằng kết quả vừa thu được:

The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

natas12:EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

One thought on “[Writeup] [OverTheWire] [Natas] Level 11

  1. Pingback: [Writeup] [OverTheWire] [Natas] Level 12, Level 13 | yeuchimse

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s