星CTF-Rever


*CTF-REVER-WP

0x1 Simple File System

1

找到关键加密位置

2

动调得到V4的值

3

在image.flag找到密文。因为*ctf加密开头是不变的,所以通过特征码搜索。

data=[0x00, 0xD2, 0xFC, 0xD8, 0xA2, 0xDA, 0xBA, 0x9E, 0x9C, 0x26, 0xF8, 0xF6, 0xB4, 0xCE,
      0x3C, 0xCC,0x96, 0x88, 0x98, 0x34, 0x82, 0xDE, 0x80, 0x36, 0x8A, 0xD8, 0xC0, 0xF0, 0x38, 0xAE,0x40, 0]
for i in range(len(data)):
    for j in range(32,128):
        x = j
        x = (x >> 1) | (x << 7)&0xff
        x ^= 0xef
        x = (x >> 2) | (x << 6)&0xff
        x ^= 0xbe
        x = (x >> 3) | (32 * x)&0xff
        x ^= 0xed
        x = (x >> 4) | (16 * x)&0xff
        x ^= 0xde
        x = (x >> 5) | (8 * x)&0xff
        if x ==data[i]:
            print(chr(j),end="")
#*CTF{Gwed9VQpM4Lanf0kEj1oFJR6}*

python爆破一下

0x2 NaCl

1

第一步先是用ida脚本修复逻辑

start = 0x807FEC0
end = 0x8080AD1

address = [0 for i in range(5)]
callTarget = ["lea", "lea", "mov", "jmp"]
retnTarget = ["lea", "mov", "and", "lea", "jmp"]


def nop(s, e):
	while (s < e):
		patch_byte(s, 0x90)
		s += 1

def turnCall(s, e):
	# nop掉call之前的值
	nop(s, e)
	patch_byte(e, 0xE8)
	# 把后面的花指令去掉
	huaStart = next_head(e)  #next_head取下一条指令
	huaEnd = next_head(huaStart)
	nop(huaStart, huaEnd)

def turnRetn(s, e):
	nop(s, e)
	# 注意原来是jmp xxx
	# 所以前面nop掉一个 后面改成retn
	patch_byte(e, 0x90)
	patch_byte(e + 1, 0xC3)

p = start
while p < end:
	address[0] = p
	address[1] = next_head(p)
	address[2] = next_head(address[1])
	address[3] = next_head(address[2])
	address[4] = next_head(address[3])

	for i in range(0, 4):
		if print_insn_mnem(address[i]) != callTarget[i]: #print_insn_mnem 取指令
			break
	else:
		turnCall(address[0], address[3])
		p = next_head(next_head(address[3]))
		continue

	for i in range(0, 5):
		if print_insn_mnem(address[i]) != retnTarget[i]:
			break
	else:
		turnRetn(address[0], address[4])
		p = next_head(next_head(address[4]))
		continue

	p = next_head(p)

此脚本是pz师傅写的,可以观看视频有详细讲解原理,关注一下pz师傅。

https://www.bilibili.com/video/BV1D541127ug?spm_id_from=333.999.0.0

4

后发现,脚本没有特别完善。这里两个计算指令也nop了,修复回去即可。

2

这里观看队内wp,说是Feistel加密,没接触过。这里是动调取得key,然后剩下就是左移异或。

3

把那两个汇编修复一下就是这样,基本能当源码看

5

第二个就是xtea,修复过来后就看的非常清晰,key就是v3-24.

from ctypes import *
import binascii

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, 0x0B2B30907]


def ROL(i, index):
    return ((i << index) | (i >> (32 - index))) & 0xffffffff


def Feistel(p1, p2):
    for i in range(43, -1, -1):
        tmp = p2
        p2 = (ROL(tmp, 1) & ROL(tmp, 8)) ^ ROL(tmp, 2) ^ KEY[i] ^ p1
        p1 = tmp
    return p1,p2

def xtea(v, key, r):
    v0, v1 = c_uint32(v[0]), c_uint32(v[1])
    delta = 0x10325476
    total = c_uint32(delta * r)
    for i in range(r):
        v1.value -= (((v0.value << 4) ^ (v0.value >> 5)) + v0.value) ^ (total.value + key[(total.value >> 11) & 3])
        total.value -= delta
        v0.value -= (((v1.value << 4) ^ (v1.value >> 5)) + v1.value) ^ (total.value + key[total.value & 3])

    return v0.value, v1.value


enc = [
    0x66, 0xC2, 0xF5, 0xFD, 0x86, 0x82, 0x32, 0x7A, 0x04, 0x40,
    0x94, 0xCE, 0xDC, 0x8A, 0xE0, 0x5D, 0x0A, 0xBD, 0xE4, 0xA6,
    0xDC, 0xAD, 0xCA, 0x16, 0x0C, 0x6F, 0xCD, 0x13, 0x36, 0xD9,
    0x75, 0x1A
]
xtea_key = [
    0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
]
enc_data = [[0xFDF5C266, 0x7A328286], [0xCE944004, 0x5DE08ADC], [0xA6E4BD0A, 0x16CAADDC], [0x13CD6F0C, 0x1A75D936]]
flag = b''
for i in range(4):
    a, b = xtea(enc_data[i], xtea_key, 1 << (1 + i))
    c, d = Feistel(b, a)
    flag += binascii.a2b_hex(hex(c)[2:])
    flag += binascii.a2b_hex(hex(d)[2:])
print(flag)
#mM7pJIobsCTQPO6R0g-L8kFExhYuivBN

这里的代码是抄的队内师傅的,这里放上他的博客。

https://www.yuque.com/emtanling

0x3 jump

3

4

先用 插件figer修复函数,大致分为3个重要函数

2

第一个函数就是把输入的flag 前面加2 最后面加3 变成一个34位的数组

什么是long_jmp ,什么是set_jmp看下面这篇文章

https://blog.csdn.net/chenyiming_1990/article/details/8683413

1

可以看到截图中断到一个这个指令,后面long_jmp调用setjmp 出来的位置就是这个endbr64,图中有解答。间接跳转需要这个endbr64指令来回应

6

第二个函数 意义就是按照大小来排序每一个flag数组,左边就是存储的每一个数组

7

最终就是把每一个数组的最后一位取出来做比较

import copy
enc=[0x03, 0x6A, 0x6D, 0x47, 0x6E, 0x5F, 0x3D, 0x75, 0x61, 0x53, 0x5A, 0x4C, 0x76, 0x4E, 0x34, 0x77, 0x46, 0x78, 0x45, 0x36, 0x52, 0x2B, 0x70, 0x02, 0x44, 0x32, 0x71, 0x56, 0x31, 0x43, 0x42, 0x54, 0x63, 0x6B]
c=copy.deepcopy(enc) #copy.deepcopy函数是一个深复制函数。所谓深复制,就是从输入变量完全复刻一个相同的变量,无论怎么改变新变量,原有变量的值都不会受到影响
c.sort()   #排序
flag=[0]*34
flag[0]=2
flag[-1]=3
for i in range(32,-1,-1):
    p=c.index(flag[i+1])
    flag[i]=enc[p]
print(bytes(flag))
#\x02cwNG1paBu=6Vn2kxSCqm+_4LETvFRZDj\x03

最终就是拿出密文,然后排序好,按照索引来取值排序。


文章作者: Blue
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Blue !
评论
  目录