文档章节

模拟SSH输入密码并开启反向链接

descorg
 descorg
发布于 2016/01/26 13:31
字数 1066
阅读 19
收藏 0

SSHForward.h

/* 
 * File:   SSHForward.h
 * Author: 智欣仙子
 * tang_rong7407@163.com;496194564@qq.com
 * Created on 2016年1月26日, 上午10:07
 * ssh模拟输入密码并开启反向链接
 */

#ifndef SSHFORWARD_H
#define SSHFORWARD_H

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 需要在项目属性中的 Build -》 Linker -》Compilation Line 中添加 -lpthread
#include <pthread.h>

class SSHForward {
public:
    SSHForward();
    SSHForward(const SSHForward& orig);
    virtual ~SSHForward();
    
    /**
      * 设置服务器参数
      * @param addr
      * @param port
      * @param user
      * @param pwd
      */
    void setServer(const char *addr, int port, const char *user, const char *pwd);
    /**
     * 设置转发端口
     * @param port
     */
    void setForwardPort(int port);
    /**
      * 启动反向链接
      * @return 
      */
    int start();
    /**
      * 停止
      */
    void stop();
    
protected:
    static void *async_ssh_forward(void *lpParam);
    static void sigchld_handler(int signum);
    static void window_resize_handler(int masterpt);
    int match( const char *reference, const char *buffer, ssize_t bufsize, int state );
    void write_pass_fd( int srcfd, int dstfd );
    int handleoutput( int fd, const char *password );
    
protected:
    pthread_t m_pid;
    int lwState, server_port, forward_port, childpid;
    char username[20], password[50], server_ip[20];

};

#endif /* SSHFORWARD_H */

SSHForward.cpp

/* 
 * File:   SSHForward.cpp
 * Author: 智欣仙子
 * tang_rong7407@163.com;496194564@qq.com
 * Created on 2016年1月26日, 上午10:07
 */

#include "SSHForward.h"

static int masterpt, ourtty;

SSHForward::SSHForward()
{
    lwState     = 0;
}

SSHForward::SSHForward(const SSHForward& orig)
{
}

SSHForward::~SSHForward() {
}

void SSHForward::setServer(const char *addr, int port, const char *user, const char *pwd)
{
    snprintf(server_ip, sizeof(server_ip), "%s", addr);
    snprintf(username, sizeof(username), "%s", user);
    snprintf(password, sizeof(password), "%s", pwd);
    server_port     = port;
}

void SSHForward::setForwardPort(int port)
{
    forward_port    = port;
}

int SSHForward::start()
{
    if(lwState)
        return 0;
    
    pthread_create(&m_pid, NULL, async_ssh_forward, this);
    lwState = 1;
}

void SSHForward::stop()
{
    if(lwState)
    {
        lwState     = 0;
        kill(childpid, -9);
    }
}

void SSHForward::sigchld_handler(int signum)
{
}
void SSHForward::window_resize_handler(int signum)
{
    struct winsize ttysize; // The size of our tty
    if( ioctl( ourtty, TIOCGWINSZ, &ttysize )==0 )
        ioctl( masterpt, TIOCSWINSZ, &ttysize );
}
int SSHForward::match( const char *reference, const char *buffer, ssize_t bufsize, int state )
{
    // This is a highly simplisic implementation. It's good enough for matching "Password: ", though.
    int i;
    for( i=0;reference[state]!='\0' && i<bufsize; ++i ) {
        if( reference[state]==buffer[i] )
            state++;
        else {
            state=0;
            if( reference[state]==buffer[i] )
                state++;
        }
    }

    return state;
}
void SSHForward::write_pass_fd( int srcfd, int dstfd )
{
    int done=0;

    while( !done ) {
        char buffer[40];
            int i;
            int numread = read( srcfd, buffer, sizeof(buffer) );
            done=(numread<1);
            for( i=0; i<numread && !done; ++i ) {
                if( buffer[i]!='\n' )
                    write( dstfd, buffer+i, 1 );
                else
                    done=1;
        }
    }

    write( dstfd, "\n", 1 );
}
int SSHForward::handleoutput( int fd, const char *password )
{
    // We are looking for the string
    static int prevmatch=0; // If the "password" prompt is repeated, we have the wrong password.
    static int state1, state2;
    static const char compare1[]="password:"; // Asking for a password
    static const char compare2[]="The authenticity of host "; // Asks to authenticate host
    // static const char compare3[]="WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!"; // Warns about man in the middle attack
    // The remote identification changed error is sent to stderr, not the tty, so we do not handle it.
    // This is not a problem, as ssh exists immediately in such a case
    char buffer[40];
    int ret=0;

    int numread=read(fd, buffer, sizeof(buffer) );

    state1=match( compare1, buffer, numread, state1 );

    // Are we at a password prompt?
    if( compare1[state1]=='\0' ) {
        if( !prevmatch ) {
            write( fd, password, strlen( password ) );
            write( fd, "\n", 1 );
            state1=0;
            prevmatch=1;
        } else {
            // Wrong password - terminate with proper error code
            ret = 5;
        }
    }

    if( ret==0 ) {
        state2=match( compare2, buffer, numread, state2 );

        // Are we being prompted to authenticate the host?
        if( compare2[state2]=='\0' ) {
            ret = 5;
        }
    }

    return ret;
}

