免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7568 | 回复: 3
打印 上一主题 下一主题

Perl实现花生壳DDNS客户端[2010/12/01更新] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-30 10:48 |只看该作者 |倒序浏览
本帖最后由 coolend 于 2010-12-01 20:01 编辑

花生壳相比大家都知道吧,在国内的用户群非常广泛,其协议已经公开了(似乎有段时间了)

相关协议说明可以参考:http://open.oray.com/wiki/doku.p ... 1%E9%83%A8%E5%88%86

有位 “笑行天下” 的仁兄已经开发出C写的客户端,其博客地址为 http://blog.a1983.com.cn/?page_id=483

源代码下载地址:http://blog.a1983.com.cn/software/ddns-r257-src.tar.gz

闲着没事,想研究下用Perl来实现,呵呵~~ 能力有限,对C不懂哦,所以先抛个砖,希望感兴趣的兄弟指点指点或一起来参与

验证过程如下:

客户机发出AUTH authtype指令,authtype为一种验证类型,我们这里使用AUTH ROUTER6(CRAM-MD5扩展)验证。
服务器回应一个挑战串,该串使用客户机的IP地址、服务器的当前时间等不可重复不可预测的参数生成,服务器使用BASE64方式将该串返回客户机,回应码为334

客户机将挑战串作为key使用CRAM-MD5的单向加密方式加密自己的密码形成加密串,
将账号和加密串作为回应,其格式为:

账号名+一个空格+加密嵌入认证码+客户端信息+加密串

其中,加密嵌入认证码共4个字节,为嵌入认证码与服务器当前时间运算得到,服务
器时间是挑战串的第六字节后的4个字节,算法是嵌入认证码与该时间的取反进行或
运算后循环右移一定位数;该右移位数是用服务器时间整除30;
客户端信息也是4个字节,前两位为嵌入式的客户号,后两位为客户端版本号;
客户机使用base64方式对回应进行编码返回服务器。
  1. #!/usr/bin/perl

  2. use strict;
  3. use IO::Socket::INET;
  4. use MIME::Base64 qw(encode_base64 decode_base64);
  5. use Digest::HMAC_MD5 qw(hmac_md5);

  6. my $serverip = "ph051.oray.net";
  7. my $port = '6060';

  8. ###  登录用户名和密码
  9. my $user = 'songgongzi';
  10. my $pass =  'QrhxS25V';

  11. my $sock = IO::Socket::INET->new(
  12.     PeerAddr => $serverip,
  13.     PeerPort => $port,
  14.     Proto    => 'tcp',
  15. ) or die "ERR: unable to connect to server $! \n";

  16. my $msg;
  17. $sock->recv($msg,128);
  18. die "ERR: server not response ! \n" if (! $msg);
  19. print $msg;

  20. ## 发送验证请求
  21. print $sock "auth router6\n";
  22. $sock->recv($msg,128);
  23. print $msg;

  24. ## BASE64 解码
  25. $msg =~ s/^\d+\s+//;
  26. my $reply = decode_base64($msg);

  27. print "Reply message content is: ",unpack("H*",$reply),"\n";

  28. ## 服务器时间是挑战串的第六字节后的4个字节
  29. my $stime = substr($reply,6,4);
  30. my $tm_stime = unpack("H*",$stime);
  31. $tm_stime =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$4$3$2$1/;
  32. $tm_stime = hex($tm_stime);

  33. ## 打印下服务器的时间,便于调试
  34. print "Server time is $tm_stime, ",&timenow($tm_stime),"\n";

  35. ### 以下信息从 “笑行天下” 的 DDNS代码中借用的
  36. my $client_ID = "0x26A0";   # 客户端ID
  37. my $client_VER = "0x9899"; # 客户端版本
  38. my $auth_KEY = "0x1E0808B7"; # 嵌入认证密码

  39. ### 客户端信息为客户端ID+版本号,共4字节
  40. my $client_info = ((hex($client_ID) & 0xFFFF) << 16) | (hex($client_VER) & 0xFFFF);

  41. ## 转换为16进制
  42. $client_info = sprintf ("%x",$client_info);
  43. $client_info =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$4$3$2$1/;

  44. print "Client INFO: $client_info\n";

  45. my $auth_key = hex($auth_KEY);

  46. ## 嵌入认证码与时间的取反进行或运算后循环右移
  47. $tm_stime = $tm_stime | (~$auth_key);
  48. print "DBG1: $tm_stime\n";

  49. ### 右移位数是用服务器时间整除30后的余数
  50. my $mv = $tm_stime % 30;
  51. print "Move count is $mv\n";

  52. ### 加密嵌入认证码
  53. my $auth_enc  = $tm_stime << ((32 - $mv) & 0x0000001F);
  54. $auth_enc   |= ($tm_stime) >> ($mv & 0x0000001F);
  55. $auth_enc = sprintf ("%x",$auth_enc);
  56. $auth_enc =~ s/^(\w{2})(\w{2})(\w{2})(\w{2})$/$2$1$4$3/;

  57. print "AUTH_ENC: $auth_enc\n";

  58. ## 加密串
  59. my $enc_str = unpack("H*",hmac_md5($pass, $reply));
  60. print "ENC STR: $enc_str\n";

  61. my $header = pack("H*","$auth_enc$client_info$enc_str");
  62. print "HEADER: " . unpack("H*",$header) , " LEN: " , length($header),"\n";

  63. ## 生成回应串用BASE64编码
  64. my $lines = join('',$user,' ',$header);
  65. my $base64 = encode_base64 $lines;
  66. print "Send BASE64: $base64\n";

  67. ### 发送给服务端
  68. print $sock "$base64\n";
  69. $sock->recv($msg,128);
  70. print $msg;

  71. ### 注册域名
  72. print $sock "regi a songgongzi.gicp.net\n";
  73. $sock->recv($msg,128);
  74. print $msg;

  75. ## 退出
  76. print $sock "quit\n";

  77. $sock->shutdown(1);
  78. $sock->close();

  79. sub timenow {
  80.     my $tm = time();
  81.     my ($sec,$min,$hur,$day,$mon,$year) = (localtime($tm))[0,1,2,3,4,5];
  82.     $year += 1900; ++ $mon ;

  83.     $mon  = "0$mon" if (length($mon) < 2);
  84.     $day  = "0$day" if (length($day) < 2);
  85.     $hur  = "0$hur" if (length($hur) < 2);
  86.     $min  = "0$min" if (length($min) < 2);
  87.     $sec  = "0$sec" if (length($sec) < 2);

  88.     return "$year-$mon-$day $hur:$min:$sec";
  89. }
