【问题标题】:Why can the execve system call run "/bin/sh" without any argv arguments, but not "/bin/ls"?为什么 execve 系统调用可以在没有任何 argv 参数的情况下运行“/bin/sh”,但不能运行“/bin/ls”?
【发布时间】:2016-08-08 23:56:49
【问题描述】:

我对@9​​87654322@ 的系统调用感到困惑。当我学习linux系统调用时。我知道使用execve 的正确方法是这样的:

char *sc[2]; 
sc[0]="/bin/sh"; 
sc[1]= NULL; 
execve(sc[0],sc,NULL); 

然后函数execve将调用syscall()进入系统内核,并将参数放在寄存器EAXEBXECXEDX上。但是,如果我使用它仍然会成功

execve("/bin/sh",NULL,NULL);

但是如果我用"/bin/ls"替换"/bin/sh",它会失败:

A NULL argv[0] was passed through an exec system call.

我想知道为什么"/bin/sh"可以在没有足够参数的情况下成功执行而"/bin/ls"却失败了?

【问题讨论】:

  • 我完全不依赖NULL 在那里工作; execve 手册页说 argv 是一个参数字符串数组; NULL 指针不是指向数组的有效指针。 (将NULL 用于env 看起来都不好看;相反,使用execvexecvp,或传递指向char *p = NULL 的指针。)
  • 当作为函数参数传递时,数组是指向其第一个元素的指针,因此 NULL 在这里肯定是有效的。
  • @AnttiHaapala: Linux's execve(2) does accept a NULL pointer,并将其视为指向空列表的指针。这是不鼓励且不可移植的,但特别是在 Linux 上是面向未来的。我见过的主要用例是利用 shellcode 在系统调用(x86 int 0x80syscall)之前将几个寄存器归零,而不是推送 0 并将指向它的指针放入两个寄存器。即它节省了几个字节的漏洞利用负载大小,并且如果"/bin/sh" 字符串已经在负载中,则不需要写入内存。
  • @petercordes 很好,hellcodez 保持兼容
  • 但是,手册页确实提到了这个例外

标签: c linux system-calls glibc shellcode


【解决方案1】:

这不是内核问题。无论argvenvp 是否为NULL,内核都将使用execvefilename 参数运行。 argv[0] 指向程序名称只是一个 Unix 约定。

你所看到的只是正常的,即没有任何问题。因为ls 是GNU 的coreutils 的一部分,并且coreutils 包中的所有程序都调用set_program_name 来做一些设置工作。你可以在源码中看到:它检查argv[0]是否为NULL,当它为NULL时它会调用abort

另一方面,/bin/sh 显然是一个不属于 coreutils 的程序,并且不检查 argv[0]。这就是它运行没有问题的原因。

参考源码:

【讨论】:

猜你喜欢
  • 2019-04-29
  • 2022-01-02
  • 2015-12-23
  • 1970-01-01
  • 2016-08-15
  • 2011-01-30
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
相关资源
最近更新 更多