Hacking my health insurance security token generation

Following up with my quest to clean my phone from apps that I was forced to install by living in a civilization that doesn't care about bloated software. This time it was the turn of my health insurance app.

I have OSDE. On there, in order to have a medical appointment, purchase discounted medications and other related actions, you MUST have installed the OSDE app, not only for presenting the card credential number, but for it to give you a "token" that generates every 5 minutes.

You show this token to the person who is taking your medical appointment or purchase, thus validating that you are authorized to do it.

OSDE App with generated token, in this case is 602 and it will be valid for 2 minutes

I don't think this seem like a particularly bad way to validate your authority to use the service, but I'd rather not have an app installed for something that could be a card. And I knew this could be circunvented because it works offline.

So here we go with the hack.

OTP

Asking to a friend about this, I realized that this app implements a cryptographic One-Time Password (OTP) just like Google Authenticator.

In short this takes a static identity seed, the current timestamp (mod by 5 minutes), and hashes it, producing a number that should guarantee the user's identity in that moment.

Knowing this, and having my phone rooted, I could grep the app's storage and find the needed seed.

After a few attempts I found what I was looking for:

$ strings /data/data/ar.com.osde.ads/databases/credencialDigitalSqlite | grep OTP
credenciales"[ ... ,\"semilla\":\"( This is it )\" ... ]"/

Matching the token

Having the seed, all I had to do was replicate the same encodings and options that the app uses.

After a few failed attempts with publicly available OTP libraries, I realized that it would be easier to decompile the app and take a look at how the app is actually hashing the seed.

As with the trains app hack, I used the jadx program and took a peek inside.

Quickly I found it:

