niedziela, 21 października 2012

wladca's PayGol script

Wladca posted on Otland.net script to allow people to pay with PayGol services.

Code:
<?php
/*


Note:Before starting you have to create an account at http://www.paygol.com/register?affiliatecode=T8Y7-LK0M-NY0R-Y6O3


*/


// check that the request comes from PayGol server
if(!in_array($_SERVER['REMOTE_ADDR'],
  array('109.70.3.48', '109.70.3.146', '109.70.3.58'))) {
  header("HTTP/1.0 403 Forbidden");
  die("Error: Unknown IP");
}
  

// get the variables from PayGol system
$message_id = $_GET['message_id'];
$service_id = $_GET['service_id'];
$shortcode = $_GET['shortcode'];
$keyword = $_GET['keyword'];
$message = $_GET['message'];
$sender = $_GET['sender'];
$operator = $_GET['operator'];
$country = $_GET['country'];
$custom = $_GET['custom'];
$points = $_GET['points'];
$price = $_GET['price'];
$currency = $_GET['currency'];

//Replace these parameters by your database details
$dbhost     = "localhost"; //Your database domain
$dbuser     = "root"; //Database username
$dbpassword = "dbpass"; //Database password
$db         = "dbname"; //Database name

//Connect to Database
$conn = mysql_connect($dbhost, $dbuser, $dbpassword);
mysql_select_db($db);

$sql = "UPDATE accounts SET premium_points = premium_points+$points WHERE name = '$custom'";
mysql_query($sql);

mysql_close($conn);

?>
He was sure that this script is secure because it allows connection only from IP's of PayGol.
I explained him that user provides the 'custom' GET parameter, so as his account name he can put anything, also something what will for example add points to all users. I fixed that for him but today I came with another idea.

I've created PayGol account, created own multiprice service with price 1 euro, 9000000 points for that and IPN URL pointing to... wladca's website.
Than I turned on testing mode, made the purchase in testing mode and on wladca's server I had 9000000 points :)


So what is the solution for this problem?
Check if parameters passed to your IPN script match the values you obtained from PayGol (especially service_id, price and points).

C++ TFS packet flood protection

Recently I posted the The Forgotten Server Firewall codes on the Premium Board of OTLand.net but noone implemented it in tfs core. I believe that developers are using it on their own servers to gain some advantage over competition.

I don't like this kind of attitude so I decided to release it here.
WARNING: This is not simple copy&paste code. You need to read it carefully and add some variables in files. Ok, you have been warned - so here you are:
Add this function & function's prototype:


bool ProtocolGame
::gotCooldown(Playerplayerint recvbyte)
{
    if(!
player)
        return 
false;
    if(
player->isRemoved())
        return 
false;
    
int64_t tNow time(NULL);
 
    if(
cooldownExceedAttemp g_config.getNumber(ConfigManager::COOLDOWN_EXCEED_ATTEMP)) //20
    
{
        
disconnectClient(0x14"Tried to send too many packets.");
        
std::clog<<"[ DOS ATTEMPT FROM ] "<< player->getName()<<std::endl;
        return 
false;
    }
    if(
cooldownLast != tNow)
    {
        if(
cooldownCounter g_config.getNumber(ConfigManager::COOLDOWN_EXCEED_WARNING)) //5
            
cooldownCounter 0;
        else
        {
            if(
cooldownExceed g_config.getNumber(ConfigManager::COOLDOWN_EXCEED_SECONDS) < tNow//SECONDS
                
cooldownCounter 0;
            else
            {
                
cooldownExceedAttemp++;
                
cooldownCounter g_config.getNumber(ConfigManager::COOLDOWN_EXCEED_WARNING); //5
            
}
        }
        
cooldownLast tNow;
        return 
false;
    }
    else
    {
        
cooldownCounter++;
        if(
cooldownCounter g_config.getNumber(ConfigManager::COOLDOWN_PPS)) //10
            
return false;
        else
            
cooldownExceed tNow;
    } 
    return 
true;
}  
in 
PHP Code:
void ProtocolGame::parsePacket(NetworkMessage &msg)  
before
PHP Code:
        switch(recvbyte)
        {  
add:
PHP Code:
if(recvbyte >= 0x6F && recvbyte != 0x96 && recvbyte <= 0xF1)
            if(
gotCooldown(playerrecvbyte))
                return;  

in:
PHP Code:
bool ProtocolGame::parseFirstPacket(NetworkMessagemsg)  
after
if(g_game.getGameState() == GAMESTATE_SHUTDOWN)
{
getConnection()->close();
return false;
}
add
PHP Code:
cooldownLast 0;
    
cooldownCounter 0;
    
cooldownExceed 0;
    
cooldownExceedAttemp 0;  
and add above in protocolgame.h
And add those config variables from 1st function to the configmanager.


And you can now limit incoming packets based on the character to prevent too fast items moving, or too fast attacking creatures or even too fast using talkactions or items.

Good luck!

SYN_RECV flood

Today my monitoring tool reported weird traffic on the webserver.
Short investigation showed that we are under SYN_RECV flood, what looked like this:
tcp        0      0 188.165.xxx.xxx:80        107.83.110.62:1234      SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        109.143.164.196:1234    SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        109.222.2.66:1234       SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        1.118.132.82:1234       SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        114.19.38.196:1234      SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        115.71.32.78:1234       SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        117.157.27.87:1234      SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        118.0.125.227:1234      SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        1.183.162.94:1234       SYN_RECV    -               
tcp        0      0 188.165.xxx.xxx:80        119.19.140.214:1234     SYN_RECV    -               
......... and many, many more ;]
Having syncookies turned on, I couldn't do much more about this than limiting connections with SYN_RECV to 1 per second per IP address.

Attacker tried like 5-10 times more to bring down our server but without success. The whole bandwidth of attack varied between 90-200 mbps.

To protect the website in future, I implemented Varnish Cache mechanism with Apache for dynamic content and nginx for static.

It works really well, page serving time dropped from 4s to 2.5s (including downloading all images, styles and javascripts).