欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

php bugs代碼審計(jì)基礎(chǔ)詳解

 更新時(shí)間:2022年11月14日 10:12:57   作者:w350809090  
代碼審計(jì)不會(huì),學(xué)習(xí)知識(shí)需要積累一下基礎(chǔ),因此來(lái)搭建php_bugs進(jìn)行相關(guān)學(xué)習(xí),題解如下,希望能對(duì)在學(xué)習(xí)代碼審計(jì)的同學(xué)們有所幫助

變量覆蓋漏洞

<?php
$flag='xxx'; 
extract($_GET);
 if(isset($shiyan))
 { 
    $content=trim(file_get_contents($flag));  //將讀取$flag內(nèi)容并去除左右空白后保存到$content
    if($shiyan==$content)
    { 
        echo'ctf{xxx}'; 
    }
   else
   { 
    echo'Oh.no';
   } 
   }
?>

重要點(diǎn)為$shiyan==$content只要滿足這個(gè)條件就可以獲取flag。

首先extract()函數(shù)的作用為從數(shù)組將變量導(dǎo)入到當(dāng)前符號(hào)表,也就是說我們?nèi)绻麡?gòu)造

xxx.com/index.php?$shiyan=1則會(huì)生成一個(gè)名字為$shiyan的變量,值為1。

然后通過isset函數(shù)來(lái)判斷剛生成的$shiyan變量是否為null,如果為null就進(jìn)入判斷。

$content變量則是通過file_get_contents函數(shù)和trim函數(shù)來(lái)讀取文件,但是此時(shí)它所讀取的文件$flag值為xxx,此時(shí)這個(gè)目錄是不存在的,所以它的值為空。

所以我們此時(shí)要做的就是將$shiyan的值變?yōu)榭占纯伞?/p>

所以構(gòu)造鏈接xxx.com/index.php?$shiyan=&flag=1即可獲得ctf{xxx}

繞過過濾空白字符

<?php
$info = ""; 
$req = [];
$flag="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
ini_set("display_error", false); //為一個(gè)配置選項(xiàng)設(shè)置值
error_reporting(0); //關(guān)閉所有PHP錯(cuò)誤報(bào)告
if(!isset($_GET['number'])){
   header("hint:26966dc52e85af40f59b4fe73d8c323a.txt"); //HTTP頭顯示hint 26966dc52e85af40f59b4fe73d8c323a.txt
   die("have a fun!!"); //die — 等同于 exit()
}
foreach([$_GET, $_POST] as $global_var) {  //foreach 語(yǔ)法結(jié)構(gòu)提供了遍歷數(shù)組的簡(jiǎn)單方式 
    foreach($global_var as $key => $value) { 
        $value = trim($value);  //trim — 去除字符串首尾處的空白字符(或者其他字符)
        is_string($value) && $req[$key] = addslashes($value); // is_string — 檢測(cè)變量是否是字符串,addslashes — 使用反斜線引用字符串
    } 
} 
function is_palindrome_number($number) { 
    $number = strval($number); //strval — 獲取變量的字符串值
    $i = 0; 
    $j = strlen($number) - 1; //strlen — 獲取字符串長(zhǎng)度
    while($i < $j) { 
        if($number[$i] !== $number[$j]) { 
            return false; 
        } 
        $i++; 
        $j--; 
    } 
    return true; 
} 
if(is_numeric($_REQUEST['number'])) //is_numeric — 檢測(cè)變量是否為數(shù)字或數(shù)字字符串 
{
   $info="sorry, you cann't input a number!";
}
elseif($req['number']!=strval(intval($req['number']))) //intval — 獲取變量的整數(shù)值
{
     $info = "number must be equal to it's integer!! ";  
}
else
{
     $value1 = intval($req["number"]);
     $value2 = intval(strrev($req["number"]));  
     if($value1!=$value2){
          $info="no, this is not a palindrome number!";
     }
     else
     {
          if(is_palindrome_number($req["number"])){
              $info = "nice! {$value1} is a palindrome number!"; 
          }
          else
          {
             $info=$flag;
          }
     }
}
echo $info;

根據(jù)代碼判斷,它需要滿足多個(gè)條件才可以執(zhí)行$info=$flag;之后echo出來(lái)的才是flag。

if(is_numeric($_REQUEST['number'])) //is_numeric — 檢測(cè)變量是否為數(shù)字或數(shù)字字符串 
{
   $info="sorry, you cann't input a number!";
}

先來(lái)看看第一個(gè)條件,它要求number參數(shù)傳入的內(nèi)容不能為數(shù)字,否則返回sorry, you cann't input a number!

但是它的第二個(gè)要求為數(shù)字必須為整數(shù),否則輸出number must be equal to it's integer!!

elseif($req['number']!=strval(intval($req['number']))) //intval — 獲取變量的整數(shù)值
{
     $info = "number must be equal to it's integer!! ";  
} 

導(dǎo)致我們輸入字符串也會(huì)報(bào)錯(cuò)

這里我們用到%00來(lái)繞過is_numeric函數(shù)的判斷。

根據(jù)報(bào)錯(cuò),再來(lái)看看$value1,它是$req["number"]的整數(shù)值,$value2則為反轉(zhuǎn)之后的$req["number"]的整數(shù)值。

$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));  
if($value1!=$value2){
          $info="no, this is not a palindrome number!";
     }

所以第三步要滿足的條件為,它必須為回文數(shù)即從左往右和從右往左讀取都要相同的數(shù)值,所以我們構(gòu)造如下

以上三個(gè)條件都滿足后,接下來(lái)看看最后一個(gè)條件

          if(is_palindrome_number($req["number"])){
              $info = "nice! {$value1} is a palindrome number!"; 
          }
          else
          {
             $info=$flag;
          }

這里調(diào)用了is_palindrome_number()函數(shù),我們看看函數(shù)內(nèi)容

function is_palindrome_number($number) { 
    $number = strval($number); //strval — 獲取變量的字符串值
    $i = 0; 
    $j = strlen($number) - 1; //strlen — 獲取字符串長(zhǎng)度
    while($i < $j) { 
        if($number[$i] !== $number[$j]) { 
            return false; 
        } 
        $i++; 
        $j--; 
    } 
    return true; 
} 

可以看到這里函數(shù)的作用是判斷數(shù)字是否是對(duì)稱的,我們的要求是讓它執(zhí)行return false來(lái)執(zhí)行$info=$flag;所以這里想到的是在數(shù)字前加字符串+字符串+is_numeric中是被無(wú)視的,也就是說+100與100相等。

所以我們構(gòu)造%00%2b454即可

多重加密

<?php
    include 'common.php';
    $requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
    //把一個(gè)或多個(gè)數(shù)組合并為一個(gè)數(shù)組
    class db
    {
        public $where;
        function __wakeup()
        {
            if(!empty($this->where))
            {
                $this->select($this->where);
            }
        }
        function select($where)
        {
            $sql = mysql_query('select * from user where '.$where);
            //函數(shù)執(zhí)行一條 MySQL 查詢。
            return @mysql_fetch_array($sql);
            //從結(jié)果集中取得一行作為關(guān)聯(lián)數(shù)組,或數(shù)字?jǐn)?shù)組,或二者兼有返回根據(jù)從結(jié)果集取得的行生成的數(shù)組,如果沒有更多行則返回 false
        }
    }
    if(isset($requset['token']))
    //測(cè)試變量是否已經(jīng)配置。若變量已存在則返回 true 值。其它情形返回 false 值。
    {
        $login = unserialize(gzuncompress(base64_decode($requset['token'])));
        //gzuncompress:進(jìn)行字符串壓縮
        //unserialize: 將已序列化的字符串還原回 PHP 的值
        $db = new db();
        $row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
        //mysql_real_escape_string() 函數(shù)轉(zhuǎn)義 SQL 語(yǔ)句中使用的字符串中的特殊字符。
        if($login['user'] === 'ichunqiu')
        {
            echo $flag;
        }else if($row['pass'] !== $login['pass']){
            echo 'unserialize injection!!';
        }else{
            echo "(╯‵□′)╯︵┴─┴ ";
        }
    }else{
        header('Location: index.php?error=1');
    }
?> 

因題目中并沒有給出數(shù)據(jù)庫(kù)配置文件,所以直接看題,在題目中重點(diǎn)部分為

    if(isset($requset['token']))
    //測(cè)試變量是否已經(jīng)配置。若變量已存在則返回 true 值。其它情形返回 false 值。
    {
        $login = unserialize(gzuncompress(base64_decode($requset['token'])));
        //gzuncompress:進(jìn)行字符串壓縮
        //unserialize: 將已序列化的字符串還原回 PHP 的值
        $db = new db();
        $row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
        //mysql_real_escape_string() 函數(shù)轉(zhuǎn)義 SQL 語(yǔ)句中使用的字符串中的特殊字符。
        if($login['user'] === 'ichunqiu')
        {
            echo $flag;
        }else if($row['pass'] !== $login['pass']){
            echo 'unserialize injection!!';
        }else{
            echo "(╯‵□′)╯︵┴─┴ ";
        }
    }else{
        header('Location: index.php?error=1');
    }

條件1為判斷是否存在token參數(shù),如果存在,那么就將token得值進(jìn)行反序列化和解壓縮后的值進(jìn)行base64解密。

解密完成后會(huì)帶入上面寫得db類中得select方法查詢。

接著就是需要注意得重點(diǎn),if($login['user'] === 'ichunqiu')即需要傳入的user值為ichunqiu

所以我們逆推出來(lái)需要做得就是先將user設(shè)定值為ichunqiu,隨后進(jìn)行base64加密得到值,但是我們剛才說到它在傳值過程中進(jìn)行了反序列話和解壓縮,所以我們也需要進(jìn)行壓縮和序列化,分別用

gzcompress來(lái)壓縮gzuncompress解壓縮。

serialize來(lái)序列化unserialize反序列化。

最終得到如下代碼,并得到token的值為eJxLtDK0qs60MrBOAuJaAB5uBBQ=,提交token即可echo $flag

<?php
$arr = array(['user'] === 'ichunqiu');
$token = base64_encode(gzcompress(serialize($arr)));
print_r($token);
?>

WITH ROLLUP注入

<?php
error_reporting(0);
if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
    echo '<form action="" method="post">'."<br/>";
    echo '<input name="uname" type="text"/>'."<br/>";
    echo '<input name="pwd" type="text"/>'."<br/>";
    echo '<input type="submit" />'."<br/>";
    echo '</form>'."<br/>";
    echo '<!--source: source.txt-->'."<br/>";
    die;
}
function AttackFilter($StrKey,$StrValue,$ArrReq){  
    if (is_array($StrValue)){
//檢測(cè)變量是否是數(shù)組
        $StrValue=implode($StrValue);
//返回由數(shù)組元素組合成的字符串
    }
    if (preg_match("/".$ArrReq."/is",$StrValue)==1){   
//匹配成功一次后就會(huì)停止匹配
        print "水可載舟,亦可賽艇!";
        exit();
    }
}
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){ 
//遍歷數(shù)組
    AttackFilter($key,$value,$filter);
}
$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
    die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
//設(shè)置活動(dòng)的 MySQL 數(shù)據(jù)庫(kù)
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql); 
//執(zhí)行一條 MySQL 查詢
if (mysql_num_rows($query) == 1) { 
//返回結(jié)果集中行的數(shù)目
    $key = mysql_fetch_array($query);
//返回根據(jù)從結(jié)果集取得的行生成的數(shù)組,如果沒有更多行則返回 false
    if($key['pwd'] == $_POST['pwd']) {
        print "CTF{XXXXXX}";
    }else{
        print "亦可賽艇!";
    }
}else{
    print "一顆賽艇!";
}
mysql_close($con);
?>

第四題我們先來(lái)看看flag輸出得條件

    if($key['pwd'] == $_POST['pwd']) {
        print "CTF{XXXXXX}";
    }else{
        print "亦可賽艇!";
    }

要滿足post中提交得pwd與$key = mysql_fetch_array($query);數(shù)據(jù)庫(kù)中讀取到得pwd相等,所以考點(diǎn)在于注入。

但是在AttackFilter函數(shù)和$filter中已經(jīng)限制了sql注入得關(guān)鍵字,所以沒辦法直接進(jìn)行注入。

其實(shí)在報(bào)錯(cuò)得過程中已經(jīng)進(jìn)行了提示亦可賽艇!,諧音為因缺思汀也就是WITH ROLLUP繞過注入

WITH ROLLUP是對(duì)group by分組后得結(jié)果進(jìn)行進(jìn)一步得匯總,如果按照列名進(jìn)行分組,因?yàn)榱械脤傩圆煌?,所以?huì)生成一條值null得新數(shù)據(jù),如果查詢結(jié)果時(shí)單一得情況下會(huì)生成一條列為null得數(shù)據(jù)。

我們來(lái)看看演示,值直接進(jìn)行查詢是有結(jié)果得

使用group by語(yǔ)句分組查詢也是正常顯示

但是當(dāng)我們?cè)?code>group by語(yǔ)句后添加WITH ROLLUP,可以看到效果如下

但是我們只需要其中第二列得數(shù)據(jù),所以使用limit 1讀取1條數(shù)據(jù)并使用offset去除一行數(shù)據(jù)得到我們需要得第二行

pwd得值被設(shè)置為了null,所以此題我們可以通過提交admin' GROUP BY pwd WITH ROLLUP LIMIT 1 OFFSET 1-- -來(lái)達(dá)到$key['pwd'] == $_POST['pwd']得條件并獲取flag。

erge截?cái)?/h2>
<?php 
$flag = "flag";
if (isset ($_GET['password'])) 
{
  if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
  {
    echo '<p>You password must be alphanumeric</p>';
  }
  else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
   {
     if (strpos ($_GET['password'], '*-*') !== FALSE) //strpos — 查找字符串首次出現(xiàn)的位置
      {
      die('Flag: ' . $flag);
      }
      else
      {
        echo('<p>*-* have not been found</p>'); 
       }
      }
     else 
     {
        echo '<p>Invalid password</p>'; 
      }
   } 
?>

先來(lái)梳理流程 首先條件一用ereg函數(shù)來(lái)寫死get參數(shù)password得值必須是數(shù)字大小寫字母,否則輸出You password must be alphanumeric。

第二個(gè)條件為strlen($_GET['password']) < 8 && $_GET['password'] > 9999999也就是必須長(zhǎng)度小于8但是值又要大于9999999。

所以我們需要用科學(xué)計(jì)數(shù)法來(lái)繞過這里得限制1e7為10得7次方10000000。

第三個(gè)條件為strpos ($_GET['password'], '*-*') !== FALSE在值中必須存在*-*如果滿足此條件,就沒辦法滿足條件一,所以這里可以采用%00截?cái)喾▉?lái)進(jìn)行繞過,因?yàn)?code>ereg函數(shù)遇到%00后就不會(huì)繼續(xù)進(jìn)行判斷

?password=1e7%00*-*即可滿足全部條件,執(zhí)行die('Flag: ' . $flag);來(lái)獲取flag

strcmp比較字符串

<?php
$flag = "flag";
if (isset($_GET['a'])) {  
    if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果兩者相等,返回 0。 
    //比較兩個(gè)字符串(區(qū)分大小寫) 
        die('Flag: '.$flag);  
    else  
        print 'No';  
}
?>

這題得考點(diǎn)在于strcmp函數(shù),它的作用在于兩個(gè)字符串相比較,如果兩者相等就會(huì)==0。

此函數(shù)是用來(lái)處理字符串參數(shù)的,如果提交的值是數(shù)組的話會(huì)返回個(gè)null在判斷中使用的是==等值符,如果類型不相同的情況下會(huì)轉(zhuǎn)換為同類型進(jìn)行比較,所以null==0,執(zhí)行die('Flag: '.$flag);

所以我們提交一個(gè)數(shù)組類型的值即可?a[]=1。

sha()函數(shù)比較繞過

<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password'])) 
{
    if ($_GET['name'] == $_GET['password'])
        echo '<p>Your password can not be your name!</p>';
    else if (sha1($_GET['name']) === sha1($_GET['password']))
      die('Flag: '.$flag);
    else
        echo '<p>Invalid password.</p>';
}
else
    echo '<p>Login first!</p>';
?>

這題的考點(diǎn)在于sha1($_GET['name']) === sha1($_GET['password'])

他這里使用的是===等同符,他要求兩邊值得類型相同,才會(huì)去比較值,否則會(huì)直接返回false

首先來(lái)看條件一$_GET['name'] == $_GET['password'] name要與password不相等才會(huì)執(zhí)行else if

但是else if又要求===,所以我們可以利用sha1函數(shù)不能處理數(shù)組得機(jī)制來(lái)繞過

?name[]=1&password[]=2既滿足了name與password不相等,也滿足了因sha1無(wú)法處理數(shù)組,導(dǎo)致返回值為false=false所以會(huì)執(zhí)行die('Flag: '.$flag);

到此這篇關(guān)于php bugs代碼審計(jì)基礎(chǔ)詳解的文章就介紹到這了,更多相關(guān)php bugs內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論