Problems tracking downloads in the rewards plugin

enricodias4654

Member
YetiShare User
Jan 13, 2015
411
1
16
Hello.

I've found several problems in the way the rewards plugin tracks downloads. Those problems can be exploited by users to earn money with incomplete downloads. I'll post details in a reply in this topic to protect sensitive information.
 

enricodias4654

Member
YetiShare User
Jan 13, 2015
411
1
16
So, I guess people already know that using xsendfile will call the plugin early and log the download before sending the file to the user. The users may start the download and stop it after few bytes and still earn the money in the PPD program.

Another issue is about partial downloads. Even using php to handle downloads a user can send a http range header of few bytes and the rewards plugin will log it the same way as a complete download.

The plugin also doesn't use transactions and this may be exploited to log multiple downloads with the same ip by sending the multiple requests at the same time to multiple direct servers with a http range header of a few bytes at the same time. And a little bit of luck, of course.

With a home adsl connection a malicious user can create a script that downloads 100 bytes of a file, reconnect to change the public ip and repeat the process. This can be exploited to log thousands of downloads per day and earn thousands of dollars per month with the PPD program.


The follow modifications are needed to solve this problem:

1) Use transactions in the sql queries.
2) Add a new field in the download_tracker table to hold the downloaded bytes.
3) In the download_tracker updates, update the downloaded bytes using the $length var in the download class.
4) Use ignore_user_abort(true) to keep the script running.
5) In the file.class.php, check the user connection in each interaction of the last loop and break it if the user disconnects.
6) Update the downloaded bytes in the download_tracker in the finish() method.
7) Add a new status in the ppd_details named "incomplete_download".
8) Change this query in the rewards plugin

$sql = "SELECT * FROM plugin_reward_ppd_detail WHERE download_ip = " . $db->quote($usersIp) . " AND file_id = " . $file->id . " AND DATE(download_date) = " . $db->quote(date('Y-m-d'));

to this:

$sql = "SELECT * FROM plugin_reward_ppd_detail WHERE download_ip = " . $db->quote($usersIp) . " AND file_id = " . $file->id . " AND DATE(download_date) = " . $db->quote(date('Y-m-d')." AND status = 'pending'";

9) Use the following code in the rewards plugin before logging the download:

$downloaded_size = $db->getValue('SELECT SUM(`downloaded_bytes`) AS `downloaded_size` FROM `download_tracker` WHERE `file_id` = '.$file->id.' AND `ip_address` = \''.$usersIp.'\' AND `date_started` > DATE_SUB(NOW(), INTERVAL 2 DAY)');
if ($downloaded_size < $file->fileSize) {

$rewardAmount = 0;
$status = 'incomplete_download';

}

6 and 7 are needed to log the downloaded size even if the user loses connection.
9 will allow the log only if that ip downloaded the entire file in the last 2 days. This can be changed to use the username instead of the ip.

The new field in the download_tracker will also make it possible to display downloaded % in the active downloads page in the admin.


There is also an issue with downloads using ipv6, since most ISPs gives a large amount of addresses to each customer. The modifications in this reply don't solve this issue.
 

enricodias4654

Member
YetiShare User
Jan 13, 2015
411
1
16
The solution I gave in the last post will write the status "finished" when the user drops the connection, but this is easy to solve.

if (connection_status() != CONNECTION_NORMAL) {

$status = 'cancelled';
break;

}

...

if (SITE_CONFIG_DOWNLOADS_TRACK_CURRENT_DOWNLOADS == 'yes') $downloadTracker->finish($status, $length);