rsync认证协议分析及python类的实现

admin 2016年8月1日14:48:08评论227 views字数 3000阅读10分0秒阅读模式

rsync认证协议分析及python类的实现

好久没发帖子,最近看到有坛友用python写了个口令扫描工具(https://www.t00ls.net/articles-28731.html),效果不错,同时作者提到了关于python对rsync认证支持的问题。于是上PyPi找了一下,跟rsync有关的库要么是用python实现rsync的文件对比算法,要么是直接调用rsync命令来执行一些任务的,有关rsync认证协议的还真是没找到。所以打算把rsync认证部分的源码过一遍,结果rsync的作者已经在源码里把rsync的其中一种认证协议单独用文档进行了说明,参照他的说明再稍微分析一下代码就可以用python实现对rsync登录认证的破解了。下面是大致过程:

0x01.认证方式
    按照网上各种文章的说明,rsync认证主要有两种方式:ssh和rsync,ssh方式使用的就是系统ssh的账户,只要rsync服务器开启了ssh服务,并且ssh破解成功,就能用这种方式进行文件同步,所以这种认证方式跟ssh认证没有区别。
    这里主要对另外一种方式进行分析:rsync方式,这种方式需要先在服务器上进行配置,然后开启一个守护进程,服务器默认监听873端口。
    配置文件里包括了3个跟认证有关的关键参数:
        a)模块名称:rsync可以在一个配置文件里设置多个模块,每个模块可以对应不同的文件目录,并授权给不同的用户,同一个配置文件里,模块名称是唯一的。
        b)ip白名单:每个模块可以指定一个ip白名单,只有白名单内的ip才能访问该模块。
        c)用户名和密码:rsync进行用户身份认证时候使用的账户。
    认证时,仅当客户端提供的模块名称有效,并且该模块已对当前用户授权时,才能通过认证。

0x02.rsync认证过程
    根据作者的说明文档,结合源码分析与本地测试,对其认证步骤进行说明:

a)client -> server:873 (客户端连接服务器873端口)
b)client <- server:873 {content:"@RSYNCD: 30.0n"} //客户端收到服务器的回应,30.0表示服务器上当前rsync协议的版本号
c)client -> server:873 {content:"@RSYNCD: 30.0n"} //客户端发送自己的rsync协议版本号,使用与服务器相同的字符串即可。
d)client -> server:873 {content:"wwwn"}           //客户端发送模块名称
    d1)client <- server:873 {content:"@ERROR: Unknown module 'wwwn'"}  //如果模块名称不存在,服务器直接返回错误,并断开连接
    d2)client <- server:873 {content:"@RSYNCD: AUTHREQD eIulXgZlbB+CaXEb6MiDbQn"} //如果模块名称有效,服务器返回一串随机生成的base64字符串,称为challenge
e)client -> server:873 {content:"root gvT9xrkJTqsnxmSJ6SCe5An"}  //客户端使用函数F(challenge,password)产生response,将其与用户名一起发送到服务器
    e1)client <- server:873 {content:"@ERROR: auth failed on module www"} //如果认证失败,客户端会收到错误信息
    e2)client <- server:873 {content:"@RSYNCD: OKn"} //如果认证通过,客户端会收到OK的提示


0x03.函数F(challenge,password)的算法分析:
    分析源码后发现,不同版本的程序在生成hash值时,有一定的区别,对于版本号>=30的程序使用的是一种方式,版本号<30的程序使用的是另一种。为了向下兼容,客户端和服务器在认证前会进行协商,并以最低的版本号为准。考虑到有不少linux主机还是2.6的内核,自带的rsync都是26甚至更低的版本,有必要把所有版本的认证过程都分析一遍。原则上只需要将27以下版本的认证算法实现即可,但是为了避免兼容性问题,这里把不同版本的认证算法都实现了。实际认证时,客户端直接使用与服务器相同的版本号。

if 版本号>=30:
    md5=hashlib.md5()
    md5.update(password)
    md5.update(challenge)
    response = base64.b64encode(md5.digest())
elif 版本号<30:
    md4=hashlib.new('md4')
    tmp =  '' + password + challenge
    md4.update(tmp)
    response = base64.b64encode(md4.digest())
result, number = re.subn(r'=+$','',response)
return result

    另外一个需要注意的地方是,rsync源码里产生的base64不需要在结尾添加=补齐,而python会自动为base64编码添加=,所以这里还要把response末尾的=去掉。

0x04.用python实现登录认证
    剩下的过程就比较简单了,用python建立socket连接,然后根据上面的逻辑进行处理即可。这里写了个rsync_client的模块,可以直接进行调用。在认证的时候,用户可能不知道服务器上有哪些模块,客户端在连接服务器,并发送自己的协议版本号之后,直接发送一个0x0a,获取服务器上的模块列表。下面是使用方法:

import rsync_client
r = rsync_client.rsync('127.0.0.1')
res = r.getModules()
modules = []
for line in res.split('n'):
    modulename = line[:line.find(' ')]
    modules.append(modulename)
print 'modules:',modules

r = rsync_client.rsync('127.0.0.1')  //由于协议的原因,执行了getModules之后服务器会断开连接,需要重新建立
res = r.login('www', 'root', 'toor') //每次一次连接只能完成一次认证,如果认证失败,需要重建连接
print res
if res.find('OK'):
    r.close() //如果认证成功,需要手动关闭连接,否则连接会持续到超时

    本来想仿照python的ftplib写个rsynclib的,但是精力实在有限,而且需求不是很明显,所以就不造这个轮子了。

代码请访问:https://www.t00ls.net/thread-29003-1-1.html

参考文献:
1.《关于 rsync 中: 和 :: 及 rysnc 和 ssh 认证协议的区别》,http://my.oschina.net/leejun2005/blog/75007
2.rsync源码及相关文档

rsync认证协议分析及python类的实现

本文始发于微信公众号(T00ls):rsync认证协议分析及python类的实现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2016年8月1日14:48:08
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   rsync认证协议分析及python类的实现https://cn-sec.com/archives/351569.html

发表评论

匿名网友 填写信息