На 20 ноември 2018 г. беше открита задна врата в npm модула event-stream, инжектиран от потребителя на GitHub right9ctrl чрез злонамерения модул flatmap-stream, създаден от потребителя на GitHub hugeglass. Задната вратичка ще бъде активирана само ако кодът е включен в портфейла с отворен код на BitPay Copay или във всякакви разклонения, които не променят описанието на проекта и биха ексфилтрирали частния ключ на портфейла. Официалните версии на портфейла на Copay от 5.0.2 до 5.1.0 бяха „издадени“ с тази задна вратичка на място и изграждането директно от изходния код между „25 октомври 2018 г.“ и „26 ноември 2018 г.“ би създало задна врата версия на Доплащане.

Нека да разгледаме какво се случи.

Задната вратичка на модула flatmap-stream съществуваше само в минимизираната версия на кода, който беше качен в npm, и никога не беше качен в GitHub, така че проста проверка на файла index.js или получения минифициран код на GitHub би да не разкрие нищо подозрително. Манифестът package.json за хранилището беше доста шаблонен и посочи автора на хранилището като „Antonio Macias“. По време на откриването имаше само един комит в хранилището, но npm имаше три публикувани версии. Копие на страницата на npm беше извлечено от кеша на Google, след като npm премахна злонамерения пакет. Според npm пакетът е бил изтеглен 867 232 пъти, въпреки че не е ясно колко от тези изтегляния са злонамерената версия или предишната версия, която не съдържа зловреден софтуер.

Задната врата, която беше включена в пакета flatmap-stream, беше разпространена чрез включване на flatmap-stream като зависимост в популярен модул за възли, event-stream. Хранилището за поток от събития преди това беше управлявано от потребителя на GitHub dominictarr, който спря да прави големи приноси към хранилището през 2015 г.. Потребителят на GitHub right9ctrl „изпрати имейл“ на dominictarr и предложи да поддържа хранилището, а dominictarr даде на right9ctrl достъп за писане, след като опитът за прехвърляне на собственост беше „предотвратен“ от създадено разклонение на right9ctrl. right9ctrl направиха своя първи принос към хранилището на 4 септември 2018 г. и продължиха да правят корекции на малки грешки и да изпълняват задачи по поддръжка на хранилището до 20 септември 2018 г. На 9 септември 2018 г. right9ctrl добави потока с плоска карта зависимост, която по това време беше при версия 0.1.0. Тази версия не съдържа задната врата, тъй като разликата на версиите 0.1.0 и 0.1.1 на npm разкрива, че първият етап на задната врата е добавен към минимизирания код с версия 0.1.1.

На 16 септември 2018 г. right9ctrl премахна импортирането на поток от плоска карта и замени кода с функции, записани в потока от събития, и в следващ ангажимент премахна изцяло зависимостта от поток от плоска карта, като същевременно сблъска основната версия от 3 до 4. Този бум на основната версия не позволява на пакетите, зависещи от потока от събития, да се актуализират до изчистената версия поради semver, като същевременно прави главния чист отново. Почти три седмици след като тази промяна е направена в event-stream, злонамерената версия 0.1.1 на flatmap-stream е „избутана“ към npm от hugeglass на 5 октомври 2018 г. event-stream беше конфигуриран да изтегли тази актуализирана версия, когато flatmap-stream първоначално беше добавен към версия 3, като се гарантира, че бъдещи компилации версия 3 на импортирания поток от събития ще бъдат компрометирани. Това остава привидно незабелязано до 29 октомври 2018 г., когато се отваря „проблем“ в проекта „nodemon“, съобщаващ предупреждение за оттегляне при стартиране. Оказва се, че кодът, инжектиран в flatmap-stream, използва API, отхвърлен във възел 10, crypto.createDecipher.

Тази атака беше описана за първи път като такава в „проблем“, отворен в потока на събитията на 20 ноември 2018 г., и получи много повече внимание след „публикация в хакерски новини“ на 26 ноември 2018 г. Точно в този момент бях уведомен на проблема и започна разследване. Както често се случва, умът на интернет кошера вече се движеше с главоломна скорост, за да анализира атаката и проблемът с потока от събития се превърна в продуктивен и ефективен разговор, който разкри същността на атаката.

Разследването

От първоначалния проблем, отворен за потока на събития, беше ясно, че полезният товар е AES криптиран и затова първата задача при оценката на това, което атаката всъщност е направила, е да декриптира полезния товар. Участниците в проблема постигнаха добър напредък в „обръщането“ на злонамерения софтуер и откриването, че повикването за декриптиране предоставя ключа като process.env.npm_package_description.

