khanfarris
I wanted to play around with some of my devices and see what I could mess with from my PC. I started with the two LIFX bulbs on my desk because they seemed like the least interesting yet easiest target I could start with.
Everything below happened on my own network, against hardware I own. TLDR: played with my light bulbs from my terminal, but the cool part to me was — I did not have to authenticate to anything (hell yeah). If they were someone elses light bulbs, it could make for some fun times.
Step 1 — Figuring out where I actually was
A preliminary note to remember when I spin up a new instance - before scanning anything I needed to confirm my Kali VM could even see the stuff on the network. A bridged VM sits on the real LAN; a NAT'd one lives in its own little bubble and will never find my light bulb.
ipconfig # Windows: my IPv4 + gateway
ip a # Kali: check the eth0 inet address
Windows came back 10.0.0.mywindowsip, Kali came back 10.0.0.mykaliip. Same
10.0.0.x subnet, so the bridge was working and Kali confirmed to be able to see every device
on the network. My network was 10.0.0.0/24 with the gateway at 10.0.0.1.
10.0.2.x or 172.x, that's
the NAT bubble — switch the VM adapter from NAT to Bridged and try again. Nothing else works until
this does.
Step 2 — Initial Scan for devices
sudo nmap -sn 10.0.0.0/24
A ping sweep, no port scanning. The output lists every host with its MAC vendor, and that vendor tag is what identified the bulbs. Two entries I came across were tagged Lifi Labs Management. That's LIFX.
Step 3 — The scan that lied to me
sudo nmap -sV -sC -p- 10.0.0.7
All 65,535 TCP ports came back closed. I was about to ff 15 but then decided there's probably something going on here. If I'd stopped there I would have written "nothing exposed, looks fine" and moved on. That wouldn't be too great.
The bulb doesn't speak TCP at all. It speaks UDP. Always remember the fundamentals. So I did some 'research' and found out about port 56700.
sudo nmap -sU -sV -p 56700 10.0.0.7
Result: 56700/udp open|filtered. That open|filtered state means nmap sent
a generic probe and got nothing back — completely normal for UDP. The bulb only answers packets
that are actually shaped like the LIFX protocol. Ahhhhhhh.
The nmap flags I used (some not in writeup), and why
sudo— nmap's raw-packet scans need root.-sn— host discovery only, no port scan. Just find live devices.-sV— version detection. Identifies the service and its version, which is what you feed into CVE lookups later.-sC— runs nmap's default safe scripts: default creds, exposed info, common misconfigs.-p-— all 65,535 ports instead of the default top 1,000. Slow, but complete.-p 56700— one specific port I already knew about. Fast and targeted.-sU— UDP scan. Essential here, since LIFX only listens on UDP.-Pn— skip host discovery and assume the host is up. Useful when a device blocks pings but you know it's there.
Step 4 — How I'd have found port 56700 on my own
Tbh I didn't pull this port out of thin (AI)r. But afterwards I did make sure to get familiar with ways to get there without being told, and I'll try to remember these methods for unfamiliar device / no help challenge scenario:
- nmap already knows it — it's listed in
nmap-servicesaslifx. - Vendor docs. Searching "LIFX LAN protocol" lands on
https://lan.developer.lifx.com/docs/querying-the-device-for-data, which documents the whole thing. - Open-source tools. Reading
lifxlanor the Home Assistant integration on GitHub shows you exactly what port they talk to. - Wireshark. Sniff the official phone app toggling a light and read the packets yourself.
Step 5 — Actually speaking the protocol
This is where it stopped being recon. I installed the community Python library:
pip install lifxlan --break-system-packages
The --break-system-packages flag is needed because Kali marks its system Python as
externally-managed and pip refuses to touch it otherwise.
Discovery
python3 -c "from lifxlan import LifxLAN; lan = LifxLAN(); \
[print(d.get_label(), d.get_ip_addr(), d.get_power()) for d in lan.get_devices()]"
This broadcasts a LIFX discovery packet, and every bulb on the network replies with its name, IP,
and current power state. No authentication, no pairing, no token. I got back
Desk Lamp Right at 10.0.0.lightbulb1 and Desk Lamp Left at
10.0.0.lightbulb2.
That reply is the finding. My unauthenticated bulb just announced itself to me.
Fun time
python3 -c "from lifxlan import LifxLAN; import time; lan=LifxLAN(); \
d=[x for x in lan.get_devices() if x.get_label()=='Desk Lamp Left'][0]; \
d.set_power(True); time.sleep(2); d.set_power(False)"
The lamp came on, sat there for two seconds, and went off. Physical control of something in my room from a terminal, with zero credentials. SICK.
Color
python3 -c "from lifxlan import LifxLAN, RED, GREEN, BLUE; import time; \
d=[x for x in LifxLAN().get_devices() if x.get_label()=='Desk Lamp Left'][0]; \
[(d.set_color(c), time.sleep(1)) for c in (RED, GREEN, BLUE)]"
Red, green, blue, one second each. Same unauthenticated channel — it isn't just an on/off switch, it's full control of the device's state.
Finding & fix
Verdict: the old critical LIFX flaws — the ones where plaintext Wi-Fi credentials could be pulled off the hardware — required physical access and have been patched. What's still live is the unauthenticated LAN control protocol, and that one is working as designed. Anyone already on my Wi-Fi can find and control my bulbs.
Remediation: put IoT devices on a separate guest/IoT network or VLAN, so a compromised bulb is isolated from the PCs and phones that actually matter. The protocol isn't going to change; the network segmentation is the control I actually own.
The repeat checklist
Next time I run this, on this device or any other:
ip a/ipconfig— confirm I'm on the same subnet as the target.sudo nmap -sn 10.0.0.0/24— find the device by MAC vendor.sudo nmap -sU -sV -p 56700 <ip>— confirm the control port.lifxlandiscover, thenset_power/set_colorto control.
It seems like I can swap the IP and the workflow is identical for any device. The only part that changes is the research step — figuring out which ports and protocol the thing actually speaks.
The full runbook
Every command above, in a single reference sheet: