运行PHP执行指令后,程序可到断点处,然后通过调用栈可知:底层通过CreateProcessW系统API调用来启动相关进程、然后通过cmd进程来执行相关指令(此处echo为cmd内置指令)(注意:这里也可查看到PHP程序的完整调用链)
JavaJava - 底层不调用系统终端,自己启动传入的可执行程序 Mode => Window:Command || Linux:Command
但是在Java语言里面,针对Linux平台,系统命令echo 111 > shell.txt传入CommandExecFunc函数,最终在底层相当于执行/bin/echo 111 > shell.txt成功打印一个字符串"111 > shell.txt"并没有创建文件shell.txt。【执行过程相当于:运行可执行程序/bin/echo并传入参数111 > shell.txt进行打印输出,这里的特殊字符>被当作普通字符串被echo程序打印。这里的echo作为可执行程序出现,而不是终端中的命令】【进程相关:一个进程/bin/echo,在/bin/echo进程中传入字符串参数111 > shell.txt进行打印输出】【有关可执行程序怎么查询:从环境变量中进行查询】
测试代码如下
import org.apache.commons.io.IOUtils;
import java.lang.Runtime;
public class CommandExec1 {
public static void main(String[] args) {
try{
String str = IOUtils.toString(Runtime.getRuntime().exec("whoami").getInputStream());
System.out.println(str);
}
catch(Exception a){
System.out.println(a);
}
}
}
- 跟踪一下程序执行流程:For Linux
程序执行监视情况:从系统环境变量中查找输入的指令可执行程序位置,然后由execve系统调用来启动相关程序进程(并未涉及系统终端调用)。
┌──(roottoor)-[~/桌面/CodeDebug/java]
└─# strace -f -e execve java CommandExec1
execve("/usr/bin/java", ["java", "CommandExec1"], 0x7ffdb259ee90 /* 53 vars */) = 0
strace: Process 3923 attached
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
[pid 3923] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
strace: Process 3924 attached
strace: Process 3925 attached
strace: Process 3926 attached
strace: Process 3927 attached
strace: Process 3928 attached
strace: Process 3929 attached
strace: Process 3930 attached
strace: Process 3931 attached
strace: Process 3932 attached
[pid 3932] execve("/mnt/hgfs/QSec/Pentest/Red-Team/\347\245\236\345\205\265\345\210\251\345\231\250/Windows/VSCode/VSCode-linux-x64/whoami", ["whoami"], 0x7ffd28368b80 /* 53 vars */) = -1 ENOENT (没有那个文件或目录)
[pid 3932] execve("/usr/local/sbin/whoami", ["whoami"], 0x7ffd28368b80 /* 53 vars */) = -1 ENOENT (没有那个文件或目录)
[pid 3932] execve("/usr/local/bin/whoami", ["whoami"], 0x7ffd28368b80 /* 53 vars */) = -1 ENOENT (没有那个文件或目录)
[pid 3932] execve("/usr/sbin/whoami", ["whoami"], 0x7ffd28368b80 /* 53 vars */) = -1 ENOENT (没有那个文件或目录)
[pid 3932] execve("/usr/bin/whoami", ["whoami"], 0x7ffd28368b80 /* 53 vars */) = 0
[pid 3932] exited with 0
[pid 3923] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3932, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 3933 attached
root
[pid 3931] exited with 0
[pid 3927] exited with 0
[pid 3924] exited with 0
[pid 3923] exited with 0
[pid 3933] exited with 0
[pid 3930] exited with 0
[pid 3929] exited with 0
[pid 3928] exited with 0
[pid 3926] exited with 0
[pid 3925] exited with 0
exited with 0
┌──(roottoor)-[~/桌面/CodeDebug/java]
└─#
同理,针对Windows平台,系统命令echo 111 > shell.txt传入CommandExecFunc函数,最终在底层相当于执行系统环境变量/echo.exe 111 > shell.txt成功打印一个字符串"111 > shell.txt"并没有创建文件shell.txt。
但是,正常情况下,这里执行上述指令会报错,因为Windows平台,默认情况下系统环境变量中不存在echo.exe可执行程序,导致指令无法正常执行
# 无法定位echo可执行程序
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>where echo
INFO: Could not find files for the given pattern(s).
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>where whoami
C:\Windows\System32\whoami.exe
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>
# 执行报错
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>javac RuntimeRCE.java
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>java RuntimeRCE
java.io.IOException: Cannot run program "echo": CreateProcess error=2, The system cannot find the file specified
D:\QSec\Code-Audit\Tools\Java\Kits\RCE>
Python
Python - 底层调用系统终端,执行命令 Mode => Window:cmd.exe /c Command || Linux:sh -c Command
而Python语言,命令执行函数底层原理实现同PHP语言。
总结起来,也就是,命令执行函数执行分为两类,一类:传入的命令仅仅作为可执行终端中的命令执行;另一类:传入的命令仅仅是运行传入的命令中的可执行程序。对象不同,一类:是底层语言系统终端帮我们执行传入的命令;另一类:是自己启动传入的可执行程序。
参考链接- Build your own PHP on Windows
- Visual Studio docs
- Visual Studio Code docs
- 《PHP 7底层设计与源码实现 PHP7内核剖析》
- 深入理解 PHP 内核
- WINDOWS下用VSCODE调试PHP7源代码
- 调式PHP源码
- 用vscode调试php源码
- GDB: The GNU Project Debugger
- CreateProcessW function
- 命令注入成因小谈
- 浅谈从PHP内核层面防范PHP WebShell
- Program execution Functions
- linux系统调用
- system calls