Чрез откриване какви стойности могат да бъдат в тази променлива ще бъде възможно да се създаде набор от потенциални ключове и в крайна сметка да се дешифрира полезният товар. npm документация предполага, че тази стойност е дефинирана от ключа packagedescription в package.json манифеста, но други участници посочиха и демонстрираха как тази стойност може да идва и от README.md на проекта.

Наличен е „пълен архив“ на npm метаданни и се „предполага“, че в най-лошия случай може да се генерира почти изчерпателен списък с описания на пакети за брутфорс.

В крайна сметка потребителят на GitHub maths22 „открива“ правилния ключ е „Сигурен биткойн портфейл“ и предполага, че целта може да е „форк“ на портфейла за доплащане на BitPay за Dash. Пълно копие на етапите на полезния товар са достъпни тук. В последния етап на злонамерения софтуер виждаме, че частният ключ е извлечен, шифрован с публичен ключ и качен през HTTP.

Разклонението на copay-dash не промени оригиналното описание на пакета, което означава, че тази атака ще работи и върху оригиналния портфейл на Copay. Предвид относителната популярност на Copay, вярвам, че е безопасно да се предположи, че целта на тази атака е Copay.

В Copay се отваря „проблем“, където екипът на Copay „потвърждава“ засегнатите версии и незабавно премахва задната врата.

Търсене в GitHub показва горна граница от 190 проекта, които могат да бъдат засегнати от тази атака. Изглежда, че търсенето ми не включва думата „А“, както попитах, така че тази оценка е твърде широка. Не съм сигурен защо търсенето не върна само точни съвпадения на низове.

Към този момент не е ясно колко криптовалута е била открадната, ако има такава, като част от тази атака. Зловреден софтуер ексфилтрира частни ключове; не е изпратил баланса на портфейла на различен адрес. Въпреки че това затруднява оценката на обхвата на атаката от този анализ, това означава, че потребителите, които са били засегнати, имат шанс да преместят своите монети, преди нападателите да го направят. Ако сте съхранявали средства във версии на Copay от 5.0.2 до 5.1.0 (или произволни разклонения), незабавно изпратете тези средства на адрес, контролиран от различен ключ.

Индикатори за компрометиране

Въпросът, отворен към BitPay, включва „коментар“, подчертаващ IOC, включително:

  • Името на хоста copayapi.host
  • IP адресите 51.38.112.212, 145.249.104.239 и 111.90.151.134

Възможно е тези IP адреси да не са собственост на нападателите и по-скоро компрометирани сървъри, които се използват от нападателите.

Какво можем да научим?

Използването на зависимости винаги изисква известна степен на доверие.

Когато импортират нова зависимост, инженерите трябва да направят всичко възможно, за да разберат качеството на хранилищата, които включват в своите проекти. Това не е всичко, тъй като е непрактично да се проверява всяка зависимост, от която зависи вашата зависимост, и всичките им зависимости и т.н. Но все пак импортирането на неподдържани пакети не трябва да се счита за безопасно.

Екосистемата за разработка на софтуер би се възползвала от по-тясна връзка между изходния код и публикуваните пакети.

При тази атака кодът, хостван от npm, се различава от кода, видим в GitHub. Това противоречи на предположението, което повечето разработчици биха направили, че ако модулът е изграден от това хранилище, той съдържа кода от това хранилище. Една по-добра система би могла да потвърди, че кодът, хостван от хранилище на зависимости, се генерира от хранилището източник по всяко време.

Фокусирането върху решаването на проблема по време на криза помага на всички.

Може да е изкушаващо да посочим начини, по които всичко това е могло да бъде предотвратено, и да посочим с пръст онези, които може да изглеждат отговорни. Факт е обаче, че в тази атака нямаше нито една точка на провал. Когато дискусията беше съсредоточена върху коригирането на текущия проблем и обсъждането на обвиненията и дългосрочните корекции, разговорът стана много по-продуктивен и общността бързо се зае с проблема.

В заключение

BitPay не е направил нищо извън нормата в софтуерното инженерство, което е довело до тази атака. Те използваха популярна зависимост, нещо, за което повечето инженери никога не биха се замислили. Този тип атака ще продължи да бъде проблем, докато контролите за сигурност около управлението на зависимостите не бъдат подобрени. Всички ние трябва да помогнем за изграждането на бъдеще, в което икономиката на сигурността прави тази атака по-малко практична. Нападателите ще инвестират ресурсите си само на места, където разходите им са по-малки от наградата, и чрез подобряване на сигурността на управлението на зависимостите можем да направим атаката по веригата на доставки твърде скъпа, за да си струва времето им.

Благодаря за четенето! Последвайте ме в twitter, за да сте в течение за бъдещи статии.