PHP Race Condition Vulnerability Example
This article based-on the excellent article "Practical Race Condition Vulnerabilities in Web Applications". I have made my own sample source-code for testing.
================
# Let's start!
Log-into MySQL(or MariaDB) Shell to create sample database
We'll test with User-1's account.
Source code for testing
==================
# First test-case: Withdrawing money 128 times sequentially, $100 each time.
Run something
Check User-1's balance in DB. The balance will (probably) equal 20000 - 128*100 = $7200 by logical calculate.
It's OK, nothing wrong here.
Return User-1's balance to $20000 for the next test-case
==================
# Next test-case: Withdrawing money 128 times with 128 concurrent process, $100 each process.
Check User-1's balance in DB. The balance will (probably) equal 20000 - 128*100 = $7200 by logical calculate. But wait, something not logical here... User-1's balance now is $8100
Race condition vulnerability here => Hackers (User-1 in our example) stole 8100 - 7200 = $900 from his bank.
Enjoy hacking!
================
# Let's start!
Log-into MySQL(or MariaDB) Shell to create sample database
MariaDB [test]> create database test character set utf8 collate utf8_general_ci; MariaDB [test]> grant all privileges on test.* to test@'localhost' identified by 'test@123'; MariaDB [test]> flush privileges; MariaDB [test]> create table bank_accounts(uid int auto_increment primary key,ucode varchar(10) not null,balance int(11) not null default 0,uname varchar(50) not null); MariaDB [test]> insert into bank_accounts(ucode,uname,balance) values ('BANK000001','User 1',20000),('BANK000002','User 2',5500),('BANK000003','User 3',8700);
We'll test with User-1's account.
MariaDB [test]> select * from bank_accounts; +-----+------------+---------+--------+ | uid | ucode | balance | uname | +-----+------------+---------+--------+ | 1 | BANK000001 | 20000 | User 1 | | 2 | BANK000002 | 5500 | User 2 | | 3 | BANK000003 | 8700 | User 3 | +-----+------------+---------+--------+ 3 rows in set (0.00 sec)
Source code for testing
$ git clone https://github.com/doantranhoang/php-race-condition-example.git $ cd php-race-condition-example
- poc.php: move into your web-server directory.
- withdraw_normal.py: Code for the first test-case.
- withdraw_race.py: Code for the second test-case with race condition vulnerability.
==================
# First test-case: Withdrawing money 128 times sequentially, $100 each time.
Run something
$ python withdraw_normal.py Your balance before withdraw $100 is $20000 Your balance after withdraw $100 is $19900 Your balance before withdraw $100 is $19900 Your balance after withdraw $100 is $19800 ... ... ... ... Your balance before withdraw $100 is $7500 Your balance after withdraw $100 is $7400 Your balance before withdraw $100 is $7400 Your balance after withdraw $100 is $7300 Your balance before withdraw $100 is $7300 Your balance after withdraw $100 is $7200
Check User-1's balance in DB. The balance will (probably) equal 20000 - 128*100 = $7200 by logical calculate.
MariaDB [test]> select * from bank_accounts;
+-----+------------+---------+--------+
| uid | ucode | balance | uname |
+-----+------------+---------+--------+
| 1 | BANK000001 | 7200 | User 1 |
| 2 | BANK000002 | 5500 | User 2 |
| 3 | BANK000003 | 8700 | User 3 |
+-----+------------+---------+--------+
3 rows in set (0.00 sec)
It's OK, nothing wrong here.
Return User-1's balance to $20000 for the next test-case
MariaDB [test]> update bank_accounts set balance = 20000 where uid = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [test]> select * from bank_accounts;
+-----+------------+---------+--------+
| uid | ucode | balance | uname |
+-----+------------+---------+--------+
| 1 | BANK000001 | 20000 | User 1 |
| 2 | BANK000002 | 5500 | User 2 |
| 3 | BANK000003 | 8700 | User 3 |
+-----+------------+---------+--------+
3 rows in set (0.00 sec)
==================
# Next test-case: Withdrawing money 128 times with 128 concurrent process, $100 each process.
$ python withdraw_race.py Your balance after withdraw $100 is $10500 Your balance before withdraw $100 is $10700 Your balance after withdraw $100 is $10500 Your balance before withdraw $100 is $10700 ... ... ... Your balance after withdraw $100 is $8200 Your balance before withdraw $100 is $8300 Your balance after withdraw $100 is $8100 Your balance before withdraw $100 is $8200 Your balance after withdraw $100 is $8100
Check User-1's balance in DB. The balance will (probably) equal 20000 - 128*100 = $7200 by logical calculate. But wait, something not logical here... User-1's balance now is $8100
MariaDB [test]> select * from bank_accounts;
+-----+------------+---------+--------+
| uid | ucode | balance | uname |
+-----+------------+---------+--------+
| 1 | BANK000001 | 8100 | User 1 |
| 2 | BANK000002 | 5500 | User 2 |
| 3 | BANK000003 | 8700 | User 3 |
+-----+------------+---------+--------+
3 rows in set (0.00 sec)
Race condition vulnerability here => Hackers (User-1 in our example) stole 8100 - 7200 = $900 from his bank.
Enjoy hacking!
Nhận xét
Đăng nhận xét