สวัสดีครับ วันนี้เนื่องจากว่างหรือเปล่าไม่รู้เลยหาบัคเก่าๆหาอ่านเล่นๆ ไปเจอบัคในตำนานของ 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
ไม่มีความคิดเห็น:
แสดงความคิดเห็น