Skip to main content
Software View

Main navigation

  • Home
  • Trainer Profile
  • Blog
  • Contact
User account menu
  • Log in

Breadcrumb

  1. Home
  2. Blog

Poor man's telnet program

By Kamal Wickramanayake, 9 July, 2010

About 10 years ago I wanted to write a telnet client in PHP. My need was to login, execute some commands and logout. I was lazy to read the telnet protocol details. Hence I used the following approach to do it which worked for my purpose. Let your programming language be Java, C, C++, PHP, C# or anything else. It needs to have a TCP socket creation facility (TCP networking).

Here are the steps:

  1. Have the telnet server running.
  2. Use a network traffic monitoring tool running (or use a proxy).
  3. Use a commonly availale telnet client and login to the server.
  4. Stop the network traffic monitoring tool and identify the client/server conversation byte streams. Identify the different chunks of data sent to the server (by the client) and to the client (by the server).
  5. Write your telnet client (in your preferred programming language) to send the same chunks of bytes to the server and implement the conversation.

Special Note: This approach is not that great if you think of using your new telnet client with different telnet servers (which may have different telnet session negotiation mechanism) or if the telnet server software is updated and server configurations are changed where the same chunks of bytes may not work after such changes. If such a general purpose telnet client is needed and you want to write from the scratch, you need read the telnet protocol details well.

Here's the telnet client I wrote in PHP. Look at the connect() function. You see that a new TCP socket is created and chunks of bytes are sent to the server and read from the server. That is in fact the handshaking taking place. I didn't go about understanding the exact meaning of these messages. I just wanted to get the login prompt. And then I continuted with executing commands.

<?php

class Telnet {
    var $host;
    var $port;
    var $login;
    var $connection;
    var $errno;
    var $errstr;
    var $bashPrompt = "apacheTelnetPrompt";
    var $timeout = 30; // Set this to 30
 
    function Telnet($host,$port) {
    	$this->host = $host;
	$this->port = $port;
    }

    function connect() {
	$this->connection =fsockopen($this->host, $this->port, $this->errno, $this->errstr, 30);
	fread($this->connection, 3);
	$send = array(255,251,24);
	$this->sendBytes($send);
	fread($this->connection, 9);

	$send = array(255,251,32,255,252,35,255,251,39);
	$this->sendBytes($send);
	fread($this->connection, 18);

	$send = array(255, 250, 32, 0, 51, 56, 52, 48, 48, 44, 51, 56,
			 52, 48, 48, 255, 240, 255, 250, 39, 0, 255, 240,
			 255, 250, 24, 0, 76, 73, 78, 85, 88, 255, 240);
	$this->sendBytes($send);
	fread($this->connection, 15);

	$send = array(255, 253, 3, 255, 252, 1, 255, 251, 31, 255, 250, 31,
			0, 80, 0, 25, 255, 240, 255, 253, 5, 255, 251, 33);
	$this->sendBytes($send);

// Get the login prompt
	if($this->expect("login: "))
	    return TRUE;
	else
	    return FALSE;
    }

// Loing method
// Accepts two strings (login name , password)
    function login($login, $password) {
	$this->login = $login;

	$send = array(255, 253, 1);
	$this->sendBytes($send);
// Send the login name here
	$this->send($this->login."\r".chr(0));
	
// Expect the Password prompt and send the password
	if(!$this->expect("Password: "))
	    return FALSE;

// Send the password
	$this->send($password."\r".chr(0));

// Expect the success in login
	if(!$this->expect("Last login: "))
	    return FALSE;

// Set the prompt
	$this->send("export PS1=$this->bashPrompt\r".chr(0));
// Read the echoed output
	if(!$this->expect("export PS1=$this->bashPrompt\r\n"))
	    return false;

// Expect the changed prompt
	if(!$this->expect($this->bashPrompt))
	    return FALSE;

// You are logged in, return true
	return true;
    }

// Accepted: an array of integers
    function sendBytes($send) {
	for($i = 0; $i < sizeof($send); $i++)
	    if(fwrite($this->connection, chr($send[$i])) == -1)
		return false;
	return true;
    }

    function expect($expected) {
	while(true) {
	    $read = $this->getCharWithTimeout($this->timeout);
	    if(!$read)
		return false;
	    if($read != $expected[0])
		continue;

	    $index = 1;
	    while($index < strlen($expected)) {
		$read = $this->getCharWithTimeout($this->timeout);
		if(!$read)
		    return false;
		if($read == $expected[$index])
		    $index++;
		else if($read == $expected[0])
		    $index = 1;
		else
		    continue 2;
	    }
	    return true;
	}
    }

// Send a string to the socket
// Accepted: the string to be sent
    function send($string) {
	if(fwrite($this->connection, $string) == -1)
	    return false;
	else
	    return true;
    }

    function getCharWithTimeout($timeout) {
	socket_set_blocking($this->connection, false);
	for($i = 0; $i < $timeout; $i++) {
	    $read = fgetc($this->connection);
	    // remove the line below
	    //echo $read;
	    if($read) {
		socket_set_blocking($this->connection, true);
		return $read;
	    } else
		sleep(1);
	}
	socket_set_blocking($this->connection, true);
	return false; 
    }

