Linux Privilege Escalation - Sockets for CTF Creators
Sockets
A Unix-domain socket allows communication between two different processes on the same machine or different machines in client-server application frameworks. It facilitates inter-process communication using standard Unix file descriptors.
Sockets can be configured using .socket
files.
For more information regarding sockets, refer to the systemd.socket man page. Information regarding special systemd units can be found on the systemd.special man page.
Note that
SOCK_SEQPACKET
(i.e.ListenSequentialPacket=
) is only available forAF_UNIX
sockets.SOCK_STREAM
(i.e.ListenStream=
) when used for IP sockets refers to TCP sockets,SOCK_DGRAM
(i.e.ListenDatagram=
) to UDP.
Understanding Sockets
Install socat with the apt
package manager:
|
|
Let’s create a socket file:
|
|
In this case, we’re going to create an echo socket and use only a listening directive and the Accept
directive:
|
|
Options:
- ListenStream: means
SOCK_STREAM
and when used for IP sockets refers to TCP sockets. - Accept: Takes a boolean argument. If yes, a service instance is spawned for each incoming connection and only the connection socket is passed to it. If no, all listening sockets themselves are passed to the started service unit, and only one service unit is spawned for all connections. Since we want to send information from one machine to another, you will be using an AF_INET, and for that the best thing to do is have
Accept
set totrue
oryes
. - WantedBy=sockets.target: A special target unit that sets up all socket units (see systemd.socket(5) for details) that shall be active after boot. Services that can be socket-activated shall add
Wants=
dependencies to this unit for their socket unit during installation. This is best configured via aWantedBy=sockets.target
in the socket unit’s [Install] section.
Create a service file. In most cases, the service will have the same name as the socket unit, except with an @ and the service suffix. As your socket unit was echo.socket, your service will be echo@.service:
|
|
The service itself is also pretty basic:
|
|
The service Type
is simple
, which is already the default, so there is no need to include it. "ExecStart
” points to the echo_write.py script you will see in a minute, and the "StandardInput"
for said script comes from the socket set up by echo.socket.
Let’s see where python is located:
|
|
Create a script:
|
|
The echo_write.py script is just three lines long:
|
|
This reads a line of text from STDIN, which, as you can see, is accessed through the socket. 'sys.stdin.readline().strip()
’ then removes all spaces from the beginning and end of the line and converts it to uppercase .upper()
. It then transmits it back through the socket to the transmitting computer’s terminal ('sys.stdout.write([...])'
). This means that a user can connect to the socket on your receiving system, write a string, and have it repeated back in upper case.
Add execution permissions:
|
|
Start the socket unit with:
|
|
The echo.socket will automatically call echo@.service (which runs echo_write.py) each time someone tries to push a string to the server through port 4444.
Now check that the port listening:
|
|
To do that, on the sending computer, you can use a program like socat:
|
|
PrivilegeEscalation via Writable .socket files
Let’s add write permissions for others:
|
|
If we find a writable .socket
file we can add at the beginning of the [Socket]
section something like ExecStartPre=/home/user/backdoor
and the backdoor will be executed before the socket is created. Therefore, we will probably need to wait until the machine is rebooted if we can’t reboot the machine with our current user.
Add a reverse shell to the script or any other malicious command:
|
|
Edit the socket file and add a script that it will be executed before the listening sockets/FIFOs are created and bound, we can do this with the ExecStartPre=
option:
|
|
Let’s restart the socket:
|
|
Alternatively, we could restart the computer:
|
|
Receive the reverse shell as the root user:
|
|
PrivilegeEscalation via Socket Command Injection
Create a file named socket_injection.py
:
|
|
Write the following code:
|
|
Add execution permissions:
|
|
Create the following socket:
|
|
Write the following configuration:
|
|
Then create this service:
|
|
Write the following instructions:
|
|
Now start the socket:
|
|
Check if the port is listening:
|
|
Run the following commands:
|
|
Spawn bash with SUID and print the Effective UID:
|
|
Remove the bash SUID binary:
|
|