Виявлення дефектів коду типу «Expression Issues» (CWE-569)

Цією статтею ми продовжуємо серію оглядів, присвячених виявлення вразливостей в open-source проектах з допомогою статичного аналізатора коду AppChecker.
В рамках цієї серії розглядаються найбільш часто зустрічаються дефекти в програмному коді, які можуть призвести до серйозних вразливостей. У цій статті ми зупинимося на широкому класі дефектів типу "Expression Issues".

У міжнародній класифікації CWE даний тип дефектів відомий як CWE-569: Expression Issues. До нього відносяться різні помилки в логічних виразах в коді програми. Приватним випадком дефект такого класу є дефект «замість Присвоювання порівняння».

замість Присвоювання порівняння (CWE-481: Assigning instead of Comparing) – дефект, як видно з назви, полягає в тому, що замість оператора порівняння в коді програми використовується оператор присвоювання. Подібна помилка в коді веде до некоректної роботи програми і може призвести до серйозної проломи в безпеці.
Страх вчинення подібних помилок довів того, що з'явилася так звана нотація Йоди (Yoda notation), що вимагає написанні константи або виклику функції ліворуч від оператора порівняння: «7 == j» замість звичного «j == 7». Давайте подивимося код. Наприклад, такий:
pswd=GetText();
if (consthash=hash(pswd)); //авторизувати користувача

Припустимо, що pswd – змінна, в якій зберігається введений користувачем пароль. В умовному операторі повинно відбуватися порівняння хеша від пароля з наперед заданим значенням. Якщо ці значення збігаються, вважається, що пароль збігся, і користувач отримує доступ. Однак у цьому прикладі замість оператора порівняння «==» варто оператор присвоювання «=». У цьому випадку змінної consthash присвоїти значення hash(pswd), і оскільки ця операція виконана успішно, програма вважає, що умова виконується, що, в свою чергу, призведе до авторизації користувача, незалежно від введеного їм пароля.
Здавалося б, що цей приклад досить штучний і навряд чи може зустрітися в серйозних програмних продуктах. Однак, аналіз opensource проектів показав, що цей дефект зустрічається досить часто. Зазвичай такі дефекти виникають через неуважність розробника. Подібні дефекти можна виявляти за допомогою сигнатурному-евристичного аналізу.
Логічно припустити, що існує і зворотний дефект: порівняння замість присвоювання. Дійсно, класифікація CWE визначає цей тип дефектів, як CWE-482: Comparing instead of Assigning.
Далі наведемо приклад реального коду, в якому, навпаки, замість операції присвоювання використовується операція порівняння.
if ($mValueCount == floor($mValueCount)) {
...
} else { 
$mValueCount == floor($mValueCount);
... 
}

Як видно, помилково програміста вираження в умови і тілі умовного оператора ідентичні, хоча в другому випадку явно повинен бути оператор присвоювання. Цей фрагмент коду взято з бібліотеки для роботи з документами з допомогою PHP – PHPExcel версії 1.8.1. Ми повідомили розробників про виявлений за допомогою AppChecker дефект, і вже випущений патч, в якому цей дефект був виправлений (https://github.com/PHPOffice/PHPExcel/pull/710/files).
Ще один приклад такого типу дефектів був знайдений у бібліотеці для роботи з MP3, яка входить до складу деяких CMS, зокрема wordpress і написаною на мові PHP – getID3-1.9.10:
if (ord($frame_ownerid) === 0) {
$frame_ownerid == ";
}

Як видно з цього фрагмента коду в тілі умовного оператора відбувається порівняння, хоча за логікою має бути присвоювання. Ми повідомили розробників про цей дефект, і вони оперативно цей дефект виправили (https://github.com/JamesHeinrich/getID3/pull/57/files).
Тим не менш, клас «Дефекти в виразах» не обмежується цими двома дефектами. Іншим прикладом може бути дефект «Вираз завжди вірно» (CWE-571: Expression is always true) і «Вираз завжди хибним» (CWE-570: Expression is always false). Як очевидно з назви, ці дефекти мають на увазі написання умов в умовному операторі, яке буде завжди вірно/завжди хибно, що в свою чергу означає, що в умовному операторі в даній ділянці коду немає ніякої потреби.
В якості прикладу розглянемо фрагмент коду CMS з відкритим вихідним кодом Chamilo LMS 1.10.4, написаної на мові PHP:
if ($row['item_type'] != 'dokeos_chapter' || $row['item_type'] != 'dokeos_module') {

Вираз в умовному операторі завжди вірно, оскільки для нього необхідно, щоб одне і те ж значення 'item_type' було або не одно 'dokeos_chapter', або не одно 'dokeos_module'. Таким чином, єдиним варіантом, при якому цей вираз буде хибним – коли 'item_type' одночасно дорівнює обом, в загальному випадку, різним значенням. Розробники були повідомлені про дефект і оперативно його виправили (https://github.com/chamilo/chamilo-lms/pull/1109/files). Як виявилося, у вираженні повинен стояти оператор «&&» замість «||».
В якості зворотного прикладу, розглянемо платформу для електронної комерції з відкритим кодом OpenCart 2.2.0.0:
if ($chr == 252 && $chr == 253) {

Очевидно, що $chr не може бути одночасно дорівнює 252 і 253. Цей дефект також розробники усунулиhttps://github.com/opencart/opencart/pull/4231/files). Як виявилося, у вираженні повинен стояти оператор «||» замість «&&».
Так само до дефектів виду «Expression Issues» можна віднести випадки, коли обидві частини бінарного вираження ідентичні (в окремому випадку це призводить до самоприсваиванию). Розглянемо наступний фрагмент коду на Java:
if (s2.getClass() != s2.getClass()) return false;

Як видно з цього фрагмента коду, s2.getClass() порівнюється сам з собою, в результаті чого умова завжди буде хибним. Найімовірніше це просто помилка програміста, але випадок далеко не штучний. Цей приклад взятий з google sageTV – кроссплатформної системи управління медіа-даними. Розробники були повідомлені про це дефект і оперативно його виправили (https://github.com/google/sagetv/commit/93144762681a5f441ad011564ff8309095d9ca31).
Очевидно, що такі дефекти також не залежать від мови програмування. За допомогою AppChecker такі дефекти виявляються для всіх підтримуваних мов.
Наступний приклад на мові PHP взято з OpenEMR-4.2.1:
if ( !empty($obx24) || !empty($obx24) || !empty($obx25) )

Як видно з цього фрагмента коду, значення $obx24 перевіряється двічі, хоча за логікою у першому випадку повинно бути $obx23. Подібна неуважність розробника може призвести до серйозних проблем у роботі програми. З цим згодні і розробники OpenEMR – вони оперативно виправили цей дефект, коли ми про нього повідомилиhttps://github.com/openemr/openemr/pull/179).
Подібні дефекти можуть залишатися непоміченими дуже довго, але програма при цьому буде працювати некоректно, а в деяких випадках, як ми вже з'ясували, і зовсім може призвести до вразливостей безпеки. Варто відзначити, що дефект є логічним, а тому незалежним від мови програмування.
У цій статті були розглянуті дефекти типу «Expression Issues». Незважаючи на простоту і уявну банальність такого роду дефектів, вони зустрічаються досить часто, як в open-source, так і в комерційних проектах.
PS>
Безкоштовну версію AppChecker можна завантажити з нашого сайту: https://file.cnpo.ru/index.php/s/o1cLkNrUX4plHMV
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.