That time I reported a security problem to TIM

Posted on 13 June 2019

TL;DR TIM had a security issue with their Consip 6 website, leading to disclose sensitive data about their customers. I reported, they fixed, the web is a safer place, and I am in their Hall of Fame!

Convenzione Mobile 6, or simply Consip 6, is a contract between Telecom Italia and Public Administration to provide business mobile services to public employees. The web site for this service has always been problematic for me due to some incompatibilities with the Debian Sid versions of Google Chrome and Mozilla Firefox. This is why sometimes I had to look at their HTML and Javascript code to figure out an alternative way to download my invoices, just to do an example.

On 20 March 2019 I could not authenticate with my credentials, which was already strange because I use generated password and store them with a password manager. Anyhow, I tried to reset my password. It is a two-steps procedure, where the first step asks for the registered email address. If such an address is actually registered, a one-time password (OTP) should be sent by email. The second step asks for the OTP and a new password.

Here I faced a first problem: I did not receive any OTP. Just to exclude that I was using the wrong email address, I started the procedure to recover my username providing my mobile phone number and the VAT number of my university. Well, I received my username on the expected email address. Why did I not receive OTPs to reset my password?

I had a look at their HTML and Javascript code, and found a couple of interesting things. The validation method for the OTP was the following:

jConsip6RecuperaPassword.clickStep3 = function(codiceVerifica) {
  jConsip6RecuperaPassword.post("/service/getCodiceVerificaEmail", "", function(result) {
    console.log("Result getCodiceVerificaEmail :" + result);
    if (result !== "") {
      if (codiceVerifica === result.codiceVerifica) {
        console.log("Il codice di verifica inserito e corretto!");
        jConsip6RecuperaPassword.resetUserPassword();
      } else {
        console.log("Il codice di verifica inserito non e corretto!");
        $(".error").remove();
        $("#rec_pw_steup03").prepend("<p class='error'>" + $("input[name='codiceVerificaEmail']").attr("message") + "</p>");
      }
    } else {
      // TODO MSG ERRORE IMPOSSIBILE RECUPERARE IL CODICE VERIFICA
    }
  });
};

I think that the problem is under the sun, but let me explain it for those that are not computer scientists. The method above executes an asynchronous call to a REST service

https://www.convenzionemobile6.telecomitalia.it/service/getCodiceVerificaEmail

which returns something like the following:

{"codiceVerifica":null,"esito":4}

Property codiceVerifica is null, likely because no email was actually sent. Clearly, this service is already a problem by itself: an attacker may start the password reset procedure and find the OTP thanks to this service; no need to read the emails of the attacked user.

Anyhow, there is another problem with the method above, even more visible than the first: OTP validation is done on the client. Well, I am the client, let me execute directly the reset method in the Javascript console of the browser:

> jConsip6RecuperaPassword.resetUserPassword()

And finally I reset my password and authenticated to my account.

Now, I could use the same procedure to reset passwords of other accounts knowing only their email addresses. For example, I could (but I did not) reset passwords of my collegues. And this is not the end of the story. Client-side validation was done also at the first step of the password reset procedure, that is, to verify the existance of a user associated with the email address entered in the reset form, additionally disclosing sensitive data. Essentially, a REST service

https://www.convenzionemobile6.telecomitalia.it/service/searchUsers?input_email=***@***.**

was providing several sensitive data associated with a registered email address:

{"exitCode":0,"description":"OK","usersFound":[{"area":"M","createTimestamp":"27\/11\/2016 21:19","customerFiscalCode":"***removed***","emailCertified":"***removed***","emailNotCertified":null,"firstName":"Mario","isnew":false,"lastName":"Alviano","mobile":true,"mobileUsername":"***removed***","modifyTimestamp":null,"mycReferent":false,"newsletterAgreement":false,"newsletterTimestamp":"27\/11\/2016 21:19","personalAgreement":true,"prospect":false,"sourceChannel":"CONSIPREG","telephoneCertified":"***removed***","telephoneNotCertified":null,"userFiscalCode":"***removed***","wired":false,"wiredUsername":null,"webProfile":0,"webProfileDescription":null,"webProfileMode":0,"webProfileExitCode":0,"webProfileLastModifyDate":null,"legacySourceSystem":null,"avatarPresent":false,"avatar":null,"avatarMimeType":null,"telecomItaliaID":null,"username":"***removed***","accountState":true,"lastLogin":"20\/03\/2019 16:46","countErrorLogin":0,"lastChangePassword":"Wed Mar 20 16:37:54 CET 2019","previousLastLogin":"Wed Mar 20 16:38:13 CET 2019","login":true,"secretAnswer":null,"secretQuestion":null}]}

Mobile phone number is there. Whether a secret question is set or not is there. All the above without any authentication.

I reported these issues to Telecom Italia following their responsible disclosure procedure. They acknowledged the reception of my email within one day, confirmed the vulnerabilities after 12 days, and fixed them after 72 days.

All in all, I was a bit surprised to see these kind of vulnerabilities in the wild, but somehow the responsible disclosure procedure worked well. We hope for the future to see less vulnerabilities like these, and this is why several courses about CyberSecurity are popping out here and there in several universities. Do you want to know more? Enter my class about Secure Software Design, and you will touch with your hands common vulnerabilities and mitigation techniques.