Dynamic PHP telnet / ssh login

I have a problem that puzzled me.

I am trying to automate the CLI login for a router and run some commands received from a web page. However, I don't know if the router supports telnet or SSH (maybe one, the other, or both), and I have a list of possible username and password combinations that I need to try to access.
Oh, and I canโ€™t change either the protocol type or the credentials on the device, so this is not an option.

I managed to figure out how to connect to a router with a known protocol and login credentials and execute the necessary commands (see below), but I donโ€™t know whether to use the if / else block to work through telnet / ssh solutions or if the switch statement can to be better? Would using Expect inside PHP be easier?

function tunnelRun($commands,$user,$pass, $yubi){ $cpeIP = "1.2.3.4"; $commands_explode = explode("\n", $commands); $screenOut = ""; $ssh = new Net_SSH2('router_jumphost'); if (!$ssh->login($user, $pass . $yubi)) { exit('Login Failed'); } $ssh->setTimeout(2); $ssh->write("ssh -l username $cpeIP\n"); $ssh->read("assword:"); $ssh->write("password\n"); $ssh->read("#"); $ssh->write("\n"); $cpePrompt = $ssh->read('/.*[#|>]/', NET_SSH2_READ_REGEX); $cpePrompt = str_replace("\n", '', trim($cpePrompt)); $ssh->write("config t\n"); foreach ($commands_explode as $i) { $ssh->write("$i\n"); // note the "\n" $ssh->setTimeout(2); $screenOut .= $ssh->read(); } $ssh->write("end\n"); $ssh->read($cpePrompt); $ssh->write("exit\n"); echo "Router Update completed! Results below:<br><br>"; echo "<div id=\"text_out\"><textarea style=\" border:none; width: 700px;\" rows=\"20\">".$screenOut."</textarea></div>"; 

Update:

The solution I was working with was the switch time / cycle. I would go on the Expect route, but all the time I had problems connecting the Expect module to PHP on my server (Windows window.) If I were using a Unix / Linux server, then Expect would be the easiest way to achieve this. At the moment I just turned it into a working demo, so there are many options left in the case arguments, and error handling still needs to be clarified, but there is a basic idea. I still want to move the preg_match instructions about a few times to match at the top of the while loop (so I am not spamming the entire case section with different preg_match lines), but this may turn out to be more work than I want now. Hope this helps someone else trying to do the same!

  <?php include('Net/SSH2.php'); define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX); ini_set('display_errors', 1); $conn = new Net_SSH2('somewhere.outthere.com'); if (!$conn->login($user, $pass . $yubi)) { exit('Login Failed'); } $prompt = "Testing#"; $conn->setTimeout(2); $conn->write("PS1=\"$prompt\""); $conn->read(); $conn->write("\n"); $screenOut = $conn->read(); //echo "$screenOut is set on the shell<br><br>"; echo $login_db[3][0]. " ". $login_db[3][1]; $logged_in = false; $status = "SSH"; $status_prev = ""; $login_counter = 0; while (!$logged_in && $login_counter <=3) { switch ($status) { case "Telnet": break; case "SSH": $conn->write("\n"); $conn->write("ssh -l " . $login_db[$login_counter][0] . " $cpeIP\n"); $status_prev = $status; $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX); break; case (preg_match('/Permission denied.*/', $status) ? true : false): $conn->write(chr(3)); //Sends Ctrl+C $status = $conn->read(); if (strstr($status, "Testing#")) { $status = "SSH"; $login_counter++; break; } else { break 2; } case (preg_match('/[pP]assword:/', $status) ? true : false): $conn->write($login_db[$login_counter][1] . "\n"); $status_prev = $status; $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX); break; case (preg_match('/yes\/no/', $status) ? true : false): $conn->write("yes\n"); $status_prev = $status; $status = $conn->read('/\n([.*])$/', NET_SSH2_READ_REGEX); break; case (preg_match('/(^[a-zA-Z0-9_]+[#]$)|(>)/', $status,$matches) ? true : false): $conn->write("show version\n"); $status = $conn->read(">"); if(preg_match('/ADTRAN|Adtran|Cisco/', $status)? true:false){ $logged_in = true; break; } default: echo "<br>Something done messed up! Exiting"; break 2; } //echo "<pre>" . $conn->getLog() . "</pre>"; } if ($logged_in === true) { echo "<br> Made it out of the While loop cleanly"; } else { echo "<br> Made it out of the While loop, but not cleanly"; } echo "<pre>" . $conn->getLog() . "</pre>"; $conn->disconnect(); echo "disconnected cleanly"; } ?> 
+6
source share
2 answers

If statements can make your code unreadable.
In this case, I suggest you use blocks with a switching housing,
since the switch enclosure will allow you to write clearer code and allow you to use exceptional values โ€‹โ€‹more efficiently.

Using Expect in php is simple:

 <?php> ini_set("expect.loguser", "Off"); $stream = fopen("expect://ssh root@remotehost uptime", "r"); $cases = array ( array (0 => "password:", 1 => PASSWORD) ); switch (expect_expectl ($stream, $cases)) { case PASSWORD: fwrite ($stream, "password\n"); break; default: die ("Error was occurred while connecting to the remote host!\n"); } while ($line = fgets($stream)) { print $line; } fclose ($stream); ?> 
+3
source

There are several complications using the wait file_wrapper function. If it were me, I would just go for a simple socket for telnet and polling for prompts (with a timeout) if ssh failed.

On a casual inspection, the telnet client here seems to be well written - and with a little renaming, the same interface can be provided as the ssh2 Client Extension (except for the connection bit).

0
source

Source: https://habr.com/ru/post/989498/


All Articles