Ruby
How to hijack, proxy and smuggle sockets with Rack/Ruby
Summarized using AI

How to hijack, proxy and smuggle sockets with Rack/Ruby

by Dávid Halász

In this talk, Dávid Halász, a software engineer at Red Hat, explores the concept of hijacking, proxying, and smuggling sockets using Ruby. He introduces the problem of needing to transmit data between browsers and virtual machines, which typically communicate through HTTP or WebSocket, but often require a different protocol like VNC. The session covers a variety of technical approaches and implementations, focused on efficient data handling using sockets.

Key points discussed during the presentation include:

  • Background: Dávid shares his transition from C programming to Ruby, emphasizing his experience in open-source contributions and his work on in-browser remote consoles.
  • Socket Management: The talk explains how sockets operate, introducing both blocking I/O and non-blocking I/O operations. The importance of using the select system call to query socket readiness is highlighted.
  • Efficiency Challenges: The downsides of using select with multiple sockets are discussed, alongside strategies like event-driven solutions and using dynamic arrays to optimize socket readiness checks.
  • Advanced Socket Techniques: Alternatives such as epoll and KQueue for socket management are introduced, offering efficient ways to handle multiple connections.
  • WebSockets and Rack: Dávid explains the role of WebSockets in extending HTTP connections, and demonstrates how to hijack sockets in a Rack server environment to gain control over data communications.
  • TCP Traffic Smuggling: He delves into the concept of smuggling TCP traffic through HTTP connections. By upgrading connections to other protocols, users can bypass firewall restrictions.
  • Live Demonstration: A live demo is presented showcasing how his architecture can connect to VNC and SSH servers via a browser plugin, leveraging the principles discussed.
  • Complex Architecture: The implementation combines various technologies such as Rack with Ruby, JavaScript client interaction, and Docker for isolated service management.

In conclusion, Hálsz emphasizes that manipulating connections effectively allows for seamless access to remote systems despite network constraints, demonstrating the power of Ruby in developing creative networking solutions. He encourages further exploration and application of these techniques as potential tools for developers navigating networking challenges.

00:00:00.149 Dávid Halász is a software engineer working for Red Hat. He originally started as a C programmer but fell in love with Ruby early on and has been coding in it since 2012. He has given talks in various places, including Vienna, Brno, and Albania. Despite traveling from cold weather, he has come to present today in the hot, humid climate of Melbourne. In this talk, he will be discussing hijacking some sockets and HTTP connections.
00:52:920 Hello everyone, my name is Dávid. You can find me on Twitter under my full name or on GitHub as caitlin. Today, I'll be explaining how to hijack, proxy, and smuggle sockets using Ruby. I hail from the Czech Republic where I live in a town called Brno, which is famous for beer and MotoGP.
01:20:640 As a software engineer at Red Hat, I focus exclusively on open source, contributing to the ManageIQ project, which is a management platform for hybrid infrastructures. One feature I'm working on involves in-browser remote consoles. This means if you have a pool of virtual machines, you can open a VM and have a pop-up window displaying its virtual screen. When you use a browser, the VM operates in a hypervisor providing the remote console service. However, browsers typically do not understand VNC; they only comprehend HTTP or WebSocket. Therefore, we need something in between to translate the protocols.
02:36:340 The system I’m describing translates and transmits data between two points: Point A and Point B. When A is ready to read, and B is ready to write, the transmission occurs. This implementation requires sockets that act as abstractions around the networking stack, enabling operations akin to normal file handling in UNIX systems.
03:09:900 To utilize these sockets in Ruby, you need to require the necessary libraries. I am also demonstrating how I am opening an HTTP connection to the RubyConf website. When sending a request, I'm getting redirected, but I want to highlight that I'm reading and writing data. When you write to a socket, the operating system takes the data from the buffer, forms packets, and dispatches them to the network card. Depending on the data amount, this process may take varying durations due to network usage.
04:02:140 Data reading functions similarly. If there’s no data in the buffer, the thread will block and wait until data becomes available. This is what we call blocking I/O. Conversely, with non-blocking I/O, operations proceed without waiting for the entire buffer, instead operating only with the data currently available.
05:02:320 In Ruby, operations like write and read are part of specific methods that will raise exceptions when conditions like empty or full buffers occur. For non-blocking transfers, you could set up a loop until data becomes available, but this is not ideal as it consumes CPU cycles unnecessarily. To properly manage this, we use a system call called select. It allows you to query the operating system about the readiness of sockets within a specified timeframe, which can be adjusted according to need.
06:24.600 However, using select comes with downsides, especially when dealing with multiple sockets simultaneously, such as having two buffers testing readiness. A situation could arise where one socket is ready for reading whereas the other may not be ready for writing, which can lead to inefficiencies and an endless loop if not handled carefully.
07:14:680 To mitigate these issues, you can use blocking I/O with threads or explore event-driven solutions that effectively simulate non-blocking I/O. In our current setup, I redesigned the process to utilize dynamic arrays for sockets in action. When a socket is ready for reading, it gets removed from the array preventing re-checking in subsequent iterations, thus eliminating unnecessary CPU usage.
09:17.150 Even though the select method isn’t the most efficient, especially when working with numerous sockets, I explored alternatives like epoll, which registers sockets and provides a way to check their readiness in a more efficient manner. I also discovered interesting features in KQueue for BSD systems, allowing for greater efficiency in socket management.
11:42.700 The topic also leads me to discuss WebSockets, which extend HTTP connections allowing for bi-directional communications. In Ruby, web servers function via Rack, utilizing lambdas or Proc objects to manage requests and responses efficiently.
12:59.600 With respect to socket hijacking in Rack, it involves requesting the server to release its control over the socket. By leveraging Rack's hijack methods, we gain direct control over the socket, allowing us to manage further interactions directly, as illustrated in my code example.
13:59.440 Next, I delved into the concept of smuggling TCP traffic through HTTP connections. Essentially, if you can upgrade a connection to another protocol, you can essentially hijack the socket to use it for your preferred protocol, such as VNC or SSH. This would facilitate efficient connectivity through firewalls that only permit HTTP.
14:31.330 I've developed a proof of concept using a browser plugin, allowing users to connect to a remote desktop via SSH or VNC seamlessly, employing the principles of HTTP hijacking to create direct access paths without the hassle of complex routing.
15:45.780 The architecture is indeed complex, utilizing inputs from multiple sources and technologies. The server is implemented in Rack with Ruby, using a web extension plugin in JavaScript for client interaction, and this forms the backbone of the system, allowing user requests to be channeled effectively.
17:22.310 Finally, I showcased a live demonstration using Docker to connect to a VNC server and an SSH server running in isolated containers. My setup included deploying a static website enabling me to direct requests to the appropriate servers based on user needs without exposing any direct ports.
18:30.120 In conclusion, this setup illustrates how we can extend and manipulate connections using Ruby, opening up new pathways for accessing remote systems effectively while navigating around network constraints. Thank you for your attention!
Explore all talks recorded at RubyConf AU 2019
+10