Tuesday, October 28, 2014

BSides-DC '14 Industrial Control Systems Lab

I love exploring knew technologies and protocols. What hacker doesn't? When BSides-DC announced it was going to have an Industrial Control Systems (ICS or SCADA to most people) lab, I knew this would be my favorite part of the convention.

Obligatory robot arm photo is obligatory
Prior to this lab, my knowledge of ICS was limited to stuxnet inspired research into ladder-logic and gcode. I am still very much a newb, and wasn't aware at the time the difference between ICS and SCADA.

Phoenix Contact Starter Kit
I sat down next to a starter kit shown above. The purpose of this lab was simple, you press a button and it lights up, press it again and it turns off. Doing a simple recon I found that the device had tcp ports 21 (FTP), 80 (HTTP), 502 (ModBus), and 41100 open.

I made a copy of everything in FTP for later analysis. One note, FTP allowed anonymous write, so I could have overwritten any file, and potentially uploaded my own firmware, but I did understand how the device used FTP at the time. This will be something to explore more fully at the next lab.

Image used in Web Interface. Sorry not a proper screenshot
With a web service open, I poked around that first to see what "attacks" I could do. The interface was similar to the actual device. Clicking the representation of buttons with the mouse turned on/off the buttons on the actual device. By proxying the connection through BurpSuite (note, the webapp broke when proxied through OWASP ZAP), I observed that pressing the buttons would send a get request with the button (red or green) and the press state (1 for down press, and 0 for release). The button light when turn on or off went a down press state was sent. By not sending the subsequent release state, the button could no longer change light states even when being manually pressed. With this discovery, I was able to effectively fix the green button in a permanent disabled state, and the red button in a permanent enabled state.

This was a nice victory, but I wanted to play with the ports I was not familiar with. Sadly, due to last minute schedule changes, I only had about 4 hours to work on this lab, and did not have enough time to do everything I wanted to do. I was able to obtain some packet interrogation via Nmap.

For TCP port 502

