$30 off During Our Annual Pro Sale. View Details »

What’s wrong with WebSocket APIs? Unveiling vulnerabilities in WebSocket APIs.

What’s wrong with WebSocket APIs? Unveiling vulnerabilities in WebSocket APIs.

Slides from Hacktivity 2019 conference - https://hacktivity.com/index.php/presentations/.

Mikhail Egorov

October 25, 2019
Tweet

More Decks by Mikhail Egorov

Other Decks in Programming

Transcript

  1. What’s wrong with w/ WebSocket API?
    Unveiling vulnerabilities in
    WebSocket APIs
    Mikhail Egorov / @0ang3el
    #HACKTIVITY2019

    View Slide

  2. # whoami
    2
    ▪ Security researcher / full-time bug hunter
    ▪ https://bugcrowd.com/0ang3el
    ▪ https://hackerone.com/0ang3el
    ▪ Conference speaker
    ▪ https://www.slideshare.net/0ang3el
    ▪ https://speakerdeck.com/0ang3el

    View Slide

  3. Previous work
    3
    ▪ https://media.blackhat.com/bh-us-
    12/Briefings/Shekyan/BH_US_12_Shekyan_Toukharian_Hacking_Websocket_Slides
    .pdf
    ▪ https://www.nccgroup.trust/us/about-us/newsroom-and-
    events/blog/2017/may/wssip-a-websocket-manipulation-proxy/
    ▪ https://chybeta.github.io/2018/04/07/spring-messaging-Remote-Code-Execution-
    %E5%88%86%E6%9E%90-%E3%80%90CVE-2018-1270%E3%80%91/
    ▪ https://www.twistlock.com/labs-blog/demystifying-kubernetes-cve-2018-1002105-
    dead-simple-exploit/
    ▪ https://github.com/andresriancho/websocket-fuzzer
    ▪ https://www.irongeek.com/i.php?page=videos/derbycon9/stable-35-old-tools-new-
    tricks-hacking-websockets-michael-fowl-nick-defoe

    View Slide

  4. 4
    WebSocket protocol essentials

    View Slide

  5. WebSocket protocol – RFC 6455
    5
    ▪ Efficient two-way communication protocol
    ▪ WebSocket is stateful (HTTP is stateless)
    ▪ Two main parts: handshake and data transfer

    View Slide

  6. WebSocket protocol – RFC 6455
    6
    ▪ Extensibility: subprotocols and extensions
    ▪ Subprotocols
    ▪ https://www.iana.org/assignments/websocket/websocket.xml#subpro
    tocol-name
    ▪ Wamp
    ▪ Stomp
    ▪ Soap
    ▪ …

    View Slide

  7. WebSocket protocol – RFC 6455
    7
    ▪ Extensibility: subprotocols and extensions
    ▪ Extensions
    ▪ https://www.iana.org/assignments/websocket/websocket.xml#extens
    ion-name
    ▪ permessage-deflate
    ▪ bbf-usp-protocol

    View Slide

  8. WebSocket protocol – RFC 6455
    8
    ▪ Origin-based security model (Browser clients)
    ▪ No authentication
    ▪ Client must do client-to-server masking

    View Slide

  9. WebSocket protocol support
    9
    ▪ Major web browsers
    ▪ Web servers / Proxies
    ▪ Apache httpd, Nginx, IIS, …
    ▪ HAProxy, Traefik, Varnish, Envoy, …
    ▪ Cloud providers
    ▪WebSocket API (api gateways)
    ▪WebSocket proxying (load balancers)

    View Slide

  10. WebSocket handshake
    10
    Upgrade request
    Base64(Random nonce)
    Protocol version
    Required HTTP version

    View Slide

  11. WebSocket handshake
    11
    Required status code
    BASE64(SHA1(Sec-WebSocket-Key || CONST ))

    View Slide

  12. WebSocket data transfer
    12
    \x00 – continuation frame
    \x01 – text frame
    \x02 – binary frame
    \x08 – close frame
    \x09 – ping
    \x0A – pong
    other values are reserved

    View Slide

  13. WebSocket data transfer - masking
    13
    ▪ Masking key is 32-bit long passed inside frame
    ▪ Client must send masked data
    ▪ MASKED = MASK ^ DATA (^ - XOR)
    ▪ Mechanism protects against cache poisoning and
    smuggling attacks

    View Slide

  14. 14
    Cross-Site WebSocket Hijacking

    View Slide

  15. WebSocket security for Web Browser
    15
    ▪ SOP doesn’t work for WebSocket in web browser
    ▪ Read from WebSocket cross-origin
    ▪ Write to WebSocket cross-origin
    ▪ Header Origin should be checked on handshake
    step (origin-based security model)

    View Slide

  16. CSWSH
    16
    ▪ Cookies are used to authenticate upgrade request
    ▪ Header Origin isn’t checked or checked poorly

    View Slide

  17. CSWSH
    17
    ▪ CORS tricks from @albinowax are applicable to
    WebSocket
    ▪ https://portswigger.net/research/exploiting-cors-misconfigurations-
    for-bitcoins-and-bounties
    ▪ Null origin
    ▪ Pre-domain wildcard
    ▪ Post-domain wildcard
    ▪ …

    View Slide

  18. CSWSH – Null origin
    18
    ▪ nullorigin.html

    View Slide

  19. CSWSH
    19
    ▪ Playground
    ▪ https://portswigger.net/web-security/websockets/cross-site-
    websocket-hijacking

    View Slide

  20. CSWSH – template for attack
    5

    View Slide

  21. Demo
    5

    View Slide

  22. 22
    Authentication / IDOR issues

    View Slide

  23. Authentication
    23
    ▪ WebSocket protocol doesn’t offer authentication
    ▪ Developers have to roll out their own AuthN
    ▪ It’s secure to check AuthN only during handshake
    ▪ Common secure implementations
    ▪ Session cookies
    ▪ Tokens

    View Slide

  24. Broken authentication – Case 1
    24
    ▪ Some ID / GUID is required in Upgrade request
    ▪ Guess ID
    ▪ Leak GUID (minor IDOR, …)

    View Slide

  25. Broken authentication – Case 2
    25
    ▪ No authentication during handshake step
    ▪ Some ID / GUID required in API messages
    ▪ Guess ID
    ▪ Leak GUID (minor IDOR, …)

    View Slide

  26. Broken authentication – Case 2
    26
    ▪ Exposing GraphQL subscriptions w/o AuthN
    ▪ https://github.com/righettod/poc-graphql#subscriptions-
    websocket-endpoint-default-enabling
    ▪ Path /subscriptions

    View Slide

  27. Insecure Direct Object Reference issues
    27
    ▪ Strong authentication during handshake step
    ▪ Some ID / GUID required in API messages
    ▪ Guess ID
    ▪ Leak GUID (minor IDOR, …)

    View Slide

  28. 28
    Smuggling through WebSocket

    View Slide

  29. Reverse proxying WebSocket connection
    29
    Client
    Frontend
    Reverse proxy
    Backend
    /socket.io/
    Public WebSocket API

    View Slide

  30. Reverse proxying WebSocket connection
    30
    Client
    Frontend
    Reverse proxy
    Upgrade request Upgrade request
    Backend
    /socket.io/

    View Slide

  31. Reverse proxying WebSocket connection
    31
    Client
    Frontend
    Reverse proxy
    Upgrade request Upgrade request
    HTTP/1.1 101
    HTTP/1.1 101
    Backend
    /socket.io/

    View Slide

  32. Reverse proxying WebSocket connection
    32
    Client
    Frontend
    Reverse proxy
    Upgrade request Upgrade request
    HTTP/1.1 101
    HTTP/1.1 101
    WebSocket connection
    direct WebSocket connection
    Client - Backend
    Backend
    /socket.io/

    View Slide

  33. Smuggling through WebSocket connection
    33
    Client
    Frontend
    Reverse proxy
    (vulnerable)
    Private REST API
    Public WebSocket API
    Backend
    /internal
    /socket.io/

    View Slide

  34. 34
    Backend
    Client
    Frontend
    Reverse proxy
    (vulnerable)
    /internal
    Upgrade request
    /socket.io/
    Sec-WebSocket-Version: 1337
    Upgrade request
    Sec-WebSocket-Version: 1337
    Version correctness isn’t checked!
    Smuggling through WebSocket connection

    View Slide

  35. 35
    Backend
    Client
    Frontend
    Reverse proxy
    (vulnerable)
    /internal
    Upgrade request
    /socket.io/
    Sec-WebSocket-Version: 1337
    Upgrade request
    Sec-WebSocket-Version: 1337
    HTTP/1.1 426
    HTTP/1.1 426
    Response correctness isn’t checked!
    Smuggling through WebSocket connection

    View Slide

  36. 36
    Backend
    Client
    Frontend
    Reverse proxy
    (vulnerable)
    /internal
    Upgrade request
    /socket.io/
    Sec-WebSocket-Version: 1337
    Upgrade request
    Sec-WebSocket-Version: 1337
    HTTP/1.1 426
    HTTP/1.1 426
    TLS connection
    direct TLS connection
    Client – Backend
    not WebSocket!!!
    Client can access
    /internal
    Smuggling through WebSocket connection

    View Slide

  37. Challenge – challenge.0ang3el.tk
    37
    ▪ URL
    ▪ https://challenge.0ang3el.tk/websocket.html
    ▪ You need to access flag on localhost:5000
    ▪ Seems no one solved

    View Slide

  38. Challenge – challenge.0ang3el.tk
    38
    ▪ Frontend
    ▪ Not disclosed WebSocket reverse proxy
    ▪ socket.io.js
    ▪ Proxies only WebSocket API - /socket.io/ path
    ▪ Backend
    ▪ Flask, Flask-SoketIO, Flask-Restful
    ▪ Listens on localhost:5000 only

    View Slide

  39. challenge1.py

    View Slide

  40. challenge1.py - DEMO

    View Slide

  41. Vulnerable reverse proxies
    41
    ▪ Vulnerable
    ▪ Varnish, Envoy proxy <= 1.8.0, other non-disclosed
    ▪ Not vulnerable
    ▪ Nginx, HAProxy, Traefik, others

    View Slide

  42. Varnish response
    42
    ▪ WebSocket proxying configuration
    ▪ https://varnish-cache.org/docs/6.3/users-guide/vcl-example-
    websockets.html

    View Slide

  43. Smuggling through WebSocket connection
    43
    Client
    Frontend
    Reverse proxy
    (Nginx or another)
    Private REST API
    Public WebSocket API & REST API
    Backend
    /internal
    /api/socket.io/
    /api/health

    View Slide

  44. Smuggling through WebSocket connection
    44
    Client
    Frontend
    Reverse proxy
    (Nginx or another)
    Backend
    /internal
    /api/socket.io/
    /api/health
    example.com
    GET
    HTTP/1.1 200

    View Slide

  45. Smuggling through WebSocket connection
    45
    Client
    Frontend
    Reverse proxy
    (Nginx or another)
    Backend
    /internal
    /api/socket.io/
    /api/health
    Only Upgrade: websocket header is checked!
    POST /api/health?u= POST /api/health?u=

    View Slide

  46. Smuggling through WebSocket connection
    46
    Client
    Frontend
    Reverse proxy
    (Nginx or another)
    Backend
    /internal
    /api/socket.io/
    /api/health
    attacker.com
    GET
    HTTP/1.1 101
    HTTP/1.1 101
    HTTP/1.1 101
    Only status code is checked for response!
    POST /api/health?u= POST /api/health?u=

    View Slide

  47. Smuggling through WebSocket connection
    47
    Client
    Frontend
    Reverse proxy
    (Nginx or another)
    Backend
    /internal
    /api/socket.io/
    /api/health
    HTTP/1.1 101
    HTTP/1.1 101
    TLS connection
    direct TLS connection
    Client – Backend
    not WebSocket!!!
    Client can access
    /internal
    POST /api/health?u= POST /api/health?u=
    Client-to-Server
    masking isn’t checked
    by proxy!!!

    View Slide

  48. Challenge2 – challenge2.0ang3el.tk
    48
    ▪ URL
    ▪ https://challenge2.0ang3el.tk/websocket.html
    ▪ You need to access flag on localhost:5000
    ▪ Seems no one solved

    View Slide

  49. Challenge2 – challenge2.0ang3el.tk
    49
    ▪ Frontend
    ▪ Nginx as WebSocket reverse proxy
    ▪ socket.io.js
    ▪ Proxies only /api/public path (socket.io and healthcheck)
    ▪ Backend
    ▪ Flask, Flask-SoketIO, Flask-Restful
    ▪ Listens on localhost:5000 only

    View Slide

  50. Challenge2 – challenge2.0ang3el.tk
    50
    ▪ Nginx config

    View Slide

  51. Challenge2 – challenge2.0ang3el.tk
    51
    ▪ REST API - healthcheck

    View Slide

  52. Challenge2.py
    5

    View Slide

  53. Challenge2.py - Demo
    5

    View Slide

  54. Vulnerable reverse proxies
    54
    ▪ Almost all proxies are affected
    ▪ But exploitation is limited
    ▪ External SSRF is required that returns status code
    ▪ …

    View Slide

  55. 55
    Discovering WebSocket APIs

    View Slide

  56. Discovering WebSocket API
    56
    ▪ Monitor Upgrade requests
    ▪ Analyze JavaScript files
    ▪ Try to establish WebSocket connection to each
    URL
    ▪ …

    View Slide

  57. 57
    Conclusion

    View Slide

  58. Ideas for further research
    58
    ▪ Security of WebSocket subprotocols
    ▪ More smuggling techniques
    ▪ HTTP/2 and WebSocket
    ▪ …

    View Slide

  59. Thank you!
    @0ang3el

    View Slide