Старый 24.01.2014, 12:58   #1
Boolean
 
Регистрация: 19.10.2011
Сообщений: 111
Репутация: 34
По умолчанию unset() или «вечная ссылка»

Всем привет, недавно проводил наткнулся на интересную вариацию бага с отсутствием выполнения функции unset().

Код конечно же изменен, но суть и идея сохранились.
PHP код:
<?php
[...]
function 
loadSomeSystemInfo($username) {
    return 
'something';
}
[...]
$db mysql_connect('localhost''user0''pass0');
mysql_select_db('dbdbdb'$db);
[...]
$forList = array(
    array(
'username' => 'xampp'),
    array(
'username' => 'wampp'),
    array(
'username' => 'rdot.org'),
);

//загружаем какую-то системную информацию
foreach ($forList AS &$user) {
    
$user['system_info'] = loadSomeSystemInfo($user['username']);
}


$flag true;
if (isset(
$_GET['user']) && !empty($_GET['user'])) {
    
$user $_GET['user'];
    
$sql "SELECT * FROM user_pwd WHERE `name`='" . @mysql_real_escape_string($user) . "'";
    
$sql mysql_query($sql$db);
    if (
$data mysql_fetch_assoc($sql)) {
        
$flag false;
        echo 
$data['data'];
    } else {
        echo 
"User not found!<br />\n";
    }
}


if (
$flag) {
    echo 
"Listing:<br />\n";
    foreach (
$forList AS $k => $v) {
        echo (
$k 1) . ": " $v['username'] . ", Registered at: ";
        
$sql "SELECT * FROM user_pwd WHERE `name`='{$v['username']}'";
        
$sql mysql_query($sql$db);
        
$data mysql_fetch_assoc($sql);
        echo 
"{$data['reg_date']}<br />\n";
    }
}

?>
Несмотря на наличие фильтрации, уязвимость все-таки есть. В пхп присутствует "фича" вечных ссылок, т.е. объект будет ссылаться на элемент в массиве до тех пор, пока его не ликвидируют через unset().



PoC:
Код:
details.php?user[username]=test' and false union select 1,2,user() -- a
__________________
|

Последний раз редактировалось Boolean; 28.01.2014 в 10:54..
Boolean вне форума   Ответить с цитированием
Старый 24.01.2014, 15:42   #2
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Прикольно! Интересно, а нафига там по ссылкам-то итерация шла с точки зрения кодера? Вроде ж loadSomeSystemInfo не пишет в аргумент.
Beched вне форума   Ответить с цитированием
Старый 24.01.2014, 15:53   #3
Boolean
 
Регистрация: 19.10.2011
Сообщений: 111
Репутация: 34
По умолчанию

Цитата:
Сообщение от Beched Посмотреть сообщение
Прикольно! Интересно, а нафига там по ссылкам-то итерация шла с точки зрения кодера? Вроде ж loadSomeSystemInfo не пишет в аргумент.
Итерация по ссылкам идет лишь для удобства, т.е. чтобы не обращаться к массиву по ключу, а сразу "на лету" изменять этот элемент массива.
Конечный результат одинаков.
PHP код:
function somefunc($var){
    return 
$var 2;

PHP код:
$array = [1,2,3,4];
foreach(
$array as $key => $value){
    
$array[$key] = somefunc($value);
}
var_dump($array); 
Код:
array(4) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  int(8)
}

PHP код:
$array = [1,2,3,4];
foreach(
$array AS &$value){
    
$value somefunc($value);
}
var_dump($array); 
Код:
array(4) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  &int(8)
}
По теме: в доке жирный варнинг стоит по этому поводу: http://www.php.net/manual/en/control-structures.foreach.php
__________________
|
Boolean вне форума   Ответить с цитированием
Старый 24.01.2014, 16:19   #4
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