    function isBashPrompt($value) {
	if($value == $this->bashPrompt)
	    return TRUE;
	else
	    return FALSE;
    }

    function getExitStatus() {
	$this->flushInput();
	$this->send("echo $?\r".chr(0));
	$this->expect("echo $?\r\n"); // Read the echoed output
	$status = fgets($this->connection, 4096);
	return $status;
    }

// Reads all the content present at the input
    function flushInput() {
	$all;
	$info = socket_get_status($this->connection);
	for($i = 0; $i < $info['unread_bytes']; $i++)
	    $all .= fgetc($this->connection);
	return $all;
    }
	
    function logout() {
	$this->send("exit\r".chr(0));
	usleep(25000);
	$this->flushInput();
	fclose($this->connection);
    }
}
?>

What follows is the usage of the telnet client. This was used as a form submission handling script to get a new Linux account created after initializing the telnet session. What's in bold text is the usage of the above Telnet class.

<?php
/*

Telnet to localhost and create a new account.

Accepts the following HTTP POST variables:
    $adduserargs - arguments to adduser command
    $privilage_login - login name of the privilaged person who can create accounts
    $privilage_password
    $submit - form submitted

*/

$exitcode = 101;


// Match the pattern of $adduserargs
// Set $exitcode to 102 if cannot be matched
$pattern = ".*[;&|><`].*";
if(ereg($pattern, $adduserargs))
    $exitcode = 102;

if($submit && ($exitcode == 101)) {

    include('Telnet.php');

    // Telnet to the machine
    $t = new Telnet("localhost", 23);

    if($t->connect()) {
    	if($t->login($privilage_login, $privilage_password)) {
	    // Gain superuser privilage
	    $t->send("sudo -v\r".chr(0));
	    if($t->expect("Password:")) {
		$t->send("$privilage_password\r".chr(0));
		if($t->expect($t->bashPrompt)) {
	    	    // Send the command
	    	    $adduserargs = stripslashes($adduserargs);
	            $t->send("sudo /usr/sbin/adduser $adduserargs\r".chr(0));
	    	    // If bash prompt cannot be seen, break the command
    	            if(!$t->expect($t->bashPrompt)) {
	    		$t->send(chr(3));
	    	    	fread($t->connection,3);
    	    	    }
		} else {
	    	    $t->send(chr(3));
	    	    fread($t->connection,3);
		}
	    } else {
	        $t->send(chr(3));
	        fread($t->connection,3);
	    }
	    
	    $exitcode = (int) $t->getExitStatus();
	    // Kill the sudo session
	    $t->send("sudo -K\r".chr(0));
	    $t->flushInput();
		
	    $t->logout();
    	} // if logged in ends
    } // if Connected ends
} // if submitted ends

echo $exitcode;
PHP

Highlights

  • O'Reilly Book "97 Things Every Software Architect Should Know" Accepts A Write Up From Kamal
  • "Service Oriented Architecture - Making IT Infrastructure Speaks Business" - Presentation At The ISACA 4th Annual Conference
  • The Second Bacth Of ICTA Nanasala e-Society Members Receives Trainings On HTML/CSS and GIMP
  • GIMP Training For ICTA Nanasala Project
  • Agile Processes Training For PPSL (Pvt) Ltd
  • Computer Society of Sri Lanka (CSSL) - Talk on "Introduction to IT Governance and Enterprise Architecture"
  • Motorola Sends A Second Batch Through Software Patterns Training
  • Kamal To Act As The Marketing Director - ISACA Sri Lanka Chapter
  • ISACA Sri Lanka Chapter Invites Kamal To Join As A Board Member
  • Epic Lanka Technologies (Pvt) Ltd Receives Java SE And Java EE Trainings From Software View
  • Patterns Training For PPSL (Pvt) Ltd
  • ISACA Members Day Presentation On "Introduction To IT Governance And Enterprise Architecture"
  • Opening Lecture On Information Technology For SLIDA Master Of Public Management Course Delivered By Kamal
  • Customized Java Enterprise Edition Training For SLIDA
  • No One To Beat Software View - Epic Lanka Technologies (Pvt) Ltd
  • Motorola Receives Software Patterns Training From Software View
  • Custom Java Enterprise Edition Training for ICTA/SLIDA - Only from Software View!
  • Java EE 5, JavaServer Faces, Hibernate And Spring For PPSL (Pvt) Ltd
  • "Brain Trust" For Linux Journal Weekly Newsletter From Kamal
  • Java Platform, Enterprise Edition 5 Training At The CEIT, University Of Peradeniya
  • Another Group Of Around 100 Sri Lanka Telecom Engineers And Managers Were Service Oriented!
  • Java Platform, Enterprise Edition 5 Training Will Be Held At The CEIT, University Of Peradeniya
  • Service Oriented Architecture: Another Two Sessions Conducted at SLT
  • Photos of IET Monthly Forum at the Peradeniya University
RSS feed
Copyright © 2007 - 2023 Software View