#TRUSTED 481ef88f30a88d6405f7b439803e328e588688917c9a57a29c8fa3ea24d47ef234fa07252d0881f2c40f654f5951e0fe57d280d2f1d571dda65d2741095bbc55fe224972e59c1463f1c387585e8700e33966ca64c33738d206d9bd4c482eaca0b6fb90689f1a83874bc8c9def5a3114c088d481c762f433580e895cfa6e481e946d88eb813e99075ce30b317716045351384bf8825457d49db7f91c94f192f57434748ca5ec31f43b15a0b513c19515658846e733d5f88e3060b973d3a6c0a1b4bf854e2906fa9186fa9e7f34be01d58a670a9eca699c3d4cab80a04b4792b47884f0923cf350ca3425f0b7d6e159465e171efa12f79245da529efebd36cf640b4faf2af87faf310e88d66f514f384e9f0b69488d9af2704c5ac8531ba0f62c5a59505f2834c09e9d3241530cdea7fa3948bfc44a6dd5feb5d9ebe834ac1eaac17b5e9a91be359ee1c04161ebd9fe2517fa4688df730fbee808940819ed8b1337689cc087a5da184b52f2446c0229303c2184f4d29df195f2a79c61dcf59992eda27e04b077fef87a7d5b689e2c5d38737c59691aff8f8d51358dbf54b5b6379bdca0e6c0bf29a494bcf5e6af72e5b1df867fe948487d61acc699ce44a460844513b0556d9efd1ff201faf3c68e948f3aa584a6e34453af8c08a5d77bf9f7f2a67e68a539f5411f7a8eed62b82d4ede2e1bfa0ad791901db56e775eba0dfcee6
#------------------------------------------------------------------------------
#
# (C) Nicolas Pouvesle
# This script is released under the version 2 to the Gnu General Public Licence
#
#
# **** You need Nessus 2.1.0 or newer to make any use of the functions in this
# ****  file
#
#

global_var session_id, enc_keys, seqn_w, seqn_r;
global_var local_channel, remote_channel;
global_var dh_pub, dh_priv;

function kb_ssh_login()
{
 return string(get_kb_item("SSH/login"));
}

function kb_ssh_password()
{
 return string(get_kb_item("SSH/password"));
}

function kb_ssh_privatekey()
{
 return string(get_kb_item("SSH/privatekey"));
}

function kb_ssh_publickey()
{
 return string(get_kb_item("SSH/publickey"));
}

function kb_ssh_passphrase()
{
 return string(get_kb_item("SSH/passphrase"));
}

function kb_ssh_transport()
{
 local_var r;
 r = get_kb_item("Services/ssh");

 if ( r ) return int(r);
 else return 22;
}

#-----------------------------------------------------------------#
# Convert network long (buffer) to long                           #
#-----------------------------------------------------------------#
function ntol(buffer,begin)
{
 local_var len;

 len = 16777216*ord(buffer[begin]) +
       ord(buffer[begin+1])*65536 +
       ord(buffer[begin+2])*256 +
       ord(buffer[begin+3]);

 return len;
}

#-----------------------------------------------------------------#
# Convert int to network long (raw_string)                        #
#-----------------------------------------------------------------#
function raw_int32(i)
{
 local_var buf;

 buf = raw_string (
		 (i>>24) & 255,
        (i>>16) & 255,
        (i>>8) & 255,
        (i) & 255
		 );
 return buf;
}

#-----------------------------------------------------------------#
# Convert char to network char (raw_string)                       #
#-----------------------------------------------------------------#
function raw_int8(i)
{
 local_var buf;

 buf = raw_string (
        (i) & 255
		 );
 return buf;
}


#-----------------------------------------------------------------#
# Init packet sequence number and channel number                  #
#-----------------------------------------------------------------#
function init()
{
 # sequence packet = 0
 seqn_w = seqn_r = 0;
 local_channel = 0;
}


#-----------------------------------------------------------------#
# Decode base64 string - ported from public domain code           #
#-----------------------------------------------------------------#
function base64decode(str)
{
 local_var len, i, j, k, ret, base64, b64;
 len = strlen(str);
 ret = "";

 base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

 for (i = 0; i < 256; i++)
   b64[i] = 0;
 for (i = 0; i < strlen(base64); i++)
   b64[ord(base64[i])] = i;

 for(j=0;j<len;j+=4)
 {
   for (i = 0; i < 4; i++)
   {
    c = ord(str[j+i]);
    a[i] = c;
    b[i] = b64[c];
   }
 
   o[0] = (b[0] << 2) | (b[1] >> 4);
   o[1] = (b[1] << 4) | (b[2] >> 2);
   o[2] = (b[2] << 6) | b[3];
   if (a[2] == ord('='))
     i = 1;
   else if (a[3] == ord('='))
     i = 2;
   else
     i = 3;
   for(k=0;k<i;k++)
      ret += raw_int8(i:o[k]);
   
   if (i < 3) 
     break;
 }

 return ret;
}


