ctf-web:字符串和正則匹配


匹配過濾

在有的 Web 題目中會使用字符串匹配或正則表達式過濾傳入的變量,此時看懂匹配規則構造正確的變量就很重要。

JavaScript match() 方法

match() 方法可在字符串內檢索指定的值,或找到一個或多個正則表達式的匹配。該方法類似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。語法如下,函數的返回值為存放匹配結果的數組,該數組的內容依賴於 regexp 是否具有全局標志 g。

stringObject.match(searchvalue)
stringObject.match(regexp)

 

參數 說明
searchvalue 必需,規定要檢索的字符串值。
regexp 必需,規定要匹配的模式的 RegExp 對象。

PHP preg_match() 函數

preg_match 函數用於執行匹配正則表達式,搜索 subject 與 pattern 給定的正則表達式的一個匹配。函數返回 pattern 的匹配次數,值是 0 次(不匹配)或 1 次,因為 preg_match() 在第一次匹配后 將會停止搜索。preg_match_all() 不同於此,它會一直搜索subject 直到到達結尾。如果發生錯誤 preg_match() 返回 FALSE。函數語法為:

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

 

參數 說明
pattern 要搜索的模式,字符串形式。
subject 被正則匹配的字符串。
matches 如果提供了參數matches,它將被填充為搜索結果。matches[0] 將包含完整模式匹配到的文本,$matches[1] 將包含第一個捕獲子組匹配到的文本以此類推。
flags 可以被設置為標記值。
offset 搜索從目標字符串的開始位置開始。

PHP ereg() 函數

ereg() 函數用於正則表達式匹配,以區分大小寫的方式在 string 中尋找與給定的正則表達式 pattern 所匹配的子串。函數語法如下:

ereg ( string $pattern , string $string [, array &$regs ] ) : int

 

如果找到與 pattern 中圓括號內的子模式相匹配的子串並且函數調用給出了第三個參數 regs,則匹配項將被存入 regs 數組中。regs[1]regs[1]包含第一個左圓括號開始的子串,regs[2] 包含第二個子串以此類推,$regs[0] 包含整個匹配的字符串。如果在 string 中找到 pattern 模式的匹配則返回 所匹配字符串的長度,如果沒有找到匹配或出錯則返回 FALSE。如果沒有傳遞入可選參數 regs 或者所匹配的字符串長度為 0,則本函數返回 1。

  • 使用 Perl 兼容正則表達式語法的 preg_match() 函數通常是比 ereg() 更快的替代方案。

例題:bugku-字符?正則?

源碼如下,目的很明確,傳入一個符合正則匹配的參數 id 即可得到 flag。

<?php 
highlight_file('2.php');
$key ='KEY{********************************}';
$IM = preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){ 
    die('key is: '.$key);
}
?>

 

接下來分析匹配的正則表達式,所用的表達式語法如下:

正則表達式 匹配內容
. 匹配除 "\n" 之外的任何單個字符
* 匹配它前面的表達式 0 次或多次,等價於{0,}
.{4,7} 匹配 4 到 7 個任意字符
/ 匹配 /,\ 是為了轉義
[a-z] 匹配所有小寫字母
[:punct:] 匹配任何標點符號
/i 表示不分大小寫

根據以上規則,構造出一個符合要求的字符串,提交獲得 flag。

?id=keyakeyaaaakey:/a/akeya;

 

例題:bugku-ereg 正則 %00 截斷

源碼如下,這題首先要求通過第一個分支語句,使用 ereg() 實現一個正則匹配,匹配的內容是一個以上的數字或字母。第二個分支語句要判斷輸入的字符串長度是否小於 8,同時它的值要大於 9999999。最后還要判斷字符串是否有包含“-”,如果包含則輸出 flag。

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

 

這里需要實現的內容很多,首先需要傳入的字符串長度小於 8,也就是說最大傳入的數字不會大於 9999999。這里可以用科學技術法來替代,10000000 的科學計數法的表達為 1e7。接着在字符串中要包含字符 “-”,但是第一個分支的正則匹配會阻止繼續,這時可以使用 “%00” 來階段字符串,使得正則匹配只匹配到前面的部分,而字符 “-” 就放在 “%00” 的后面。綜上所述,構造 payload:

?password=1e7%00*-*

 

例題:bugku-數字驗證正則繞過

題目的源碼如下,首先要用 preg_match() 一個正則表達式匹配,[: graph:] 表示任意一個可打印字符,此處要求 password 長度大於 12。接下來要用 preg_match_all() 進行全局匹配,每匹配成功一次就加 1,一直匹配到字符串結束。這要求 password 中必須包含標點符號、數字、大寫字母、小寫字母等,並且被檢測到 6 次以上才能繞過。

<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
    $password = $_POST['password'];
    if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 執行一個正則表達式匹配
    {
          echo 'flag';
          exit;
    }
    while (TRUE)
    {
          $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
          if (6 > preg_match_all($reg, $password, $arr)){
                break;
          }
          
          $c = 0;
          $ps = array('punct', 'digit', 'upper', 'lower'); 
          //[[:punct:]] 任何標點符號 [[:digit:]] 任何數字 [[:upper:]] 任何大寫字母 [[:lower:]] 任何小寫字母
          foreach ($ps as $pt)
          {
                if (preg_match("/[[:$pt:]]+/", $password))
                      $c += 1;
          }
          
          if ($c < 3)
                break;
          //>=3,必須包含四種類型三種與三種以上
          if ("42" == $password)
                echo $flag;
          else 
                echo 'Wrong password';
                exit;
      }
}
?>

 

最后要判斷 password 是否等於 42,注意到這是使用 “==” 進行判斷的,可以使用熟悉的弱類型。綜上所述,password 的長度應該大於 12,同時包含數字、大寫字母、小寫字母和符號,而且開頭是 42 后接字母,使得弱類型轉換時可以轉換為 42。此時可以使用 HackBar 的 POST 提交:

password= 42Aaaaaaaaaa+

 

例題:攻防世界-NaNNaNNaNNaN-Batman
打開文件,看到一堆亂碼,根據 “script” 標簽判斷這是 JavaScript 代碼。

<script>
_='function $(){e=getEleById("c").value;
length==16^be0f23233ace98aa$c7be9){tfls_aie}na_h0lnrg{e_0iit\'_ns=[t,n,r,i];
for(o=0;o<13;++o){    [0]);
.splice(0,1)}}}    \'<input id="c">< οnclick=$()>Ok</>\');delete _var ","docu.)match(/"];/)!=null=["    write(s[o%4]buttonif(e.ment';
for(Y in $='    ') with(_.split($[Y]))_=join(pop());
eval(_)
</script>

 

修改后綴為 “.html”,打開文件是一個輸入框,此時我們要知道需要輸入什么東西。

首先我們先看懂上述代碼,注意到代碼定義了一個參數 “_”,然后給出了一個字符串看上去是個函數,然后用 eval() 函數可計算字符串,執行其中的的 JavaScript 代碼。這里可以把 eval() 函數改為 alert() 函數,該函數可以顯示一段文本,從而進行程序的調試,我們可以把這段 JavaScript 代碼的正確形式顯示出來。

<script>
_='function $(){e=getEleById("c").value;
length==16^be0f23233ace98aa$c7be9){tfls_aie}na_h0lnrg{e_0iit\'_ns=[t,n,r,i];
for(o=0;o<13;++o){    [0]);
.splice(0,1)}}}    \'<input id="c">< οnclick=$()>Ok</>\');delete _var ","docu.)match(/"];/)!=null=["    write(s[o%4]buttonif(e.ment';
for(Y in $='    ') with(_.split($[Y]))_=join(pop());
alert(_)
</script>

 

修改后打開網頁,就能得到正確的 JavaScript 代碼如下。在正則中 “^” 表示開頭,“$” 表示末尾,在這里用 match() 函數匹配在輸入框里輸入的值要滿足輸入的字符串長度必須為 16 個字符。字符串的開頭必須要匹配 “be0f23”,字符串的結尾必須要匹配 “e98aa”,字符串中要能匹配到 “233ac” 和 “c7be9”。

function $()
{
    var e = document.getElementById("c").value;
    if(e.length == 16)
          if(e.match(/^be0f23/)!=null)
            if(e.match(/233ac/)!=null)
              if(e.match(/e98aa$/)!=null)
                if(e.match(/c7be9/)!=null)
                {
                    var t=["fl","s_a","i","e}"];
                    var n=["a","_h0l","n"];
                    var r=["g{","e","_0"];
                    var i=["it'","_","n"];
                    var s=[t,n,r,i];
                    for(var o = 0; o < 13; ++o)
                    {
                        document.write(s[o%4][0]);
                        s[o%4].splice(0,1)
                    }
                }
}
document.write('<input id="c"><button onclick=$()>Ok</button>');
delete _

 

因為限制了字符串的長度,因此這里要利用重疊來構造長度為 16 且滿足所有正則表達式的字符串為 “be0f233ac7be98aa”,輸入就可以獲得 flag。或者是把下面的代碼拿到瀏覽器運行,也能跑出需要的字符串。

var t = ["fl", "s_a", "i", "e}"];
var n = ["a", "_h0l", "n"];
var r = ["g{", "e", "_0"];
var i = ["it'", "_", "n"];
var s = [t, n, r, i];
for (var o = 0; o < 13; ++o) 
{
    document.write(s[o % 4][0]);
    s[o % 4].splice(0, 1)
}

 轉載自:https://www.cnblogs.com/linfangnan/p/13588411.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM