ซ่อนอาร์กิวเมนต์ของโปรแกรมโดยไม่มีซอร์สโค้ด


15

ฉันต้องซ่อนอาร์กิวเมนต์ที่ละเอียดอ่อนบางอย่างกับโปรแกรมที่ฉันกำลังใช้งานอยู่ แต่ฉันไม่สามารถเข้าถึงซอร์สโค้ดได้ ฉันกำลังเรียกใช้สิ่งนี้บนเซิร์ฟเวอร์ที่ใช้ร่วมกันดังนั้นฉันจึงไม่สามารถใช้สิ่งที่ชอบhidepidเพราะฉันไม่มีสิทธิ์แบบ sudo

นี่คือบางสิ่งที่ฉันได้ลอง:

  • export SECRET=[my arguments]ตามด้วยการโทรศัพท์ถึง./program $SECRETแต่ดูเหมือนจะไม่ช่วย

  • ./program `cat secret.txt`secret.txtมีการถกเถียงของฉันอยู่ที่ไหนแต่ผู้ทรงอำนาจpsสามารถดมความลับของฉันออกไปได้

มีวิธีอื่นในการซ่อนข้อโต้แย้งของฉันที่ไม่เกี่ยวข้องกับการแทรกแซงของผู้ดูแลระบบหรือไม่?


โปรแกรมพิเศษนั้นคืออะไร? ถ้ามันเป็นคำสั่งปกติคุณต้องบอก (และอาจมีวิธีอื่น) ซึ่งเป็น
Basile Starynkevitch

14
ดังนั้นคุณเข้าใจว่าเกิดอะไรขึ้นสิ่งที่คุณพยายามจะไม่มีโอกาสทำงานเพราะเชลล์มีหน้าที่รับผิดชอบในการขยายตัวแปรสภาพแวดล้อมและดำเนินการทดแทนคำสั่งก่อนที่จะเรียกใช้โปรแกรม psไม่ได้ทำสิ่งมหัศจรรย์เพื่อ "ดมความลับของคุณ" อย่างไรก็ตามโปรแกรมที่เขียนขึ้นอย่างมีเหตุผลควรเสนอตัวเลือกบรรทัดคำสั่งเพื่ออ่านความลับจากไฟล์ที่ระบุหรือจาก stdin แทนที่จะใช้เป็นอาร์กิวเมนต์โดยตรง
jamesdlin

ฉันใช้โปรแกรมจำลองสภาพอากาศเขียนโดย บริษัท เอกชน พวกเขาไม่เปิดเผยซอร์สโค้ดของพวกเขาและเอกสารของพวกเขาไม่มีวิธีใด ๆ ในการแบ่งปันความลับจากไฟล์ อาจจะไม่มีตัวเลือกที่นี่
MS

คำตอบ:


25

ตามที่อธิบายไว้ที่นี่ Linux วางอาร์กิวเมนต์ของโปรแกรมในพื้นที่ข้อมูลของโปรแกรมและเก็บตัวชี้ไปที่จุดเริ่มต้นของพื้นที่นี้ นี่คือสิ่งที่ถูกใช้โดยpsและอื่น ๆ เพื่อค้นหาและแสดงข้อโต้แย้งของโปรแกรม

เนื่องจากข้อมูลอยู่ในพื้นที่ของโปรแกรมจึงสามารถจัดการได้ การทำสิ่งนี้โดยไม่เปลี่ยนแปลงโปรแกรมนั้นเกี่ยวข้องกับการโหลด shim พร้อมกับmain()ฟังก์ชั่นที่จะถูกเรียกใช้ก่อน main main ของโปรแกรม ชิมนี้สามารถคัดลอกอาร์กิวเมนต์จริงไปยังช่องว่างใหม่จากนั้นเขียนทับอาร์กิวเมนต์เดิมเพื่อที่psจะเห็น nuls

รหัส C ต่อไปนี้เป็นสิ่งนี้

/* /unix//a/403918/119298
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_main.so shim_main.c
 * LD_PRELOAD=/.../shim_main.so theprogram theargs...
 */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>

