Golang中执行Commix命令异常问题求助
问题:Golang执行Commix工具提前退出的异常分析与解决
现象描述
执行命令 commix -r req.txt --ignore-stdin --batch 时:
- 在Linux终端和Python(v3.12.3)的subprocess调用中,Commix能正常解析HTTP请求文件并启动命令注入测试
- 但在Golang(v1.22.2)自定义的
OsExec函数中,工具仅输出[info] Parsing HTTP request...就以状态码0退出,无后续测试流程
环境与代码对比
Python 正常执行代码
import subprocess cmd = "commix -r req.txt --ignore-stdin --batch" returned_value = subprocess.call(cmd, shell=True) print(returned_value)
Golang 异常执行代码
func OsExec(command, wd string) (output string) { var ( stdout, stderr string outbuf, errbuf bytes.Buffer exitCode int ) cmd := exec.Command("/bin/sh", "-c", command) cmd.Dir = wd cmd.Env = os.Environ() cmd.Stdout = &outbuf cmd.Stderr = &errbuf err := cmd.Run() stdout = outbuf.String() stderr = errbuf.String() if err != nil { log.Printf("Error executing command: %v", err) exitCode = getErrorExitCode(err) } else { exitCode = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() } if stderr == "" && exitCode != 0 { stderr += err.Error() } output = strings.Join([]string{stdout, stderr, "Exit Status: " + strconv.Itoa(exitCode)}, "\n") output = strings.TrimPrefix(output, "\n") output = strings.TrimSuffix(output, "\n") return output } func getErrorExitCode(err error) int { if exitError, ok := err.(*exec.ExitError); ok { ws := exitError.Sys().(syscall.WaitStatus) return ws.ExitStatus() } return 1 }
临时验证方案
当修改Golang代码,去掉--ignore-stdin参数,同时将cmd.Stdout、cmd.Stderr指向os.Stdout、os.Stderr,并添加cmd.Stdin = os.Stdin后,Commix恢复正常运行。
原因分析
Commix的--ignore-stdin参数并非完全屏蔽所有stdin相关检查:
- 在终端或Python环境中,子进程默认继承父进程的stdin(处于打开状态),即使没有输入,Commix也能继续执行后续流程
- 而Golang的
exec.Command默认不设置Stdin,导致子进程的stdin处于关闭状态。Commix在解析完请求后,可能因检测到stdin关闭而提前退出,而非触发命令注入测试逻辑
解决方案
在Golang的OsExec函数中,显式为子进程设置Stdin,即使使用--ignore-stdin参数也能正常执行:
修改后的OsExec函数
func OsExec(command, wd string) (output string) { var ( stdout, stderr string outbuf, errbuf bytes.Buffer exitCode int ) cmd := exec.Command("/bin/sh", "-c", command) cmd.Dir = wd cmd.Env = os.Environ() cmd.Stdout = &outbuf cmd.Stderr = &errbuf // 显式设置Stdin为os.Stdin,保持stdin处于打开状态 cmd.Stdin = os.Stdin err := cmd.Run() stdout = outbuf.String() stderr = errbuf.String() if err != nil { log.Printf("Error executing command: %v", err) exitCode = getErrorExitCode(err) } else { exitCode = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() } if stderr == "" && exitCode != 0 { stderr += err.Error() } output = strings.Join([]string{stdout, stderr, "Exit Status: " + strconv.Itoa(exitCode)}, "\n") output = strings.TrimPrefix(output, "\n") output = strings.TrimSuffix(output, "\n") return output } func getErrorExitCode(err error) int { if exitError, ok := err.(*exec.ExitError); ok { ws := exitError.Sys().(syscall.WaitStatus) return ws.ExitStatus() } return 1 }
替代方案(无交互场景)
如果不需要从stdin读取输入,也可以将Stdin设置为io.NopCloser(strings.NewReader("")),模拟一个打开但无内容的stdin:
import "strings" import "io" // 在cmd设置中替换为: cmd.Stdin = io.NopCloser(strings.NewReader(""))
内容的提问来源于stack exchange,提问作者PotatoDeveloper
相关产品推荐
相关产品推荐

