Last active
August 7, 2025 22:48
-
-
Save divinity76/544d7cadd3e88e057ea3504cb8b3bf7e to your computer and use it in GitHub Desktop.
login to gmail.com with curl, pretending to be a browser.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types = 1); | |
| // header ( "content-type: text/plain;charset=utf8" ); | |
| // https://github.com/divinity76/hhb_.inc.php/blob/master/hhb_.inc.php | |
| require_once ('hhb_.inc.php'); | |
| function loginGmail(string $username, string $password, string $recoveryEmailChallengeAnswer) : \hhb_curl | |
| { | |
| $hc = new hhb_curl('', true); | |
| $hc->setopt_array(array( | |
| CURLOPT_TIMEOUT => 20, // i just have a shitty connection :( | |
| CURLOPT_CONNECTTIMEOUT => 10 | |
| )); | |
| if (0) { | |
| $hc->setopt_array(array( | |
| CURLOPT_USERAGENT => 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1' | |
| )); | |
| } | |
| $html = $hc->exec('https://accounts.google.com/signin')->getStdOut(); | |
| //hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die(); | |
| $domd = @DOMDocument::loadHTML($html); | |
| $inputs = getDOMDocumentFormInputs($domd, true, false)['gaia_loginform']; | |
| //hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die(); | |
| $loginUrl = $domd->getElementById("gaia_loginform")->getAttribute("action"); | |
| $inputs['Email'] = $username; | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_POST => 1, | |
| CURLOPT_POSTFIELDS => http_build_query($inputs), | |
| CURLOPT_URL => $loginUrl | |
| ))->exec()->getStdOut(); | |
| //hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die(); | |
| // without this next GET, login will block you for "not running javascript".. luckily v seems to only be a random number. | |
| $hc->setopt_array(array( | |
| CURLOPT_HTTPGET => 1, | |
| CURLOPT_URL => 'https://accounts.youtube.com/accounts/CheckConnection?pmpo=https%3A%2F%2Faccounts.google.com&' . http_build_query( | |
| array( | |
| 'v' => rand(),// ??? | |
| 'timestamp' => ((int)(microtime(true) * 1000)), | |
| ) | |
| ), | |
| ))->exec(); | |
| //hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die(); | |
| $domd = @DOMDocument::loadHTML($html); | |
| $inputs = getDOMDocumentFormInputs($domd, true, false)['gaia_loginform']; | |
| // hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ); | |
| $loginUrl = $domd->getElementById("gaia_loginform")->getAttribute("action"); | |
| $inputs['Passwd'] = $password; | |
| { | |
| // a couple of missing ones added by javascript... | |
| $inputs['continue'] = 'https://accounts.google.com/ManageAccount'; | |
| $inputs['checkedDomains'] = 'youtube'; | |
| $inputs['checkConnection'] = 'youtube:356:1'; | |
| $inputs['rip'] = 1; | |
| $inputs['pstMsg'] = 1; | |
| $inputs['rmShown'] = 1; | |
| $inputs['bgresponse'] = 'my_massive_dong';//bgresponse MUST exist, MUST have content, and the content CAN NOT include the phrase "js_disabled" | |
| } | |
| try { | |
| $starttime = microtime(true); | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_POST => 1, | |
| CURLOPT_POSTFIELDS => http_build_query($inputs), | |
| CURLOPT_URL => $loginUrl | |
| ))->exec()->getStdOut(); | |
| //hhb_var_dump($hc->getStdErr(), $hc->getStdOut(), $inputs) & die(); | |
| } | |
| finally { | |
| // hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs, (microtime ( true ) - $starttime) ) & die (); | |
| } | |
| $loginErrorText = ''; | |
| $domd = @DOMDocument::loadHTML($html); | |
| $xp = new DOMXPath($domd); | |
| $refresh = $xp->query("//meta[@http-equiv='refresh']"); | |
| if (!$refresh->length) { | |
| hhb_var_dump($hc->getStdErr(), $hc->getStdOut(), $inputs);; | |
| throw new \RuntimeException("login failed - google did not try to redirect us after sending password!"); | |
| } | |
| $refresh = $refresh->item(0); | |
| $content = $refresh->getAttribute("content"); | |
| if (false === stripos($content, 'accounts.google.com/ManageAccount')) { | |
| throw new \RuntimeException("login failed - google did not try to redirect us to account management page after sending password!"); | |
| } | |
| $nextUrl; | |
| if (!preg_match('/(https\:\/\/[^\;]+)/', $content, $nextUrl)) { | |
| throw new \LogicException("wtf??? should never happen"); | |
| } | |
| //hhb_var_dump($nextUrl) & die(); | |
| $nextUrl = $nextUrl[1]; | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_URL => $nextUrl, | |
| CURLOPT_HTTPGET => 1, | |
| ))->exec()->getStdOut(); | |
| // TODO: some way to verify that we're actually logged in now. | |
| //hhb_var_dump($hc->getStdErr(), $hc->getStdOut(), $inputs, (microtime(true) - $starttime)) & die(); | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_URL => 'https://gmail.com', | |
| CURLOPT_HTTPGET => 1, | |
| ))->exec()->getStdOut(); | |
| //hhb_var_dump($hc->getStdErr(), $hc->getStdOut(), $inputs, (microtime(true) - $starttime)) & die(); | |
| $domd = @DOMDocument::loadHTML($html); | |
| $xp = new DOMXPath($domd); | |
| $authChallenge = $domd->getElementById("challengePickerList"); | |
| if (null !== $authChallenge) { | |
| // gotdammit... got an auth challenge page, asking you to choose a challenge | |
| $loginErrorText .= ' - got an auth challenge page, asking you to choose a challenge: ' . trim($authChallenge->textContent); | |
| // TODO: automatically select "provide recovery email" here instead of throwing a login error exception. | |
| } else { | |
| if (false !== stripos($html, 'Enter recovery email') && null !== ($authChallenge = $domd->getElementById("challenge"))) { | |
| // got an auth challenge for providing recovery email.. | |
| // luckily, we can automatically recover from this. | |
| $inputs = getDOMDocumentFormInputs($domd, true, false)['challenge']; | |
| assert(array_key_exists('email', $inputs)); | |
| $inputs['email'] = $recoveryEmailChallengeAnswer; | |
| $url = $authChallenge->getAttribute("action"); | |
| if (!parse_url($url, PHP_URL_HOST)) { | |
| $url = 'https://' . parse_url($hc->getinfo(CURLINFO_EFFECTIVE_URL), PHP_URL_HOST) . $url; | |
| } | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_POST => 1, | |
| CURLOPT_POSTFIELDS => http_build_query($inputs), | |
| CURLOPT_URL => $url | |
| ))->exec()->getStdOut(); | |
| $domd = @DOMDocument::loadHTML($html); | |
| $xp = new DOMXPath($domd); | |
| // TODO: detect incorrect recovery email supplied error here. | |
| } | |
| } | |
| unset($authChallenge); | |
| if (!empty($loginErrorText)) { | |
| throw new \RuntimeException('errors loggin in: ' . $loginErrorText); | |
| } else { | |
| // logged in! :D | |
| } | |
| // now we need to enable HTML view, it's a <form> POST request, but we can't use getDOMDocumentFormInputs (bug?) | |
| if (0) { | |
| foreach ($xp->query("//form") as $form) { | |
| hhb_var_dump($domd->saveHTML($form)); | |
| } | |
| die(); | |
| } | |
| $res = $xp->query('//form[@id="null" and contains(@action,"zy=d")]'); | |
| if ($res->length !== 1) { | |
| $str = 'failed to find HTML version request form!'; | |
| hhb_var_dump($str, $hc->getStdErr(), $hc->getStdOut(), $inputs); // & die (); | |
| throw new \RuntimeException($str); | |
| } | |
| $form = $res->item(0); | |
| $url = $form->getAttribute("action"); | |
| if (!parse_url($url, PHP_URL_HOST)) { | |
| $url = $hc->getinfo(CURLINFO_EFFECTIVE_URL) . $url; | |
| } | |
| // hhb_var_dump ( $url ) & die (); | |
| $inputs = []; | |
| foreach ($form->getElementsByTagName("input") as $input) { | |
| $name = $input->getAttribute("name"); | |
| if (empty($name)) { | |
| continue; | |
| } | |
| $inputs[$name] = $input->getAttribute("value"); | |
| } | |
| //hhb_var_dump($inputs) & die(); | |
| $html = $hc->setopt_array(array( | |
| CURLOPT_POST => 1, | |
| CURLOPT_POSTFIELDS => http_build_query($inputs), | |
| CURLOPT_URL => $url | |
| ))->exec()->getStdOut(); | |
| //hhb_var_dump($hc->getStdErr(), $hc->getStdOut(), $inputs); // & die (); | |
| return $hc; | |
| } | |
| function rightTrim($str, $needle, $caseSensitive = true) { | |
| $strPosFunction = $caseSensitive ? "strpos" : "stripos"; | |
| if ($strPosFunction ( $str, $needle, strlen ( $str ) - strlen ( $needle ) ) !== false) { | |
| $str = substr ( $str, 0, - strlen ( $needle ) ); | |
| } | |
| return $str; | |
| } | |
| function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false, bool $getElements = true): array { | |
| // :DOMNodeList? | |
| if (! $getOnlyFirstMatches && ! $getElements) { | |
| throw new \InvalidArgumentException ( '!$getElements is currently only implemented for $getOnlyFirstMatches (cus im lazy and nobody has written the code yet)' ); | |
| } | |
| $forms = $domd->getElementsByTagName ( 'form' ); | |
| $parsedForms = array (); | |
| $isDescendantOf = function (\DOMNode $decendant, \DOMNode $ele): bool { | |
| $parent = $decendant; | |
| while ( NULL !== ($parent = $parent->parentNode) ) { | |
| if ($parent === $ele) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| }; | |
| // i can't use array_merge on DOMNodeLists :( | |
| $merged = function () use (&$domd): array { | |
| $ret = array (); | |
| foreach ( $domd->getElementsByTagName ( "input" ) as $input ) { | |
| $ret [] = $input; | |
| } | |
| foreach ( $domd->getElementsByTagName ( "textarea" ) as $textarea ) { | |
| $ret [] = $textarea; | |
| } | |
| foreach ( $domd->getElementsByTagName ( "button" ) as $button ) { | |
| $ret [] = $button; | |
| } | |
| return $ret; | |
| }; | |
| $merged = $merged (); | |
| foreach ( $forms as $form ) { | |
| $inputs = function () use (&$domd, &$form, &$isDescendantOf, &$merged): array { | |
| $ret = array (); | |
| foreach ( $merged as $input ) { | |
| // hhb_var_dump ( $input->getAttribute ( "name" ), $input->getAttribute ( "id" ) ); | |
| if ($input->hasAttribute ( "disabled" )) { | |
| // ignore disabled elements? | |
| continue; | |
| } | |
| $name = $input->getAttribute ( "name" ); | |
| if ($name === '') { | |
| // echo "inputs with no name are ignored when submitted by mainstream browsers (presumably because of specs)... follow suite?", PHP_EOL; | |
| continue; | |
| } | |
| if (! $isDescendantOf ( $input, $form ) && $form->getAttribute ( "id" ) !== '' && $input->getAttribute ( "form" ) !== $form->getAttribute ( "id" )) { | |
| // echo "this input does not belong to this form.", PHP_EOL; | |
| continue; | |
| } | |
| if (! array_key_exists ( $name, $ret )) { | |
| $ret [$name] = array ( | |
| $input | |
| ); | |
| } else { | |
| $ret [$name] [] = $input; | |
| } | |
| } | |
| return $ret; | |
| }; | |
| $inputs = $inputs (); // sorry about that, Eclipse gets unstable on IIFE syntax. | |
| $hasName = true; | |
| $name = $form->getAttribute ( "id" ); | |
| if ($name === '') { | |
| $name = $form->getAttribute ( "name" ); | |
| if ($name === '') { | |
| $hasName = false; | |
| } | |
| } | |
| if (! $hasName) { | |
| $parsedForms [] = array ( | |
| $inputs | |
| ); | |
| } else { | |
| if (! array_key_exists ( $name, $parsedForms )) { | |
| $parsedForms [$name] = array ( | |
| $inputs | |
| ); | |
| } else { | |
| $parsedForms [$name] [] = $tmp; | |
| } | |
| } | |
| } | |
| unset ( $form, $tmp, $hasName, $name, $i, $input ); | |
| if ($getOnlyFirstMatches) { | |
| foreach ( $parsedForms as $key => $val ) { | |
| $parsedForms [$key] = $val [0]; | |
| } | |
| unset ( $key, $val ); | |
| foreach ( $parsedForms as $key1 => $val1 ) { | |
| foreach ( $val1 as $key2 => $val2 ) { | |
| $parsedForms [$key1] [$key2] = $val2 [0]; | |
| } | |
| } | |
| } | |
| if ($getElements) { | |
| return $parsedForms; | |
| } | |
| $ret = array (); | |
| foreach ( $parsedForms as $formName => $arr ) { | |
| $ret [$formName] = array (); | |
| foreach ( $arr as $ele ) { | |
| $ret [$formName] [$ele->getAttribute ( "name" )] = $ele->getAttribute ( "value" ); | |
| } | |
| } | |
| return $ret; | |
| } |
not working sir
login failed - google did not try to redirect us after sending password!
Not work
You're trying to log into a browser or app where we can't protect your account.
Use a different browser.
Author
@sutorrinaldi @Nzt2 Google changed the login system again,
i can probably fix it for $50, but since i don't need it myself now, i won't waste time updating it for free.
@sutorrinaldi @Nzt2 Google changed the login system again,
i can probably fix it for $50, but since i don't need it myself now, i won't waste time updating it for free.
can you write me telegram or skype i can pay you if you can fix problem ? cryptr.org@gmail.com
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
not working sir
how to use?
call email | pass