部分内容来自队友
web
日记本
利用dirsearch工具扫描发现一个登录路由和actuator泄露,还有swagger-ui.html

但是正常的注册/api/auth/v1/register无法成功,通过查看/actuator/mappings找到了/api/auth/v2/register这样的注册路由。


这样就可以注册了。登录进去后,api路由还有一个/api/auth/update,这里可以更新账户信息。我们利用actuator/heapdump工具拿到了key:

然后通过这个路由修改刚刚注册的账号为admin了

然后就可以查看admin的api,发现hint里是源码:

反编译源码后,查看依赖:

发现有fastjson1.2.26和CC3.2.1的依赖,可以通过jndi打ldap触发反序列化再打CC链。
在/api/admin/diaries路由可以触发fastjson反序列化。

执行一下/readflag就可以了

利用java-chians工具:

由于fastjson版本是1.2.26,又存在myBatis依赖

所以payload:


简单的仓库
注册用户1234:1234
登录后分析源码可以发现有文件展示功能以及重置和开通vip的功能,挨个抓包测试。

构造报文,进行测试,可以发现显示我们登录后对应账号的文件。

由此可以得到admin有哪些文件。

接着测试充值api可以发现带了权限字段,修改为admin即可充值成功。


利用充值后的余额开通vip,获得文件下载的功能。

根据url中的文件名和user参数下载文件,我们可以读取admin的readme文件。

发现flag路径,我们可以去/api/files验证一下。

是可以当做用户处理的。
访问/download/flag.txt?user=/var/tmp即可。

Misc
异常行为溯源
取log,在tcp层
# from json import load from pyshark import FileCapture from base64 import b64decode from json import loads for packet in FileCapture(input_file="network_traffic.pcap", keep_packets=False): tcp = packet.tcp data = bytes.fromhex(tcp.payload.replace(":", "")).decode() data = b64decode(data).decode() data = loads(data) msg = data["msg"] type = data["type"] msg = b64decode(msg).decode().strip() print(msg)直接统计ip频次就行了。
import re from datetime import datetime logs = open("log.log").readlines() log_match = re.compile(r'(\d+\.\d+\.\d+\.\d+) ?- - \[(.*) \+\d+\] "(\w+) ([\w\/.-]+) HTTP\/1\.1" \d+ \d+ "-" ".*"') ip_maps = {} for log in logs: m = log_match.match(log) ip = m.group(1) time = m.group(2) time = datetime.strptime(time, "%d/%b/%Y:%H:%M:%S") method = m.group(3) url = m.group(4) # print(time_match.match(time).group()) ip_maps[ip] = ip_maps.get(ip, 0) + 1 # print() ip_maps = sorted(ip_maps.items(), key=lambda x: x[1], reverse=True) for ip, count in ip_maps: print(ip, count) break数据校验
from hashlib import md5 from ecdsa import VerifyingKey, BadSignatureError from base64 import b64decode data = open("data.csv").readlines()[1:] data = [i.strip().split(",") for i in data] data = [{ "Serial_Number": i[0], "UserName": i[1], "UserName_Check": i[2], # md5 hash for username "Password": i[3], "Password_Check": i[4], # md5 hash for password "IP": i[5], "Signature": i[6], # ecdsa sign for username. } for i in data] whitelist = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" lst = [] for d in data: if d["UserName"][:5] != "User-": print(d["Serial_Number"], "UserName format Error") lst.append(d["Serial_Number"]) continue if md5(d["UserName"].encode()).hexdigest() != d["UserName_Check"]: print(d["Serial_Number"], "UserName hash Error") lst.append(d["Serial_Number"]) continue r = 0 for i in d["Password"]: if i not in whitelist: print(d["Serial_Number"], "Password format Error") r = 1 break if r == 1: lst.append(d["Serial_Number"]) continue t = d["IP"].split(".") if len(t) != 4: print(d["Serial_Number"], "IP format Error") lst.append(d["Serial_Number"]) continue r = 0 for i in t: if not i.isdigit() or int(i) > 255: print(d["Serial_Number"], "IP format Error") r = 1 break if r == 1: lst.append(d["Serial_Number"]) continue if md5(d["Password"].encode()).hexdigest() != d["Password_Check"]: print(d["Serial_Number"], "Password hash Error") lst.append(d["Serial_Number"]) continue try: vk = VerifyingKey.from_pem(open(f"ecdsa-key/{d['Serial_Number']}.pem").read()) vk.verify(b64decode(d["Signature"]), d["UserName"].encode()) except BadSignatureError: print(d["Serial_Number"], "Username Signature Error") lst.append(d["Serial_Number"]) lst = list(set(lst)) lst = sorted(lst) t = "_".join(lst) print(t) print("flag{" + md5(t.encode()).hexdigest() + "}")Strange_Database
数据库内容
from sqlite3 import connect from os import listdir from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP from base64 import b64decode keys = listdir("key") keys = {int(key.split(".")[0].split("-")[1]):key for key in keys} # print(keys) for db_file in listdir("database"): ids = db_file.split(".")[0].replace("database-", "") key_file = f"key/{keys[int(ids)]}" password = key_file.split(".")[0].split("-")[2] # print(password) key = RSA.importKey(open(key_file).read(), passphrase=password) cipher = PKCS1_OAEP.new(key) db = connect(f"database/{db_file}") cursor = db.cursor() cursor.execute("SELECT * FROM sqlite_master WHERE type='table';") tables = cursor.fetchall() for table in tables: cursor.execute(f"SELECT * FROM {table[1]};") rows = cursor.fetchall() for row in rows: # print(,row[2]) # print() type = cipher.decrypt(b64decode(row[0])).decode() number = row[1] name = cipher.decrypt(b64decode(row[2])).decode() password = cipher.decrypt(b64decode(row[3])).decode() remark = cipher.decrypt(b64decode(row[4])).decode() print(type, number, name, password, remark) db.close()database里有enc和key字段的东西,应该就是flag相关了。
lines = open("log.log").readlines() data = [line.split() for line in lines] d_map = {} for i in data: d_map[i[0]] = d_map.get(i[0],0) + 1 print(d_map)
lines = open("log.log").readlines() data = [line.split() for line in lines] enc = [] key = [] for i in data: if i[0] == "Enc": print(i) enc.append(i[-1]) if i[0] == "Key": print(i) key.append(i[-1])最后是rc4。
Crypto
qaq
很多参数已知
由于 Weil 配对 T 的值在某个小阶子群中,对 T 进行适当的指数运算后可以“消去”这个随机因素。
weil配对,参考文章:什么是weil配对 - 玩剑的Fiora - 博客园
构造一个新的数组有
out=(output^qwq) mod p =(weil_pairing(P1,P2,qwq)^3*c)^(qaq*qwq)=c^(qaq*qwq) mod p这里隐含Weil 配对 中的weil_pairing(P1,P2,qwq) 被指数运算后归一化为 1,从而使得加密操作对 c 仅留下一个可逆的指数变换。
只需要对原文2个字节(也就是16个二进制)的数字位进行爆破2^16位即可解密
from Crypto.Util.number import long_to_bytesfrom tqdm import tqdmfrom sage.all import GF, EllipticCurveres = [4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272555731, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272556223, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272556437, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272556749, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272557237, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272557459, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272557687, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272558239, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272558627, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559239, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559523, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272560169, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272560343, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272560433, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272560751, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272560969, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272561441, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272562103, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272562601, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272563261, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272563297, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272563391, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272563511, 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272563711]p = res[11]output = [2258729984869869545899085887518820011795880892632317458813070773270633871398785757696896679887453336507722151037267, 1843407310728065127389586068976768146728145160643439144895915852634291722663455873979176336542780552480617232750208, 1107061034832953338095294459542523703297843192927313275050958753437078121375795698115353665062727895555487155331316, 460337686287218470707660572908024613140030922587867288532588857547792028112129697850035268228038619747643899804437, 1659483062154723617504533638726171721668768657049197025961515070605996080663312140357834824850074607457421362000265, 3150528329201636320206556304125544975332446992414777732425647667048147102509308959254762895094589762017857965981432, 3338854035461286314545186888372727000962778038359519702308782495912356677650264814573463929190025956045491115654437, 3042574495339632074308497406446851120362994432361876743901608172567070991832258762751304397604780567703759317642849, 380771388315580393673388198522357440257018642337119013880143084485482127962577943753495690258532782147018511750175, 507222017133457507399048159541059729302482262298099528096040456818913085187752925782279385808732260473494863290057, 533663958640518878580794848474449572155795564171089765377581587253792204491009275840408579120376539757958097910250, 2681145160205204287930367627648683111546318004811732016137828270063753300095675791698398080219566725174890793619305, 3259478178021541801713314504097142165241891541242669456591074651894459393333167453811425864198267757724232689747676, 3553147298452254907907643059383506744982654808021508866104139240155822133286673657139615950259800036058045049186173, 1778776925369812510137824472396145391840300438509021838870105004154301861222612045533034046889878767915343446874895, 3409071358092535255033136229525415652816479844958949032220987821989305575696869929136493897719813036034016228268240, 571819148781137687997336847709735468532344087614483867682513640750800758034003212746545051127998686475933050072942, 2676666310158795770609746651024766841212271213339384335651155407291004834251914242990757216402110096603729617413168, 2557670339976470006330058052583841683167706755578266425502679937976714609864257535859316483527764340425703004883241, 973319024062640263364951783086923560907216776835485042157036675663719529568519121997200478026304141184810597275543, 1189768012357955450386827626693191057999220508190415783719135619271537446794904663649700073564180453068646130539863, 790522915783756530835443034667719516913120763875831140857606265058871034793645280121113275798239222760522467771184]qwq = 0x320238bK = GF(p)E = EllipticCurve(K, (0, 4))qaq = E.order() // (qwq ** 2)out = [pow(i, qwq, p) for i in output]flag_chars = []for encrypted_value in tqdm(output1, desc="Decrypting blocks"): for i in range(1, 65536): decrypted_value = pow(i, qwq * qaq, p) if decrypted_value == encrypted_value: decoded_char = long_to_bytes(i).decode() flag_chars.append(decoded_char) breakflag = "".join(flag_chars)print(flag)