คุณสามารถบอกเชลล์ของคุณให้บอกแอปพลิเคชันว่าเชลล์โค้ดใดบ้างที่นำไปสู่การดำเนินการ ตัวอย่างเช่นด้วยการzsh
ส่งข้อมูลใน$SHELL_CODE
ตัวแปรสภาพแวดล้อมโดยใช้preexec()
hook ( printenv
ใช้เป็นตัวอย่างคุณจะใช้getenv("SHELL_CODE")
ในโปรแกรมของคุณ):
$ preexec() export SHELL_CODE=$1
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv SHELL_CODE
printenv CODE
$ $(echo printenv SHELL_CODE)
$(echo printenv SHELL_CODE)
$ for i in SHELL_CODE; do printenv "$i"; done
for i in SHELL_CODE; do printenv "$i"; done
$ printenv SHELL_CODE; : other command
printenv SHELL_CODE; : other command
$ f() printenv SHELL_CODE
$ f
f
ทั้งหมดเหล่านั้นจะดำเนินการprintenv
เป็น:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
อนุญาตให้printenv
เรียกคืนรหัส zsh ที่นำไปสู่การดำเนินการprintenv
กับอาร์กิวเมนต์เหล่านั้น สิ่งที่คุณต้องการจะทำกับข้อมูลนั้นไม่ชัดเจนสำหรับฉัน
ด้วยbash
คุณลักษณะที่ใกล้เคียงกับzsh
's preexec()
จะใช้มัน$BASH_COMMAND
ในDEBUG
กับดัก แต่ทราบว่าbash
จะระดับของการเขียนใหม่ในการที่ (และใน refactors เฉพาะบางส่วนของช่องว่างที่ใช้เป็นตัวคั่น) และที่นำไปใช้กับทุกคน (ดีพอใช้) บางคำสั่ง ทำงานไม่ใช่บรรทัดคำสั่งทั้งหมดตามที่ป้อนที่พรอมต์ (ดูเพิ่มเติมที่functrace
ตัวเลือก)
$ trap 'export SHELL_CODE="$BASH_COMMAND"' DEBUG
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv $(echo 'SHELL_CODE')
printenv $(echo 'SHELL_CODE')
$ for i in SHELL_CODE; do printenv "$i"; done; : other command
printenv "$i"
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printf '%s\n' "$(printenv "SHELL_CODE")"
$ set -o functrace
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printenv "SHELL_CODE"
$ print${-+env } $(echo 'SHELL_CODE')
print${-+env } $(echo 'SHELL_CODE')
ดูว่าช่องว่างบางส่วนที่เป็นตัวคั่นในไวยากรณ์ภาษาของเชลล์ถูกบีบอัดเป็น 1 และวิธีที่บรรทัดคำสั่งเต็มไม่ได้ถูกส่งผ่านไปยังคำสั่งเสมอไป ดังนั้นอาจไม่มีประโยชน์ในกรณีของคุณ
โปรดทราบว่าฉันไม่แนะนำให้ทำสิ่งนี้เนื่องจากคุณอาจรั่วไหลข้อมูลที่ละเอียดอ่อนไปยังทุกคำสั่งเช่นเดียวกับใน:
echo very_secret | wc -c | untrustedcmd
จะรั่วไหลความลับที่ทั้งสองและwc
untrustedcmd
แน่นอนคุณสามารถทำสิ่งนั้นกับภาษาอื่นที่ไม่ใช่เปลือก ตัวอย่างเช่นใน C คุณสามารถใช้มาโครบางตัวที่ส่งออกรหัส C ที่ดำเนินการคำสั่งไปยังสภาพแวดล้อม:
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define WRAP(x) (setenv("C_CODE", #x, 1), x)
int main(int argc, char *argv[])
{
if (!fork()) WRAP(execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (!fork()) WRAP(0 + execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (argc > 1 && !fork()) WRAP(execvp(argv[1], &argv[1]));
wait(NULL);
return 0;
}
ตัวอย่าง:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
ดูว่าช่องว่างบางส่วนถูกรวมโดยตัวประมวลผลล่วงหน้า C เช่นในกรณีทุบตี ส่วนใหญ่ถ้าไม่ใช่ทุกภาษาจำนวนเนื้อที่ที่ใช้ในตัวคั่นนั้นไม่ต่างกันดังนั้นจึงไม่น่าแปลกใจที่คอมไพเลอร์ / ล่ามใช้เสรีภาพกับพวกเขาที่นี่