#-----------------------------------------------------------------#
# Reads a SSH packet (comes from smb_nt.inc)                      #
#-----------------------------------------------------------------#
function ssh_recv(socket, length)
{
   local_var header, len, trailer;

   header = recv(socket:socket, length:4, min:4);
   if (strlen(header) < 4)return(NULL);
   len = ntol (buffer:header, begin:0);
   if (len == 0)return(header);
   trailer = recv(socket:socket, length:len, min:len);
   if(strlen(trailer) < len )return(NULL);
   
   seqn_r++;
   return strcat(header, trailer);
}

#-----------------------------------------------------------------#
# Waits for the server identification string, and sends our own   #
# identification string.                                          #
#-----------------------------------------------------------------#
function ssh_exchange_identification(socket)
{
 local_var buf, sshversion, num, prot;

 buf = recv_line(socket:socket, length:1024);

 if (!buf)
  return 0;

 # server ident : SSH-%d.%d-servername #
 if (!ereg(string:buf, pattern:"^SSH-*[0-9]\.*[0-9]-*[^\n]"))
  return 0;

 sshversion = split(buf, sep:"-", keep:0);
 num = split(sshversion[1], sep:".", keep:0);

 # version supported = 2 & 1.99
 if ((num[0] != 2) && !((num[0] == 1) && (num[1] == 99)))
  return 0;

 # We use 2.0 protocol
 prot = "SSH-2.0-Nessus"+raw_string(0x0a);
 send(socket:socket, data:prot);

 if ( '\r\n' >< buf ) buf = buf - '\r\n';
   else buf = buf - '\n';

 # all is correct
 return buf;
}


#-----------------------------------------------------------------#
# check pattern in buffer                                         #
# return next len in buffer or -1                                 #
#-----------------------------------------------------------------#
function check_pattern(buffer,pattern,length)
{
 local_var alglen, len, alg;

 alglen = ntol (buffer:buffer, begin:length);
 len = length+4+alglen;
 alg = substr(buffer,length+4,len-1);
 if (!ereg(string:alg, pattern:pattern))
  return -1;

 return len;
}

#-----------------------------------------------------------------#
# Create key exchange packet                                      #
#-----------------------------------------------------------------#
function kex_packet(payload,code)
{
 local_var len, padding_len, full_len, kex;

 len = 
   # padding length
     1 +
     # msg code
     1 +
     # payload length
     strlen(payload);
  
 #padding (mod 8) = 8 - ( (len+packet_len(4) ) % 8 ) 
 padding_len = 8 - ((len + 4) % 8);

 # if padding len is less than 4 add block size
 if (padding_len < 4)
   padding_len += 8;
 
 full_len = len + padding_len;

 kex =
    # packet length
    raw_int32 (i:full_len) +
    # padding length
    raw_int8 (i:padding_len) +
    #msg code (32 = Diffie-Hellman GEX Init)
    code +
    # Payload (Pub key)
    payload +
    # Padding
    crap(data:raw_string(0),length:padding_len);

 return kex;
}


#-----------------------------------------------------------------#
# mac compute                                                     #
#-----------------------------------------------------------------#
function mac_compute(data, type)
{
 local_var to_hash;

 # we only support sha1! enc_keys[5] == mac_out key
 if (!type)
 {
  to_hash = raw_int32(i:seqn_w) + data;
  hash = HMAC_SHA1(data:to_hash, key:enc_keys[4]);
 }
 else
 {
  to_hash = raw_int32(i:seqn_r) + data;
  hash = HMAC_SHA1(data:to_hash, key:enc_keys[5]);
 }

 return hash;
}


#-----------------------------------------------------------------#
# crypt data                                                      #
#-----------------------------------------------------------------#
function crypt(data)
{
 local_var crypted;

 crypted = bf_cbc_encrypt(data:data, key:enc_keys[2], iv:enc_keys[0]);

 enc_keys[0] = crypted[1];

 return crypted[0];
}

#-----------------------------------------------------------------#
# decrypt data                                                    #
#-----------------------------------------------------------------#
function decrypt(data)
{
 local_var decrypted;

 decrypted = bf_cbc_decrypt(data:data, key:enc_keys[3], iv:enc_keys[1]);

 enc_keys[1] = decrypted[1];

 return decrypted[0];
}

