LED Therapy: Intro to Hardware Hacking Using the Neutrogena Light Therapy Mask

In the pre-Covid BeforeTime, my friend told me about this LED face mask she bought. The idea is that it lights up red and blue LEDs to treat your skin (I don’t know how effective it is, but that’s not the point of this blog post).

The product consists of the LED mask, and an “activator” that powers the mask (via 4 AA batteries) and starts a 10 minute timer. It also has a screen that shows a number, starting at 30. It counts down with each (daily) usage, and when it hits 0, the activator no longer works, even if you switch out the batteries. As a result, you have to throw it away and buy a new $15 activator each month, even though the electronics inside are still good.

There are plenty of guides online to bypass the counter in hardware instead of software (such as by adding a switch), which is much easier, but not the approach I wanted to take.

The product has since been recalled for other reasons so this was less of a practical project as much as an exercise in learning how the firmware (and my Bus Pirate) works, and a fun challenge. :)

It also serves as a pretty good guideline for hardware hacking in general, which is why I’m sharing it here.

Without further ado:

Step 1: get something to hack

This seems simple enough, but it’s still worth covering.

What I am showing in this post is this extremely creepy Red & Blue Light Therapy Acne Mask. I’ve already explained some of the motivation for digging into this… mostly to learn something, not necessarily to save money or present something that’s easily usable for other people.

It’s unfortunate that Neutrogena decided to go this route and make people throw away $15 and plastics/electronics. In this case, I’m looking for a method to reuse the (perfectly good) electronics.

But in other cases, you might be looking for something else: typically vulnerabilities in the product that allow unintended access or control. These vulnerabilities usually require code execution or understanding of the firmware first.

Motivations are likely different in those cases too, for example, if you are being paid to evaluate the security of a product as a security researcher. If that’s the case, hopefully the customer has provided you with several copies of the device to be tested. Why multiple copies? Because if you break something on accident, or on purpose (for example, removing a chip and dumping the memory) then no worries, you’ve got a spare. If you are doing research on your own, you can often find electronics on Ebay, such as used car parts that contain interesting ECUs [legal disclaimer don’t do illegal stuff].

Step 2: (physically) disassemble it

Tools needed: a screw driver and caution

The first real step is to get the device disassembled to the point that you can see the circuit board(s) inside.

In this case, all I needed was a screwdriver to remove the small screws holding the board in.

Then I was able to remove the top plastic cover so that the batteries remained in place, with the interesting side of the board facing up.

Sometimes there’s much more to the device, whether as part of a rugged design (such as something mounted in a vehicle) or there’s anti-tampering built into the physical design. For example, see these two videos on de-potting, or this other video that is about removing epoxy just over a single component.

Step 3: identify what’s on the board

Tools needed: a camera (your phone will work) and Google

By this point you should have a clear view of the PCB, and if possible, maintain a way of powering the board. In this case, it’s easy, because the battery holder is (mostly) built-in, but sometimes you will need to come up with additional wiring to keep the PCB powered if you can no longer use the original cables.

Once you’ve got all the packaging removed, start looking at things.

Before we get into the details, let’s talk about reference designators. With more exposure to electronic components, you’ll be able to guess what a lot of components are, based on their appearance and nearby components. But you can use reference designators to help you out.

Reference designators are naming patterns typically followed by board designers, and are used to aid in board manufacturing. “C” is for capacitors, so items labeled “C” followed by a number can safely be assumed to be a capacitor. Resistors use “R”, connectors or jumpers use “J”, and integrated circuits use “U”. Of all the types of components, the “U” components will be most interesting to us because that is where the software, logic, and control will be implemented.

In general, when we’re looking at the board, we’re trying to identify components, groups of components, or traces that represent:

Step 3a: take high-res photos of the board (or use a microscope)

Now that we’ve covered that, let’s start identifying things. First, take your phone camera or a microscope if you have one, and get close up photos of the board. [enhance]

These photos need to have enough resolution to see the markings on the electronic components.

Don’t worry so much about the smaller, passive components. Focus on the “U” (integrated circuit) components and jumpers. If you have a lot of components on your board, consider making a spreadsheet to track things. Thankfully this board is pretty sparse and straightforward.

Step 3b: Google lots of things

Now it’s time to identify the exact part numbers based on the markings. This is more of an art than a science, I’m afraid.

Head over to Google and search [numbers] smd and look for electronic datasheets in the results. Play around with how much of the marking you include in your search result. Since often times the markings include the brand, part number and variant, you can alter your search results accordingly (leave out the variant, for example).

You can also use smdmark.com.

Confirm the markings if possible within the document. Sometimes the markings will tell you which particular variant of the chip is used. Verify that the chip on your board matches the packaging listed in the datasheet in terms of pins, size, spacing, and so on.

You can further verify that you’ve got the correct datasheet by measuring voltages on the pins on your board and comparing against the datasheet. For example, if pin #1 is expected to be at 5V and pin #8 is GND, measure the pins with a DMM. This is how I realized I had the wrong datasheet for the EEPROM on this board–the datasheet pins didn’t match up with the physical reality of the board, so I kept looking.

