สวัสดีครับ วันนี้เนื่องจากว่างหรือเปล่าไม่รู้เลยหาบัคเก่าๆหาอ่านเล่นๆ ไปเจอบัคในตำนานของ Wordpress นั่นคือ TimThumb.php ที่สามารถทำ Remote Code Execution ได้ครับ
อย่ากระนั้นเลย เกิดความสงสัยว่าทำไมถึงได้มีช่องโหว่ RCE ได้ที่เห็นตามเว็บว่าเจ้า TimThumb.php นี้เจอเยอะใน Plugin/Theme ต่างๆของ Wordpress ผมจึงตามหาไฟล์ที่บัคเพื่อดูและวิเคราะห์โค้ดอย่างละเอียดจึงได้คำตอบมาเขียนได้อีก Topic หนึ่ง ._.
เริ่มกันเลยดีกว่า TimThumb เป็น Plugin ในการย่อขยายรูปภาพอัตโนมัติ โดยที่ว่าเมื่อ User ทำการ Request ไปที่ Path includes/timthumb.php?src=[path ของรูปภาพ] แล้ว timthumb.php จะทำการสร้างรูปใหม่และไฟล์ cache ไว้ที่ cache/externel_[md5 ของลิงค์ src].php จากที่ดูตอนนี้น่าจะแก้หมดแล้ว ซึ่งบรรทัดที่ทำการรับค่า GET src มาก็คือบรรทัดที่ 40 เก็บไว้ในตัวแปร $src ครับ
$src = get_request ('src', '');
ตัวแปรที่เก็บชื่อไฟล์ที่ถูกสร้างใน cache อยู่ที่บรรทัด 602
$filename = 'external_' . md5 ($src);
ตัวแปรที่เก็บค่าไฟล์และที่อยู่ของไฟล์อยู่ที่บรรทัด 603
$local_filepath = DIRECTORY_CACHE . '/' . $filename . '.' . strtolower ($fileDetails['extension']);
ส่วนโค้ดที่ใช้เขียนไฟล์ลง cache อยู่ที่บรรทัด 647 เป็นต้นไปครับ โดยมีการเช็คว่ามีฟังก์ชั่น curl_init ทำงานอยู่หรือเปล่าถ้ามีให้ทำงานตั้งแต่ 647 - 673
if (function_exists ('curl_init')) {
global $fh;
$fh = fopen ($local_filepath, 'w');
$ch = curl_init ($src);
curl_setopt ($ch, CURLOPT_TIMEOUT, CURL_TIMEOUT);
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
curl_setopt ($ch, CURLOPT_URL, $src);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt ($ch, CURLOPT_HEADER, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_FILE, $fh);
curl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'curl_write');
// error so die
if (curl_exec ($ch) === FALSE) {
unlink ($local_filepath);
touch ($local_filepath);
display_error ('error reading file ' . $src . ' from remote host: ' . curl_error ($ch));
}
curl_close ($ch);
fclose ($fh);
}
จากบรรทัดที่ 651 มีการเปิดไฟล์ cache ที่จะเขียนด้วยฟังก์ชั่น fopen
$fh = fopen ($local_filepath, 'w');
แล้วใช้ curl ในการ Request ไปหาเว็บเป้าหมายที่มีโค้ดของ php shell ฝังอยู่
curl_setopt ($ch, CURLOPT_URL, $src);
จากนั้นถูกระบุไฟล์ที่จะถูกเขียนตัวแปร $local_filepath ด้วย CURLOPT_FILE ซึ่งเป็น Option ของ cURL นั่นเอง
curl_setopt ($ch, CURLOPT_FILE, $fh); //The file that the transfer should be written to. The default is STDOUT (the browser window).
บรรทัดต่อมาส่งข้อมูลที่จะเขียนลงไปในฟังก์ชั่น curl_write ที่ทำหน้าที่เขียนไฟล์ดังกล่าวด้วย CURLOPT_WRITEFUNCTION ครับ
curl_setopt ($ch, CURLOPT_WRITEFUNCTION, 'curl_write'); //The internal CURLOPT_WRITEFUNCTION will write the data to the FILE * given with this option, or to stdout if this option hasn't been set.
มาดูฟังก์ชั่น curl_write กันครับ :)
function curl_write ($handle, $data) {
global $external_data_string, $fh;
fwrite ($fh, $data);
$external_data_string .= $data;
if (strlen ($external_data_string) > MAX_FILE_SIZE) {
return 0;
} else {
return strlen ($data);
}
}
จะเห็นว่ามีการใช้ fwrite ซึ่งเป็นฟังก์ชั่นเขียนไฟล์ของ php ครับ
fwrite ($fh, $data);
แต่ถ้าออกนอกเงื่อนไขซึ่งไม่มี curl_init จะทำคำสั่งด้านหลัง else คือเขียนไฟล์ด้วยฟังก์ชั่น file_put_contents
} else {
if (!$img = file_get_contents ($src)) {
display_error ('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');
}
if (file_put_contents ($local_filepath, $img) == FALSE) {
display_error ('error writing temporary file');
}
}
ซึ่งจากโค้ดคือการอ่านไฟล์จาก URL ในตัวแปร $src มาเก็บไว้ในตัวแปร $img แล้วทำการเขียนลงใน Path ที่อยู่ในตัวแปร $local_filepath ด้วยฟังก์ชั่น file_put_contents ครับ
แต่ช่องโหว่นี้ต้อง GET Request ลิงค์ที่มี malicious code ฝังอยู่แต่เนื้อหาด้านในต้องเป็นรูปภาพเพราะ Timthumb เป็น Plugin ที่ใช้ย่อขนาดของรูปภาพ จบการชำแหละครับ ส่วนวิธีการป้องกันก็ Update ให้เป็น Version ใหม่ครับ,, ICheer_No0M
Ref : timthumb.php 1.27
Ref : Multiple Wordpress Plugin timthumb.php Vulnerabilites
Ref : TimThumb Demo: Part 2 – Images on External Websites
ไม่มีความคิดเห็น:
แสดงความคิดเห็น