void *SSHForward::async_ssh_forward(void *lpParam)
{
    SSHForward *ssh = (SSHForward *)lpParam;
    
    int slavept, status = 0, terminate = 0;
    struct winsize ttysize;
    pid_t wait_id;
    sigset_t sigmask, sigmask_select;
    // We need to interrupt a select with a SIGCHLD. In order to do so, we need a SIGCHLD handler
    signal( SIGCHLD, sigchld_handler );

    // Create a pseudo terminal for our process
    masterpt = open("/dev/ptmx", O_RDWR);
    if( masterpt == -1 ) {
        printf("%s %d\nFailed to get a pseudo terminal\n\n", __FILE__, __LINE__);
        ssh->lwState = 0;
        return 0;
    }
    
    fcntl(masterpt, F_SETFL, O_NONBLOCK);
    if( grantpt( masterpt )!=0 ) {
        printf("%s %d\nFailed to change pseudo terminal's permission\n\n", __FILE__, __LINE__);
        ssh->lwState = 0;
        return 0;
    }
    if( unlockpt( masterpt )!=0 ) {
        printf("%s %d\nFailed to unlock pseudo terminal\n\n", __FILE__, __LINE__);
        ssh->lwState = 0;
        return 0;
    }
    
    ourtty = open("/dev/tty", 0);
    if( ourtty!=-1 && ioctl( ourtty, TIOCGWINSZ, &ttysize )==0 ) {
        signal(SIGWINCH, ssh->window_resize_handler);

        ioctl( masterpt, TIOCSWINSZ, &ttysize );
    }
    
    const char *name = ptsname(masterpt);
    ssh->childpid = fork();
    if( ssh->childpid == 0 )
    {
        setsid();
        // This line makes the ptty our controlling tty. We do not otherwise need it open
        slavept=open(name, O_RDWR );
        close( slavept );
        close( masterpt );
        
        //ssh -o StrictHostKeyChecking=no -R 171.92.208.225:2222:localhost:22 xxx@171.92.208.225 -p 10222
        char cmd[1024] = {0};
        snprintf(cmd, sizeof(cmd), "ssh -o StrictHostKeyChecking=no -R %s:%d:localhost:22 %s@%s -p %d", ssh->server_ip, ssh->forward_port, ssh->username, ssh->server_ip, ssh->server_port);
        printf("%s %d\n%s\n\n", __FILE__, __LINE__, cmd);
        execl("/bin/sh", "sh", "-c", cmd, (char *)0);
    }
    else if(ssh->childpid < 0)
    {
        printf("%s %d\nsshpass: Failed to create child process\n\n", __FILE__, __LINE__);
        ssh->lwState = 0;
        return 0;
    }
    
    // We are the parent
    slavept = open(name, O_RDWR | O_NOCTTY );
    // Set the signal mask during the select
    sigemptyset(&sigmask_select);
    // And during the regular run
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGCHLD);
    sigprocmask( SIG_SETMASK, &sigmask, NULL );
    
    do
    {
        if( !terminate )
        {
            fd_set readfd;
            FD_ZERO(&readfd);
            FD_SET(masterpt, &readfd);
            int selret = pselect( masterpt+1, &readfd, NULL, NULL, NULL, &sigmask_select );
            if( selret>0 )
            {
                if( FD_ISSET( masterpt, &readfd ) )
                {
                    int ret;
                    if( (ret = ssh->handleoutput( masterpt, ssh->password )) )
                    {
                        if( ret>0 ) {
                            close( masterpt ); // Signal ssh that it's controlling TTY is now closed
                            close(slavept);
                        }
                        terminate = ret;
                    }
                }
            }
            wait_id = waitpid( ssh->childpid, &status, WNOHANG );
        }
        else
        {
            wait_id = waitpid( ssh->childpid, &status, 0 );
        }
    } while(ssh->lwState && (wait_id==0 || (!WIFEXITED( status ) && !WIFSIGNALED( status ))) );
    
    ssh->lwState = 0;
    return 0;
}


© 著作权归作者所有

descorg
粉丝 1
博文 3
码字总数 1828
作品 0
高级程序员
私信 提问
xshell连接Ubuntu系统

Xshell是一个安全终端模拟软件,可以进行远程登录。我使用XShell的主要目的是在Windows环境下登录Linux终端,做相应操作。 1、下载安装xshell客户端 2、安装完成之后,如果你直接连接Ubuntu主...

anlve
2017/12/11
27
2
ssh登录一段时间后断开的解决方案

Method 1: 修改/etc/ssh/sshd_config配置文件,设置ClientAliveCountMax值大一点,单位是分钟。然后重启ssh服务使生效:service sshd reload Method 2: 找到所在用户的.ssh目录,如root用户该...

沉淀岁月
2016/11/22
22
0
linux 主机互信

目的:A主机想要无需输入密码连接B主机 分下面三步: (1)在A本机生成公钥与私钥 cd .ssh ssh-keygen -t rsa 此时在.ssh目录下生成了idrsa和idrsa.pub。其中idrsa是私钥,本机要用;idrsa.p...

a8757906
2017/07/03
0
0
网络基础CCNP|网络安全与配置

网络安全 设置的密文密码优先级大于明文密码。 service password-encryption之前所有的明文密码都加密 Show running-config | exclude !显示除了!开头的所有行 Show running-config | incl...

kissjz
2018/02/08
0
0
解决ssh登录后闲置时间过长而断开连接

解决ssh登录后闲置时间过长而断开连接 时我们通过终端连接服务器时,当鼠标和键盘长时间不操作,服务器就会自动断开连接,我们还的需要重新连接,感觉很麻烦,总结一下解决此问题的方法 方法...

thinkyoung
2015/03/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
今天
13
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
今天
7
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
今天
10
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
今天
12
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部