#-----------------------------------------------------------------#
# Send ssh packet                                                 #
#-----------------------------------------------------------------#
function send_ssh_packet(socket,payload,code)
{
 local_var len, padding_len, full_len, buf, res, macbuf, crypted;

 len = 
   # padding length
     1 +
     # msg code
     1 +
     # payload length
     strlen(payload);
  
 #padding (mod 8) = 8 - ( (len+packet_len(4) ) % 8 ) 
 padding_len = 8 - ((len + 4) % 8);

 # if padding len is less than 4 add block size
 if (padding_len < 4)
   padding_len += 8;
 
 full_len = len + padding_len;

 padding = "";
 for (i=0;i<padding_len;i++)
    padding = padding + raw_int8(rand() % 256); 


 buf =
    # packet length
    raw_int32 (i:full_len) +
    # padding length
    raw_int8 (i:padding_len) +
    #msg code (32 = Diffie-Hellman GEX Init)
    code +
    # Payload (Pub key)
    payload +
    # Padding
    padding;

 macbuf = mac_compute(data:buf, type:0);
 
 crypted = crypt(data:buf);

 buf = crypted + macbuf;

 send(socket:socket, data:buf);

 seqn_w++;
}


#-----------------------------------------------------------------#
# Receive ssh packet                                              #
#-----------------------------------------------------------------#
function recv_ssh_packet(socket, timeout)
{
 local_var len, need, padding_len, full_len, buf, res, macbuf, decrypted;
 local_var hmac, hmacbuf, mac, payload;


 payload = raw_int8(i:0);

 # blockbytes = 8 for blowfish-cbc
 buf = recv(socket:socket, length:8, min:8, timeout:timeout);
 if (strlen(buf) != 8)
   return payload;
 
 decrypted = decrypt(data:buf);
 
 len = ntol(buffer:decrypted, begin:0);
 # 8 = blocksize ... i know it is not generic and it will be hard to change all
 need = 4 + len - 8;
 buf = recv(socket:socket, length:need, min:need, timeout:timeout);
 if (strlen(buf) != need)
   return payload;
 
 decrypted = decrypted + decrypt(data:buf);

 # hmac-sha1 length = 20 ... same comment as before
 mac = recv(socket:socket, length:20, min:20, timeout:timeout);
 if (strlen(mac) != 20)
   return payload;

 macbuf = mac_compute(data:decrypted, type:1);

 hmac = hexstr(mac);
 hmacbuf = hexstr(macbuf);
 if (hmac >!< hmacbuf)
   return payload;

 payload = substr(decrypted, 5, strlen(decrypted)-ord(decrypted[4])-1);
 seqn_r++;

 return payload;
}


#-----------------------------------------------------------------#
# Get payload from packet                                         #
#-----------------------------------------------------------------#
function packet_payload(packet,code)
{
 local_var packetlen, paddinglen, msgcode;

 packetlen = ntol(buffer:packet, begin:0);
 paddinglen = ord(skexr[4]);
 msgcode = ord(skexr[5]);
 
 # Diffie-Hellman Key Exchange Reply
 if (msgcode != code)
  return 0;
 
 payload = substr(packet,6,packetlen-1);
 return payload;
}

#-----------------------------------------------------------------#
# Get string (lenght,string)                                      #
#-----------------------------------------------------------------#
function getstring(buffer,pos)
{
 local_var buf_len, buf;

 buf_len = ntol (buffer:buffer,begin:pos);
 buf = substr(buffer,pos+4,pos+4+buf_len-1);

 return buf;
}

#-----------------------------------------------------------------#
# Put string (string)                                             #
#-----------------------------------------------------------------#
function putstring(buffer)
{
 local_var buf;

 buf = raw_int32(i:strlen(buffer)) + buffer;
 
 return buf;
}

#-----------------------------------------------------------------#
# Put bignum (string)                                             #
#-----------------------------------------------------------------#
function putbignum(buffer)
{
 local_var len, buf;

 if (ord(buffer[0]) & 0x80)
 {
   len = strlen(buffer)+1;
   buf = raw_int32(i:len) + raw_string(0x00) + buffer;
 }
 else   
   buf = raw_int32(i:strlen(buffer)) + buffer;
 
 return buf;
}

#-----------------------------------------------------------------#
# RSA verify signature                                            #
#-----------------------------------------------------------------#
function ssh_rsa_verify(e, n, signature, data)
{
 local_var hash, id_sha1, sigtype, nlen,
	next, tmp_sig, siglen, len, sig,
	hdecoid, hshaoid, hhash, decrypted ;

#comes directly from OpenBSD
 id_sha1 = raw_string(
	0x30, 0x21, 
	0x30, 0x09,
	0x06, 0x05,
	0x2b, 0x0e, 0x03, 0x02, 0x1a, 
	0x05, 0x00,
	0x04, 0x14 
	);

 if (!n)
   return 0;

 sigtype = getstring(buffer:signature, pos:0);
 if (sigtype >!< "ssh-rsa")
   return 0;

 nlen = strlen(n);
 if (ord(n[0]) == 0)
   nlen--;
 
 # check minimum n size
 if ( (nlen*8) < 768 )
   return 0;

 next = 4 + strlen(sigtype);
 tmp_sig = getstring(buffer:signature,pos:next);
 siglen = strlen(tmp_sig);

 # bad signature (should be less than n)
 if (siglen > nlen)
   return 0;
 
 # Add padding if needed
 if (siglen < nlen)
 { 
   len = nlen - siglen;
   sig = crap(data:raw_string(0x00), length:len) + tmp_sig;
 }
 else
   sig = tmp_sig;

 hash = SHA1(data);

 if (strlen(hash) != 20)
   return 0;

 # must call RSA_public_decrypt from openssl, so convert arg - see ssh-rsa.c
 decrypted = rsa_public_decrypt(sig:sig,e:e,n:n);
 if (!decrypted)
   return 0;
 
 if (strlen(decrypted) != (strlen(id_sha1)+20))
   return 0;

 hdecoid = hexstr(substr(decrypted,0,strlen(id_sha1)-1));
 hshaoid = hexstr(id_sha1);

 if (hdecoid >!< hshaoid)
   return 0; 

 hdecoid = hexstr(substr(decrypted,strlen(id_sha1),strlen(decrypted)-1));
 hhash = hexstr(hash);

 if (hdecoid >!< hhash)
   return 0; 

 return 1;
}


#-----------------------------------------------------------------#
# DSA verify signature                                            #
#-----------------------------------------------------------------#
function ssh_dss_verify(p, q, g, pub, signature, data)
{
 local_var sigtype, next, tmp_sig, siglen, r, s, hash;

 sigtype = getstring(buffer:signature, pos:0);
 if (sigtype >!< "ssh-dss")
   return 0;

 next = 4 + strlen(sigtype);
 tmp_sig = getstring(buffer:signature,pos:next);
 siglen = strlen(tmp_sig);

 r = substr(tmp_sig, 20, 39);
 s = substr(tmp_sig, 40, 59);

 hash = SHA1(data);

 return dsa_do_verify(p:p,g:g,q:q,pub:pub,r:r,s:s,data:hash);
}


#-----------------------------------------------------------------#
# Derive keys  (this function works because we only use sha1 and  #
# blowfish so keylen is 20 due to sha1)                           #
#-----------------------------------------------------------------#
function derive_keys(hash,shared,session_id)
{
 local_var c, i, to_hash, keys;
 # c = 'A';
 c = 65;
 for (i = 0;i < 6; i++)
 {
   to_hash = putbignum(buffer:shared) + hash + raw_int8(i:c) + session_id;
   keys[i] = SHA1(to_hash);
   c++;
 }

 #         MODE OUT  MODE IN
 # enc.iv    0         1
 # enc.key   2         3
 # mac.key   4         5

 return keys;
}


#-----------------------------------------------------------------#
# Check is public key is correct                                  #
#-----------------------------------------------------------------#
function dh_valid_key(key, p)
{
 local_var val,i;

 if (ord(key[0]) > 0x80)
   return 0;

 val = 0;
 for(i=0;i<strlen(key);i++)
 {
  val = val + ord(key[i]);
  if (val > 1)
    break;
 }

 # ok if key < p
 if ((val>1) && (bn_cmp(key1:key,key2:p) == -1))
   return 1;

 return 0;
}


#-----------------------------------------------------------------#
# Genereate dh public & private keys                              #
#-----------------------------------------------------------------#
function dh_gen_key(p, g)
{
 local_var tries,keys;
 
 dh_pub = dh_priv = "";

 tries = 0;

 if (!p)
   return keys;

 # { "blowfish-cbc", 	SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc }
 # hash = sha1 = 20 (len) = 20 * 8 (bits)
 need = 20 * 8;

 # need won't be > than INT_MAX / 2
 # maybe we must test if 2*need >= numbits ...
 #if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p))
 #  return keys;

 for (tries = 0; tries < 10; tries++)
 {
   dh_priv = bn_random(need:(need*2));
   if (!dh_priv)
     return -1;
   dh_pub = dh_generate_key(p:p, g:g, priv:dh_priv);
   if (!dh_pub)
     return -1;
   if (dh_valid_key(key:dh_pub, p:p))
     break;
 }

 if (tries++ >= 10)
   return -1;

 return 0;
}


#-----------------------------------------------------------------#
# Waits for the server identification string, and sends our own   #
# identification string.                                          #
#-----------------------------------------------------------------#
function ssh_kex2(socket,server_version)
{
 local_var packetlen, paddinglen, msgcode, len, len2;
 local_var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;
 local_var skexkex, kexr, skexr, gex, gexr, nk;
 local_var sinit, scookie, ccookie, cinit;
 local_var payload; 
 local_var keys, server_host_key_blob, shared; 
 local_var alg_type, type;
 local_var start, next, correct; 
 local_var rsa_e, rsa_n, dsa_p, dsa_q, dsa_g, dsa_pub_key; 
 local_var server_dh_public_key, signed_h, to_hash, hash;
	

 # supported algorithms
 key_exchange_algo        = "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1";
 server_host_key_algo     = "ssh-rsa,ssh-dss";
 enc_alg_client_to_server = "blowfish-cbc";
 enc_alg_server_to_client = "blowfish-cbc";
 mac_alg_client_to_server = "hmac-sha1";
 mac_alg_server_to_client = "hmac-sha1";
 cmp_alg_client_to_server = "none";
 cmp_alg_server_to_client = "none";

 # version
 client_version = "SSH-2.0-Nessus";


### Key exchange send client Init ###

 skex = ssh_recv(socket:socket, length:2000);

 packetlen = ntol (buffer:skex, begin:0);
 paddinglen = ord(skex[4]);
 msgcode = ord(skex[5]);
 if (msgcode != 20)
  return -1;

 sinit = substr(skex,6,packetlen+4-paddinglen-1);

 scookie = substr(skex,6,21);
 
 len = check_pattern(buffer:skex, pattern:key_exchange_algo, length:22);
 if (len == -1)
  return -1;

 len2 = check_pattern(buffer:skex, pattern:"ssh-rsa", length:len);
 if (len2 == -1)
 {
   len2 = check_pattern(buffer:skex, pattern:"ssh-dss", length:len);
   if (len2 == -1)
     return -1;
 }

 len = check_pattern(buffer:skex, pattern:enc_alg_client_to_server, length:len2);
 if (len == -1)
  return -1;

 len2 = check_pattern(buffer:skex, pattern:enc_alg_server_to_client, length:len);
 if (len2 == -1)
  return -1;

 len = check_pattern(buffer:skex, pattern:mac_alg_client_to_server, length:len2);
 if (len == -1)
  return -1;

 len2 = check_pattern(buffer:skex, pattern:mac_alg_server_to_client, length:len);
 if (len2 == -1)
  return -1;

 len = check_pattern(buffer:skex, pattern:cmp_alg_client_to_server, length:len2);
 if (len == -1)
  return -1;

 len2 = check_pattern(buffer:skex, pattern:cmp_alg_server_to_client, length:len);
 if (len2 == -1)
  return -1;


### Key exchange recv server Init ###

 ccookie = "";
 for (i=0;i<16;i++)
    ccookie = ccookie + raw_int8(rand() % 256); 

 cinit =
    # cookie (random)
    ccookie +
    # key algorithms (length + string)
    raw_int32(i:strlen(key_exchange_algo)) + key_exchange_algo +
    # server host key algorithms (length + string)
    raw_int32(i:strlen(server_host_key_algo)) + server_host_key_algo +
    # encryption algorithms client to server (length + string)
    raw_int32(i:strlen(enc_alg_client_to_server)) + enc_alg_client_to_server +
    # encryption algorithms server to client (length + string)
    raw_int32(i:strlen(enc_alg_server_to_client)) + enc_alg_server_to_client +
    # mac algorithms client to server (length + string)
    raw_int32(i:strlen(mac_alg_client_to_server)) + mac_alg_client_to_server +
    # mac algorithms server to client (length + string)
    raw_int32(i:strlen(mac_alg_server_to_client)) + mac_alg_server_to_client +
    # compression algorithms client to server (length + string)
    raw_int32(i:strlen(cmp_alg_client_to_server)) + cmp_alg_client_to_server +
    # compression algorithms server to client (length + string)
    raw_int32(i:strlen(cmp_alg_server_to_client)) + cmp_alg_server_to_client +
    # languages client to server (lenght)
    raw_int32(i:0) +
    # languages server to client (lenght)
    raw_int32(i:0) +
    # payload
    crap(data:raw_string(0x00), length:5);

 # msg code (20 = key exchange init)
 kex = kex_packet(payload:cinit,code:raw_string(0X14));

 send(socket:socket, data:kex);
 seqn_w++;


### Key exchange Request : Diffie-Hellman GEX Request ###

 payload = raw_string(0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00);
 # msg code (34 = Diffie-Hellman GEX Request)
 kexr = kex_packet(payload:payload,code:raw_string(34));
 
 send(socket:socket, data:kexr);
 seqn_w++;


### Key exchange Reply : Diffie-Hellman Key Exchange Reply ###

 skexr = ssh_recv(socket:socket, length:1000);

 # code = 31 (Diffie-Hellman Key Exchange Reply)
 payload = packet_payload(packet:skexr, code:31);
 if (!payload)
  return -1;

 # get p bignum for dh group
 p = getstring (buffer:payload,pos:0);

 # get g bignum for dh group
 start = 4+strlen(p);
 g = getstring(buffer:payload,pos:start);

 # generate public and private keys
 ret = dh_gen_key(p:p,g:g);
 if (ret != 0)
  return -1;


### Diffie Hellman GEX Init ###

 payload = raw_int32(i:strlen(dh_pub)) + dh_pub;

 # msg code (32 = Diffie-Hellman GEX Init)
 gex = kex_packet(payload:payload,code:raw_string(0x20));
 
 send(socket:socket, data:gex);
 seqn_w++;

### Diffie Hellman GEX Reply ###

 gexr = ssh_recv(socket:socket, length:2000);

 payload = packet_payload(packet:gexr, code:31);
 if (!payload)
  return -1;

 # server host key blob
 server_host_key_blob = getstring (buffer:payload,pos:0);

 # extract server host key
 alg_type = getstring (buffer:server_host_key_blob, pos:0);
 next = 4 + strlen(alg_type);

 if (alg_type >< "ssh-rsa")
  {
   # rsa type == 0
   type = 0; 

   # e
   rsa_e = getstring (buffer:server_host_key_blob,pos:next);
   next = next + 4 + strlen(rsa_e);

   # n
   rsa_n = getstring (buffer:server_host_key_blob,pos:next);
   next = next + 4 + strlen(rsa_n);
  }
 else
  {
   if (alg_type >< "ssh-dss")
    {
     # dsa type == 1
     type = 1; 

     # p
     dsa_p = getstring (buffer:server_host_key_blob,pos:next);
     next = next + 4 + strlen(dsa_p);

     # q
     dsa_q = getstring (buffer:server_host_key_blob,pos:next);
     next = next + 4 + strlen(dsa_q);

     # g
     dsa_g = getstring (buffer:server_host_key_blob,pos:next);
     next = next + 4 + strlen(dsa_g);

     # pub key
     dsa_pub_key = getstring (buffer:server_host_key_blob,pos:next);
     next = next + 4 + strlen(dsa_pub_key);
    }
   else
    # bad key algo - should not occur
    return -1;
  }  


 # server dh public key
 start = 4 + strlen(server_host_key_blob);
 server_dh_public_key = getstring(buffer:payload,pos:start);

 # signed H
 start = start + 4 + strlen(server_dh_public_key);
 signed_h = getstring(buffer:payload,pos:start);
  
 if (!dh_valid_key(key:server_dh_public_key, p:p))
   return -1;

 # shared secret #
 shared = dh_compute_key(p:p,g:g,dh_server_pub:server_dh_public_key,
  pub_key:dh_pub,priv_key:dh_priv);
 if (!shared)
   return -1;


 # hash data
 to_hash = 
	# client version
	putstring(buffer:client_version) +
	# server version
	putstring(buffer:server_version) +
	# client cookie (cookielen,SSH2_MSG_KEXINIT,cookie)
	raw_int32(i:(strlen(cinit)+1)) + raw_int8(i:20) + cinit +
	# server cookie (cookielen,SSH2_MSG_KEXINIT,cookie)
	raw_int32(i:(strlen(sinit)+1)) + raw_int8(i:20) + sinit +
	# server host key blob
	putstring(buffer:server_host_key_blob) +
	# min,wantbits,max
	raw_string(0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x20,0x00) +
	# p bignum
	putbignum(buffer:p) +
	# g bignum
	putbignum(buffer:g) +
	# public key bignum
	putbignum(buffer:dh_pub) +
	# server dh public key bignum
	putbignum(buffer:server_dh_public_key) +
	# shared bignum
	putbignum(buffer:shared);

 hash = SHA1(to_hash); 

 if (type == 0)
   correct = ssh_rsa_verify(e:rsa_e, n:rsa_n, signature:signed_h, data:hash);
 else
   # Not implemented
   correct = ssh_dss_verify(p:dsa_p, q:dsa_q, g:dsa_g, pub:dsa_pub_key, signature:signed_h, data:hash);

 if (!correct)
   return -1;

 session_id = hash;
 enc_keys = derive_keys(hash:hash,shared:shared,session_id:session_id);


 # what is that data ???
 mac_data = recv(socket:socket, length:16, min:16);
 seqn_r++;

### New keys ###

 payload = NULL;

 # msg code (21 = New keys)
 nk = kex_packet(payload:payload,code:raw_string(0x15));
 
 send(socket:socket, data:nk);
 seqn_w++;

 # all is correct
 return 0; 
}