Getting the correct datasheet for your components in the beginning will save you a lot of time down the road, so it is worth the extra effort to get it correct early on.

As best as I can tell, our board has these active components:

I’d like to identify the microcontroller on this board but it is covered with epoxy and I only have one board, so I don’t want to risk damaging it. However, all of its pins are exposed elsewhere, so maybe we can go on without it. This will probably be true of your board: you can’t identify 100% of the components most of the time, so get enough to continue learning more about the board.

As for the other components, the LDO tells us that the EEPROM is powered off of 3.3V. The MOSFET is part of the power circuitry so as long as we have a way of powering the board, we don’t need to pay too much attention to it. I’ve also largely ignored the display since it isn’t storing any information. Let’s focus on the EEPROM first, since we know what it is and we’ve got easy physical access to it.

Step 4: download some data sheets understand what’s goin’ on

Tools needed: Google, a DMM, and coffee

In the previous step, you probably opened a lot of datasheets. I hope you’ve got the correct ones still open, because we’re going to need them. Save all the relevant datasheets and product note PDFs.

In this section, we’ll want to read as much about the chip as possible. What is the purpose of the component? Can you summarize what it does, within the context of the board you are working on? How does it communicate? Does it have security features? Are there measurable pins that determine the configuration of that component, and if so, what are the voltage/etc levels on those pins?

Look at the pinouts and mentally (or physically, with a DMM) trace the connections. This might be difficult due to: BGA parts, blind vias, internal layers. Cheaper boards typically only have the top and bottom layer, non-BGA parts, exposed vias and leads. If your board is more difficult, you might have to get creative with finding points to probe, for example, following pins through traces and finding a probing point at a via or intermediary component.

Look at the dot on the packages to orient yourself. If unsure, match up ground pins with known grounds on the board.

In the case of this very simple board, we could probably reconstruct the entire circuit diagram. As mentioned before, sometimes it’s not feasible to know the entire board’s worth of components or how everything functions. Dig into what you can and work from there.

If you have enough components to understand the overall functionality of different parts of the PCB, then draw a block diagram or logically group parts:

For most of the chips, you don’t need to understand it to an EE level! Start with an understanding of how the chip is used on the board or used by the other parts and then go from there. For example, you don’t need to understand why this power regulation circuit uses the capacitors that it does, or what most of the resistors or capacitors are for. If you can understand that the LDO regulates a voltage level down to something usable (e.g. 3.3V) by the other connected components, you’re good. Obviously more understanding will help, but don’t let it trip you up.

If something is new to you, look for communication protocols to orient yourself:

If a board has components that talk to one another, a strategy might be to eavesdrop on this communication to learn more about what is happening, and then MiTM the connection.

As for this board, the microcontroller talks to the EEPROM through a 3-wire SPI protocol, as described in the datasheet (Chip Select, clock, data in, data out). The datasheet also describes a set of instructions to read, write, erase, and write-enable/write-disable the chip.

By the end of this section, you should have a solid understanding of what is going on the board conceptually, and have identified specific pins that will allow you to read or write data in the next steps. Obviously, this example is pretty simple, but having the blocks (especially with part numbers!) written out will make life easier on your future self.

Step 5: identify a way in

Tools needed: DMM, oscilloscope, Bus Pirate, soldering iron

Now that we have a good idea of what’s going on with this board, we can figure out how to gain access. This board is pretty minimal, so we don’t have a lot of options. My goal is to re-enable the functionality of the “activator” (which is the PCB we’ve been looking at). There may be more than one way to do this, but the one way we already know will work is by finding the stored value of remaining uses (which was previously at 30, and has now counted down to 0), and make it a non-zero value again.

We don’t have easy access to the microcontroller, or even know what the microcontroller is, so communicating with that chip to alter the logic seems unlikely. BUT! We have easy access to the EEPROM, we know how it works, and it is presumably storing the value (otherwise, why have it there?)

If this was a different board, again, the method of access would largely rely on methods of communication, either out (wifi, bluetooth, external wired connections, etc) or debugging options in (such as an RX/TX serial line, JTAG, etc). Those methods likely won’t be enough on their own and you’ll need to find a flaw in the security of that access method. For example, you might able to get in via glitching a serial line.

It’s likely that you’ll need to get specialized hardware at this point, but I will be using the (affordable) Bus Pirate to communicate with the EEPROM.

The end goal on most devices (not this one) is code execution. Start with a method that will get you there and if it doesn’t work, work your way down the list of options.

The end goal on this device is to change the count to a high number and if possible, remove the software check altogether.

Step 5a: establish communication

Since I already identified the EEPROM chip, I have soldered on leads to the relevant pins: DI (data in), DO (data out), SK (sclk), CS (chip select), plus lines to 3.3V (VCC) and ground, just in case. If you have one, you can also use a chip clip.

I’ve hooked these up to the Bus Pirate using this guide where MISO <-> DI, MOSI <-> DO, CLK <-> SK and CS <-> CS. Make sure you have the Bus Pirate ground connected to a ground on the PCB, otherwise your readings will be inaccurate.

