Saturday, April 25, 2009

Srun3000 客户端协议分析

Srun3000的新版终于上线了,之前的内测报了好几个安全漏洞,于是给了一份安全检测报告。结果现在自己想拿都很麻烦了,至少目前还没拿下 XD

然后,说客户端。
目前这个版本的客户端,感觉和上次内测的区别不大,不过至少我提出注册表数据加密之后,srun那边还是做了些工作,虽然那块儿今天没去调。
整体协议还是基于http的,因为还是没有keepalive的设计,所以最关键的就只是登陆的部分。也就是说,登陆的POST串的内容和结构才是我这次最关注的。

直接从客户端的exe文件里就可以提取出这样的字串
username=%s&password=%s&drop=%d&type=2&n=%d&mac=%s
显然,用户名,密码,drop,type=2,n,mac
drop是是否只访问免费资源;type=2是写死的,应该就是表示windows客户端吧,linux的我没看,无所谓;n=7,跟出来的,上个版本是2吧,不记得了,不清楚到底有什么用;mac就不用说了

客户端没有加壳,直接OllyDBG载入
根据字串资源信息,很快地定位到了输入的函数,同时也找到了密码加密函数的入口

我手头这个版本 57,344 字节,加密函数的入口 在 0x00401350。
有许多地方调用了,但是这个不是我关注的,我只需要知道这个算法的内容。

根据push的规则,还原成C的代码,函数声明格式应该是类似
void encrypt(void* pwd_in, void* key,  void* pwd_out);
返回值我不管了,因为没去那边往下跟,无所谓。
中间的几个 void* 具体应该是 unsigned char* 或者 char*,依旧无所谓。

pwd_in 就是密码输入框的内容
key的部分是通过当前系统时间算出来的

关于key的分析可以见我在联盟的帖子
http://www.bitunion.org/redirect.php?goto=findpost&ptid=10141437&pid=8567446
或者
http://kiss.bitunion.org/redirect.php?goto=findpost&ptid=10141437&pid=8567446

稍后考虑也贴过来

算法的部分很简单
两个字符串,一个password,一个key
设password 为 12345678
key为 20678439

逆序循环取key的字符,也就是 9,3,4,8,7,6,0,2,9,3,...
分别与password 的 [0], [1], [2] ... 直到password结束 进行异或运算
对于结果,一个字符

[0],[2],....[2n]的字符,译码之后:(低4位 加上 0x36 )连上 (高4位 加上 0x63)
[1],[3],....[2n+1]的字符,译码之后:(高4位 加上 0x63)连上 (低4位 加上 0x36 )

然后连接之后的结果就是提交的密码的密文
当然,提交的时候,得 实现 urlencode或类似的函数处理这段数据

代码很乱,无所谓了
能改描述清楚问题,并且实现功能就行

Sample Code in PHP:
<?php
$password = '123456';
echo encrypt($password);

function encrypt($password)
{
 $key = strval(floor((time() + 43084)/60));
 return _encrypt($password, $key);
}

function _encrypt($pass, $key)
{
 $pass = substr($pass, 0, 16);
 $len = strlen($pass);
 $ret = '';
 for ($i=0; $i<$len; $i++)
 {
  $_pass = ord($pass[$i]);

  $_key  = _get_keychar($key, $i);

  $_key  = $_key ^ $_pass;
  $ret .= _build_key($_key, $i%2);
 }
 return $ret;
}

function _get_keychar($str_in, $num)
{
 $len = strlen($str_in);
 return ord($str_in[ $len - $num % $len - 1 ]);
}

function _build_key($num, $reverse=0)
{
 $ret = '';
 
 $_low = $num & 0x0f;
 
 $_high = $num >> 4;
 $_high = $_high & 0x0f;
 
 if (!$reverse)
 {
  $ret .= chr($_low  + 0x36);
  $ret .= chr($_high + 0x63);
 }
 else
 {
  $ret .= chr($_high + 0x63);
  $ret .= chr($_low  + 0x36);
 }
 return $ret;
}

No comments:

Post a Comment