05-23-2019, 02:16 AM
Securing telnet connections with stunnel
<div><p>Telnet is a client-server protocol that connects to a remote server through TCP over port 23. Telnet does not encrypt data and is considered insecure and passwords can be easily sniffed because data is sent in the clear. However there are still legacy systems that need to use it. This is where <strong>stunnel</strong> comes to the rescue.</p>
<p>Stunnel is designed to add SSL encryption to programs that have insecure connection protocols. This article shows you how to use it, with telnet as an example.</p>
<h2>Server Installation</h2>
<p>Install stunnel along with the telnet server and client <a href="https://fedoramagazine.org/howto-use-sudo/">using sudo</a>:</p>
<pre class="wp-block-preformatted">sudo dnf -y install stunnel telnet-server telnet</pre>
<p>Add a firewall rule, entering your password when prompted: </p>
<pre class="wp-block-preformatted">firewall-cmd --add-service=telnet --perm<br />firewall-cmd --reload</pre>
<p>Next, generate an RSA private key and an SSL certificate:</p>
<pre class="wp-block-preformatted">openssl genrsa 2048 > stunnel.key<br />openssl req -new -key stunnel.key -x509 -days 90 -out stunnel.crt</pre>
<p>You will be prompted for the following information one line at a time. When asked for <em>Common Name</em> you must enter the correct host name or IP address, but everything else you can skip through by hitting the <strong>Enter</strong> key.</p>
<pre class="wp-block-preformatted">You are about to be asked to enter information that will be<br />incorporated into your certificate request.<br />What you are about to enter is what is called a Distinguished Name or a DN.<br />There are quite a few fields but you can leave some blank<br />For some fields there will be a default value,<br />If you enter '.', the field will be left blank.<br />-----<br />Country Name (2 letter code) [XX]:<br />State or Province Name (full name) []:<br />Locality Name (eg, city) [Default City]:<br />Organization Name (eg, company) [Default Company Ltd]:<br />Organizational Unit Name (eg, section) []:<br />Common Name (eg, your name or your server's hostname) []:<br />Email Address []</pre>
<p>Merge the RSA key and SSL certificate into a single <em>.pem</em> file, and copy that to the SSL certificate directory:</p>
<pre class="wp-block-preformatted">cat stunnel.crt stunnel.key > stunnel.pem<br />sudo cp stunnel.pem /etc/pki/tls/certs/</pre>
<p>Now it’s time to define the service and the ports to use for encrypting your connection. Choose a port that is not already in use. This example uses port 450 for tunneling telnet. Edit or create the <em>/etc/stunnel/telnet.conf</em> file:</p>
<pre class="wp-block-preformatted">cert = /etc/pki/tls/certs/stunnel.pem<br />sslVersion = TLSv1<br />chroot = /var/run/stunnel<br />setuid = nobody<br />setgid = nobody<br />pid = /stunnel.pid<br />socket = l:TCP_NODELAY=1<br />socket = r:TCP_NODELAY=1<br />[telnet]<br />accept = 450<br />connect = 23</pre>
<p>The <strong>accept </strong>option is the port the server will listen to for incoming telnet requests. The <strong>connect</strong> option is the internal port the telnet server listens to.</p>
<p>Next, make a copy of the systemd unit file that allows you to override the packaged version:</p>
<pre class="wp-block-preformatted">sudo cp /usr/lib/systemd/system/stunnel.service /etc/systemd/system</pre>
<p>Edit the <em>/etc/systemd/system/stunnel.service</em> file to add two lines. These lines create a chroot jail for the service when it starts.</p>
<pre class="wp-block-preformatted">[Unit]<br />Description=TLS tunnel for network daemons<br />After=syslog.target network.target<br /><br />[Service]<br />ExecStart=/usr/bin/stunnel<br />Type=forking<br />PrivateTmp=true<br /><strong>ExecStartPre=-/usr/bin/mkdir /var/run/stunnel<br />ExecStartPre=/usr/bin/chown -R nobody:nobody /var/run/stunnel<br /></strong><br />[Install]<br />WantedBy=multi-user.target</pre>
<p>Next, configure SELinux to listen to telnet on the new port you just specified:</p>
<pre class="wp-block-preformatted">sudo semanage port -a -t telnetd_port_t -p tcp 450<br /></pre>
<p>Finally, add a new firewall rule:</p>
<pre class="wp-block-preformatted">firewall-cmd --add-port=450/tcp --perm<br />firewall-cmd --reload</pre>
<p>Now you can enable and start telnet and stunnel.</p>
<pre class="wp-block-preformatted">systemctl enable telnet.socket [email protected] --now</pre>
<p>A note on the <em>systemctl</em> command is in order. Systemd and the stunnel package provide an additional <a href="https://fedoramagazine.org/systemd-template-unit-files/">template unit file</a> by default. The template lets you drop multiple configuration files for stunnel into <em>/etc/stunnel</em>, and use the filename to start the service. For instance, if you had a <em>foobar.conf</em> file, you could start that instance of stunnel with <em>systemctl start [email protected]</em>, without having to write any unit files yourself.</p>
<p>If you want, you can set this stunnel template service to start on boot:</p>
<pre class="wp-block-preformatted">systemctl enable [email protected]</pre>
<h2>Client Installation</h2>
<p>This part of the article assumes you are logged in as a normal user (<a href="https://fedoramagazine.org/howto-use-sudo/">with sudo privileges</a>) on the client system. Install stunnel and the telnet client:</p>
<pre class="wp-block-preformatted">dnf -y install stunnel telnet</pre>
<p>Copy the <em>stunnel.pem</em> file from the remote server to your client <em>/etc/pki/tls/certs</em> directory. In this example, the IP address of the remote telnet server is 192.168.1.143.</p>
<pre class="wp-block-preformatted">sudo scp [email protected]:/etc/pki/tls/certs/stunnel.pem<br />/etc/pki/tls/certs/</pre>
<p>Create the <em>/etc/stunnel/telnet.conf</em> file:</p>
<pre class="wp-block-preformatted">cert = /etc/pki/tls/certs/stunnel.pem<br />client=yes<br />[telnet]<br />accept=450<br />connect=192.168.1.143:450<br /></pre>
<p>The <strong>accept </strong>option is the port that will be used for telnet sessions. The <strong>connect</strong> option is the IP address of your remote server and the port it’s listening on.</p>
<p>Next, enable and start stunnel:</p>
<pre class="wp-block-preformatted">systemctl enable [email protected] --now</pre>
<p>Test your connection. Since you have a connection established, you will telnet to <em>localhost</em> instead of the hostname or IP address of the remote telnet server:</p>
<pre class="wp-block-preformatted">[user@client ~]$ <strong>telnet localhost 450</strong><br />Trying ::1...<br />telnet: connect to address ::1: Connection refused<br />Trying 127.0.0.1...<br />Connected to localhost.<br />Escape character is '^]'.<br /><br />Kernel 5.0.9-301.fc30.x86_64 on an x86_64 (0)<br />server login: <strong>myuser</strong><br />Password: <strong>XXXXXXX</strong><br />Last login: Sun May 5 14:28:22 from localhost<br />[myuser@server ~]$</pre>
</div>
<div><p>Telnet is a client-server protocol that connects to a remote server through TCP over port 23. Telnet does not encrypt data and is considered insecure and passwords can be easily sniffed because data is sent in the clear. However there are still legacy systems that need to use it. This is where <strong>stunnel</strong> comes to the rescue.</p>
<p>Stunnel is designed to add SSL encryption to programs that have insecure connection protocols. This article shows you how to use it, with telnet as an example.</p>
<h2>Server Installation</h2>
<p>Install stunnel along with the telnet server and client <a href="https://fedoramagazine.org/howto-use-sudo/">using sudo</a>:</p>
<pre class="wp-block-preformatted">sudo dnf -y install stunnel telnet-server telnet</pre>
<p>Add a firewall rule, entering your password when prompted: </p>
<pre class="wp-block-preformatted">firewall-cmd --add-service=telnet --perm<br />firewall-cmd --reload</pre>
<p>Next, generate an RSA private key and an SSL certificate:</p>
<pre class="wp-block-preformatted">openssl genrsa 2048 > stunnel.key<br />openssl req -new -key stunnel.key -x509 -days 90 -out stunnel.crt</pre>
<p>You will be prompted for the following information one line at a time. When asked for <em>Common Name</em> you must enter the correct host name or IP address, but everything else you can skip through by hitting the <strong>Enter</strong> key.</p>
<pre class="wp-block-preformatted">You are about to be asked to enter information that will be<br />incorporated into your certificate request.<br />What you are about to enter is what is called a Distinguished Name or a DN.<br />There are quite a few fields but you can leave some blank<br />For some fields there will be a default value,<br />If you enter '.', the field will be left blank.<br />-----<br />Country Name (2 letter code) [XX]:<br />State or Province Name (full name) []:<br />Locality Name (eg, city) [Default City]:<br />Organization Name (eg, company) [Default Company Ltd]:<br />Organizational Unit Name (eg, section) []:<br />Common Name (eg, your name or your server's hostname) []:<br />Email Address []</pre>
<p>Merge the RSA key and SSL certificate into a single <em>.pem</em> file, and copy that to the SSL certificate directory:</p>
<pre class="wp-block-preformatted">cat stunnel.crt stunnel.key > stunnel.pem<br />sudo cp stunnel.pem /etc/pki/tls/certs/</pre>
<p>Now it’s time to define the service and the ports to use for encrypting your connection. Choose a port that is not already in use. This example uses port 450 for tunneling telnet. Edit or create the <em>/etc/stunnel/telnet.conf</em> file:</p>
<pre class="wp-block-preformatted">cert = /etc/pki/tls/certs/stunnel.pem<br />sslVersion = TLSv1<br />chroot = /var/run/stunnel<br />setuid = nobody<br />setgid = nobody<br />pid = /stunnel.pid<br />socket = l:TCP_NODELAY=1<br />socket = r:TCP_NODELAY=1<br />[telnet]<br />accept = 450<br />connect = 23</pre>
<p>The <strong>accept </strong>option is the port the server will listen to for incoming telnet requests. The <strong>connect</strong> option is the internal port the telnet server listens to.</p>
<p>Next, make a copy of the systemd unit file that allows you to override the packaged version:</p>
<pre class="wp-block-preformatted">sudo cp /usr/lib/systemd/system/stunnel.service /etc/systemd/system</pre>
<p>Edit the <em>/etc/systemd/system/stunnel.service</em> file to add two lines. These lines create a chroot jail for the service when it starts.</p>
<pre class="wp-block-preformatted">[Unit]<br />Description=TLS tunnel for network daemons<br />After=syslog.target network.target<br /><br />[Service]<br />ExecStart=/usr/bin/stunnel<br />Type=forking<br />PrivateTmp=true<br /><strong>ExecStartPre=-/usr/bin/mkdir /var/run/stunnel<br />ExecStartPre=/usr/bin/chown -R nobody:nobody /var/run/stunnel<br /></strong><br />[Install]<br />WantedBy=multi-user.target</pre>
<p>Next, configure SELinux to listen to telnet on the new port you just specified:</p>
<pre class="wp-block-preformatted">sudo semanage port -a -t telnetd_port_t -p tcp 450<br /></pre>
<p>Finally, add a new firewall rule:</p>
<pre class="wp-block-preformatted">firewall-cmd --add-port=450/tcp --perm<br />firewall-cmd --reload</pre>
<p>Now you can enable and start telnet and stunnel.</p>
<pre class="wp-block-preformatted">systemctl enable telnet.socket [email protected] --now</pre>
<p>A note on the <em>systemctl</em> command is in order. Systemd and the stunnel package provide an additional <a href="https://fedoramagazine.org/systemd-template-unit-files/">template unit file</a> by default. The template lets you drop multiple configuration files for stunnel into <em>/etc/stunnel</em>, and use the filename to start the service. For instance, if you had a <em>foobar.conf</em> file, you could start that instance of stunnel with <em>systemctl start [email protected]</em>, without having to write any unit files yourself.</p>
<p>If you want, you can set this stunnel template service to start on boot:</p>
<pre class="wp-block-preformatted">systemctl enable [email protected]</pre>
<h2>Client Installation</h2>
<p>This part of the article assumes you are logged in as a normal user (<a href="https://fedoramagazine.org/howto-use-sudo/">with sudo privileges</a>) on the client system. Install stunnel and the telnet client:</p>
<pre class="wp-block-preformatted">dnf -y install stunnel telnet</pre>
<p>Copy the <em>stunnel.pem</em> file from the remote server to your client <em>/etc/pki/tls/certs</em> directory. In this example, the IP address of the remote telnet server is 192.168.1.143.</p>
<pre class="wp-block-preformatted">sudo scp [email protected]:/etc/pki/tls/certs/stunnel.pem<br />/etc/pki/tls/certs/</pre>
<p>Create the <em>/etc/stunnel/telnet.conf</em> file:</p>
<pre class="wp-block-preformatted">cert = /etc/pki/tls/certs/stunnel.pem<br />client=yes<br />[telnet]<br />accept=450<br />connect=192.168.1.143:450<br /></pre>
<p>The <strong>accept </strong>option is the port that will be used for telnet sessions. The <strong>connect</strong> option is the IP address of your remote server and the port it’s listening on.</p>
<p>Next, enable and start stunnel:</p>
<pre class="wp-block-preformatted">systemctl enable [email protected] --now</pre>
<p>Test your connection. Since you have a connection established, you will telnet to <em>localhost</em> instead of the hostname or IP address of the remote telnet server:</p>
<pre class="wp-block-preformatted">[user@client ~]$ <strong>telnet localhost 450</strong><br />Trying ::1...<br />telnet: connect to address ::1: Connection refused<br />Trying 127.0.0.1...<br />Connected to localhost.<br />Escape character is '^]'.<br /><br />Kernel 5.0.9-301.fc30.x86_64 on an x86_64 (0)<br />server login: <strong>myuser</strong><br />Password: <strong>XXXXXXX</strong><br />Last login: Sun May 5 14:28:22 from localhost<br />[myuser@server ~]$</pre>
</div>