(GetRequest,9,"GET\x20\0\x03H\xd4\x01")
(HTTPOptions,9,"OPTI\0\x03S\xa0\x01")
(RTSPRequest,9,"OPTI\0\x03S\xa0\x01")
(RPCCheck,9,"\x80\0\0\(\0\x03\x1d\x93\x01")
(DNSVersionBindReq,9,"\0\x1e\0\x06\0\x03\0\x81\x03")
(Help,9,"HELP\0\x03\0\x81\x03")
(Kerberos,9,"\0\0\0q\0\x03n\xb0\x01")
(SMBProgNeg,9,"\0\0\0\xa4\0\x03M\xc2\x01")
(FourOhFourRequest,9,"GET\x20\0\x03i\xe3\x01")
(LPDString,9,"\x01def\0\x03l\xf4\x01")
(LDAPBindReq,89,"0\x0c\x02\x01\0\x83\x07\x02\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
(SIPOptions,9,"OPTI\0\x03S\xa0\x01")
(NCP,9,"DmdT\0\x03\0\x97\x03")
(WMSRequest,9,"\x01\0\0\xfd\0\x03\x0b0\x01");

For those not familiar with Nmap Service Fingerprints, the above is a set of tuples reporting what probe was used, the number of bytes returned (in hex), and the (escaped) response. Nmap reports them in a big block of text, to separate them out  simply replace the '%r' with a carriage return. To learn more about what was sent in each probe you can perform this command `grep "Probe TCP" /usr/share/nmap/nmap-service-probs`. Nmap uses these probes to determine a service's version information (-sV).

What do we learn from this? First, that the first four characters of the probe is sent back in the response. This possibly indicates the first field is about 32bits. With careful observation, we also notice that the 7th byte of the probe is echo'd back, possibly indicating an 8 bit field. Since these fields are echo'd back to us, they're request dependent, possibly a transaction value or function code. 

Second, between these two fields are two bytes, the first is always a 0, and the second is mostly \x03, except for the one lengthy response to the LDAPBindReq, where it's \x83. This correlates with the response size which is usually 0x09 bytes, but 0x89 bytes for the LDAPBindReq, and that this byte does contain the number of bytes remaining in the response. This is most certainly a length field.

Generally we see length fields in TLV tuples. TLV is a handy parser sequence for interpreting dynamic data which stands for  Type, Length, and Value. The type field describes the value either in broad terms such as integer and string or more specific terms such as address and temperature. The Length field tells the parser how long the value is. The Value field being the value being interpreted. TLV is useful when you want a protocol to handle data of non-predetermined sizes and types. The alternative (and faster) is to use fixed length fields, which we often see in protocols. 

This tells us the fifth byte is possibly a type field, or since it's always 0 it could the leading byte of a 16 bit length field.

For the rest of the data, there isn't enough samples to find a strong correlation. We are left with a small clue though. The following probes are very similar with the last three bytes. 

(DNSVersionBindReq,9,"\0\x1e\0\x06\0\x03\0\x81\x03")
(Help,9,"HELP\0\x03\0\x81\x03")
(NCP,9,"DmdT\0\x03\0\x97\x03")

This tells us that something about the NCP probe is similar enough to the other two probes to evoke the same response in byte 7 and 9, but different enough to get a different value in byte 8. This also tells us that these three bytes are three different fields.

From the analysis, this is how I think the modbus protocol is structured.

32 bit address/transaction
16 bit length
8 bit function
8 bit unknown
dynamic-size data

Wikipedia tells us this


I wouldn't say I was too far off. There was nothing in the responses that would have indicated that Transaction and Protocol fields were separate, since both of these were set by the probes. Its odd to me to find the length field in the middle of fix-length fields, thus I didn't think the next byte set by the probe would be an address. Also in this protocol, the data field handles both responses and commands. I assumed the commands would be in a separate enumerated field. However, this should demonstrate the value of Nmap service fingerprints when investigating new services.

The next unknown service on this device is TCP port 41100. The following is the Nmap service fingerprint for this port.

(GenericLines,23,"\r\n\x04\0\0\0\0\0\0\0\0\0\0\0\xee\xf5\x05\0\0@\x0b\0EclrErrors\0\0\0")
(DNSStatusRequest,23,"\0\x0c\x04\0\0\0\0\0\0\0\0\0\0\0\xfb\xf3\x05\0\0@\x0b\0EclrErrors\0\0\0")
(Help,23,"HE\x04\0\0\0\0\0\0\0\0\0\0\0\xb3\xba\x05\0\0@\x0b\0EclrErrors\0\0\0")
(X11Probe,23,"l\0\x04\0\0\0\0\0\0\0\0\0\0\x08\x8f\xf7\x05\0\0@\x0b\0EclrErrors\0\0\0")
(LPDString,23,"\x01d\x04\0\0\0lte%20po\x86b\x05\0\0@\x0b\0EclrErrors\0\0\0")
(LDAPBindReq,23,"0\x0c\x04\0\0\0\x07\x02\x01\x02\x04\0\x80\0\?\xef\x05\0\0@\x0b\0EclrErrors\0\0\0")
(TerminalServer,23,"\x03\0\x04\0\0\0\0\0\0\0ME\0\0\xab\xba\x05\0\0@\x0b\0EclrErrors\0\0\0")
(NCP,23,"Dm\x04\0\0\0\0\x17\0\0\0\x01\0\0\xb7z\x05\0\0@\x0b\0EclrErrors\0\0\0")
(kumo-server,23,"\x94\0\x04\0\0\0\x91\x03\0\0\0\x02\0\0\xd6\xf9\x05\0\0@\x0b\0EclrErrors\0\0\0")

This is a mess doesn't offer us too many clues. Each response is 0x23 bytes and they all seem to be an error of some kind. From analyzing patterns in the bytes, here's the structure I'm able to figure out. 

16 bit transaction
32 bit unknown constant '\x04\0\0\0'
64 bit unknown
16 bit unknown
8 bit length field for data1? (constant '\x05')
40 bit data1 unknown constant '\0\0@\x0b\0'
dynamic-size data2 unknown constant 'EclrErrors\0\0\0'

Building out protocol structures like this, allow us to create smarter protocol fuzzers. Rather than sending random lengths of random data, we can attempt to fuzz a field at a time and see what responses we get until we've mastered the entire protocol...or the service crashes.
 
The most interesting part of this protocol is the ''EclrErrors' string. Eclr is a reference to Embedded Common Runtime Language, or in other words .Net on a Chip. A protocol that speaks directly to the processor. Oh the fun this protocol presents, not even the organizers of the ICS lab were aware of this port or its function. Sadly, something else for the next lab.

Ethernet Switches used to connect attackers to various PLCs
Access to the PLCs was provided via these Phoenix Contact Ethernet switches, which support a span-port so the lab organizers could monitor traffic (green wire). While the switches aren't PLCs, they were fair game in this lab, so I scanned them as well and found one unusual port, TCP 44818.

Nmap only returned one fingerprint for this service. Not a lot to go on.

(NotesRPC,18,":\0\0\0\0\0\0\0\x01\0\0\0\x02\x0f\0\x01\0=\x05\0\0\0\0\0");

In conclusion I had a fun time and learned a bit, but my experience was limited to 4 hours. With more time, who knows what else I could have accomplished. Also, if you're interested in setting up your own lab, you can purchase a variety of these starter kits from Phoenix Contact. Any kit with a ILC 131 ETH controller will give you a similar experience to this lab. 

No comments:

Post a Comment