typedef int (*pfi)(int, char **, char **);
static pfi real_main;

/* copy argv to new location */
char **copyargs(int argc, char** argv){
    char **newargv = malloc((argc+1)*sizeof(*argv));
    char *from,*to;
    int i,len;

    for(i = 0; i<argc; i++){
        from = argv[i];
        len = strlen(from)+1;
        to = malloc(len);
        memcpy(to,from,len);
        memset(from,'\0',len);    /* zap old argv space */
        newargv[i] = to;
        argv[i] = 0;
    }
    newargv[argc] = 0;
    return newargv;
}

static int mymain(int argc, char** argv, char** env) {
    fprintf(stderr, "main argc %d\n", argc);
    return real_main(argc, copyargs(argc,argv), env);
}

int __libc_start_main(pfi main, int argc,
                      char **ubp_av, void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void), void (*stack_end)){
    static int (*real___libc_start_main)() = NULL;

    if (!real___libc_start_main) {
        char *error;
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if ((error = dlerror()) != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    real_main = main;
    return real___libc_start_main(mymain, argc, ubp_av, init, fini,
            rtld_fini, stack_end);
}

มันเป็นไปไม่ได้ที่จะเข้าไปแทรกแซงmain()แต่คุณสามารถเข้าไปแทรกแซงในฟังก์ชั่นไลบรารีมาตรฐาน C __libc_start_mainซึ่งจะไปเรียกหลัก รวบรวมไฟล์นี้shim_main.cตามที่ระบุไว้ในความคิดเห็นที่เริ่มต้นและเรียกใช้ตามที่แสดง ฉันได้ใส่printfรหัสไว้ดังนั้นคุณตรวจสอบว่ามันถูกเรียกจริงๆ ตัวอย่างเช่นเรียกใช้

LD_PRELOAD=/tmp/shim_main.so /bin/sleep 100

จากนั้นทำpsและคุณจะเห็นคำสั่งว่างและ args จะถูกแสดง

ยังมีเวลาอีกเล็กน้อยที่คำสั่ง args อาจมองเห็นได้ เพื่อหลีกเลี่ยงปัญหานี้ตัวอย่างเช่นคุณสามารถเปลี่ยน shim เพื่ออ่านความลับของคุณจากไฟล์และเพิ่มไปยัง args ที่ส่งไปยังโปรแกรม


12
แต่จะยังคงมีหน้าต่างสั้น ๆ ในระหว่างที่/proc/pid/cmdlineจะแสดงความลับ (เช่นเดียวกับเมื่อcurlพยายามซ่อนรหัสผ่านที่ได้รับในบรรทัดคำสั่ง) ในขณะที่คุณใช้ LD_PRELOAD คุณสามารถล้อมหลักเพื่อให้ความลับถูกคัดลอกจากสภาพแวดล้อมไปยัง argv ที่ main ได้รับ เช่นเดียวกับการโทรLD_PRELOAD=x SECRET=y cmdที่คุณโทรmain()กับargv[]การเป็น[argv[0], getenv("SECRET")]
Stéphane Chazelas

/proc/pid/environคุณไม่สามารถใช้สภาพแวดล้อมที่จะซ่อนความลับที่มันสามารถมองเห็นได้ผ่านทาง สิ่งนี้อาจเขียนทับได้ในลักษณะเดียวกับ args แต่ออกจากหน้าต่างเดียวกัน
meuh

11
/proc/pid/cmdlineเป็นสาธารณะ/proc/pid/environไม่ใช่ มีบางระบบที่ps(ปฏิบัติการที่ setuid) เปิดเผยสภาพแวดล้อมของกระบวนการใด ๆ แต่ฉันไม่คิดว่าคุณจะเจอทุกวันนี้ สภาพแวดล้อมโดยทั่วไปถือว่าปลอดภัยเพียงพอ ไม่ปลอดภัยที่จะสอดแนมจากกระบวนการที่มี euid เหมือนกัน แต่สิ่งเหล่านั้นมักจะสามารถอ่านหน่วยความจำของกระบวนการด้วย euid ต่อไปดังนั้นคุณจึงไม่สามารถทำอะไรได้มากนัก
Stéphane Chazelas

4
@ StéphaneChazelas: หากมีใครใช้สภาพแวดล้อมในการส่งผ่านความลับโดยเฉพาะอย่างยิ่งเสื้อคลุมที่ส่งต่อไปยังmainวิธีการของโปรแกรมที่ห่อก็จะลบตัวแปรสภาพแวดล้อมเพื่อหลีกเลี่ยงการรั่วไหลของกระบวนการเด็ก อีกทางเลือกหนึ่ง wrapper สามารถอ่านอาร์กิวเมนต์บรรทัดคำสั่งทั้งหมดจากไฟล์
David Foerster

@ DavidFoerster จุดดี ฉันได้อัปเดตคำตอบเพื่อนำมาพิจารณาแล้ว
Stéphane Chazelas

16
  1. อ่านเอกสารประกอบของอินเตอร์เฟสบรรทัดคำสั่งของแอปพลิเคชันที่เป็นปัญหา อาจมีตัวเลือกในการระบุความลับจากไฟล์แทนที่จะเป็นอาร์กิวเมนต์โดยตรง

  2. หากล้มเหลวให้ยื่นรายงานข้อผิดพลาดกับแอปพลิเคชันโดยอ้างว่าไม่มีวิธีที่ปลอดภัยในการส่งข้อมูลลับให้

  3. คุณสามารถปรับแก้ปัญหาด้วยคำตอบของความต้องการเฉพาะของคุณ พิจารณาเป็นพิเศษถึงความคิดเห็นของStéphaneและการติดตามผล


12

หากคุณต้องการส่งผ่านข้อโต้แย้งไปยังโปรแกรมเพื่อให้ทำงานได้คุณจะโชคดีไม่ว่าคุณจะทำอะไรถ้าคุณไม่สามารถใช้hidepidprocfs ได้

เนื่องจากคุณพูดถึงว่านี่เป็นสคริปต์ทุบตีคุณควรมีซอร์สโค้ดอยู่แล้วเนื่องจากทุบตีไม่ใช่ภาษาที่รวบรวม

ความล้มเหลวที่คุณอาจจะสามารถที่จะเขียน cmdline ของกระบวนการที่ใช้gdbหรือคล้ายกันและการเล่นรอบกับargc/ argvเมื่อมีการเริ่มต้นแล้ว แต่:

  1. สิ่งนี้ไม่ปลอดภัยเนื่องจากคุณยังคงเปิดเผยข้อโต้แย้งของโปรแกรมในตอนแรกก่อนที่จะเปลี่ยนแปลง
  2. นี่มันแฮ็กสวยแม้ว่าคุณจะเอามันไปใช้งานได้ฉันก็ไม่แนะนำให้ใช้มัน

ฉันแค่แนะนำให้รับซอร์สโค้ดหรือคุยกับผู้จำหน่ายเพื่อขอแก้ไขโค้ด การจัดหาความลับบนบรรทัดคำสั่งในระบบปฏิบัติการ POSIX ไม่สามารถทำงานร่วมกับการดำเนินการที่ปลอดภัยได้


11

เมื่อกระบวนการดำเนินการคำสั่ง (ผ่านการexecve()เรียกของระบบ) หน่วยความจำของมันจะถูกเช็ด ในการส่งผ่านข้อมูลบางส่วนระหว่างการดำเนินการการเรียกของexecve()ระบบจะใช้อาร์กิวเมนต์สองตัวคือ: argv[]และenvp[]อาร์เรย์

นี่คือสองอาร์เรย์ของสตริง:

  • argv[] มีข้อโต้แย้ง
  • envp[]มีนิยามตัวแปรสภาพแวดล้อมเป็นสตริงในvar=valueรูปแบบ (ตามแบบแผน)

เมื่อคุณทำ:

export SECRET=value; cmd "$SECRET"

(ที่นี่เพิ่มคำพูดที่ขาดหายไปรอบ ๆ การขยายตัวพารามิเตอร์)

คุณกำลังดำเนินการcmdกับความลับ ( value) ผ่านทั้งในและargv[] จะเป็นและสิ่งที่ต้องการ เนื่องจากไม่ได้ดำเนินการใด ๆหรือเทียบเท่าเพื่อดึงค่าความลับจากตัวแปรสภาพแวดล้อมนั้นการวางไว้ในสภาพแวดล้อมจึงไม่มีประโยชน์envp[]argv[]["cmd", "value"]envp[][..., "PATH=/bin:...", "HOME=...", ..., "SECRET=value", "TERM=xterm", ...]cmdgetenv("SECRET")SECRET

argv[]เป็นความรู้สาธารณะ psมันแสดงให้เห็นในการส่งออกของ envp[]ทุกวันนี้ไม่ได้ บน Linux /proc/pid/environก็แสดงให้เห็นใน มันแสดงให้เห็นในการส่งออกของps ewwwบน BSDs (และกับ procps-ng psบน Linux) แต่เฉพาะกับกระบวนการทำงานด้วย uid ที่มีประสิทธิภาพเดียวกัน (และมีข้อ จำกัด มากขึ้นสำหรับ executables setuid / setgid) มันอาจแสดงในบันทึกการตรวจสอบบางอย่าง แต่ผู้ดูแลระบบควรเข้าถึงบันทึกการตรวจสอบเหล่านั้นได้

ในระยะสั้นสภาพแวดล้อมที่ส่งผ่านไปยังการปฏิบัติการหมายถึงความเป็นส่วนตัวหรืออย่างน้อยเกี่ยวกับความเป็นส่วนตัวเป็นหน่วยความจำภายในของกระบวนการ ยังถูกทิ้งลงดิสก์)

เนื่องจากargv[]เป็นความรู้สาธารณะคำสั่งที่คาดว่าข้อมูลที่เป็นความลับในบรรทัดคำสั่งจะถูกทำลายโดยการออกแบบ

โดยปกติแล้วคำสั่งที่จำเป็นต้องให้ความลับให้อินเทอร์เฟซอื่นสำหรับการทำเช่นผ่านตัวแปรสภาพแวดล้อม ตัวอย่างเช่น

IPMI_PASSWORD=secret ipmitool -I lan -U admin...

หรือผ่านตัวให้คำอธิบายไฟล์เฉพาะเช่น stdin:

echo secret | openssl rsa -passin stdin ...

( echoการสร้างขึ้นภายในจะไม่แสดงในผลลัพธ์ของps)

หรือไฟล์เช่นคำสั่ง.netrcfor ftpและคำสั่งอื่น ๆ หรือ

mysql --defaults-extra-file=/some/file/with/password ....

แอปพลิเคชันบางอย่างเช่นcurl(และนี่เป็นวิธีการที่ @meuh ที่นี่ ) พยายามซ่อนรหัสผ่านที่พวกเขาได้รับargv[]จากการสอดรู้สอดเห็น (ในบางระบบโดยเขียนทับส่วนของหน่วยความจำที่argv[]เก็บสตริงไว้) แต่นั่นไม่ได้ช่วยและให้สัญญาความปลอดภัยผิด ๆ ที่ออกจากหน้าต่างในระหว่างexecve()และการเขียนทับที่psจะยังคงแสดงความลับ

ตัวอย่างเช่นหากผู้โจมตีรู้ว่าคุณกำลังเรียกใช้สคริปต์ที่ทำcurl -u user:somesecret https://...(ตัวอย่างเช่นในงาน cron) สิ่งที่เขาต้องทำคือขับไล่ออกจากแคชห้องสมุด (หลายแห่ง) ที่curlใช้ (เช่นการเรียกใช้sh -c 'a=a;while :; do a=$a$a;done') เพื่อชะลอการเริ่มต้นและการทำสิ่งที่ไม่มีประสิทธิภาพuntil grep 'curl.*[-]u' /proc/*/cmdline; do :; doneก็เพียงพอที่จะใช้รหัสผ่านนั้นในการทดสอบของฉัน

หากการขัดแย้งเป็นวิธีเดียวที่คุณสามารถส่งความลับไปยังคำสั่งอาจมีบางสิ่งที่คุณสามารถลอง

ในบางระบบรวมถึง Linux เวอร์ชันเก่ามีเพียงไม่กี่ไบต์แรก (4096 บน Linux 4.1 และก่อน) ของสตริงที่argv[]สามารถสอบถามได้

ที่นั่นคุณสามารถทำ:

(exec -a "$(printf %-4096s cmd)" cmd "$secret")

และความลับจะถูกซ่อนไว้เพราะผ่าน 4096 ไบต์แรก ตอนนี้คนที่ได้ใช้วิธีการที่จะต้องเสียใจมันตั้งแต่ตอนนี้ลินุกซ์ตั้งแต่ 4.2 ไม่ตัดทอนรายการ args /proc/pid/cmdlineใน โปรดทราบด้วยว่านั่นไม่ใช่เพราะpsจะไม่แสดงมากกว่าหนึ่งไบต์ของบรรทัดคำสั่ง (เช่น FreeBSD ซึ่งดูเหมือนว่าจะถูก จำกัด อยู่ที่ 2048) ซึ่งไม่สามารถใช้กับ API เดียวกันpsได้เพื่อให้ได้มากขึ้น วิธีการนั้นใช้ได้ในระบบที่psเป็นวิธีเดียวที่ผู้ใช้ทั่วไปสามารถดึงข้อมูลนั้นได้ (เช่นเมื่อ API ได้รับการยกเว้นและpssetgid หรือ setuid เพื่อใช้งาน) แต่ก็อาจไม่สามารถพิสูจน์ได้ในอนาคต

อีกวิธีหนึ่งที่จะไม่ผ่านความลับในargv[]แต่รหัสฉีดลงในโปรแกรม (ใช้gdbหรือ$LD_PRELOADสับ) ก่อนที่จะmain()มีการเริ่มต้นที่แทรกลับเข้าไปในที่ได้รับจากargv[]execve()

ด้วยLD_PRELOAD, สำหรับ non-setuid / setgid ที่เชื่อมโยงแบบไดนามิก executables บนระบบ GNU:

/* 
 * replace ***** with secret read from fd 9
 * gcc -Wall -fpic -shared -o inject_secret.so inject_secret.c -ldl 
 * LD_PRELOAD=/.../inject_secret.so cmd -p '*****' 9<<< secret
 */
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>

#define PLACEHOLDER "*****"
static char secret[1024];

int __libc_start_main(int (*main) (int, char**, char**),
                      int argc,
                      char **argv,
                      void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void),
                      void (*stack_end)){
    static int (*real_libc_start_main)() = NULL;
    int n;

    if (!real_libc_start_main) {
        real_libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if (!real_libc_start_main) abort();
    }

    n = read(9, secret, sizeof(secret));
    if (n > 0) {
      int i;

      if (secret[n - 1] == '\n') secret[--n] = '\0'; 
      for (i = 1; i < argc; i++)
        if (strcmp(argv[i], PLACEHOLDER) == 0)
          argv[i] = secret;
    }

    return real_libc_start_main(main, argc, argv, init, fini,
                                rtld_fini, stack_end);
}

แล้ว:

$ gcc -Wall -fpic -shared -o inject_secret.so inject_secret.c -ldl
$ LD_PRELOAD=$PWD/inject_secret.so  ps '*****' 9<<< "-opid,args"
  PID COMMAND
 7659 /bin/zsh
 8828 ps *****

ไม่มีจุดที่จะpsแสดงให้เห็นว่าps -opid,argsมี ( -opid,argsเป็นความลับในตัวอย่างนี้) โปรดทราบว่าเรากำลังเปลี่ยนองค์ประกอบของargv[]อาร์เรย์ของตัวชี้psไม่เอาชนะสตริงชี้ไปตามคำแนะนำเหล่านั้นซึ่งเป็นเหตุผลที่การปรับเปลี่ยนของเราไม่ได้แสดงให้เห็นในการส่งออกของ

ด้วยgdbยังสำหรับ non-setuid / setgid ที่เชื่อมโยงแบบไดนามิก executables และระบบ GNU:

tmp=$(mktemp) && cat << EOF > "$tmp" &&
break __libc_start_main
commands 1
set argv[1]="-opid,args"
continue
end
run
EOF

gdb -n --batch-silent --return-child-result -x "$tmp" --args ps '*****'
rm -f -- "$tmp"

ด้วยgdbวิธีการที่ไม่ใช่ GNU โดยเฉพาะที่ไม่ต้องพึ่งพาไฟล์ประมวลผลที่เชื่อมโยงแบบไดนามิกหรือมีสัญลักษณ์แก้จุดบกพร่องและควรใช้งานได้กับ ELF ที่รันได้บน Linux อย่างน้อยก็อาจเป็น:

#! /bin/sh -
# gdb+sh polyglot script to replace "*****" arguments with the content
# of the SECRET environment variable *after* execve and before calling
# the executable's main() function.
#
# Usage: SECRET=somesecret cmd --password '*****'

if ':' - ':'
then
  # running in sh
  # retrieve the start address for the executable
  start=$(
    LC_ALL=C objdump -f -- "$(command -v -- "${1?}")" |
    sed -n 's/^start address //p'
  )
  [ -n "$start" ] || exit
  # re-exec ourself with gdb.
  exec gdb -n --batch-silent --return-child-result -iex "set \$start = $start" -x "$0" --args "$@"
  exit 1
fi
end
# running in gdb
break *$start
commands 1
  # The stack on startup contains:
  # argc argv[0]... argv[argc-1] 0 envp[0] envp[1]... 0 argv[] and envp[] strings
  set $argc = *((int*)$sp)
  set $argv = &((char**)$sp)[1]
  set $envp = &($argv[$argc+1])
  set $i = 0
  while $envp[$i]
    # look for an envp[] string starting with "SECRET=". We can't use strcmp()
    # here as there's no guarantee that the debugged executable has such
    # a function
    set $e = $envp[$i]
    if $e[0] == 'S' && \
       $e[1] == 'E' && \
       $e[2] == 'C' && \
       $e[3] == 'R' && \
       $e[4] == 'E' && \
       $e[5] == 'T' && \
       $e[6] == '='
      set $secret = &($e[7])
      # replace SECRET=xxx<NUL> with SECRE=<NUL>
      set $e[5] = '='
      set $e[6] = '\0'
      # not calling loop_break as that causes a SEGV with my version of gdb
    end
    set $i = $i + 1
  end
  if $secret
    # now looking for argv[] strings being "*****" and replace them with
    # the secret identified earlier
    set $i = 0
    while $i < $argc
      set $a = $argv[$i]
      if $a[0] == '*' && \
       $a[1] == '*' && \
       $a[2] == '*' && \
       $a[3] == '*' && \
       $a[4] == '*' && \
       $a[5] == '\0'
        set $argv[$i] = $secret
      end
      set $i = $i + 1
    end
  end
  # using "continue" as "detach" causes a SEGV with my version of gdb.
  continue
end
run

ทดสอบกับปฏิบัติการที่เชื่อมโยงแบบคงที่:

$ SECRET=/proc/self/cmdline ./replace_secret busybox cat '*****' | tr '\0' '\n'
/bin/busybox
cat
*****

เมื่อปฏิบัติการอาจคงที่เราไม่มีวิธีที่เชื่อถือได้ในการจัดสรรหน่วยความจำเพื่อเก็บความลับดังนั้นเราจึงต้องรับความลับจากที่อื่นที่อยู่ในหน่วยความจำกระบวนการ นั่นเป็นเหตุผลที่สภาพแวดล้อมเป็นตัวเลือกที่ชัดเจนที่นี่ นอกจากนี้เรายังซ่อนSECRETenv var ให้กับกระบวนการ (โดยเปลี่ยนเป็นSECRE=) เพื่อหลีกเลี่ยงการรั่วไหลหากกระบวนการตัดสินใจถ่ายโอนข้อมูลสภาพแวดล้อมด้วยเหตุผลบางอย่างหรือดำเนินการแอปพลิเคชันที่ไม่น่าเชื่อถือ

ที่ยังใช้งานได้บน Solaris 11 (gdb ที่ให้บริการและ GNU binutils มีการติดตั้ง (คุณอาจต้องเปลี่ยนชื่อobjdumpไปgobjdump)

บน FreeBSD (อย่างน้อย x86_64 ผมไม่แน่ใจว่าสิ่งที่แรก 24 ไบต์ (ซึ่งกลายเป็น 16 เมื่อ gdb (8.0.1) มีการโต้ตอบบอกว่าอาจจะมีข้อผิดพลาดใน gdb มี) ในกองมี) แทนargcและargvคำจำกัดความ ด้วย:

set $argc = *((int*)($sp + 24))
set $argv = &((char**)$sp)[4]

(คุณอาจต้องติดตั้งgdbแพ็กเกจ / พอร์ตเนื่องจากเวอร์ชันที่มาพร้อมกับระบบนั้นเก่าแก่)


Re (ที่นี่เพิ่มเครื่องหมายคำพูดที่ขาดหายไปรอบ ๆ การขยายพารามิเตอร์): เกิดอะไรขึ้นถ้าไม่ใช้เครื่องหมายคำพูด? มีความแตกต่างจริงๆเหรอ?
yukashima huksay

@ yukashimahuksay ให้ดูตัวอย่างความหมายของความปลอดภัยในการลืมอ้างตัวแปรใน bash / POSIX shellsและคำถามที่เชื่อมโยงอยู่ที่นั่น
Stéphane Chazelas

3

สิ่งที่คุณอาจทำคือ

 export SECRET=somesecretstuff

จากนั้นสมมติว่าคุณเขียนของคุณ./programใน C (หรือคนอื่นทำและสามารถเปลี่ยนแปลงหรือปรับปรุงให้คุณ) ใช้getenv (3)ในโปรแกรมนั้นอาจจะเป็น

char* secret= getenv("SECRET");

และหลังจากที่export คุณเพิ่งทำงาน./programในเปลือกเดียวกัน หรือชื่อตัวแปรสภาพแวดล้อมสามารถส่งผ่านได้ (โดยการเรียกใช้./program --secret-var=SECRETฯลฯ ... )

psจะไม่บอกเกี่ยวกับความลับของคุณ แต่proc (5)ยังสามารถให้ข้อมูลจำนวนมาก (อย่างน้อยกับกระบวนการอื่น ๆ ของผู้ใช้เดียวกัน)

ดูสิ่งนี้เพื่อช่วยในการออกแบบวิธีที่ดีกว่าในการส่งอาร์กิวเมนต์ของโปรแกรม

ดูคำตอบนี้สำหรับคำอธิบายที่ดีกว่าเกี่ยวกับการปัดเศษและบทบาทของเปลือกหอย

บางทีคุณอาจprogramมีวิธีอื่นในการรับข้อมูล (หรือใช้การสื่อสารระหว่างกระบวนการอย่างชาญฉลาด) กว่าข้อโต้แย้งของโปรแกรมธรรมดา (แน่นอนควรถ้ามีวัตถุประสงค์เพื่อประมวลผลข้อมูลที่ละเอียดอ่อน) อ่านเอกสารของมัน หรือบางทีคุณอาจใช้โปรแกรมนั้นในทางที่ผิด (ซึ่งไม่ได้มีวัตถุประสงค์เพื่อประมวลผลข้อมูลลับ)

การซ่อนข้อมูลลับเป็นเรื่องยากมาก ไม่ผ่านมันผ่านโปรแกรมข้อโต้แย้งไม่เพียงพอ


5
มันสวยใสจากคำถามที่ว่าเขาไม่ได้มีรหัสที่มาสำหรับ./programดังนั้นในช่วงครึ่งแรกของคำตอบนี้ไม่ได้ดูเหมือนจะมีความเกี่ยวข้อง
ท่อ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.