Author Topic: Preventing loop holes (dupes) ?  (Read 1435 times)

Offline leZourite

  • Level 12
  • *
  • Posts: 81
  • Reputation: +2/-0
    • View Profile
    • After doomsday
Preventing loop holes (dupes) ?
« on: January 18, 2008, 08:02:06 PM »
I have been working for some months now on my own PBBG, i am wondering how the hell the guys are finding these dupe, well why coding my game (i don't use any pre-made scripts like grpg that is so infamous for its holes and used in fairly all fighting/mafia games out there), i did notice how something could be duped and fixed them right away.

But for most part i am really wondering how it happens, server lag maybe ? (script too busy to process and thus repeating refresh will increment the money ?)  i put a lot of checks (a little paranoid are we on the security :D) before even processing something so i guess that the checks would catch even under massive loads... but really i am wondering.

If someone could enlighten me of some of these exploits (from already patched game or whatever i am not going to cheat on these games for the sake of it) i would gladly appreciate it.

In the meaning time i am working on my framework so i can log anything that has been bought/transfered (i have many table dedicated).

One of the first exploits i have been aware of while coding my game was about "virtual shops", say you are in a city and then there are some shops around (weapons, armors, goods, etc), obviously we have to work with query strings, say you don't properly check that the shop is located in the city you currently are, then by just changing a number in the query string you can access shops from other cities. Moreover the checks should be also done for the goods sold from theses shops, because say you change the post information on the fly to get a weapon from another shop and thus without proper checks you can buy whatever you want !

Theses kind of holes are more dependent on flaws in logic then really buggy code, but i am interested in the other kind of exploits, how to prevent them.

Offline JGadrow

  • Level 35
  • **
  • Posts: 1,133
  • Reputation: +23/-2
    • View Profile
Re: Preventing loop holes (dupes) ?
« Reply #1 on: January 21, 2008, 12:06:02 PM »
You've already identified it. Bugs arise from flaws in the application's logic.

I've found the two leading causes of bugs are:
Data corruption
Unexpected input

Data corruption is bad because it is extremely difficult to diagnose and reproduce.

The best thing to do is to imagine that when you're finished with your application that you are going to try every dirty, underhanded trick to break the application. Also, be sure to comment your code frequently. If you code a user management segment and you know you need to somehow test for multi-byte character integrity but don't have the time or resources to do it now, comment it to remind you later!

Let's face it, code logic sometimes becomes inconsistent because it is not coded all at once. Something you do one day and forget about could rear its ugly head months later when you've forgotten all about it. Happens to everyone. That's why Q&A teams exist :)
Idiocy - Never underestimate the power of stupid people in large groups.


Offline leZourite

  • Level 12
  • *
  • Posts: 81
  • Reputation: +2/-0
    • View Profile
    • After doomsday
Re: Preventing loop holes (dupes) ?
« Reply #2 on: January 21, 2008, 09:50:27 PM »
Well first and foremost as the coding was done with security in mind (not like the infamous GRPG script bugg/security ridden) unless i forget (unlikely) to parse an input i am doomed.

We are 2 people working on it (best teams are small at least 2-3 people at most) and each time each other produce code, it's tested thoroughly and usually checked (at the code level) to see if there is any inconsistencies..

I didn't get the chance to look at the code in GRPG (won't waste 100$ for that) but i am really wondering why so many company dealing with this kind of games don't even try to check the code before making it gold.... and well not talking about the dozen (if not hundreds) of game with the "beta" tag that pops every now and then so they can make a quick buck and check "bugs" when people are actually playing the game.

Don't get me wrong, of course any project this size (at first starting my project i thought : crap this is shit easy to code ! let's try !, after some time though, even if we didn't get any real difficulties it does take some time to do) will be prone to defects/bugs, as in unbalanced algorithm, or forget to implement some functions.

Generally when i produce code i test it 5/6 times in all the cases (expected inputs, unexpected inputs) the only thing unknown yet what will happen under heavy load in the game... but i will know that when the game goes live!

Offline JGadrow

  • Level 35
  • **
  • Posts: 1,133
  • Reputation: +23/-2
    • View Profile
Re: Preventing loop holes (dupes) ?
« Reply #3 on: January 22, 2008, 07:56:27 AM »
lol I had the same thought when I started coding the browser game I currently have 'on hold.'

But after a while I realized that even though I was utilizing OOP, I wasn't performing it in a manner that allowed me to modularize the code for easy feature addition / subtraction / modification. Most of my objects had knowledge of the inner workings of other objects and each new item I added started to become a nightmare.

