ฉันสามารถป้องกันโฟลเดอร์ที่สร้างชื่อเฉพาะได้หรือไม่?


16

ฉันกำลังทำงานกับ LAMP เว็บแอพและมีกระบวนการที่กำหนดไว้ที่ไหนสักแห่งที่จะสร้างโฟลเดอร์ที่เรียกว่าshopในรากของเว็บไซต์ ทุกครั้งที่สิ่งนี้ปรากฏขึ้นจะทำให้เกิดความขัดแย้งกับกฎการเขียนซ้ำในแอปไม่ดี

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


4
เพื่อหาสิ่งที่ทำสร้างคุณสามารถเปิดใช้งานการตรวจสอบ
Andrew Henle

คำตอบ:


30

คุณทำไม่ได้เนื่องจากผู้ใช้ที่สร้างไดเรกทอรีมีสิทธิ์เพียงพอที่จะเขียนในไดเรกทอรีหลัก

คุณสามารถใช้ประโยชน์จากinotifyตระกูลของการโทรของระบบโดยเคอร์เนล Linux เพื่อเฝ้าดูการสร้าง (และตัวเลือกmv) ของไดเรกทอรีshopในไดเรกทอรีที่กำหนดถ้าสร้าง (หรือสร้างทางเลือกmv) rmไดเรกทอรี

โปรแกรม userspace ที่คุณต้องการในกรณีนี้คือinotifywait(มาพร้อมกับinotify-toolsติดตั้งก่อนถ้าจำเป็น)


สมมติว่าไดเรกทอรีshopจะอยู่ใน/foo/barไดเรกทอรีให้ตั้งค่าการตรวจสอบเพื่อ/foo/bar/shopสร้างและrmทันทีหากสร้าง:

inotifywait -qme create /foo/bar | \
             awk '/,ISDIR shop$/ { system("rm -r -- /foo/bar/shop") }'
  • inotifywait -qme create /foo/barเฝ้าดู/foo/barไดเรกทอรีสำหรับไฟล์ / ไดเรกทอรีใด ๆ ที่อาจสร้างขึ้นเช่นเฝ้าดูcreateเหตุการณ์ใด ๆ

  • หากสร้างขึ้นให้awk '/,ISDIR shop$/ { system("rm -r -- /foo/bar/shop") }'ตรวจสอบว่าไฟล์เกิดขึ้นเป็นไดเรกทอรีหรือไม่และชื่อคือshop( /,ISDIR shop$/) ถ้าเป็นเช่นนั้นrmไดเรกทอรี ( system("rm -r -- /foo/bar/shop"))

คุณต้องเรียกใช้คำสั่งในฐานะผู้ใช้ที่มีสิทธิ์เขียนในไดเรกทอรี/foo/barเพื่อลบออกshopจากไดเรกทอรี


หากคุณต้องการตรวจสอบmvการทำงานด้วยให้เพิ่มการเฝ้าดูmoved_toกิจกรรมด้วย:

inotifywait -qme create,moved_to /foo/bar | \
             awk '/,ISDIR shop$/ { system("rm -r -- /foo/bar/shop") }'

ที่จะต้องทราบหากคุณกำลังมองหาไฟล์ไม่ใช่ไดเรกทอรีชื่อshop:

inotifywait -qme create /foo/bar | \
                 awk '$NF == "shop" { system("rm -- /foo/bar/shop") }'

inotifywait -qme create,moved_to /foo/bar | \
                 awk '$NF == "shop" { system("rm -- /foo/bar/shop") }'

2
ยิ่งไปกว่านั้นถ้าคุณใช้inotifywaitในการทำสิ่งนี้อาจเป็นไปได้ว่าไกก็สามารถจับกระบวนการด้วยps -ef
roaima

30

ตอบตัวอักษรตามคำถามที่ป้องกันไม่ให้สร้างโฟลเดอร์ชื่อที่แน่นอน

touch shop

คุณไม่สามารถสร้างไดเรกทอรีได้หากไฟล์ที่มีชื่อเหมือนกันอยู่แล้ว

mkdir: cannot create directory ‘shop’: File exists