#-----------------------------------------------------------------#
# Authenticate to SSH server                                      #
#-----------------------------------------------------------------#
function ssh_userauth2(socket, server_user, password, pub, priv, passphrase)
{
 local_var payload, buf, support, pass, pkey, authenticated, blobpub, signature, blobpriv, privkey, typestr, next, e, n, hash2, hash;

 pass = pkey = authenticated = 0;

 payload = putstring(buffer:"ssh-userauth");

 # code 5 (SSH2_MSG_SERVICE_REQUEST)
 send_ssh_packet(socket:socket, payload:payload, code:raw_string(0x05));

 # code 6 (SSH2_MSG_SERVICE_ACCEPT)
 payload = recv_ssh_packet(socket:socket);
 if (ord(payload[0]) != 6)
   return -1;

 # service accepted
 # code 50 (SSH2_MSG_USERAUTH_REQUEST)
 # none request: we need to know what authentification server supports
 payload = putstring(buffer:server_user) + putstring(buffer:"ssh-connection") +
	putstring(buffer:"none");
 send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:50));

 # (51 == SSH2_MSG_USERAUTH_FAILURE)
 payload = recv_ssh_packet(socket:socket);
 if (ord(payload[0]) != 51)
   return -1;

 support = getstring(buffer:payload,pos:1);

 if ((pub && priv) && ereg(string:support, pattern:"publickey"))
   pkey = 1;
 else
   pass = 1;
 

 if (pass)
 {
  # code 50 (SSH2_MSG_USERAUTH_REQUEST)
  ###### need extra pad !!!! ######
  ###### Is it usefull ?? #####
  payload = putstring(buffer:server_user) + putstring(buffer:"ssh-connection") +
	putstring(buffer:"password") + raw_int8(i:0) + putstring(buffer:password)
	;

  send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:50));

  # code 52 (SSH2_MSG_USERAUTH_SUCCESS)
  payload = recv_ssh_packet(socket:socket);
  if (ord(payload[0]) == 52)
     authenticated = 1;
 }
 if (!authenticated && pkey)
 {
  blobpub = base64decode(str:pub);

  # code 50 (SSH2_MSG_USERAUTH_REQUEST)
  ###### need extra pad !!!! ######
  ###### Is it usefull ?? #####

  payload = putstring(buffer:server_user) + putstring(buffer:"ssh-connection") +
	putstring(buffer:"publickey") + raw_int8(i:1) ; 

  to_hash = putstring(buffer:session_id) + raw_int8(i:50);

  typestr = getstring(buffer:blobpub, pos:0);
  if (typestr >< "ssh-rsa")
  {
    next = 4 + strlen(typestr);
    e = getstring(buffer:blobpub, pos:next);
    next = next + 4 + strlen(e);
    n = getstring(buffer:blobpub, pos:next);

    privkey = pem_to_rsa(priv:priv, passphrase:passphrase);
    if (!privkey)
      return -1;

    payload += putstring(buffer:"ssh-rsa") + putstring(buffer:blobpub);

    to_hash += payload;

    hash = SHA1(to_hash);
    signature = rsa_sign(e:e, n:n, d:privkey, data:hash);
    if (!signature)
      return -1;

    signature = putstring(buffer:"ssh-rsa") + putstring(buffer:signature);
  }
  else if (typestr >< "ssh-dss")
  {
    # p
    next = 4 + strlen(typestr);
    p = getstring (buffer:blobpub,pos:next);
    next = next + 4 + strlen(p);

    # q
    q = getstring (buffer:blobpub,pos:next);
    next = next + 4 + strlen(q);

    # g
    g = getstring (buffer:blobpub,pos:next);
    next = next + 4 + strlen(g);

    # pub key
    pub_key = getstring (buffer:blobpub,pos:next);
 
    privkey = pem_to_dsa(priv:priv, passphrase:passphrase);
    if (!privkey)
      return -1;

    payload += putstring(buffer:"ssh-dss") + putstring(buffer:blobpub);

    to_hash += payload;

    hash = SHA1(to_hash);
    signature = dsa_do_sign(p:p, q:q, g:g, pub:pub_key, priv:privkey, data:hash);
    if (!signature)
      return -1;

    signature = putstring(buffer:"ssh-dss") + putstring(buffer:signature);

  }
  else
     return -1;

  payload += putstring(buffer:signature);

  send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:50));

  # code 60 (SSH2_MSG_USERAUTH_PK_OK)
  payload = recv_ssh_packet(socket:socket);
  if ((ord(payload[0]) == 52) || (ord(payload[0]) == 60))
     authenticated = 1;
 }

 if (!authenticated)
   return -1;

 # all is ok, user is authenticated
 return 0;
}


