Hacking an intercom security system to open the door with a phone

How it started…

The office I currently work at is located in a building that has an interphone system. So when any of us wants to get in, just push the button an awaits for someone to answer and push a button on the interphone auricular to open the door.

The problem arise when there’s no one inside (or is in the bathroom) to open the door.

So we came up with the idea of creating a service to open the door with the phone. How do we do this?

The algorithm goes something like this:
1)  Find out how the auricular button works
2)  Create a circuit to hack the signal
3)  Code a service to activate the circuit
4)  Code a phone application to communicate with the service

So let’s get it on!

Find out how the auricular works

Fortunately, I work with very skilled folks. So I asked one of them, Javier, to take a look at the device. It turns out that the door works with a magnetic device. The button interrupts the power that keeps the magnet energized. It does that by touching 2 small plates. It couldn’t be any simpler.

Create a circuit to hack the signal

Using a breadboard, Javier came up with a circuit that consisted of a recircuit1lay and an arduino (together with an ethernet shield). The idea was to hook some cables into the plates, and use the relay to close the circuit. To activate the relay, we would have to send an instruction to the Arduino connected to the modem. So all we have to do it’s to connect to the wireless network and send a command to the Arduino’s ip address.

Code a service to activate the circuit

Since i didn’t have any significative experience coding anything on an Arduino (though I had coded something for a rabbit microcontroller before) i went with one of the demos for a web server. After some tweaking and testing, ended up with something like:

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0x60, 0xA5, 0xEA, 0x0E, 0x07, 0x10
};
IPAddress ip(200, 200, 200, 200);

EthernetServer server(80);

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  pinMode(7,OUTPUT);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
 
 // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    
// an http request ends with a blank line
    boolean currentLineIsBlank = true;
    String currentLine = "";
    String command = "";
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        currentLine = currentLine + c;
        
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        
        if (c == '\n' && currentLineIsBlank && command == "some command") {

          digitalWrite(7, HIGH);  
          delay(1000);              
          digitalWrite(7, LOW);    
          //delay(1000);  
          
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");            
          client.println(command);
          client.println("</html>");
          command = "";
          break;
        }
        
        // you're starting a new line 
        if (c == '\n') {                                 
          currentLineIsBlank = true;
          Serial.println("current line = " + currentLine);
          currentLine = "";
        } 
       // you've gotten a character on the current line 
       else if (c != '\r') {                          
          currentLineIsBlank = false;
        } 

       //get the command
       else if (c == '\r' and currentLine.startsWith("GET")){ 
          int start = currentLine.indexOf('/')+1;
          int endAt = currentLine.indexOf(' ',start);
          command = currentLine.substring(start, endAt);         
        }
      }
    }

    // give the web browser time to receive the data
    delay(1);

    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    Ethernet.maintain();
  }
}

The idea behind was to provide a web API that listens for the request to a particular URL. It then extracts the last part of the requested url and uses that command to activate the relay and therefore close the door. Anyone with the ip address and the right URL can activate the relay, as long as it’s one the same subnet as the Arduino.

Code a phone application to communicate with the service

So, Josue (another coworker) suggested that since I had created the web api I could as well create a phone app to consume it. Since most of the people on the office use an android phone, i thought this would be a good opportunity to test the platform. I have zero knowledge of the Android programming model, so on Josues suggestion I took a look to Xamarin. It turn out to be fairly simple. I still have to learn more of the platform tough….

Here’s the code:

 [Activity(Label = "Jarvis", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        private string url = "http://200.200.200.200/";

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.MyButton);
            TextView text = FindViewById<TextView>(Resource.Id.textView1);
            
            button.Click += async(sender,e) =>
            {
                try
                {
                    await send(jarvisCommands.openDoor);
                    text.Text += "Get in! \n\r";
                }
                catch (Exception ex)
                {
                    text.Text += ex.Message + "\n\r" + Resources.GetString(Resource.String.Error) + "\n\r";
                }

            };
        }

        private async Task send(jarvisCommands command)
        {
                HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(new Uri(url + command.ToString()));
                request.ContentType = "application/text";
                request.Method = "GET";
                await request.GetResponseAsync();
         
        }

        enum jarvisCommands { openDoor}
    }

Learned things:
1) Necessity is the mother of ingenuity
2) You can create interesting stuff when you are surrounded by interesting people
3) If you know Java, C++, C# or any other curly braces language, odds are that you’re already capable of writing something for the Arduino
4) The Intent concept on the Android platform it’s just an implementation of a message bus

I think this is it. Until the next post! (I’ll write often, promise)