【问题标题】:shellcode is executed in two loops instead of oneshellcode 在两个循环而不是一个循环中执行
【发布时间】:2021-05-05 18:57:45
【问题描述】:

我成功构建了我的 shellcode。

[BITS 64]

segment .text
    global _start

_start: jmp call

back:   lea rsi, [rsp]
    mov rdi, [rsi]
    xor rax, rax
    push rax
    lea rdx, [rsp]
    mov al, 0x3b
    syscall
call:   call back
    db "/bin/sh",0

但代码执行有一些神秘之处。我仍然无法弄清楚是什么问题,也许有人能够提供帮助。

当我使用radare2调试代码时,设置参数和系统调用的整个过程会执行两次。我不知道它有什么问题。寄存器,翻录等看起来不错。最后,shell 在第二个循环后弹出。但是对于堆栈上的执行来说,这是一件很痛苦的事情,因为我的 /bin/sh 在第二个循环中搞砸了。

第一个系统调用返回 -14(错误地址)

我已经尝试了一些代码变体和 RTFM。帮助

提前谢谢你:)

【问题讨论】:

  • 有趣;通常 jmp/call 技巧是使用 pop 将地址放入寄存器中完成的,但在这里您实际上是在尝试在堆栈上构建指针数组,而不是仅使用 argv=envp=0。
  • 是的,我想自己从头开始,结果就是这样。也许这些额外的字节由于干净的指针排列,在不是 /bin/sh 时会给出一些额外的“umpf”?

标签: linux assembly x86-64 shellcode


【解决方案1】:

好吧,argv 数组格式不正确。 您将该参数设置为堆栈上的地址,但您没有放置空指针来终止它。

这是执行_start 的第一条指令时的堆栈(下部):

...
0
argN
...
arg0
argc <-- rsp

注意,这些是你的程序的参数。另请注意,&lt;-- 表示“指向”(或:包含地址)。

back 被调用时,栈是:

...
0
argN
...
arg0
count
ptr to shell path <-- rsp

leas 之后(顺便说一句,lea 具有如此简单的寻址模式只是一个mov)和xor,堆栈是:

...
0
argN
...
arg0
count
ptr to shell path <-- rsp, rsi
                  rdi = ptr to shell path

那么就在syscall 之前,我们有:

...
0
argN
...
arg0
count
ptr to shell path <-- rsi
                  rdi = ptr to shell path
0                 <-- rsp, rdx
            

然后execve 将从rdi(检查)读取可执行路径,从rdx(检查)读取envp,从rsi 读取argv(失败)。
最后一个失败是因为execve 会从shell 的路径读取堆栈到第一个0,但是count 不是一个有效的指针(它可能是1)。

系统调用失败,执行到call back,重复这些步骤,但这次来自上一次迭代的0将正确终止argv

...
0
argN
...
arg0
count
ptr to shell path
0
ptr to shell path <-- rsi
                  rdi = ptr to shell path
0                 <-- rsp, rdx

你可以:

  • 什么都不做,并以这种方式保留它,这是调用 shell 的一种棘手方法(请注意,count 的某些值可以解释为有效指针,给 shell 一个参数)。
  • count 更改为零。您可以将xor eax, eax 向上移动并使用mov [rsp+8], rax。只要您可以在[rsp+8] 写信,这在其他情况下也有效。
  • 自己按零。要么在寄存器中弹出返回地址,然后在推入零后将其推入,或者使用xchg 或类似名称。
  • argvenvp 传递为NULL(即清零rsirdx)。在 Linux 上,这与您已经在执行的操作具有相同的效果(使用单个空指针传递数组)。
  • 如果你想将你的程序参数传递给 shell,你可以双重弹出然后推送返回地址或弹出返回地址并使用mov 覆盖count

【讨论】:

  • 哇,这太棒了。非常感谢你。我在想我的 argv 的相反方向,并认为 envp 的 0 是 argv 的最终 0。
  • @bplinux 很高兴为您提供帮助。指针和堆栈很容易被欺骗:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 2014-01-24
相关资源
最近更新 更多