#-----------------------------------------------------------------#
# Open channel                                                    #
#-----------------------------------------------------------------#
function ssh_open_channel(socket)
{
 local_var payload;

 local_channel++;

 # session = "session"
 # initial window size = 32768
 # maximum packet size = 32768
 payload = putstring(buffer:"session") + raw_int32(i:local_channel) +
	raw_int32(i:32768) + raw_int32(i:32768);

 # SSH2_MSG_CHANNEL_OPEN == 90
 send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:90));

 # SSH2_MSG_CHANNEL_OPEN_CONFIRMATION == 91 (92 == failure)
 payload = recv_ssh_packet(socket:socket);
 if (ord(payload[0]) != 91)
   return -1;

 remote_channel = ntol(buffer:payload, begin:5);

 # all is ok, user is authenticated
 return 0;

}

#-----------------------------------------------------------------#
# Close channel                                                   #
#-----------------------------------------------------------------#
function ssh_close_channel(socket)
{
 local_var payload;

 local_channel = 4444;

 # session = "session"
 # sender channel = 4444  / should we try different number on failure ?
 # initial window size = 32768
 # maximum packet size = 32768
 payload = raw_int32(i:remote_channel);

 # SSH2_MSG_CHANNEL_CLOSE == 97
 send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:97));

 # SSH2_MSG_CHANNEL_CLOSE == 97
 payload = recv_ssh_packet(socket:socket);
 while((ord(payload[0]) != 97) && (ord(payload[0]) != 0))
    payload = recv_ssh_packet(socket:socket);

 if (ord(payload[0]) != 97)
   return -1;

 # all is ok, user is authenticated
 return 0;

}