So, I scrapped the entire project and started fresh. I now have a common library of functions and objects as well as an application framework that I'm working with. Both are still in what I would consider their 'beta' stage as there are probably still some bugs and some features that should be added, but it's allowed me to start following a Model-View-Controller approach to my PHP development.

But, this is all a little OT ;) As far as errors go, they are (nearly) always specific to the application so knowledge of one person's bugs likely won't help you with your application. The best method of learning to avoid bugs is to encounter them yourself. Frustrating, but still the best method :)
Idiocy - Never underestimate the power of stupid people in large groups.


Offline greendots

  • Level 3
  • *
  • Posts: 8
  • Reputation: +0/-0
    • View Profile
Re: Preventing loop holes (dupes) ?
« Reply #4 on: May 15, 2008, 02:56:56 AM »
Think about changing your tables to a type with table locking, and build in some transaction-safe code (perhaps queueing commands or actions to be run in sequence rather than in parallel.)

Offline JohnMunsch

  • Level 7
  • *
  • Posts: 32
  • Reputation: +1/-0
    • View Profile
    • JohnMunsch.com
Re: Preventing loop holes (dupes) ?
« Reply #5 on: May 15, 2008, 11:36:57 PM »
But for most part i am really wondering how it happens, server lag maybe ? (script too busy to process and thus repeating refresh will increment the money ?)  i put a lot of checks (a little paranoid are we on the security :D) before even processing something so i guess that the checks would catch even under massive loads... but really i am wondering.

If someone could enlighten me of some of these exploits (from already patched game or whatever i am not going to cheat on these games for the sake of it) i would gladly appreciate it.

greendots is right on the money but he (she?) didn't bother explaining much of the "how" of things going wrong just due to timing. So let me take a shot...

Let's say I'm a user in your new game and I open up two tabs in my browser. Each one is setup to execute a command to build a widget which costs 10 land and $100. I only have 10 land and $100 so if I hit the button in one tab, flip over to the other one and hit the button there two, we want only one operation to succeed and the other to fail. But, if it gets to the server and the server is doing all of its logic right there in the page, each of those pages is probably running on a different thread in the web app server (PHP, Rails, JSP, whatever). If the second one gets started in another thread before the first one is finished, here's what can happen.

Thread A
======
Let's see, the player wants to build a widget. That costs 10 land and $100 and I do a query to check balances and sure enough he has 10 land and $100.

At this point Thread B interrupts because it gets task switched to
=======================================
Let's see, the player wants to build a widget. That costs 10 land and $100 and I do a query to check balances and sure enough he has 10 land and $100.

I'll subtract 10 land from his total land and that leaves him with zero and do the same for money and that's also zero. I'll write those two to the database and now I can create him a widget.

Thread A gets another turn
=================

I'll subtract 10 land from his total land and that leaves him with zero and do the same for money and that's also zero. I'll write those two to the database and now I can create him a widget.

Whoops!!! Each one read from the database independently, updated the totals and wrote back, not realizing that another thread was doing the same thing at the same time for another request the user made and suddenly the user got two widgets for the price of one. The user doesn't even have to be intentionally trying to scam you for this to happen, on a busy server a player can make one request and then another and another perhaps before the server got a chance to finish the first one because other players are doing a lot of stuff. Suddenly you're running multiple actions for the same user at the same time and the kind of timing mistakes I mentioned above get made. It's not an exploit, it's not a bug (at least not in the traditional sense), it's all about timing and multiple things all happening at the same time.

One easy way to address this kind of problem is to use what is called "optimistic locking" (or as Wikipedia calls it, "optimistic concurrency" http://en.wikipedia.org/wiki/Optimistic_concurrency_control). The gist of it is that instead of doing this:

update PLAYER
set land = 0, money = 0

you instead do this:

update PLAYER
set land = 0, money = 0
where land = 10 and money = 100

See the difference? Now if the two threads both try to execute that same update, only one of them will do it. And when you look at the number of records that got updated (something that is usually returned from doing a SQL update) you will see 1 when it worked and 0 when it didn't. Then you can give them an error message telling them to try again or you can loop back to the top and start all over again. This time though, you'll see how much money and land they have and they've got ZIP. So they can't have two widgets, they only get one.

You've coded around the timing problem by using optimistic locking. 99% of the time you didn't have to do anything special to the record because you didn't need to, 1% of the time it will catch weird little timing things.

If you need more information we can talk about how transactions work and why you need those when you've got stuff to update in two different tables rather than just one.
My PBBG development blog is at http://MadGamesLab.com

Offline Chris

  • Game Owner
  • Level 35
  • *
  • Posts: 2,217
  • Reputation: +28/-1
    • View Profile
Re: Preventing loop holes (dupes) ?
« Reply #6 on: May 16, 2008, 05:06:00 AM »
I think, in the end you can not prevent 100% bugs or glithes no matter what you do. For example, I was testing for a whole month a feature on a test server with 100 players, then after transferring it to a live game the bug pup out because there were more players... I would not call one month test by 100 people an inadequate testing, right? We need to deal with bugs and accept that these will be once in a while no matter the efforts...

Quick tips:
1) Set MAGIC_QUOTES directive.
2) Always check input (especially if they put negative integer values in forms, this is the most common one)
3) make "UPDATE SET money=money-100" not "UPDATE SET money=500" , this will prevent many concurrency errors (the more calculations you put on database side instead of php/perl/etc side the better)
4) make backups (sooner or later you will let something major slip)
5) Do not get paranoid, your players do not play the game because it is 100% bug free or always online, but because it is fun. Make the game fun and they will forgive your other mistakes.