otplib_otplib_browser__WEBPACK_IMPORTED_MODULE_4__["totp"].options = {
    digits: 3,
    step: 300,
    algorithm: 'sha256',
    createHmacSecret: function (secret, params) {
        return secret;
    }

With this I've got both the encodings and the js library used (otplib).

And finally I was able to reproduce the same token generation as the app:

const { totp } = require('otplib');

const seed = "...";

totp.options = {
    digits: 3,
    step: 300,
    algorithm: "sha256",
    createHmacSecret: function (secret, params) {
        return secret;
    }
};

console.log(totp.generate(seed));
$ node index.js
602

Minimizing the code

From previous work experience, I have had major problems relying on external cryptographic libraries. So this time I would like to not depend on otplib and have it to manually generate the token by myself.

By scrapping the otplib code and minimizing it to only do the generation for this type of token, I ended up with a compact version of it:

const { createHmac } = require("crypto");

const seed = "...";

const generateToken = (secret) => {
  const counter = Math.floor(new Date().getTime() / 300000)
    .toString(16)
    .padStart(16, "0");
  const digest = createHmac("sha256", secret)
    .update(Buffer.from(counter, "hex"))
    .digest();
  const offset = digest[digest.length - 1] & 0xf;
  const binary =
    ((digest[offset] & 0x7f) << 24) |
    ((digest[offset + 1] & 0xff) << 16) |
    ((digest[offset + 2] & 0xff) << 8) |
    (digest[offset + 3] & 0xff);
  const tokenNumber = binary % Math.pow(10, 3);
  return tokenNumber.toString().padStart(3, "0");
};

console.log(generateToken(seed));

OSDE-CLI

For the final touch I ended up adding a few optional parameters and printing extra information. This way anyone could use this "terminal version of the OSDE app", without the need to use the official one.

Running it on Termux, much faster than the OSDE app

I published it on a github repository, so anyone can use it freely.

I hope you liked this blogpost, until next time.

Self-hosting my alarm clock radio

I don’t like waking up, before going to sleep I tend to schdule many alarms and the next morning I turn off each one of them.

When I was younger I remember having an old radio alarm that would turn on at a scheduled time, I used it as an wake up alarm and I remember being effective.

Maybe because hearing people talking would be less numbing that hearing the same song every day, and it would motivate me more to not turn off the alarm, maybe, I don’t know.

But I wanted to try this.

Radio

The trivial solution would be to just buy a radio with an alarm, but I discarded this from the start because

  1. I don't like the radio static, and even less when I can listen to a live broadcast on the internet very clearly.
  2. I didn’t want to spend money

Mobile

My first attempt was downloading an app that would do this. As I’m already waking up with my cellphone I might as well continue using it.

I tried the RadioDroid app, it seems like it has the features I want, it connects to a radio URL and can be used as an alarm clock. But upon using a few nights I’ve noted that the alarm doesn’t always go off. I guess it might be because it’s trying to attempt an active connection and Android goes into idle mode after a while?

Besides I like to turn Wi-Fi off at night, and I realise that it lacks some other nice-to-haves, like adjusting the volume incrementally.

I tried others apps but this was the more promising, I don't want payware, and I surely didn’t feel like programming in Android, so it seemed like I would need another option.

Raspberry Pi

I have a couple of raspberry pis through the house, one of them I use it as a server for various services that are running all day long. So I thought about using it for this purpose as well.

I moved the raspi to the bedroom and connected to it some old PC speakers I had.

Ignore the poor state of the raspberry

Having the interface of a whole computer now I had much more control, as I can program it however I want. All I had to do is play audio through the speakers at a certain time.

The player

The core of the schedule is to just to reproduce audio through the raspberry’s speakers, so I needed an audio player for it.

My priorities were that I needed a program that would be lightweight, CLI so I could run it directly on the terminal, and that could also play radio files.

I wasn’t going to install anything fancy like VLC or MPV just to play an audio file. So after searching around I found mpg123, which fullfilled my needs perfectly, it is extremely lightweight, is CLI, doesn’t have an interface and reproduces radio files directly from the URL.

The radio

As I said on the beginning, I wanted to hear people talking, so I searched for an AM radio. The most popular here regardless of political spectrum is Radio Mitre, which I don't find it entirely despicable, so it works for me.

I scrapped it’s web and found a link for a MP3 file that could be reproduced directly

http://27323.live.streamtheworld.com/AM790_56.mp3

And after executing the following on the raspberry pi.

$ mpg123 http://27323.live.streamtheworld.com/AM790_56.mp3
High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
	version 1.26.4; written and copyright by Michael Hipp and others
	free software (LGPL) without any warranty but with best wishes

Directory: http://27323.live.streamtheworld.com/

Terminal control enabled, press 'h' for listing of keys and functions.

Playing MPEG stream 1 of 1: AM790_56.mp3 ...
ICY-NAME:
ICY-URL: https://radiomitre.com.ar/

MPEG 1.0 L III cbr96 44100 j-s

ICY-META: StreamTitle='SEP WHATSAPP MITRE -SMD';

It’s working! The live radio is coming out from the speakers.

Off button

Now that it works, I need a way to turn it off when I’m already awake.

As I was thinking about how I could attach a physical button to the raspi and having to attach wires and other electronical things and such. I thought to myself

”Wait, I’m a Node.js developer, I don’t need buttons, I can host a bloated express server just to listen for an action, and then send a HTTP request from my phone to trigger it.”

So I had all the elements to start programming.

Programming

I started with the core functionality, spawning the radio process.

const { spawn } = require('node:child_process');

const play = spawn('mpg123', ['http://27323.live.streamtheworld.com/AM790_56.mp3']);

And then handling the process killing on an express endpoint.

const express = require('express');

const app = express();

app
  .get('/apagar', (_req, res) => {
    try {
      play.kill(9);
      res.send('Apagado\n');
      process.exit(0);
    } catch (error) {
      res.status(500).send(error);
      process.exit(1);
    }
  })
  .listen(3000);

On my phone, I created a termux shortcut script that does the HTTP request.

curl $RASPBERRY_IP:3000/apagar

From this I can turn the alarm off with a single tap on my phone.

And the core functionality is done!

Cron job

All I had to do now is set the alarm in motion each morning, which I simply added a cron job to execute it at a determined time. In this case at 08:30.

30 8 * * * cd radespertador && npm run start

Increasing volume and parametrizing

One last feature I’d like to have is to the volume being increasing slowly, I don’t want to get startled all of the sudden of my sleep.

I had to spawn another child process with a call to control the volume, and in intervals call the controller with smaller increments of the percentage for the volume.

const setVolume = volume => spawn('amixer', ['sset', "'Headphone'", `${volume}%`]);

setVolume(0);
let currentVolume = 0;
setInterval(() => {
  setVolume(currentVolume > 99 ? currentVolume : ++currentVolume);
}, 2000);

And of course it would be a bad practice to leave all of this with literals and magic numbers, so I had everything parameterized, and the values can be tweaked on the config file.

You can see the final code here.

Final result

Here’s a recording of how it works, for demostration purpose the increment for the volume is way more frequent than it is in reality

Wait for it

Conclusion

Did it work? Kind of, I still struggle to wake up. But at least now I can listen to boomers say random things on the morning before turning off the alarm, and I can say that I build that.