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.