序言
针对不同平台/措辞下的命令实行是不相同的,存在很大的差异性。因此,这里对不同平台/措辞下的命令实行函数进行深入的探究剖析。
文章开头会对不同平台(Linux、Windows)下:终真个指令实行、措辞(PHP、Java、Python)的命令实行进行先容剖析。后面,紧张以PHP措辞为工具,针对不同平台,对命令实行函数进行底层深入剖析,这个过程包括:PHP内核源码的编译、运行、调试、审计等,其它措辞剖析事理思路类似。19
该系列剖析文章紧张分为四部分,如下:
第一部分:命令实行底层事理探究-PHP (一)
针对不同平台(Linux、Windows)下:终真个指令实行、措辞(PHP、Java、Python)的命令实行进行先容剖析。
第二部分:命令实行底层事理探究-PHP (二)紧张以PHP措辞为工具,针对不同平台,进行环境准备、PHP内核源码的编译、运行、调试等。
第三部分:命令实行底层事理探究-PHP (三)针对Windows平台下,PHP命令实行函数的底层事理剖析。
第四部分:命令实行底层事理探究-PHP (四)针对Linux平台下,PHP命令实行函数的底层事理剖析。
本文《 命令实行底层事理探究-PHP (一) 》紧张讲述的是第一部分:针对不同平台(Linux、Windows)下:终真个指令实行、措辞(PHP、Java、Python)的命令实行进行先容剖析。
平台措辞不同平台终端指令实行
不同平台终端中实行的命令办法一样平常有两种:自身终端封装的指令(内置)、终端下调用其它目录下的可实行程序(外部)。
LinuxLinux下终端一样平常为/bin/bash、/bin/sh、/bin/zsh等,这里以bash终端为例测试。
以Linux为例【Windows等平台事理同Linux类似】,Linux下终端内建(内置)的指令类型为:shell built-in command。
所谓shell built-in command,便是那些内建在linux shell里面的command指令。
常日情形下,在linux shell下面实行一个command指令,shell会查找command是否为built-in command类型,对付built-in command指令类型,shell会自己阐明实行,而无需fork一个child process子进程来实行该command指令;对付,不是built-in command指令类型,shell会从环境变量中按顺序搜索该command指令,如果能查到则会fork一个child process子进程来实行该command指令;然而,对付找不到的command指令,一样平常为:实行的指令不存在、指令未加入到环境变量中。
那么如何进行终端内建指令的判断与查看呢,对付内建指令可以利用type指令去判断
┌──(roottoor)-[~/桌面]└─# type echo echo is a shell builtin┌──(roottoor)-[~/桌面]└─# type whoamiwhoami is /usr/bin/whoami┌──(roottoor)-[~/桌面]└─#
或着也可以利用其它指令进行查找判断:which、where
┌──(roottoor)-[~/桌面]└─# which echoecho: shell built-in command┌──(roottoor)-[~/桌面]└─# which whoami/usr/bin/whoami┌──(roottoor)-[~/桌面]└─# ┌──(roottoor)-[~/桌面]└─# where echo echo: shell built-in command echo/bin/echo┌──(roottoor)-[~/桌面]└─# where whoami/usr/bin/whoami/bin/whoami┌──(roottoor)-[~/桌面]└─#
把稳:在Linux平台,有些命令虽然为内建命令,但是系统关键目录也存在其可实行文件。
这里也可以利用enable或help指令,查看终端内建的所有指令
第一种:enable指令┌──(roottoor)-[~/桌面]└─# enable-.:[aliasautoloadbgbindkeybreakbuiltinbyecdchdircommandcompaddcompargumentscompcallcompctlcompdescribecompfilescompgroupscompquotecompsetcomptagscomptrycompvaluescontinuedeclaredirsdisabledisownechoechotcechotiemulateenableevalexecexitexportfalsefcfgfloatfunctionsgetlngetoptshashhistoryintegerjobskillletlimitlocalloglogoutnoglobpopdprintprintfprivatepushdpushlnpwdrreadreadonlyrehashreturnschedsetsetoptshiftsourcesuspendtesttimestraptruettyctltypetypesetulimitumaskunaliasunfunctionunhashunlimitunsetunsetoptvaredwaitwhencewherewhichzcompilezformatzlezmodloadzparseoptszregexparsezstatzstyle┌──(roottoor)-[~/桌面]└─#
第二种:help指令
接着对终端(内置|外置)命令进行测试,测试终端/bin/zsh:
测试:whoami指令先对whoami指令进行类型探测与指令定位查询
# 指令探测:非内置指令┌──(roottoor)-[~/桌面]└─# type whoami whoami is /usr/bin/whoami┌──(roottoor)-[~/桌面]└─## 指令定位查询:搜索创造系统分外目录存在`whoami`可实行程序┌──(roottoor)-[~/桌面]└─# where whoami/usr/bin/whoami/bin/whoami ┌──(roottoor)-[~/桌面]└─#
把稳:/bin目录为/usr/bin目录的链接
然后,在zsh终端写入For循环实行whoami指令查看是否为内部实行或外部调用
for n in {0..10000000}; do whoami ; done
另一侧,利用htop动态进程监控程序对该终端进行监控,可创造whoami指令并非zsh终端内置封装的指令
测试:echo指令
同样,对echo指令进行类型探测与指令定位查询
# 指令探测:内置指令┌──(roottoor)-[~/桌面]└─# type echo echo is a shell builtin┌──(roottoor)-[~/桌面]└─## 指令定位查询:搜索创造系统分外目录存在`echo`可实行程序,同时还创造存在`echo: shell built-in command`【终端内置指令】┌──(roottoor)-[~/桌面]└─# where echo echo: shell built-in command/usr/bin/echo/bin/echo ┌──(roottoor)-[~/桌面]└─#
然后,在zsh终端写入For循环实行echo指令查看是否为内部实行或外部调用
for n in {0..10000000}; do echo 1 ; done
另一侧,利用htop动态进程监控程序对该终端进行监控,可以创造echo指令为zsh终端内置封装的指令,并未涌现外部调用
Windows
Windows下终端一样平常为cmd.exe、powershell.exe等,这里以cmd来测试。终端指令实行事理同上述Linux讲解事理相同,分为终端内置指令与外部调用指令。
那么,针对Windows平台可实行终端,如何进行终端内建指令的判断与查看呢。可惜Windows平台终端不像Linux终端存在相应的type指令进行判断与enable、help指令查看所有内建指令。不过在Windows终端里可以借助where或set PATH指令进行指令判断。
第一种:where指令【不太友好】从系统环境变量PATH里面定位查询(把稳人为增长的环境变量的影响),如果能查到一样平常来说可以剖断为外部调用指令(打消非系统分外目录),否则为内部调用指令(打消不存在指令)
# 外部调用指令C:\Users\Qftm>where whoamiC:\Windows\System32\whoami.exeC:\Users\Qftm># 内部调用指令C:\Users\Qftm>where cdINFO: Could not find files for the given pattern(s).C:\Users\Qftm># 不存在指令C:\Users\Qftm>where qftmINFO: Could not find files for the given pattern(s).C:\Users\Qftm># 内部调用指令(打消人为增长的环境变量的影响)(打消非系统分外目录)C:\Users\Qftm>where echoD:\QSoftware\W3Server\phpstudy2019\Extensions\MySQL5.7.26\bin\echo.exeC:\Users\Qftm>
第二种:set path指令【友好】
将系统环境变量临时设置为null,然后对指令进行帮助查询,如果能查到则剖断为内置指令,否则为外部调用。
# path置空C:\Users\Qftm>set path=C:\Users\Qftm>pathPATH=(null)C:\Users\Qftm># 内部调用指令C:\Users\Qftm>cd /?Displays the name of or changes the current directory.CHDIR [/D] [drive:][path]CHDIR [..]CD [/D] [drive:][path]CD [..] .. Specifies that you want to change to the parent directory.Type CD drive: to display the current directory in the specified drive.Type CD without parameters to display the current drive and directory.Use the /D switch to change current drive in addition to changing currentdirectory for a drive.If Command Extensions are enabled CHDIR changes as follows:The current directory string is converted to use the same case asthe on disk names. So CD C:\TEMP would actually set the currentdirectory to C:\Temp if that is the case on disk.CHDIR command does not treat spaces as delimiters, so it is possible toCD into a subdirectory name that contains a space without surroundingthe name with quotes. For example: cd \winnt\profiles\username\programs\start menuis the same as: cd "\winnt\profiles\username\programs\start menu"which is what you would have to type if extensions were disabled.C:\Users\Qftm># 外部调用指令C:\Users\Qftm>whoami /?'whoami' is not recognized as an internal or external command,operable program or batch file.C:\Users\Qftm># 不存在指令C:\Users\Qftm>qftm /?'qftm' is not recognized as an internal or external command,operable program or batch file.C:\Users\Qftm>
把稳:Windows下终端help指令并不能够查询终端内建指令:首先help指令为外部调用指令,然后help指令查询出的所有指令=(内建指令+外部指令)
# help:属于外部指令C:\Users\Qftm>where helpC:\Windows\System32\help.exeC:\Users\Qftm># help:内建指令+外部指令(不同于Linux下bash等终端)C:\Users\Qftm>helpFor more information on a specific command, type HELP command-nameASSOC Displays or modifies file extension associations.ATTRIB Displays or changes file attributes.BREAK Sets or clears extended CTRL+C checking.BCDEDIT Sets properties in boot database to control boot loading.CACLS Displays or modifies access control lists (ACLs) of files.CALL Calls one batch program from another.CD Displays the name of or changes the current directory.CHCP Displays or sets the active code page number.CHDIR Displays the name of or changes the current directory.CHKDSK Checks a disk and displays a status report.CHKNTFS Displays or modifies the checking of disk at boot time.CLS Clears the screen.CMD Starts a new instance of the Windows command interpreter.COLOR Sets the default console foreground and background colors.COMP Compares the contents of two files or sets of files.COMPACT Displays or alters the compression of files on NTFS partitions.CONVERT Converts FAT volumes to NTFS. You cannot convert the current drive.COPY Copies one or more files to another location.DATE Displays or sets the date.DEL Deletes one or more files.DIR Displays a list of files and subdirectories in a directory.DISKPART Displays or configures Disk Partition properties.DOSKEY Edits command lines, recalls Windows commands, and creates macros.DRIVERQUERY Displays current device driver status and properties.ECHO Displays messages, or turns command echoing on or off.ENDLOCAL Ends localization of environment changes in a batch file.ERASE Deletes one or more files.EXIT Quits the CMD.EXE program (command interpreter).FC Compares two files or sets of files, and displays the differences between them.FIND Searches for a text string in a file or files.FINDSTR Searches for strings in files.FOR Runs a specified command for each file in a set of files.FORMAT Formats a disk for use with Windows.FSUTIL Displays or configures the file system properties.FTYPE Displays or modifies file types used in file extension associations.GOTO Directs the Windows command interpreter to a labeled line in a batch program.GPRESULT Displays Group Policy information for machine or user.GRAFTABL Enables Windows to display an extended character set in graphics mode.HELP Provides Help information for Windows commands.ICACLS Display, modify, backup, or restore ACLs for files and directories.IF Performs conditional processing in batch programs.LABEL Creates, changes, or deletes the volume label of a disk.MD Creates a directory.MKDIR Creates a directory.MKLINK Creates Symbolic Links and Hard LinksMODE Configures a system device.MORE Displays output one screen at a time.MOVE Moves one or more files from one directory to another directory.OPENFILES Displays files opened by remote users for a file share.PATH Displays or sets a search path for executable files.PAUSE Suspends processing of a batch file and displays a message.POPD Restores the previous value of the current directory saved by PUSHD.PRINT Prints a text file.PROMPT Changes the Windows command prompt.PUSHD Saves the current directory then changes it.RD Removes a directory.RECOVER Recovers readable information from a bad or defective disk.REM Records comments (remarks) in batch files or CONFIG.SYS.REN Renames a file or files.RENAME Renames a file or files.REPLACE Replaces files.RMDIR Removes a directory.ROBOCOPY Advanced utility to copy files and directory treesSET Displays, sets, or removes Windows environment variables.SETLOCAL Begins localization of environment changes in a batch file.SC Displays or configures services (background processes).SCHTASKS Schedules commands and programs to run on a computer.SHIFT Shifts the position of replaceable parameters in batch files.SHUTDOWN Allows proper local or remote shutdown of machine.SORT Sorts input.START Starts a separate window to run a specified program or command.SUBST Associates a path with a drive letter.SYSTEMINFO Displays machine specific properties and configuration.TASKLIST Displays all currently running tasks including services.TASKKILL Kill or stop a running process or application.TIME Displays or sets the system time.TITLE Sets the window title for a CMD.EXE session.TREE Graphically displays the directory structure of a drive or path.TYPE Displays the contents of a text file.VER Displays the Windows version.VERIFY Tells Windows whether to verify that your files are written correctly to a disk.VOL Displays a disk volume label and serial number.XCOPY Copies files and directory trees.WMIC Displays WMI information inside interactive command shell.For more information on tools see the command-line reference in the online help.C:\Users\Qftm>
接着对终端(内置|外置)命令进行测试,测试终端cmd.exe:
测试:whoami指令先对whoami指令进行类型探测与指令定位查询
# 类型探测:外部调用指令# 定位查询:系统可实行程序C:\Users\Qftm>where whoamiC:\Windows\System32\whoami.exeC:\Users\Qftm>
然后,在cmd终端写入For循环实行whoami指令查看是否为内部实行或外部调用
C:\Users\Qftm>for /l %i in (1,1,1000000) do whoami
另一侧,打开任务管理进行cmd终真个监控,可创造whoami指令并非cmd.exe终端内置封装的指令
测试:echo指令
同样,对echo指令进行类型探测与指令定位查询
# 类型探测:内部调用指令# 定位查询:非系统可实行程序C:\Users\Qftm>where echoD:\QSoftware\W3Server\phpstudy2019\Extensions\MySQL5.7.26\bin\echo.exeC:\Users\Qftm>
然后,在cmd终端写入For循环实行echo指令查看是否为内部实行或外部调用
for /l %i in (1,1,1000000) do echo 1
另一侧,打开任务管理进行cmd终真个监控,可以创造echo指令为终端内置封装的指令,并未涌现外部调用
措辞差异
针对命令实行函数,底层实现上是否存在命令实行程序 cmd.exe、/bin/sh、/bin/bash 等,去实行命令实行函数传入的参数【系统命令】。这个过程相称于底层是否引入第三方可实行终端去实行相应命令。
比如:可实行函数(系统命令)
CommandExecFunc(echo 111 > shell.txt); //echo是一个可实行程序
上述命令实行函数模型在【Linux平台/windows平台】不同措辞下面实行效果不同。
PHPPHP - 底层调用系统终端,实行命令 Mode => Window:cmd.exe /c Command || Linux:sh -c Command
在PHP措辞里面,针对Linux平台,系统命令echo 111 > shell.txt传入CommandExecFunc函数,终极在底层相称于实行/bin/sh -c echo 111 > shell.txt。成功创建文件shell.txt【实行过程相称于:在/bin/sh终端下实行命令echo 111,并将echo结果通过重定向符写入文件shell.txt中。这里的重定向符不是echo中的参数或字符串,而是在/bin/sh下面起分外浸染。这里的echo并不是可实行程序/bin/echo,而是/bin/sh实行终端中的内建命令】【进程干系:一个进程/bin/sh,在/bin/sh进程中实行系统命令,而不是实行系统程序】
跟踪一下程序实行流程:For Linux利用strace程序实行监视可知,底层通过execve系统调用来启动干系进程、然后通过/bin/sh进程来实行干系指令(此处echo为sh内置指令)。
┌──(roottoor)-[~/桌面/CodeDebug/php]└─# strace -f -e execve php -r "system('echo 111 > shell.txt');"execve("/usr/bin/php", ["php", "-r", "system('echo 111 > shell.txt');"], 0x7ffd51277198 / 53 vars /) = 0strace: Process 3436 attached[pid 3436] execve("/bin/sh", ["sh", "-c", "echo 111 > shell.txt"], 0x562c96ef1eb0 / 53 vars /) = 0[pid 3436] +++ exited with 0 +++--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3436, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---+++ exited with 0 +++┌──(roottoor)-[~/桌面/CodeDebug/php]└─# lsshell.txt┌──(roottoor)-[~/桌面/CodeDebug/php]└─#
同理,针对Windows平台:系统命令echo 111 > shell.txt传入CommandExecFunc函数,终极在底层相称于实行cmd.exe /c echo 111 > shell.txt。成功创建文件shell.txt【实行过程相称于:在cmd终端下实行命令echo 111,并将echo结果通过重定向符写入文件shell.txt中。【进程干系:一个进程cmd.exe,在cmd.exe进程中实行系统命令,而不是实行系统程序】
跟踪一下程序实行流程:For Windows利用OD动态调试,加载php.exe程序,对干系创建进程的系统API下断点(如果不知道是那个CreateProcess API可以把查询到的都进行断点即可)
断点之后,F9使程序运行至用户交互处,然后输入PHP实行指令system('echo 111 > shell.txt');
运行PHP实行指令后,程序可到断点处,然后通过调用栈可知:底层通过CreateProcessW系统API调用来启动干系进程、然后通过cmd进程来实行干系指令(此处echo为cmd内置指令)(把稳:这里也可查看到PHP程序的完全调用链)
Java
Java - 底层不调用系统终端,自己启动传入的可实行程序 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 /) = 0strace: Process 3923 attachedPicked 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 attachedstrace: Process 3925 attachedstrace: Process 3926 attachedstrace: Process 3927 attachedstrace: Process 3928 attachedstrace: Process 3929 attachedstrace: Process 3930 attachedstrace: Process 3931 attachedstrace: 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 attachedroot[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 echoINFO: Could not find files for the given pattern(s).D:\QSec\Code-Audit\Tools\Java\Kits\RCE>where whoamiC:\Windows\System32\whoami.exeD:\QSec\Code-Audit\Tools\Java\Kits\RCE># 实行报错D:\QSec\Code-Audit\Tools\Java\Kits\RCE>javac RuntimeRCE.javaD:\QSec\Code-Audit\Tools\Java\Kits\RCE>java RuntimeRCEjava.io.IOException: Cannot run program "echo": CreateProcess error=2, The system cannot find the file specifiedD:\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 WindowsVisual Studio docsVisual Studio Code docs《PHP 7底层设计与源码实现+PHP7内核阐发》深入理解 PHP 内核WINDOWS下用VSCODE调试PHP7源代码调式PHP源码用vscode调试php源码GDB: The GNU Project DebuggerCreateProcessW function命令注入成因小谈浅谈从PHP内核层面戒备PHP WebShellProgram execution Functionslinux系统调用system calls