📜 ⬆️ ⬇️

Shell parser with authentication XOR encryption bypass

Recently, there was a need for a parser of an online bank card account for further notification of transactions via SMS \ e-mail. It was decided to do this quickly in a shell script that will parse the page with the account at a certain frequency using the task in cron, and in case of changing the account balance - send a message to a mobile phone or e-mail. Nothing complicated at first glance, but during the writing I had to solve some difficulties that you can read about under the cut.

For parsing, it was decided to use standard unix utilities - curl, grep, sed. It was supposed to authenticate to the https server using a post-request, and then, as usual, using regular expressions, pull the necessary information from the page. But it was then that the main problem was discovered - the data during authentication (more precisely, the password) was sent to the server encrypted. Let me remind you that the banking page was taken over https, i.e. such a mechanism, in addition to TLS, is due, perhaps, to protection from local sniffers.

POST
Before sending, in the best traditions of Unicode, hieroglyphs are encoded in hex

Obviously, encryption was used on the client side, but it is difficult to imagine this process without a key, which I was looking for.
First of all, after thinking, why not, cookies were checked, it is clear that no dependencies that issued the key were detected. Plans to write a script in a hurry and continue to go about their business, began to gradually crumble. The site was written in jQuery, which further depressed my position . Using the debugger, an embedded script was detected in the events:
function () { var context = $(this).parents("#loginParamsWrapper"); var authMode = $("#AuthMode", context).val(); var form = $("#frm" + authMode, context); if (!TWIB.validForm(form)) { return false; } var data = form.formToArray(); data.push({name: "AuthMode", value: authMode}); if (authMode == "TBId") { var pan = $("#name", form).val(); var prefix = "9129120000000000"; if (prefix != "" && prefix.length > pan.length) { pan = prefix.substring(0, prefix.length - pan.length) + pan; } data.push({name: "PAN", value: pan}); } data.push({name: "PIN", value: TWIB.xorString($("#password", form).val(), "3734")}); ... } 
The PDA-version of the site was analyzed in view of resource saving during parsing; no special differences were found with the main version in the authentication mechanism

As can be seen from the code, the prefix 912912 is added to the digital login (in my case, the ten-digit one), which seems to be static, which was discovered even when viewing the http-headers. But of greater interest is the last line, which suggests that the password value is encrypted using the xorString function and the dynamic key val, in this case, 3734. Let's look for the body of the function itself in other scripts.
')
firebug

This code fragment modulo 2 adds each character of the string str (password entered) with the entire string val (key combination), the String.fromCharCode method displays the characters by their received decimal codes, and the string res is returned, which is transmitted instead of the password in the post- authentication request.
The overall picture of the defense mechanism is already there, it remains to find out where the key combination comes from.

But it turned out pretty simple. When the page is opened, the session identifier is written in the cookie, then the post ajax request (XNR) is sent to the actionParam: Logon (which, by the way, the debugger built into the last chrome did not notice at first), and the script with the key combination associated with the session id.

In order for our parser to get to the desired page, it will have to do the following:

1. Request a page, get session cookies
2. Using the received cookies, send a post-request, get a page with an embedded script
3. Dump the received json key, which will be used for XOR encryption
4. Add modulo 2 of each password character with a key combination.
4.1. Convert password characters from decimal codes
4.2. Perform operation XOR
4.3. Convert from decimal to hexadecimal
4.4. Get unicode characters from code values
5. Using the resulting string, authenticate to the site.

Some difficulty is only in obtaining an encrypted password for authentication. To begin with, we will get the key, with the help of which we will carry out further manipulations:
 curl -s -b "PDAVersion=true" -A "$ua" "$site" -c "cookies" > /dev/null 

 key=$(curl -s -b "cookies" -b "PDAVersion=true" -e "$site" -A "$ua" "$site/getData.jsp?actionParam=Logon&appendTransactions=true&format=html" | grep -om 1 "val(), '[0-9]*'" | sed "s/val(), //;s/'//g") 

Promised key manipulations:
 #ascii char -> dec char code -> xor -> hex char code -> unicode char #     dec () { for i in `echo $1 | sed 's/./&\n/g'`; do printf '%d\n' "'$i"; done } #    2   xor () { for i in $*; do echo $(($i ^$key)); done } #  xor  dec  hex hex () { for i in $*; do printf '%X\n' "$i"; done } #       unicode () { for i in $*; do printf "\u$i"; done } dec=`dec "$pass"` xor=`xor $dec` hex=`hex $xor` char=`unicode $hex` echo $char > /dev/null 

At the output we will receive an encrypted password, which we authenticate with the help of a post-request on the site:
 curl -s -b "cookies" -e "$site" -A "$ua" "$site/getData.jsp" -d AuthMode=TBId -d PAN=912912$login --data-urlencode PIN=$char -d actionParam=GetPANRq -d appendParams=true -d format=json -c cookies > /dev/null 


security
It is rather unsafe to provide information about an invalid user ID, given that theoretically the maximum number of digital IDs in the database is 10 10 , and digital passwords are only 10 6
  Just do not frantically pull the mouse in the desire to use the brutus, nothing "tasty", except for information about the owner and transfers, you will not receive, because  98.76% of accounts do not have access to financial transactions, I guarantee) 

Now you can get the necessary data from the page, in my case, the amount on the account:
 cash=$(curl -s -b "cookies" -b "twebank_authmode=TBId" -e "$site" -A "$ua" "$site/getData.jsp?actionParam=AcctsMenu&appendTransactions=true&format=html" | grep -o 'unt">.*<b' | sed 's/unt">//;s/\.[0-9][0-9]<b//;s/\ //g') 

And now let's finish our plans by writing a small script to notify about changes in the amount:
 if [ -s "$HOME/cashlog" ] then if [ `cat $HOME/cashlog` = `cat $HOME/cashlog | sed 's/[^0-9]//g'` ] then cashlog=$(<$HOME/cashlog) if [ "$cash" -gt "$cashlog" ] #if [ $(echo "$cashlog < $cash"|bc) -eq 1 ] then a=`expr $cash - $cashlog` in=$(echo "$a rub added to your account. Now you have $cash rub") echo $in python $HOME/sms_send.py -n "+79999999999" -t "$in" -l "some@mail.ru" -p "pass" echo "$cash" > "$HOME/cashlog" elif [ "$cash" -lt "$cashlog" ] then z=`expr $cashlog - $cash` out=$(echo "Exchanged $z rub, you have $cash rub") echo $out python $HOME/sms_send.py -n "+79999999999" -t "$out" -l "some@mail.ru" -p "pass" echo "$cash" > "$HOME/cashlog" #else echo "No changes, you have $cash rub" fi else echo "$cash" > "$HOME/cashlog" echo "Cash log was updated" fi else echo "$cash" > "$HOME/cashlog" echo "Cash log was created" fi 

For sending SMS via mail.ru agent services, a small python script found on the Internet is used.
Implement sending a message to the e-mail did not specifically, because it will be implemented by means of cron.

Using crontab, add an entry
*/10 * * * * /path/to/script/ca.sh
to run the script every ten minutes.

It is also worth adding to the beginning of the script a record like MAILTO=your@mail.net , with correctly configured sendmail (or its equivalent), cron will send messages to the specified soap with the results of the script output.

You can view the whole script here , tested on bash.

I admit, the implementation does not shine with elegance, but the main thing, as they say, is the result. The script was written in haste, with the thoughts “well, let it be, the main thing works,” so there are moments that were clearly worth implementing otherwise. I hope to rewrite later, you can find on the same link. With a small adjustment should work with any site that uses such an authentication scheme. The main purpose of the article is to show by example how to solve such problems using standard unix tools. I hope the article was useful to someone.

Upd: It turned out that the old version of banking has no additional protection, i.e. for its parsing there would be enough such script .

Source: https://habr.com/ru/post/127451/


All Articles