#-----------------------------------------------------------------#
# Login to SSH server                                             #
#-----------------------------------------------------------------#
function ssh_login(socket, login, password, pub, priv, passphrase)
{
 local_var server_user, ret;

 server_user = tolower(login);

 init();

 # Exchange protocol version identification strings with the server.
 server_version = ssh_exchange_identification(socket:socket);
 if (!server_version)
  return -1;

 # key exchange
 # authenticate user
 ret = ssh_kex2(socket:socket, server_version:server_version);
 if (ret != 0)
   return -1;

 ret = ssh_userauth2(socket:socket, server_user:server_user, password:password, pub:pub, priv:priv, passphrase:passphrase);  
 if (ret != 0)
   return -1;

 # all is ok
 return 0;
}


#-----------------------------------------------------------------#
# Execute command on SSH server                                   #
#-----------------------------------------------------------------#
function ssh_cmd(socket,cmd,timeout)
{
 local_var payload, ret;

 # Open channel
 ret = ssh_open_channel(socket:socket);
 if (ret != 0)
   return -1;

 payload = raw_int32(i:remote_channel) + putstring(buffer:"exec") + raw_int8(i:0) +
	 putstring(buffer:cmd);

 # SSH2_MSG_CHANNEL_REQUEST == 98
 send_ssh_packet(socket:socket, payload:payload, code:raw_int8(i:98));

 # SSH2_MSG_CHANNEL_SUCCESS == 99
 # while for previous useless messages (SSH2_MSG_CHANNEL_WINDOW_ADJUST, ...)
 payload = recv_ssh_packet(socket:socket, timeout:timeout);
 while((ord(payload[0]) == 93) || (ord(payload[0]) == 95) || (ord(payload[0]) == 98))
    payload = recv_ssh_packet(socket:socket, timeout:timeout);


 ret = NULL;
 while (ord(payload[0]) == 94)
   {
   ret += getstring(buffer:payload, pos:5);
   payload = recv_ssh_packet(socket:socket, timeout:timeout);
   }


 # Close channel
 ssh_close_channel(socket:socket);

 return ret;

}