А, тьфу, я забыл, что там присваивание ещё в коде, поэтому и ссылка.
Достаточно редкое совпадение, конечно, но можно прогрепать по движкам и эту фишку =)
Beched вне форума   Ответить с цитированием
Старый 25.01.2014, 05:35   #5
}{оттабыч
Banned
 
Регистрация: 08.10.2010
Сообщений: 188
Репутация: 53
По умолчанию

Цитата:
Несмотря на наличие фильтрации, уязвимость все-таки есть. В пхп присутствует "фича" вечных ссылок, т.е. объект будет ссылаться на элемент в массиве до тех пор, пока его не ликвидируют через unset().
объекты и ссылки разные вещи, не нужно путать. Да, для прогеров это провтык
}{оттабыч вне форума   Ответить с цитированием
Старый 25.01.2014, 06:33   #6
NameSpace
 
Регистрация: 21.12.2012
Сообщений: 146
Репутация: 52
По умолчанию

Цитата:
Сообщение от }{оттабыч Посмотреть сообщение
объекты и ссылки разные вещи, не нужно путать. Да, для прогеров это провтык
Под объектом подразумевается нечто, в данном случае переменная. Объекты (которые экземпляры классов) тут не при чем, дело только в общей области видимости.
PHP код:
$forList = array(
    
=> array('username' => 'xampp'),
    
=> array('username' => 'wampp'),
    
=> array('username' => 'rdot.org'),
);

foreach (
$forList AS &$user) {
    
$user['username'] = mysql_real_escape_string($user['username']);
}

// После выполнение $user остается ссылкой на $forList[2]

...
$user $_GET['user']; // $forList[2] = $_GET['user']
...

foreach (
$forList AS $k => $v) {
    
mysql_query("SELECT * FROM user_pwd WHERE `name`='{$v['username']}'");

Мораль сей басни такова - код рулонами не пишут.

Последний раз редактировалось NameSpace; 25.01.2014 в 06:52..
NameSpace вне форума   Ответить с цитированием
Старый 25.01.2014, 09:16   #7
}{оттабыч
Banned
 
Регистрация: 08.10.2010
Сообщений: 188
Репутация: 53
По умолчанию

Цитата:
Сообщение от NameSpace Посмотреть сообщение
Под объектом подразумевается нечто, в данном случае переменная. Объекты (которые экземпляры классов) тут не при чем, дело только в общей области видимости.
PHP код:
$forList = array(
    
=> array('username' => 'xampp'),
    
=> array('username' => 'wampp'),
    
=> array('username' => 'rdot.org'),
);

foreach (
$forList AS &$user) {
    
$user['username'] = mysql_real_escape_string($user['username']);
}

// После выполнение $user остается ссылкой на $forList[2]

...
$user $_GET['user']; // $forList[2] = $_GET['user']
...

foreach (
$forList AS $k => $v) {
    
mysql_query("SELECT * FROM user_pwd WHERE `name`='{$v['username']}'");

Мораль сей басни такова - код рулонами не пишут.
Да я понял, спс Как раз дело в ссылке (которая не удалена) и усе, область видимости это второе уже. Понятное дело она(область видимости) глобальная тут. В некотором контейнере zval с is_ref=1 в value будет наша скуля.

Последний раз редактировалось }{оттабыч; 25.01.2014 в 09:22..
}{оттабыч вне форума   Ответить с цитированием
Старый 25.01.2014, 12:16   #8
nikp
Banned
 
Регистрация: 05.07.2010
Сообщений: 201
Репутация: 183
По умолчанию

Вот еще интересная выдержка из манов.

Однако следует отметить, что ссылки в массивах являются потенциально опасными. При обычном (не по ссылке) присвоении массива, ссылки внутри этого массива сохраняются. Это также относится и к вызовам функций, когда массив передается по значению. Пример:

PHP код:
<?php
/* Присвоение скалярных переменных */
$a 1;
$b =& $a;
$c $b;
$c 7//$c не ссылка и не изменяет значений $a и $b

/* Присвоение массивов */
$arr = array(1);
$a =& $arr[0]; //$a и $arr[0] ссылаются на одно значение
$arr2 $arr//присвоение не по ссылке!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* Содержимое $arr изменилось, хотя было присвоено не по ссылке! */
?>
Иными словами, поведение отдельных элементов массива не зависит от типа присвоения этого массива.
nikp вне форума   Ответить с цитированием
Старый 31.01.2014, 13:07   #9
b10s
 
Регистрация: 10.01.2014
Сообщений: 6
Репутация: 1
По умолчанию

Цитата:
Сообщение от nikp Посмотреть сообщение
Вот еще интересная выдержка из манов.

Однако следует отметить, что ссылки в массивах являются потенциально опасными. При обычном (не по ссылке) присвоении массива, ссылки внутри этого массива сохраняются. Это также относится и к вызовам функций, когда массив передается по значению. Пример:

PHP код:
<?php
/* Присвоение скалярных переменных */
$a 1;
$b =& $a;
$c $b;
$c 7//$c не ссылка и не изменяет значений $a и $b

/* Присвоение массивов */
$arr = array(1);
$a =& $arr[0]; //$a и $arr[0] ссылаются на одно значение
$arr2 $arr//присвоение не по ссылке!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* Содержимое $arr изменилось, хотя было присвоено не по ссылке! */
?>
Иными словами, поведение отдельных элементов массива не зависит от типа присвоения этого массива.
Витиевато, но наталкивает на мысли.
Вот такой простой эксперимент показывает, что после того как мы получаем ссылку на элемент массива, сам этот элемент превращается в сырую ссылку.

PHP код:
$arr = array(1);
var_dump($arr);
$a = &$arr[0];
var_dump($arr);
unset(
$a);
var_dump($arr); 
Размножая ссылки на элемент массива

PHP код:
$arr = array(1);
var_dump($arr);
$a = &$arr[0];
var_dump($arr);
$x=& $a;
unset(
$a);
var_dump($arr); 
я начинаю догадываться, что механизм следующий: если мы создаем ссылку на объект, то этот объект переносится в другое место памяти, а по прежнему месту кладется ссылка. Вот еще немножко игры со ссылками:

PHP код:
$arr = array(1);
var_dump($arr);
$a = &$arr[0];
var_dump($arr);
$x=& $a;
unset(
$arr);
$b[0]=& $x;
var_dump($b);
$b[0]=123;
var_dump($a); 
Так же возникает мысль, что оператор $ разыменовывает автоматом и мы не можем пощупать живой адрес.

Тогда всё становится прозрачно:
- присваивая через =$переменная мы автоматом разыменовываем, и получаем значение
- присваивая какую-либо сложную структуру целиком мы сохраняем все ссылки внутри свойств этой структуры
- создавая ссылку на объект, мы получаем вместо этого объекта ссылку! (в чем сложно убедиться, ибо $ разыменовывает автоматом, но пример на массивах выше показателен)


upd:

а вот эту потерю ссылку в массиве на переменную я объяснить не могу:

PHP код:
$z=22;
$x=44;
$a[0]=& $x;
var_dump($a);
$x=& $z;
// $x=$z; //то ссылку в массиве не теряем
$x=77;
var_dump($a); 

Последний раз редактировалось b10s; 31.01.2014 в 15:12..
b10s вне форума   Ответить с цитированием
Старый 31.01.2014, 17:01   #10
nikp
Banned
 
Регистрация: 05.07.2010
Сообщений: 201
Репутация: 183
По умолчанию

Продолжаем тесты
PHP код:
$a=1;
$b=&$a;
// $b - ссылка, но и $a превратилась в ссылку, т.е. обе ссылаются на некоторую переменную $hidden
$c=&$b;
// все три переменные ссылаются на $hidden 
теперь с массивом
PHP код:
$a=array(1);
$b=&$a[0];
$c=&$b;
// $b и $c ссылаются на $a[0], $a[0] не превратился в ссылку, т.е. $hidden не задействована. 
дальше
PHP код:
$b=2;
$a=array(1);
$a[0]=&$b;
$c=&$b;
// $a[0], $b, $c - все ссылаются на $hidden 
но если массив инициализирован раньше переменной
PHP код:
$a=array(1);
$b=2;
$a[0]=&$b;
$c=&$b;
// аномальное поведение - $a[0] не превратился в ссылку, а остался значением
// т.е. в этом случае $a[0]=&$b эквивалентно $b=&$a[0], $a[0] остается значением, а $b становится ссылкой. 
два массива
PHP код:
$a = array(1);
$b = array(2);
$c=3;
$a[0]=&$c;    // $a[0] остался значением, $c стала ссылкой на $a[0]
$b[0]=&$c;    // $b[0] стал ссылкой на $a[0]
$d=&$c;        // $d ссылка на $a[0] 
Интересно, кто-нибудь представляет полную картину со сылками?
Надо бы потестить поведение при передаче в функцию массива со ссылками.

Последний раз редактировалось nikp; 31.01.2014 в 17:09..
nikp вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot