12 сентября 2016

[developer.store.yandex.ru] Stored XSS


Нестандартная XSS в сервисе для публикации Android приложений в Яндекс.Store.

При добавлении нового приложения из apk извлекаются иконки, которые доступны по адресу
https://developer.store.yandex.ru/static/icon/<app_id>/<name>.png

Я обнаружил, что для иконок проверяется только расширение по белому списку (png, gif, jpg), но отсутствует проверка содержимого и регистра названия. Оказалось, что использование нестандартного регистра в расширении (например, ic_launcher.PNG) не поддерживается веб-сервером и заголовок Content-Type начинает определяться по контенту файла.

Таким образом, если в Android приложении заменить иконку файлом <html><script>alert(1)</script></html> с названием ic_launcher.PNG, подписать его и загрузить на сервер, то получается Stored XSS.

Аналогичным образом можно было загрузить вместо иконки SWF-файл и, используя дополнительные уязвимости, найденные ранее, довести атаку до полного захвата пользовательской сессии.

А именно:
1) Небезопасная настройка crossdomain.xml на browser.export.yandex.com (файл уже недоступен)
<allow-access-from domain="*"/>

2) XScript сценарий, выводящий все Cookie пользователя, включая Session_id. Для доступа к нему необходим был заголовок Referer, соответствующий регулярному выражению yandex сайтов.
browser.export.yandex.com/xml/common.xml (файл уже недоступен)

Примеры используемых apk:
https://blackfan.ru/bugbounty/xss_html.apk
https://blackfan.ru/bugbounty/xss_flash.apk


Некорректная обработка Location в IE


Очень круто, что обнаруженный мной баг с обработкой Location в Internet Explorer (почитать можно тут, тут или тут) используется и с небольшими дополнениями выстреливает в популярных BugBounty программах.

XSS via Host header - www.google.com/cse
http://blog.bentkowski.info/2015/04/xss-via-host-header-cse.html

GitHub OAuth Code Theft
https://blog.innerht.ml/internet-explorer-has-a-url-problem/

Combining host header injection and lax host parsing serving malicious data
https://labs.detectify.com/2016/10/24/combining-host-header-injection-and-lax-host-parsing-serving-malicious-data/

How I could Steal Your Google Bug Hunter Account with Two Clicks in IE
http://ngailong.com/how-i-could-steal-your-google-bug-hunter-account-with-two-clicks-in-ie/


Баг генерации ссылок в Laravel 4


В случае, если имеется следующий blade шаблон:

<a href="{{ URL::route('index', Input::except('password')) }}">Index</a>

При обычных попытках использовать XSS ничего не получится, и при запросе

http://site.com/index?test<>'"=test<>'"

Будет сгенерирована следующая ссылка:

<a href="http://site.com/index?test%3C%3E%27%22=test%3C%3E%27%22">Index</a>

Но, если использовать числовой параметр:

http://site.com/index?123="><script>alert(1)</script>

То результат будет:

<a href="http://site.com/index?"><script>alert(1)</script>">Index</a>

Код генерации query_string:

    protected function getRouteQueryString(array $parameters)
    {
        // First we will get all of the string parameters that are remaining after we
        // have replaced the route wildcards. We'll then build a query string from
        // these string parameters then use it as a starting point for the rest.
        if (count($parameters) == 0) {
            return '';
        }
        $query = http_build_query(
            $keyed = $this->getStringParameters($parameters)
        );
        // Lastly, if there are still parameters remaining, we will fetch the numeric
        // parameters that are in the array and add them to the query string or we
        // will make the initial query string if it wasn't started with strings.
        if (count($keyed) < count($parameters)) {
            $query .= '&'.implode(
                '&', $this->getNumericParameters($parameters)
            );
        }
        return '?'.trim($query, '&');
    }

Для обычных параметров используется http_build_query, который автоматически делает urlencode, а числовые параметры добавляются без обработки.

В Laravel 5 такого уже нет, так как ссылку кодируют целиком, оставляя только символы из белого списка.

    protected $dontEncode = [
        '%2F' => '/',
        '%40' => '@',
        '%3A' => ':',
        '%3B' => ';',
        '%2C' => ',',
        '%3D' => '=',
        '%2B' => '+',
        '%21' => '!',
        '%2A' => '*',
        '%7C' => '|',
        '%3F' => '?',
        '%26' => '&',
        '%23' => '#',
        '%25' => '%',
    ];
    ...
    $uri = strtr(rawurlencode($uri), $this->dontEncode);