F2blog XMLRPC to upload arbitrary file vulnerability-vulnerability warning-the black bar safety net

ID MYHACK58:62200819178
Type myhack58
Reporter 佚名
Modified 2008-05-28T00:00:00


By: the Maple-x[B. C. T] Site:http://www.neeao.com Date:2008-5-27

Just from the official download of the latest version: F2blog-v1. 2_build_03. 01_full

There is vulnerability file: xmlrpc.php that Effect: you can upload any file to the server. Principle: get_http_raw_post_data()is to obtain the most original of the pass over the data, is also say not because of the PHP environment of the magic is on the impact. While he was in check_user_pw the time, and not filtered, combined with the following upload do not do the suffix determines all can lead directly to upload arbitrary files to the server.

Simple analysis:

function metaWeblog_newMediaObject ($values) { //2007-02-01 add support for uploading files global $settingInfo,$DMC, $DBPrefix,$defualtcategoryid; //Here the present is to determine whether the user is logged in, but the following does not do the check, only here returns whether the user is logged in a value. $userdetail = check_user_pw ($values['username'], $values['password']);

$struct=$values['struct']; //writetofile ('text1.php', $struct['bits']); //debug only if ($struct['bits'] && $struct['name']) { $writefilecontent=base64_decode($struct['bits']); if (file_exists("attachments/{$struct['name']}")) @unlink("attachments/{$struct['name']}");

$filenum=@fopen("attachments/{$struct['name']}","wb"); if (!$ filenum) { xml_error ("Sorry, uploading file ({$struct['name']}) failed."); } flock($filenum,LOCK_EX); fwrite($filenum,$writefilecontent); //Did not determine whether the file is safe, direct writing. fclose($filenum); } $xml_content=make_xml_piece ("struct", array('url'=>"{$settingInfo['blogurl']}/attachments/{$struct['name']}")); $body_xml=xml_generate($xml_content); send_response ($body_xml); }

Would have been here are able to understand, and here again the use of the method to write it: The method defined in array:

$methodFamily=array('blogger. newPost', 'blogger. the editPost', 'blogger. getUsersBlogs', 'blogger. getUserInfo', 'blogger. deletePost', 'blogger. getTemplate', 'blogger. setTemplate', 'metaWeblog. newPost', 'metaWeblog. the editPost', 'metaWeblog. getPost', 'metaWeblog. newMediaObject', 'metaWeblog. getCategories', 'metaWeblog. getRecentPosts');

Method call:

$methodName=parse_get($rawdata, 'methodName', true); if (!@ in_array($methodName, $methodFamily)) xml_error ("Method ({$methodName}) is not availble."); $values=parse_get($rawdata, 'value');

$values=parse_walk_array($values, $methodName); //print_r($values); //For debug only //exit(); //Get default category, for those editors which don't support Categories $sql="select * from ".$ DBPrefix."categories limit 0,1"; $arr_category=$DMC->fetchArray($DMC->query($sql)); $defualtcategoryid=$arr_category[id];

$methodName=str_replace('.', '_', $methodName); call_user_func ($methodName, $values);

$rawdata of the source:

$rawdata=get_http_raw_post_data(); //writetofile ("text4.xml", $rawdata); //For debug use //$rawdata=file_get_contents("text4.xml"); //For debug use

if (!$ rawdata) die ("Sorry, don't visit this web!");

$stringType_o="i4|int|boolean|struct|string|double|base64|dateTime\. iso8601"; $stringType="(".$ stringType_o.")";

$rawdata=str_replace("\r", ", $rawdata); $rawdata=str_replace("\n", ", $rawdata); $rawdata=str_replace("\t", ", $rawdata); $rawdata=str_replace("<! [CDATA[", ", $rawdata); $rawdata=str_replace("]]>", ", $rawdata); //Stupid CDATA, I don't want it $rawdata=preg_replace("/<([^>]+?) \/>/is", '<\\1></\\1>', $rawdata); //Self-closed tags //$rawdata=convert_utf8($rawdata);

$rawdata=preg_replace_callback("/<struct>(.+?)& lt;\/struct>/is", 'filter_struct', $rawdata); //Struct can be a trouble, use this to avoid values and names being parsed


function get_http_raw_post_data () { //Get http_raw_post_data global $HTTP_RAW_POST_DATA; if (isset($HTTP_RAW_POST_DATA)) { //Good, the server supports $HTTP_RAW_POST_DATA, then return it directly return trim($HTTP_RAW_POST_DATA); } elseif (PHP_OS>="4.3.0") { //PHP 4.3.0 and higher version supports another way to get it return readfromfile( 'php://input' ); } else return false; //Sorry, no way out, or $raw data is not set at all }

Bug fixes, simple point, judge whether the user has the upload attachment permissions. Other own play. Since it costs so much, then by attach a safety point method:

function metaWeblog_newMediaObject ($values) { //2008-05-27 edit by Neeao global $settingInfo,$DMC, $DBPrefix,$defualtcategoryid; $userdetail = check_user_pw ($values['username'], $values['password']);

$records=$DMC->fetchArray($DMC->query("SELECT * FROM {$DBPrefix}logs WHERE id='{$values['postid']}'")); if ($records['id']==") xml_error ("Entry does not exist."); else { $struct=$values['struct']; //writetofile ('text1.php', $struct['bits']); //debug only if ($struct['bits'] && $struct['name']) { $writefilecontent=base64_decode($struct['bits']); if (file_exists("attachments/{$struct['name']}")) @unlink("attachments/{$struct['name']}");

$filenum=@fopen("attachments/{$struct['name']}","wb"); if (!$ filenum) { xml_error ("Sorry, uploading file ({$struct['name']}) failed."); } flock($filenum,LOCK_EX); fwrite($filenum,$writefilecontent); fclose($filenum); } $xml_content=make_xml_piece ("struct", array('url'=>"{$settingInfo['blogurl']}/attachments/{$struct['name']}")); $body_xml=xml_generate($xml_content); send_response ($body_xml); } }

Not added to the file format of the judgment, a little trouble, too lazy to write.