Created
January 19, 2019 01:33
-
-
Save rgov/44ce189650859a5e895e473aedcd94bc to your computer and use it in GitHub Desktop.
File transfer-over-Telnet. For when you have no other option.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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