Python SMB1 client for the New Nintendo 3DS microSD Management feature.
Automatically discovers the 3DS on your local network via WS-Discovery, connects to the microSD share over WiFi, and provides an interactive file browser shell - no configuration needed.
python3 n3ds_smb
That's it. The tool discovers your 3DS automatically and drops you into a shell:
Scanning for 3DS... 3DS-MYNAME at 192.168.1.42 (WS-Discovery) [194ms]
Connected to 3DS-MYNAME (192.168.1.42)
Type 'help' for commands.
3ds> ls
<DIR> Nintendo 3DS
<DIR> DCIM
3ds> cd "Nintendo 3DS"
3ds> tree
...
3ds> get somefile.bin
1,234 bytes -> somefile.bin
3ds> quit
- Python 3.8+
- Core shell: no external dependencies (stdlib only)
- Optional WebDAV mode:
wsgidav+cheroot(can auto-install on first use) - New Nintendo 3DS / 3DS XL / 2DS XL with microSD Management enabled (System Settings → Data Management → microSD Management)
- Both devices on the same WiFi network
# Auto-discover (recommended)
python3 n3ds_smb
# Explicit IP and name
python3 n3ds_smb 192.168.1.42 3DS-MYNAMEClear cached discovery entry:
python3 -m n3ds_smb --clear-cacheShell commands:
| Command | Description |
|---|---|
ls [path] |
List directory contents |
cd [path] |
Change directory (no arg = root) |
pwd |
Print working directory |
get <remote> [local] |
Download a file |
put <local> [remote] |
Upload a file |
mkdir <path> |
Create a directory |
rm <file> |
Delete a file |
rmdir <path> |
Remove an empty directory |
mv <old> <new> |
Rename/move a file |
ping |
Send SMB echo request |
df |
Show total/used/free space |
tree [path] |
Recursive directory listing |
quit |
Exit |
Expose the 3DS share as a local WebDAV endpoint.
# Auto-discover + serve
python3 -m n3ds_smb --webdav
# Explicit IP and name
python3 -m n3ds_smb 192.168.1.42 3DS-MYNAME --webdavDefault endpoint: http://127.0.0.1:8080/ (localhost only).
Useful flags:
# Read-only mode
python3 -m n3ds_smb 192.168.1.42 3DS-MYNAME --webdav --readonly
# Require basic auth
python3 -m n3ds_smb 192.168.1.42 3DS-MYNAME --webdav --user alice --password secret
# Custom bind + worker threads
python3 -m n3ds_smb 192.168.1.42 3DS-MYNAME --webdav --host 127.0.0.1 --port 8080 --threads 4First time you run --webdav, the CLI checks for optional dependencies and prompts before installing:
<python> -m pip install wsgidav cherootDisable auto-install behavior with:
python3 -m n3ds_smb 192.168.1.42 3DS-MYNAME --webdav --no-auto-installIf dependencies are missing and auto-install is disabled (or declined), install manually:
python3 -m pip install wsgidav cherootWebDAV operations covered by live tests include OPTIONS, PROPFIND, GET, HEAD, PUT, COPY, MOVE, DELETE, and recursive directory moves.
from n3ds_smb import N3DSClient, discover_3ds
# Auto-discover
ip, name = discover_3ds()
# Connect
client = N3DSClient(ip, name)
client.connect()
# List files
for entry in client.listdir("\\"):
print(entry["name"], entry["size"], entry["is_dir"])
# Download
with open("backup.bin", "wb") as f:
client.get_file("\\Nintendo 3DS\\somefile", f)
# Upload
with open("local.bin", "rb") as f:
client.put_file("\\upload.bin", f)
# Other operations
client.mkdir("\\new_folder")
client.delete("\\old_file.bin")
client.rename("\\old_name.bin", "\\new_name.bin")
client.rmdir("\\empty_folder")
client.close()The tool discovers the 3DS using WS-Discovery (the same protocol Windows uses):
- Cache check (~10ms) - If we've connected before, validate the cached IP+name
- WS-Discovery Probe (~200-700ms) - Send a UDP multicast probe to
239.255.255.250:3702. The 3DS responds with its endpoint URL - HTTP metadata fetch (~30ms) - GET device metadata from the 3DS's DPWS HTTP endpoint (port 5357) which contains the NetBIOS name
- Fallback - If multicast doesn't work (e.g. network restrictions), prompt the user for the name shown on the 3DS screen
The cache is stored at ~/.n3ds_smb_cache for instant reconnection on subsequent runs.
The 3DS microSD Management exposes an SMB1 file server on TCP port 139. This client implements the minimum SMB1 protocol needed:
- NetBIOS Session Service - Session setup with the 3DS's name
- SMB_COM_NEGOTIATE - Dialect negotiation (
NT LM 0.12) - SPNEGO/NTLM Auth - The 3DS accepts any NTLM Type 1 blob without verifying credentials
- Tree Connect - Connects to the
microSDshare - File operations - TRANS2 directory listing, NT_CREATE_ANDX, read, write, close
Notable quirks of the 3DS SMB implementation:
SMB_COM_DELETEandSMB_COM_RENAMEwork, but require strict Unicode alignment aroundBufferFormatbytes- Single TCP connection at a time - the 3DS only handles one client
- Auth bypass - no credentials are ever verified
See exploits.md for detailed findings from reverse-engineering the 3DS SMB server, including:
- SPNEGO authentication bypass
- DELETE/RENAME Unicode alignment gotchas (and the now-correct native implementation)
- Tree Connect name oracle
- NetBIOS session handler bugs (including a remote DoS)
- Dual NTLM code paths and patched overflow analysis
- Three broadcast discovery protocols (NBNS, Browser, WS-Discovery)
- Active name discovery via WS-Discovery + DPWS metadata
Tests run against a live 3DS:
# SMB client live tests
N3DS_IP=<your_3ds_ip> N3DS_NAME=<your_3ds_name> python3 -m unittest tests.test_3ds -v
# WebDAV end-to-end live tests
N3DS_IP=<your_3ds_ip> N3DS_NAME=<your_3ds_name> python3 -m unittest tests.test_webdav_e2e -v
# Full live suite
N3DS_IP=<your_3ds_ip> N3DS_NAME=<your_3ds_name> python3 -m unittest tests.test_3ds tests.test_webdav_e2e -vn3ds_smb/
__init__.py - Public API: N3DSClient, discover_3ds
__main__.py - Entry point and optional WebDAV launcher
transport.py - SMB1 wire protocol: NBSS framing, headers, SMBTransport
client.py - N3DSClient: connect, auth, file operations
discovery.py - WS-Discovery based auto-discovery
shell.py - Interactive cmd.Cmd shell
webdav.py - WsgiDAV provider exposing SMB share as WebDAV
tests/
test_3ds.py - Live SMB integration tests
test_webdav_e2e.py - Live WebDAV end-to-end tests
exploits.md - Security research findings (11 discoveries)
MIT