Offline JohnMunsch

  • Level 7
  • *
  • Posts: 32
  • Reputation: +1/-0
    • View Profile
    • JohnMunsch.com
Re: Preventing loop holes (dupes) ?
« Reply #7 on: May 16, 2008, 06:58:46 AM »
No argument there. A game is probably more complex than most websites so bugs will inevitably creep in.

However... Your suggestion to push the calculation to the server really won't help much as you've written it.

"UPDATE SET money=money-100" still implies that you did the test in your page and you're doing your update based on the validity of that test. By not relying on the inherent serial nature of access to a given record that the database forces you're basically going to end up with this:

Thread A
======

Grab Player's info and test, "Got enough money?" Yup.

Thread B
======

Grab Player's info and test, "Got enough money?" Yup.

"update PLAYER
set money = money - 100"

The player's money is now zero.

Thread A
======

"update PLAYER
set money = money - 100"

The player's money is now -100. I guess that's better than before because the player did get charged for an extra widget, but he or she still got to buy something beyond what could be afforded. Whether you do the math in the page or do the math in the database, it's no protection for you from another thread having done an update unless you also verify the amount is still the same as what you thought it would be. If it's not, then your update will not happen and you can start the command over or return an error rather than possibly messing up the player's info.
My PBBG development blog is at http://MadGamesLab.com

Offline leZourite

  • Level 12
  • *
  • Posts: 81
  • Reputation: +2/-0
    • View Profile
    • After doomsday
Re: Preventing loop holes (dupes) ?
« Reply #8 on: May 16, 2008, 07:40:08 AM »
Well your example is good, but to prevent this easily (though under heavily load transactions may be better).

Is one to check that you can do the operation before, and after submitting the check. Also, do the operation itself by checking you have enough money.

"UPDATE PLAYER SET money = money - 100 WHERE playerid=$playerid AND money > 100";

<= checking then that the request sends a number of rows (at least 1) if it failed abort operation, else then proceed (ie add whatever should be added to the player inventory or something).

What i usually do is a combination of both :

check for money : if there is money make the button available.
then check the money again after the post and just before updating the db.
update the db and check that the operation was successful.
if not abort the operations (not enough money or whatever message needed).
if yes proceed to the next step.

These problems will arise more, say you have a PvP type game (like mine), and there is a part where you can "bust out" of jail other players, it usually happens when this function is badly coded and  players receive up to X events saying that X people busted them at the same time.

It can be avoided by checking at the query level (when updating the db) that the person is indeed in jail. My DB class allows me to know when a query failed or not (as IN if there is an update successful, it returns the number of rows affected) if the number of rows is 0 then it means the person was already out of jail and the process is stopped.

What makes a game bug free, is testing of course but it's the way the application is built as well, the more there are checks the better it is.

Offline Chris

  • Game Owner
  • Level 35
  • *
  • Posts: 2,217
  • Reputation: +28/-1
    • View Profile
Re: Preventing loop holes (dupes) ?
« Reply #9 on: May 16, 2008, 09:07:34 AM »
To be honest, I cheat when it comes to money :) There are many players online attacking each other to steal money (that's the main activity in my game), and buying stuff at the some time. So, when a player attacks at the some time when the target spends money, it might result in negative gold. So... instead of testing money availability and displaying "not enough gold" notice I changed the money field to UNSIGNED :) Dirty trick, but works perfectly, if this was a real money application I would go bankrupt, but since it is virtual I do not mind that the concurrency loses are covered by "the bank" :D

 


SimplePortal 2.3.3 © 2008-2010, SimplePortal