I read the 3WIRE guide from Dangerous Prototypes but it wasn’t nearly as helpful as reading forum posts such as this one.

My Bus Pirate settings looked like this. I’m powering the board off of the battery (with the mask plugged in) rather than powering it off of the Bus Pirate.

HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>7
Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz

(1)>1
CS:
 1. CS
 2. /CS *default

(2)>1
Select output type:
 1. Open drain (H=Hi-Z, L=GND)
 2. Normal (H=3.3V, L=GND)

(1)>2
Ready
3WIRE>[0b10011000 0]
CS ENABLED
WRITE: 0x98
WRITE: 0x00
CS DISABLED
3WIRE>[0b110;3  0x50;7 r;0x8]
CS ENABLED
WRITE: 0x06;3
WRITE: 0x50;7
READ: 0x97
CS DISABLED
3WIRE>

First, I want to be able to read data from the EEPROM. In order to read from the chip, we need to follow the datasheet for reading.

We need to send a 0b1, 0b10, then 8 bytes of “don’t care” (we’re in x8 mode because the ORG pin is connected to ground, as described in the datasheet). Again, the forum post came in very useful here.

In order to read 8 bits at location 0x50:

[0b110;3  0x50;7 r;0x8]

Two blog posts I read tipped me off the fact that most of the EEPROM is unused, and the counter variables are at 0x50 and 0x55. I verified this by reading 0x50 and 0x55 in memory with 0 uses left.

At this point I should probably mention that it’d be good to get a known good copy of the data in case something goes awry.

Next up we need to write something, which will be slightly more complicated because we need to disable the write protect before we do our write.

# write protect disable to allow write/erase
[0b10011000 0]

# write protect enable to disallow write/erase
[0b10000000 0]

I was unable to get a good scope capture with the equipment I had at home (snowed in) but the first blog post describes how each command is bookended with a write protect disable or enable command, e.g. write protect disable - write - write protect enable. This means that my idea of sending a write protect enable to prevent future countdowns won’t work, because the next command’s write protect disable will negate it.

To actually write a value, we need to do something like:

[0b101;3 0x50;7 0x98;8]

This will write 0x98 to location 0x50.

Experimentally, it looks like the value at 0x50 is the value at 0x55, minus 1. So if 0x50 is value 0x98, then 0x55 needs to be 0x99.

So to write 0x98 to location 0x50, and 0x99 to location 0x55, then read it back to make sure:

# write protect disable, write to 0x50, write to 0x55, write protect enable
[0b10011000 0]
[0b101;3 0x50;7 0x98;8]
[0b101;3 0x55;7 0x99;8]
[0b10000000 0]

# two reads, of 0x50 and 0x55
[0b110;3  0x50;7 r;0x8]
[0b110;3  0x55;7 r;0x8]

Aaaaand… it works!

I actually originally tried this out with values 2 and 3 instead of 98 and 99 (since I wasn’t sure if there was an upper limit and wanted to play it safe), but am showing 0x98 because it’s more impressive. :)

If your first attempt doesn’t work, keep moving down the list of communication/access methods you’ve identified and keep trying!

Step 5b: mess everything up; despair

Feeling pretty good about my progress thus far, I made some more changes and ended up in an error state (the display read -- and would not turn the mask on). I programmed it again with the last known good state and still: error.

Sooooo… now what? I ended up looking through Neutrogena documentation to find a way to reset the device (but was unable to find anything useful). I then pulled the batteries out and disconnected the Bus Pirate, waited a bit, then plugged it back in. Still nada.

What ended up being the issue here was: the big capacitor was still charged up and I didn’t wait long enough for it to fully discharge.

As a result, the system never really fully powered down, and was still working off of the previous error state. I realized this by measuring the EEPROM’s VCC pin. With the batteries still removed, I shorted out the capacitor to discharge it. After that, I was back on track.

The point of this story isn’t (just) to share my moment of panic, but to point out a few ideas that will probably save you a lot of headache later:

Step 6: persistence

At this point, we’re able to alter the EEPROM and restore our activator to a working state. What is there left to do?

Well, if I have 98 uses, I’ll have to set up my Bus Pirate again in 3 months (if my friend were still using this but given the recall info, she won’t be) and alter the EEPROM again. What if there was a way to permanently bypass this restriction?

This is what I mean by “persistence”, and it’s a concept that applies to hardware hacking in general too. If you need glitching or another error-prone or difficult way to gain access, what changes can you make to allow easier access in the future? This might look like: adding your own user/password, re-enabling a method of communication, and so on.

Here, we have fewer options. I didn’t actually get “persistence” in the way I wanted, but I did consider or try:

Recap

Altogether now:

  1. Find something to hack (and get multiple copies if possible)
  2. Physically disassemble it so you have easy access to the PCB
  3. Identify what’s on the board using close-up photos and Googling
  4. Read the datasheets and understand how it all works
  5. Come up with a plan of attack and establish communication (and avoid the pit of despair)
  6. Establish persistence if possible

If you walk away from this blog post with nothing else, remember to take a LOT of notes, and get your datasheets/info right early on to save time later.

For more hardware hacking info, check out HHV.