6
* นี้อาจไม่เพียงพอ mkdir อาจไม่สามารถทำได้ แต่สามารถทำได้ มันเป็นความพยายามครั้งแรกที่ดี
coteyr

9
บนระบบ Linux ใช้chattr +i shopเพื่อทำให้ไม่เปลี่ยนรูป จนกว่าการตั้งค่าสถานะไม่เปลี่ยนรูปจะไม่สามารถเปลี่ยนชื่อ / ลบได้
. GitHub หยุดช่วยน้ำแข็ง

1
นี่เป็นเคล็ดลับเล็ก ๆ น้อย ๆ ที่ไม่เหมาะกับสถานการณ์ของฉัน แต่เป็นความคิดที่ฉลาดสำหรับบางสถานการณ์👍
Andrew

1
@R .. น่าสนใจ ฉันคาดว่าrename(2)จะยังคงทำงานได้เนื่องจากชื่อไม่ได้เป็นส่วนหนึ่งของ inode แต่ไม่ได้ การค้นหาทางอินเทอร์เน็ตที่รวดเร็วไม่ได้เปิดเผยสาเหตุ คำใบ้ใด ๆ
domen

@domen: เพราะนั่นเป็นส่วนหนึ่งของวัตถุประสงค์ของแอตทริบิวต์ "ไม่เปลี่ยนรูป" ฉันสงสัยว่าจะใช้งานพิเศษที่ไม่น่าสนใจในระดับการใช้งานเพื่อป้องกันrenameการทำงาน
. GitHub หยุดช่วยน้ำแข็ง

4

สิ่งที่เกี่ยวกับการหักหลังmkdirsyscall ด้วยLD_PRELOAD...

$ ls
test.c
$ cat test.c 
#define _GNU_SOURCE

#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dlfcn.h>

typedef int (*orig_mkdir_func_type)(const char *path, mode_t mode);

int mkdir(const char *path, mode_t mode) {
    if(!strcmp(path, "shop")) return 1;

    orig_mkdir_func_type orig_func;
    orig_func = (orig_mkdir_func_type)dlsym(RTLD_NEXT, "mkdir");
    return orig_func(path, mode);
}
$ gcc -shared -fPIC test.c -o test.so
$ LD_PRELOAD='./test.so' mkdir test
$ LD_PRELOAD='./test.so' mkdir shop
mkdir: cannot create directory ‘shop’: No such file or directory
$ ls
test  test.c  test.so

โปรดทราบว่าในตัวจัดการนี้คุณสามารถบันทึก PID ของกระบวนการที่ต้องการสร้างไดเรกทอรีนี้แทน:

$ cat test.c 
#define _GNU_SOURCE

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dlfcn.h>

typedef int (*orig_mkdir_func_type)(const char *path, mode_t mode);

int mkdir(const char *path, mode_t mode) {
    if(!strcmp(path, "shop")) {
        FILE* fp = fopen("/tmp/log.txt", "w");
        fprintf(fp, "PID of evil script: %d\n", (int)getpid());
        fclose(fp);
    }

    orig_mkdir_func_type orig_func;
    orig_func = (orig_mkdir_func_type)dlsym(RTLD_NEXT, "mkdir");
    return orig_func(path, mode);
}
$ gcc -shared -fPIC test.c -o test.so
$ LD_PRELOAD='./test.so' mkdir shop
$ cat /tmp/log.txt 
PID of evil script: 8706

คุณต้องวางสิ่งนี้ไว้ใน~/.bashrcรูท (หรือใครก็ตามที่กำลังเรียกใช้แอปของคุณ) เพื่อให้แน่ใจว่าจะใช้สิ่งนี้:

export LD_PRELOAD=/path/to/test.so

2
สิ่งนี้ไม่ควรมีการลงคะแนนมันเป็นวิธีแก้ปัญหาและสิ่งที่ดี
cat

4
มันใช้ตู้กระเป๋าเดินทางเพื่อเปิดกระป๋องถั่ว แต่อย่างน้อยพวกมันก็จะสุก ...
Lightness Races กับโมนิก้า

2
@cat: ฉันไม่เห็นด้วย LD_PRELOADแฮ็กเช่นนี้มีพื้นผิดเสมอและถ้าคุณรู้ว่าสิ่งที่คุณทำพวกเขาสามารถไม่ดีทำลายโปรแกรมที่คุณโหลดลงโดยคุณสมบัติที่จะหมดเช่น async สัญญาณความปลอดภัยของฟังก์ชั่นที่คุณกำลังแทนที่
. GitHub หยุดช่วยน้ำแข็ง

1
นอกจากนี้ฉันคิดว่าfopenควรมี"a"แทน"w"ดังนั้นจึงสามารถเก็บบันทึกก่อนหน้านี้
cat

2
สิ่งนี้จะไม่ทำงานหากรหัสที่ไม่ดีเรียก syscall โดยตรงไม่ใช่ผ่าน libc หรือถ้ารหัสไม่ดีมีการเชื่อมโยงแบบคงที่
domen

3

(จะแสดงความคิดเห็นต่อคำตอบของ Miati แต่จำบัญชีเก่าของฉันไม่ได้และไม่มีชื่อเสียงเพียงพอสำหรับบัญชีใหม่นี้ ... )

คุณสามารถบล็อกการสร้างโดยการสร้างไฟล์แล้วเปลี่ยนคุณสมบัติของไฟล์

$ sudo touch shop
$ sudo chattr +i shop

จากนั้นความพยายามใด ๆ ที่จะทำอะไรกับไฟล์นั้นจะถูกบล็อกแม้ว่าผู้ใช้จะกลายเป็นรูต

$ rm shop
rm: remove write-protected regular empty file ‘shop’? y
rm: cannot remove ‘shop’: Operation not permitted
$ sudo rm shop
rm: cannot remove ‘shop’: Operation not permitted

2
หากคุณทราบชื่อ / ที่อยู่อีเมลของบัญชีเดิมของคุณคุณสามารถขอใช้บัญชีผสานจากแบบฟอร์มการติดต่อเชื่อมโยงที่ด้านล่างของทุกหน้า
wizzwizz4

นอกจากนี้ทำไมไม่บอกเราว่าสิ่งนี้เกี่ยวข้องกับคำตอบอื่น ๆ อย่างไรแทนที่จะเป็นเหตุผลที่คุณตัดสินใจโพสต์
jpaugh

2

สร้าง symlink ที่ชี้ไปยังตำแหน่งที่ไม่มีอยู่ภายในไดเรกทอรีที่ไม่มีอยู่ สิ่งนี้มีความหมายบางอย่างที่สนุกสนาน:

$ ln -s non-existent/foobar foo
$ ls -ln
total 0
lrwxrwxrwx 1 1000 1000 19 Okt  4 17:17 foo -> non-existent/foobar
$ mkdir foo
mkdir: cannot create directory ‘foo’: File exists
$ cat foo
cat: foo: No such file or directory
$ echo foo > foo
zsh: no such file or directory: foo
  1. mkdir ลิงก์และอื่น ๆ จะล้มเหลวด้วยEEXIST(มีไฟล์อยู่)
  2. ความพยายามในการเปิดเส้นทางสำหรับการอ่านการเขียนหรือการผนวกจะล้มเหลวด้วยENOENT(ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว)
  3. การใช้ stat (2) (ไม่ใช่ lstat (2) หรือ stat (1)) บนตำแหน่งก็ล้มเหลวเช่นกัน ENOENTเช่นกัน แน่นอนว่า lstat จะส่งคืนข้อมูลเกี่ยวกับ symlink

นี่มีข้อดีสองประการเหนือโซลูชันอื่น ๆ ที่เสนอที่นี่: (a) คุณไม่จำเป็นต้องใช้บริการที่ติดตามการสร้างไดเรกทอรีและ (b) ชื่อดูเหมือนจะไม่มีคำใดเป็นคำสั่งส่วนใหญ่

คุณจะต้องให้มันยิง แต่ฉันสงสัยว่าสิ่งที่เขียนกฎที่คุณมีพวกเขาไม่ได้ใช้คำสั่ง lstat หรือคำสั่งที่ไม่ใช่การประชุมอื่น ๆ ทำให้พวกเขาล้มเหลว

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