Author

Topic: Fix for manual payout bug for mmcfe (greedi version) - for those who need it (Read 679 times)

legendary
Activity: 2072
Merit: 1001
I have the vague feeling I reported this issue a month or so ago. While it is true that the issue is eliminated with cronjobs, it's not instant payout anymore.

less then 60 seconds until payout is instant enough. and it avoids the stateless issue and overly complex php code.

and yes, some people knew about it. but not enough in my mind.
Well, I personally like the idea of seeing a tx hash as soon as I click payout.

i admit that is appealing but mmcfe never provided that in the first place if I recall correctly.
legendary
Activity: 1862
Merit: 1011
Reverse engineer from time to time
I have the vague feeling I reported this issue a month or so ago. While it is true that the issue is eliminated with cronjobs, it's not instant payout anymore.

less then 60 seconds until payout is instant enough. and it avoids the stateless issue and overly complex php code.

and yes, some people knew about it. but not enough in my mind.
Well, I personally like the idea of seeing a tx hash as soon as I click payout.
legendary
Activity: 2072
Merit: 1001
I have the vague feeling I reported this issue a month or so ago. While it is true that the issue is eliminated with cronjobs, it's not instant payout anymore.

less then 60 seconds until payout is instant enough. and it avoids the stateless issue and overly complex php code.

and yes, some people knew about it. but not enough in my mind.
legendary
Activity: 1862
Merit: 1011
Reverse engineer from time to time
I have the vague feeling I reported this issue a month or so ago. While it is true that the issue is eliminated with cronjobs, it's not instant payout anymore.
legendary
Activity: 2072
Merit: 1001
Bump for sec issue. Could save a pool op coins.
legendary
Activity: 2072
Merit: 1001
The manual payout option for mmcfe has a bug that could allow an attacker to make multiple submissions to it in a very short
amount of time. The current code might allow multiple payouts. Here is my fix.

I assume you are running your payout.php script from cron every 60 seconds.

Create a new column in accountBalance called Being_Paid_Flag . Make it an INT and verify it defaults to 0. It should.

Make a copy of your original accountdetails.php for a backup.

Edit the file and and look for this chunk of code:

Code:
                                if($isValidAddress){
                                        //Subtract TX feee
                                        $currentBalance = $currentBalance - 0.1;
                                        //Send money//
                                        if($bitcoinController->sendtoaddress($paymentAddress, $currentBalance)) {
                                                $paid = 0;
                                                $result = mysql_query("SELECT IFNULL(paid,'0') as paid FROM accountBalance WHERE userId=".$userId);
                                                if ($resultrow = mysql_fetch_object($result)) $paid = $resultrow->paid + $currentBalance;

                                                //Reduce balance amount to zero & make a ledger entry
                                                mysql_query("UPDATE `accountBalance` SET balance = '0', paid = '".$paid."' WHERE `userId` = '".$userId."'");

                                                mysql_query("INSERT INTO ledger (userId, transType, amount, sendAddress) ".
                                                            " VALUES ".
                                                            "('$userId', 'Debit_MP', '$currentBalance', '$paymentAddress')");

                                                $goodMessage = "You have successfully sent ".$currentBalance." to the following address:".$paymentAddress;
                                                //Set new variables so it appears on the page flawlessly
                                                $currentBalance = 0;
                                        }else{
                                                $returnError = "Commodity failed to send.";
                                        }
                                }else{
                                        $returnError = "That isn't a valid Bitcoin address";


Change that chunk of code to look like this:

Code:
                                if($isValidAddress){

                                        mysql_query("UPDATE `accountBalance` SET Being_Paid_Flag = '1' WHERE `userId` = '".$userId."'");
                                        $goodMessage = "You have successfully sent " .$currentBalance. " to the following address: " .$paymentAddress. " Processing in less then 60 seconds";

                                }else{
                                        $returnError = "That isn't a valid Bitcoin address";



Next, find your cronjob script called payout.php. Make a backup copy of it.

Add this to the bottom of the file:

Code:
// Pay users who have Being_Paid_Flag set to 1 in accountBalance then set back to 0 when processing is done //
$resultZ = mysql_query("SELECT userId, balance, IFNULL(paid, 0) as paid, IFNULL(sendAddress,'') as sendAddress, Being_Paid_Flag FROM accountBalance WHERE Being_Paid_Flag = 1");
while ($resultR = mysql_fetch_object($resultZ)) {
        $currentBalance = $resultR->balance;
        $paid = $resultR->paid;
        $paymentAddress = $resultR->sendAddress;
        $userId = $resultR->userId;

        if ($paymentAddress != '')
        {
                $isValidAddress = $bitcoinController->validateaddress($paymentAddress);
                if($isValidAddress){
                        // Subtract TX fee & calculate total amount the pool will pay
                        $currentBalance = $currentBalance - 0.1;
                        $tot_paid = $resultR->paid + $currentBalance;

                        // Send the BTC!
                                // debug
                                // echo "sending: ". $currentBalance . " to ". $paymentAddress;

                        if($bitcoinController->sendtoaddress($paymentAddress, $currentBalance)) {
                                // Reduce balance amount to zero, update total paid amount, and make a ledger entry
                                mysql_query("UPDATE `accountBalance` SET balance = '0', paid = '".$tot_paid."' WHERE `userId` = '".$userId."'");

                                mysql_query("INSERT INTO ledger (userId, transType, amount, sendAddress) ".
                                            " VALUES ".
                                            "('$userId', 'Debit_MP', '$currentBalance', '$paymentAddress')");

                                mysql_query("UPDATE `accountBalance` SET Being_Paid_Flag = '0' WHERE `userId` = '".$userId."'");

                        }
                }
        }
}

Any final cosmetic tweaks to the website explaining this new way of doing things to users.
For example in accountdetails.php you might want to have this text blurb under "CASH OUT" to appear for users to read:
"Minimum withdrawl is 0.50 LTC. Manual payments are processed in less then 60 seconds. Please note: a 0.1 ltc transaction will apply when processing "On-Demand" manual payments"
Tweak if for your needs.


What this does for you is this: When a person tries to do multiple submissions for a manual payout all they are doing is setting the
Being_Paid_Flag to 1. That is all they can do.

When the payout.php script runs it will actually do the payout. This will defeat the attack and is probably the best way to solve
this since http/php is stateless.

If anyone sees a mistake or a way to improve this please post here.
If anyone wishes to throw me a LTC tip: LSLTFCpFX1V3offArHtvEGwtUKVs1H9zCJ
Jump to: