Skip to content

Instantly share code, notes, and snippets.

@rgov
Created January 19, 2019 01:33
Show Gist options
  • Save rgov/44ce189650859a5e895e473aedcd94bc to your computer and use it in GitHub Desktop.
Save rgov/44ce189650859a5e895e473aedcd94bc to your computer and use it in GitHub Desktop.
File transfer-over-Telnet. For when you have no other option.
#!/usr/bin/env python
'''
File transfer-over-Telnet. For when you have no other option.
There are probably better ways to do this.
This expects the server to drop you into a shell immediately upon connection.
It also expects the `openssl` tool to be available.
The file is transferred in small Base64-encoded chunks. After each chunk, a
checksum is computed just to make sure the chunk made it through OK.
There is no retry or resumption, though these wouldn't be so hard to implement.
If the transfer is interrupted, and your shell is broken, try entering
<ENTER>*END*<ENTER>
This has been tested with Eltima Serial to Ethernet Connector 7.0 running in
Server mode using the "RAW" protocol setting.
https://www.eltima.com/products/serial-over-ethernet/
You should install the `tqdm` module and execute under Python 3.
'''
import argparse
import base64
import hashlib
import os
import pipes
import sys
import telnetlib
import time
import tqdm
argparser = argparse.ArgumentParser()
argparser.add_argument('--host', required=True)
argparser.add_argument('--port', type=int, default=23)
argparser.add_argument('src')
argparser.add_argument('dst')
args = argparser.parse_args()
def quote(b):
if isinstance(b, bytes):
return pipes.quote(b.decode('utf-8')).encode('utf-8')
else:
return pipes.quote(b).encode('utf-8')
# Connect to the server
t = telnetlib.Telnet(args.host, args.port)
# Wake up
expected = b'I AM AT A SHELL'
t.write(b'\n\n\n\n*END*\necho %b\n' % quote(expected))
t.read_until(expected, timeout=1)
# Figure out if we can use `openssl base64 -d`?
expected = b'success'
t.write(b'echo %b | openssl base64 -d\n' % quote(base64.b64encode(expected)))
t.read_until(expected, timeout=1)
# Write the file in small chunks
md5 = hashlib.md5()
pbar = tqdm.tqdm(total=os.stat(args.src).st_size, unit='B', unit_scale=True)
with open(args.src, 'rb') as f:
first = True
while True:
pbar.update(2048)
data = f.read(2048)
if not data: break
# Send the chunk of data across
t.write(b'openssl base64 -d <<\'*END*\' %b %b\n' %
(b'>' if first else b'>>', quote(args.dst)))
t.write(base64.encodebytes(data))
t.write(b'\n*END*\n')
first = False
# Check the hash of the file so far
md5.update(data)
t.write(b'openssl dgst -md5 %b\n' % quote(args.dst))
_, mo, _ = t.expect([ br'([a-f0-9]{32})' ])
actual_md5 = mo.group(1).lower()
expected_md5 = md5.hexdigest().lower().encode('utf-8')
if actual_md5 != expected_md5:
print('Transmitted unsuccessfully (expected %s got %s)' %
(expected_md5, actual_md5))
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment