在研究嵌入式设备的过程中经常需要向设备中上传二进制文件,这里总结一下上传文件的方法。
busybox上自带ftpd服务,无身份验证,可以进行文件传输操作。
ftpd可通过设定inetd.conf由inetd启动,或者是使用tcpsvd作为单独的守护进程。
ftpd使用参数:
Usage: ftpd [-wvS] [-t N] [-T N] [DIR]
-w 允许上传
-v 打印错误信息
-S 错误信息写入SYSLOG
-t 多长时间无操作算作空闲(默认2分钟, 2 * 60)
-T 多长时间空闲后自动断开与客户端的连接(默认1小时,1 * 60 * 60)
DIR FTP根目录
tcpsvd可以建立TCP Socket,并将其绑定到某个程序上,命令格式如下:
Usage: tcpsvd [选项] IP PORT PROG [PROG ARGS]
IP: 要监听的IP地址
PORT: 要监听的端口
PROG: 要绑定的程序
PROG ARGS: 绑定应用的参数
选项:
-l NAME, 本地主机名
-u USER[:GRP], 绑定后切换到USER/GROUP
-c N, 最大连接数
-C N[:MSG] 同一个IP的最大连接数(MSG为超过时的响应信息)
-v 打印详细输出
使用tcpsvd启动ftpd:
tcpsvd 0 21 ftpd -w /ftp_dir
或者配置/etc/inetd.conf:
21 stream tcp nowait root ftpd ftpd -w /ftp_dir
启动inetd服务:
/usr/sbin/inetd &
服务端配置:
mkdir /tftp_dir
cp /bin/busybox /tftp_dir
udpsvd -vE 0 69 tftpd -c /tftp_dir & #0表示对所有ip地址都进行侦听
客户端上传文件:
busybox tftp -l test.txt -r test.txt -p 192.168.1.100
客户端下载文件:
busybox tftp -l test.txt -r test.txt -g 192.168.1.100
如果设备中安装了python的话就可以使用python脚本搭建一个临时服务器,供telnet访问:
import socket
import base64
port = 55555
filename = 'test.bin'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', port))
sock.listen(5)
while True:
connection,address = sock.accept()
try:
content = 'hello'
f = file(filename)
content = base64.b64encode(f.read())
connection.sendall(content.strip())
connection.close()
except socket.timeout:
print 'time out'
connection.close()
将二进制文件编码成文本文件,输出到telnet,再写入文件通过python解码成二进制文件:
telnet 127.0.0.1 55555 | tee > temp.txt
tail -n +4 temp.txt > temp2.txt
base64 -d < temp2.txt | tee > test.bin
另外还有通过ssh服务来上传文件的方法,这里不赘述了
之前需要往一个只拿到了telnet权限但没有ftp、ssh服务的设备上上传二进制文件。而且设备上没有python,busybox也没有带其他的解码工具,无法通过上面利用python搭服务器的方法上传文件了。
这时候想到openssl似乎有Base64编/解码的功能,那么就可以利用openssl来进行base64解码从而实现二进制文件上传操作。
import base64
fin = open("./hello", "rb")
fout = open("./base64.txt", "w")
data = fin.read()
base64_str = base64.encodestring(data).decode('ascii')
fout.write(base64_str.replace("\n", "").replace("\r", ""))
fin.close()
fout.close()
用openssl命令行做base64解码需要每64个字符换行一次,整个编码后字符串末尾也要有换行。且一次最大只能传2000行左右,超过需要分几次上传。用脚本进行编码字符串整理:
f = open('./base64.txt', 'r')
result = list()
i = 64
size = len(f.read())
f.seek(0,0)
lines = 1
while i < size:
str1 = f.read(64)
#print(str1)
str2 = str1 + '\r'
print(str2)
result.append(str2)
i = i + 64
lines = lines + 1
if i > size:
str1 = f.read(size-i)
#print(str1)
str2 = str1 + '\r'
print(str2)
result.append(str2)
lines = lines + 1
#print(result)
#print(len(result))
l = 0
num = 1
while l < lines:
open('result' + str(num) + '.txt', 'w').write('%s' % '\n'.join(result[l:l+2000]))
num = num + 1
l = l + 2000
if l > lines:
open('result' + str(num) + '.txt', 'w').write('%s' % '\n'.join(result[l:]))
f.close()
传入编码字符串,用openssl进行解码并存入文件:
# echo "
> f0VMRgEBAQAAAAAAAAAAAAMACAABAAAAAAYAADQAAABMEwAABxAAcDQAIAAKACgA
> IgAhAAYAAAA0AAAANAAAADQAAABAAQAAQAEAAAUAAAAEAAAAAwAAAHQBAAB0AQAA
> dAEAAA0AAAANAAAABAAAAAEAAAADAABwqAEAAKgBAACoAQAAGAAAABgAAAAEAAAA
......
> " | openssl enc -base64 -d >> busybox_bak
下面是用python实现上面手动传入编码字符串的脚本:
import getpass
import telnetlib
HOST = "192.168.1.100"
user = "admin"
password = "yourpasswd"
tn = telnetlib.Telnet(HOST)
tn.read_until(b"login: ")
tn.write(user.encode('ascii') + b"\n")
if password:
tn.read_until(b"Password: ")
tn.write(password.encode('ascii') + b"\n")
k = 13
filename = 'busybox'+ str(k) +'.txt'
f = open(filename, 'r')
tn.write(b"echo \"\n")
for i in range(0, 2000):
str1 = f.readline().encode('ascii')
tn.write(str1)
#tn.write(b"\n")
i = i + 1
tn.write(b"\"| openssl enc -base64 -d >> /ftp_dir/busybox_test\n")
tn.write(b"exit\n")
print(tn.read_all().decode('ascii'))