0
$\begingroup$

Currently I'm working on an intercepting proxy server for mosh connections.

I'm able to intercept the ssh session to get the shared secret and alter the connection information for the mosh client. The mosh client is able to connect with my udp proxy server which is started for the requested mosh session and redirects the traffic to the destination server. The mosh client works without any issues.

  • MOSH-port: 60010
  • MOSH-shared-secret: gy37yTEqclUSpFODXW2L+A

I got following message:

0000:    80 00 00 00 00 00 00 00 67 a3 a3 8d 18 0b 0c 45 44 8b 6c    ........g......ED.l
0013:    8e 85 11 60 89 bf 6e 81 40 50 ee 80 11 31 b2 1e 68 ae d8    ...`[email protected]..
0026:    aa 29 23 41 2f 27 d5 83 cb ec 70 8a a2 27 81 7a 1b 44 97    .)#A/'....p..'.z.D.
0039:    e0 cb 67 e7 46 d8 1f 7f 3f 4a 27 31 04 c1 06 a3 8e f3 3a    ..g.F...?J'1......:
004C:    eb 2f c5 2f ab f8 8e aa ea f4 9d 81 ea 4e ed a2 09 a0 03    ././.........N.....
005F:    60 60 1e a1 f5 9f ce 94 81 69 af dd d8 4a 75 06 47 80 13    ``.......i...Ju.G..
0072:    df 49 66 60 e6 aa 1c 17 64 3f e1 ef d1 4d d8 4b 54 12 6f    .If`....d?...M.KT.o
0085:    47 8f 34 31 d0 1f 3f 22 54 cb a7 de 15 91 b4 6d 5d 28 c8    G.41..?"T......m](.
0098:    1c a1 b5 

The first 8 bytes are used to create the nonce:

0000:    80 00 00 00 00 00 00 00         ........

According to the mosh research paper the message is encrypted with AES-128 in the Offset Codebook (OCB) mode. I have also found the function, which decrypts the message: https://github.com/mobile-shell/mosh/blob/f3665fb99bffc5929193a204d8540d74749b52c3/src/crypto/crypto.cc#L250:L286

const Message Session::decrypt( const char *str, size_t len )
{
  if ( len < 24 ) {
    throw CryptoException( "Ciphertext must contain nonce and tag." );
  }

  int body_len = len - 8;
  int pt_len = body_len - 16;

  if ( pt_len < 0 ) { /* super-assertion that pt_len does not equal AE_INVALID */
    fprintf( stderr, "BUG.\n" );
    exit( 1 );
  }

  assert( (size_t)body_len <= ciphertext_buffer.len() );
  assert( (size_t)pt_len <= plaintext_buffer.len() );

  Nonce nonce( str, 8 );
  memcpy( ciphertext_buffer.data(), str + 8, body_len );
  memcpy( nonce_buffer.data(), nonce.data(), Nonce::NONCE_LEN );

  if ( pt_len != ae_decrypt( ctx,                      /* ctx */
                 nonce_buffer.data(),      /* nonce */
                 ciphertext_buffer.data(), /* ct */
                 body_len,                 /* ct_len */
                 NULL,                     /* ad */
                 0,                        /* ad_len */
                 plaintext_buffer.data(),  /* pt */
                 NULL,                     /* tag */
                 AE_FINALIZE ) ) {         /* final */
    throw CryptoException( "Packet failed integrity check." );
  }

  const Message ret( nonce, string( plaintext_buffer.data(), pt_len ) );

  return ret;
}

I have also some problems to provide a header and a tag. Reading the source code of mosh, the tag and the nonce should be included in the message, but the header is missing.

The problem is, the nonce is created with an empty buffer and it seems the first 4 bytes are initialized with 0: https://github.com/mobile-shell/mosh/blob/f3665fb99bffc5929193a204d8540d74749b52c3/src/crypto/crypto.cc#L190:L198

Nonce::Nonce( const char *s_bytes, size_t len )
{
  if ( len != 8 ) {
    throw CryptoException( "Nonce representation must be 8 octets long." );
  }

  memset( bytes, 0, 4 );
  memcpy( bytes + 4, s_bytes, 8 );
}

I have done some tests with https://github.com/kravietz/pyOCB

The nonce should be 16 bytes, but i was not able to create a valid nonce from the data.

Reading the mosh paper, I have captured all data, which is necessary to decrypt the message.

I would be glad to get some help to decrypt the messages sent by mosh.

$\endgroup$

1 Answer 1

0
$\begingroup$

After rewriting the mosh client I was able to find out how the encryption and decryption works.

The nonce starts with 4 null-bytes and is a counter, which is sent with the message. The counter is built from the first 8 bytes and is available as plain text.

The key, which was captured by intercepting the ssh session, is base64 encoded, but the padding characters "=" are missing.

MOSH does not use associated_data.

The python cryptography package contains AESOCB3, which can be used to decrypt the data:

Following python script is able to decrypt the message from the question:

import base64
from cryptography.hazmat.primitives.ciphers.aead import AESOCB3

key = base64.b64decode("gy37yTEqclUSpFODXW2L+A" + "==")

nonce = bytes(bytearray.fromhex("000000008000000000000000"))
data = bytes(bytearray.fromhex("".join([
    '67', 'a3', 'a3', '8d', '18', '0b', '0c', '45', '44', '8b', 
    '6c', '8e', '85', '11', '60', '89', 'bf', '6e', '81', '40', 
    '50', 'ee', '80', '11', '31', 'b2', '1e', '68', 'ae', 'd8', 
    'aa', '29', '23', '41', '2f', '27', 'd5', '83', 'cb', 'ec', 
    '70', '8a', 'a2', '27', '81', '7a', '1b', '44', '97', 'e0', 
    'cb', '67', 'e7', '46', 'd8', '1f', '7f', '3f', '4a', '27', 
    '31', '04', 'c1', '06', 'a3', '8e', 'f3', '3a', 'eb', '2f', 
    'c5', '2f', 'ab', 'f8', '8e', 'aa', 'ea', 'f4', '9d', '81', 
    'ea', '4e', 'ed', 'a2', '09', 'a0', '03', '60', '60', '1e', 
    'a1', 'f5', '9f', 'ce', '94', '81', '69', 'af', 'dd', 'd8', 
    '4a', '75', '06', '47', '80', '13', 'df', '49', '66', '60', 
    'e6', 'aa', '1c', '17', '64', '3f', 'e1', 'ef', 'd1', '4d', 
    'd8', '4b', '54', '12', '6f', '47', '8f', '34', '31', 'd0', 
    '1f', '3f', '22', '54', 'cb', 'a7', 'de', '15', '91', 'b4', 
    '6d', '5d', '28', 'c8', '1c', 'a1', 'b5'
])))



aesocb = AESOCB3(key)
print(aesocb.decrypt(nonce, data, None))
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.