一、基础认证
二、基础认证钓鱼
三、curl登录路由器
四、实时获取路由器流量统计信息
一、基础认证
基础认证是是除了cookie以外的另一种验证客户身份的方法。进行基础认证时,一般页面会弹出一个框来让用户输入用户名和口令,用户输入后不会通过POST数据的形式发送给服务器,而是将(”用户名”+“:”+“密码”)三者组成的字符串进行base64编码后,放入Authorization头中传给服务器。如下面发送给路由器的HTTP头信息:
GET / HTTP/1.1
Host: 192.168.32.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/0101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Authorization: Basic ZGFzZGFzOmRhc2Rhcw==
Connection: keep-alive
基础认证的过程如下:
1、客户端发送普通请求给服务器。
2、由于发送的请求头中不存在Authorization字段,服务器返回401 Unauthorized状态给客户端,这样客户端就会弹出登陆框让用户输入用户名和口令。其中返回响应头中的WWW-Authenticate字段的信息会作为弹窗的提示显示在弹窗上。
3、用户在弹框中输入用户名和密码后,客户端会将 ”用户名:密码“进行base64编码然后放入请求头的Authorization字段中发送给服务端。
GET / HTTP/1.1
Host: 192.168.32.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/0101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Authorization: Basic ZGFzZGFzOmRhc2Rhcw==
Connection: keep-alive
4、服务端收到请求后,从请求头中的Authorization字段提取其用户名与口令(进行base64解码),提取后进行验证,如果验证通过,则返回客户端其请求的资源;如果验证没有通过,则返回401状态让客户端继续输入用户名。
ps:由于HTTP协议是无状态的,因此客户端对服务器的每个请求都要进行基础认证。通过浏览器访问时不用每个页面都输入用户名和口令是因为炎症通过后,浏览器会自动对其后的每个请求添加Authentication头。
二、基础认证钓鱼
基础认证钓鱼就是让受害者访问一个页面,服务器返回401,即header(‘WWW-Authenticate: Basic realm=”My Realm”‘);header(‘HTTP/1.0 401 Unauthorized’);,这样客户端就会弹框。受害者输入用户名和口令后,服务端就可以通过$_SERVER[‘PHP_AUTH_USER’]和$_SERVER[‘PHP_AUTH_PW’]来提取受害者输入的用户名和口令。这样就达到了通过基础认证进行钓鱼的目的了。
详情参考:/?p=672
三、curl登陆路由器
路由器的登陆一般都是通过基础认证的方式来进行的,即访问路由器地址会弹出登陆框来让用户输入用户名和口令。因此,要想自动登陆路由器,一般的做法就是在程序中在请求头中加上Authentication字段来进行认证。
curl可以通过CURLOPT_HTTPHEADER来设置请求头,因此,本来想通过curl直接加Authentication来自动登陆的,但不知是curl实现的原因还是怎么了一直验证不成功,最后查阅资料通过以下方法来自动登陆路由器:
curl_setopt($ch,CURLOPT_HTTPAUTH,CURLAUTH_BASIC);
curl_setopt($ch,CURLOPT_USERPWD,”{$username}:{$password}”);
这样的话就会更简单了,不用自己进行base64编码了。通过将CURLOPT_HTTPAUTH赋值为CURLAUTH_BASIC来设置curl进行基础认证,然后将CURLOPT_USERPWD赋值为用户名:口令即可。详细代码如下:
$username="xxx";
$password="xxx";
$ch=curl_init();
//curl_setopt($ch,CURLOPT_URL,"http://192.168.32.1/userRpm/SystemStatisticRpm.htm");
curl_setopt($ch,CURLOPT_URL,"http://192.168.32.1/");
curl_setopt($ch,CURLOPT_TIMEOUT,200);
//curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_HTTPAUTH,CURLAUTH_BASIC);
curl_setopt($ch,CURLOPT_USERPWD,"{$username}:{$password}");
$result=curl_exec($ch);
if($result===FALSE)
{
print curl_error($ch);
}
else
{
$fp=fopen('b.txt','w+');
fwrite($fp,$result);
fclose($fp);
//print $result;
}
curl_close($ch);
三、实时获取路由器流量统计信息
上面代码中自动登陆路由器,其中页面/userRpm/SystemStatisticRpm.htm可以获取到流量统计信息,当然这是不带参数的url所以获取的信息有限。完整的获取流量信息的url是:/userRpm/SystemStatisticRpm.htm?interval=5&sortType=4&autoRefresh=2&Num_per_page=10&Goto_page=2。
参数的具体意义可以参考路由器流量统计界面:
由上图路由器界面可知interval=5&sortType=4&autoRefresh=2&Num_per_page=10&Goto_page=2中interval参数是路由器统计时间间隔,sortType参数是排序的类型,autoRefresh参数是是否自动刷新,Num_per_page参数是每页显示的条数,Goto_page参数是要转到第几页。
知道了各个字段的含义了,现在要考虑的就是如何来通过这些参数来满足我们的需求了。现在麻烦的是如何获取到底有多少条记录?不过如果只是统计流量最高的前10名的话就不用在乎有多少条记录了。
ps:流量统计条数和现在在线主机数不同(因为下线的主机也曾经存在流量信息)。
1、目标:实现对流量最高的前十名信息的获取
2、url:/userRpm/SystemStatisticRpm.htm?interval=5&sortType=5&autoRefresh=2&Num_per_page=10&Goto_page=1
即按照“当前数据字节数排序”。
3、分析获取的页面信息。
可以看到流量信息在返回页面的头部,现在就是想办法通过正则表达式或其他方法提取这些信息。每一条记录的信息如下:0, “192.168.32.138”, “00-0C-29-2A-E3-86”, 40569, 39469724, 16, 15394, 0, 0, 0, 0, 0, 0 依此的含义如下:IP地址、MAC地址、数据包总数、流量总数、当前数据包数、当前流量字节数,剩下就是数据包的一些信息。现在关注的就是IP地址、MAC地址、当前流量字节数这三个信息。
提取信息过程:可以看到所有数据都存在在statList数组中,因此首先截取第一script标签的内容,然后提取()中的内容,然后用,分割成数组,然后从数组中提取信息即可。
(1)去掉无用信息。
$pos1=stripos($result,”Array(“);
$pos2=stripos($result,”);”);
$info=substr($result,$pos1+7,$pos2-$pos1-7);
获取的信息$info信息如下:
(2)使用,分割字符串,并去掉空格、换行字符等。使用explode()函数分割,使用trim()函数去掉空格、换行符等信息。
$arr=explode(‘,’,$info);
print count($arr);
foreach($arr as $item)
{
print trim($item);
}
获取的信息如下:
可以看到已经成功的获取到了每一项信息。不过注意到总的项数是10*13+2=132项,即每一条有13项还多出两项,最后这两项就不管他了。因此:IP地址对应的项是13*(i-1)+1,MAC地址对应的项是13*(i-1)+2,当前流量字节数是13*(i-1)+6,总流量是13*(i-1)+4。其中i是从0到intval(count($arr)/13)-1.
因此代码是:
for($i=0;$i
{
//打印每一项
$j=$i+1;
print “第{$j}条记录是:”;
print “IP地址是:”.trim(trim($arr[13*$i+1]),'”‘);
print ” MAC:”.trim(trim($arr[13*$i+2]),'”‘);
print ” 当前网速:”.(intval((trim($arr[13*$i+6]))/8)/1024).”KB/s”;
print ” 消耗总流量”.(intval((trim($arr[13*$i+4]))/8)/1024).”KB”;
}
效果如下:
(3)可以看到上面已经基本满足了要求了,但是还不美观,因为网速的那地方小数点太多了,还有消耗的总流量最好能够转换成相应的M/G。要限制浮点数的小数位可以使用number_format()函数(可以参考/topics/10346624)。
代码:
function getData($a)
{
$i=0;
$a=$a/8; //转换成Byte
while($a>1024 &&$i<3) //到了G就不再转换了
{
$a=$a/1024;
$i++;
}
switch($i)
{
case 0:
$unit=”B”;
break;
case 1:
$unit=”KB”;
break;
case 2:
$unit=”MB”;
break;
default:
$unit=”GB”;
}
$ret=number_format($a,2).$unit;
return $ret;
}
for($i=0;$i
{
//打印每一项
$j=$i+1;
print “第{$j}条记录是:”;
print “IP地址是:”.trim(trim($arr[13*$i+1]),'”‘);
print ” MAC:”.trim(trim($arr[13*$i+2]),'”‘);
print ” 当前网速:”.getData(trim($arr[13*$i+6])).”/s”;
print ” 消耗总流量”.getData(trim($arr[13*$i+4]));
}
效果如下:
(4)上面看起来已经不错了,但是要实现实时获取只有通过js中的setInterval()和ajax来实现。要想通过ajax来实现,需要本页面返回列表或JSON形式的数据。在php中可以将数组通过json_encode()函数转换成为json格式,代码如下:
$result=array();
for($i=0;$i
{
//将每一项放到数组中
$ip=trim(trim($arr[13*$i+1]),'””‘);
$mac=trim(trim($arr[13*$i+2]),'”‘);
$speed=number_format(trim($arr[13*$i+6])/8/1024,2).”KB/s”;
$data=number_format(trim($arr[13*$i+4])/8/1024/1024,2).”MB”;
$a=array(“IP”=>$ip,”MAC”=>$mac,”Speed”=>$speed,”Data”=>$data);
$result[$i]=$a;
}
print json_encode($result);
(5)现在可以在js中通过ajax调用了
代码如下:
效果图: