喜迎X大(涉及到这个数字后台就一直提醒可能违规,干脆)。然后,就是,我胡汉三又回来啦啦啦啦啦!!!身体养得差不多了,其实也没有什么大问题,谢谢大家关心~兄弟姐妹们,造起来啊~high起来啊~反正有大把时光~
谁再熬夜谁傻逼,以此为誓,违誓者发红包。
阅读此文大概需要8分钟,也可能80分钟
最近在公司和我们后端的兄弟聊了聊,他是FOFA 3.0的后端主要开发人员之一。把FOFA的协议识别与提取用Golang实现。 虽然没有他那么牛逼的编码技术,不过也对其架构稍稍了解。小小的学习了协议提取的知识。
下面介绍一些常用的提取方法,笔者所知主要有两种方法: 1、在使用一些客户端工具时候,Wireshark抓包提取发送和返回的数据包 2、直接发送一些指定的(特殊)字符串识别返回的banner头。
后一种方法发送什么字符串可以看看一些文档、手册或者用fuzz。
1F
RDP协议的提取
这里我以RDP协议的提取为例子。
第一步:打开wireshark,输入:ip.addr==ip_address 第二步:打开远程桌面连接
第三步:开始抓包,点击连接 我们看到抓到如下的数据包。
我们找到了发送data的这个数据包
右键追踪tcp流,可以看到如下为返回结果
我们把如下数据包的hex文本提取出来
我对windows 2k、2k3、2008、7、2012均进行测试
我们发送的数据包均为:
x03x00x00x13x0exe0x00x00x00x00x00x01x00x08x00x03x00x00x00
返回的数据包如下:
"2000": "0300000b06d00000123400" "2003": "030000130ed000001234000300080002000000" "2008": "030000130ed000001234000200080002000000" "win7OR2008R2": "030000130ed000001234000209080002000000" "2008R2DC": "030000130ed000001234000201080002000000" "2012R2OR8": "030000130ed00000123400020f080002000000"
我们看到了除了win2000外,其他的响应包的前10位均为030000130e,也就是前面的五个字节。 这边只提取这个五个作为判断。
2F
python脚本实现之最基础的socket连接判断
代码语言:javascript复制import socket
target="101.200.146.54"
port =3389
scan = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scan.settimeout(5)
address = (target, port)
scan.connect(address)
scan.send('x03x00x00x13x0exe0x00x00x00x00x00x01x00x08x00x03x00x00x00')
banner = scan.recv(5)
if banner == 'x03x00x00x13x0e':
print "%s RDP Port is %s!" % (target, port)
3F
加上多线程和指定端口范围
下面的脚本算是五脏比较全了,加了如下功能: 1、端口范围的指定初步实现 2、端口打乱(如果我们指定范围按部就班的去) 2、多线程,用信号量控制线程数 3、加锁控制错误信息的整齐打印 需要注意一点的是ips.txt这个ip地址文本虽然用xreadlines。但是由于不知道用户的输入是否有多余的不可见字符。理应在socket连接之前用strip()过滤"r、n"之类的字符。不然会出现一些异常,
比如:errno 11001 getaddrinfo failed
#!/usr/bin/python
# coding=utf-8
import random
import threading
from socket import *
import socket
print_lock = threading.Lock()
filename="ips.txt"
port_list = []
ports="3380-3390"
n,m =ports.split("-")
for line in range(int(n), int(m) 1):
port_list.append(line)
port_lists = random.sample(port_list, int(m)-int(n))
semaphore = threading.BoundedSemaphore(value=10)
def run(target):
global semaphore
suc = False
for port in port_list:
if suc:
break
scan = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
scan.settimeout(5)
if port:
address=(target,int(port))
try:
scan.connect(address)
scan.send('x03x00x00x13x0exe0x00x00x00x00x00x01x00x08x00x03x00x00x00')
banner = scan.recv(5)
if banner == 'x03x00x00x13x0e':
suc = True
with print_lock:
print "%s RDP Port is %s!"%(target,port)
else:
with print_lock:
print "RDP close!"
except Exception as e:
with print_lock:
print str(e) target.strip() " ,port:" str(port)
finally:
pass
scan.close()
semaphore.release()
def main():
with open(filename, "r") as fp:
for ip in fp.xreadlines():
semaphore.acquire()
t = threading.Thread(target=run, args=(ip.strip(),))
t.start()
if __name__ == "__main__":
main()
4F
最终版本
1、在控制台的信息打印都加了锁,以保持整齐,这里提取出一个输出的函数打印错误信息。
如下:
def print_status(ip, message, msg_type='*'):
global print_lock
with print_lock:
print "[%s] %s - %s" % (msg_type, ip, message)
2、用argparse模块处理输入的参数 3、自己封装了一个类进行指定ip段的生成
代码语言:javascript复制class gen_ip:
def __init__(self,ip):
self.ip = ip
def gen_ip(self):
start,end = [self.ip2num(x) for x in self.ip.split('-')]
ip_list= [self.num2ip(num) for num in range(start,end 1) if num & 0xff]
return ip_list
def ip2num(self,ip):
ip = [int(x) for x in ip.split('.')]
return ip[0]<<24 |ip[1]<<16 |ip[2]<<8 |ip[3]
def num2ip(self,num):!
return '%s.%s.%s.%s'%( (num & 0xff000000) >>24,
(num & 0x00ff0000) >>16,
(num & 0x0000ff00) >>8,
num & 0x000000ff
)
这个生成一个1000w以内的B段差不多10秒内。
给出项目地址如下: https://github.com/lonelyvaf/rdp_find
后续可能会把这个封装为对象去写提取一些常用的协议吧,功能定位更多是内网的探测。
本来写了一个任务分发和结果集成管理,要用到kafka,先缓缓咯,有其他的事情。后续再一篇代码审计,送个0day给大家。
往期回顾
如何快速的搭建漏洞环境到复现到PoC
oreint db 远程代码执行漏洞
从iis认证方式的学习到一个路由器漏洞的调试
日志攻防初探之windows篇(iis日志介绍)
晨星先生
憋说话,要加速了