复制代码
运行时,有时候可以成功,有时候验证失败,经反复测试,发现是加密嵌入认证码计算的问题,还有待进一步研究。

** 2010/12/01日更新

失败时的输出信息:
220 oray.cn DDNS ServerX6 Ready.
334 O6/XGgm6Kpn1TCvpouKvog==
Reply message content is: 3bafd71a09ba2a99f54c2be9a2e2afa2
Server time is 1291163946, 2010-12-01 08:41:12
Client INFO: 9998a026
DBG1: 3992452970
Move count is 20
AUTH_ENC: f67fdfae
ENC STR: ce08450f2eac389b3e7207acc9d852b3
HEADER: f67fdfae9998a026ce08450f2eac389b3e7207acc9d852b3 LEN: 24
Send BASE64: c29uZ2dvbmd6aSD2f9+umZigJs4IRQ8urDibPnIHrMnYUrM=

535 Authentication failure
500 Command unrecognized

成功时的输出信息:
220 oray.cn DDNS ServerX6 Ready.
334 O64u4vKL7Dj2TP8NEF1ZwQ==
Reply message content is: 3bae2ee2f28bec38f64cff0d105d59c1
Server time is 1291204844, 2010-12-01 20:02:05
Client INFO: 9998a026
DBG1: 3992453100
Move count is 0
AUTH_ENC: f7edecff
ENC STR: f1caf2faa67d45a46de09ed330567568
HEADER: f7edecff9998a026f1caf2faa67d45a46de09ed330567568 LEN: 24
Send BASE64: c29uZ2dvbmd6aSD37ez/mZigJvHK8vqmfUWkbeCe0zBWdWg=

250 Auth passed at level <0>
songgongzi.gicp.net
.
250 Register successfully

原来昨天晚上调试到后来花生壳的服务连接不上,是因为遭到了攻击,汗!树大招风阿
http://www.oray.com/news/420.html

论坛徽章:
0
2 [报告]
发表于 2010-11-30 12:04 |只看该作者
这个协议跟SMTP协议很像,可以拿Net::SMTP改。UI可以用Win32::GUI Tk Gtk2

论坛徽章:
0
3 [报告]
发表于 2010-11-30 13:07 |只看该作者
这个协议跟SMTP协议很像,可以拿Net::SMTP改。UI可以用Win32::GUI Tk Gtk2
黑色阳光_cu 发表于 2010-11-30 12:04


改成一个POE组件也很好的说

论坛徽章:
0
4 [报告]
发表于 2010-11-30 21:24 |只看该作者
貌似最近免费版的花生壳服务最近不大稳定,一会儿连得上,一会儿又连不了,甚至连 open.oray.net 也打不开了

请版主,大伙帮忙分析分析,看看问题出在哪, Perl 的左移右移和C似乎有点不一样,上述移位的代码是参考C里面的,但有时候可以通过验证,这就奇怪了

谢谢各位啦~~~ 
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP