BASH และพฤติกรรมการคืนรถ


11

ฉันมีหนึ่งคำถามที่รวดเร็ว
เป็นเรื่องปกติหรือไม่ที่ bash (ฉันใช้ 4.4.11) ไม่แสดงบรรทัด / ข้อความที่คั่น / จบด้วย plain \r?

ฉันรู้สึกประหลาดใจเล็กน้อยที่เห็นพฤติกรรมนี้:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

แต่ข้อความ "hello อีกครั้ง" ยังคงอยู่ที่นั่นอย่างใด "ซ่อน":

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

และทันทีที่เราเพิ่งเล่นกับ bash ก็โอเค .... แต่นี่เป็นความเสี่ยงด้านความปลอดภัยหรือไม่? เกิดอะไรขึ้นถ้าเนื้อหาของตัวแปร "a" มาจากโลกภายนอกและรวมถึง "คำสั่งที่ไม่ดี" แทนที่จะเป็นแค่คำทักทาย?

การทดสอบอื่นไม่แน่ใจในเวลานี้:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

ลองนึกภาพที่ซ่อนอยู่แทนซ่อนrmls

พฤติกรรมเดียวกันเมื่อใช้ echo -e:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

ฉันว่าเป็นสิ่งที่ผิดหรือเปล่า?

คำตอบ:


20

การecho "$a"พิมพ์ของคุณ"hello" จากนั้นกลับไปที่จุดเริ่มต้นของบรรทัด (ซึ่งเป็นสิ่งที่\rทำ) พิมพ์ "อีกครั้ง" กลับไปอีกครั้งพิมพ์ "george" กลับไปอีกครั้งและไปที่บรรทัดถัดไป ( \n) มันเป็นเรื่องปกติอย่างสมบูรณ์แบบ แต่เมื่อchepnerชี้ให้เห็นมันไม่มีอะไรเกี่ยวข้องกับ Bash: \rและ\nถูกตีความโดย terminal ไม่ใช่โดย Bash (ซึ่งเป็นเหตุผลที่คุณได้รับผลลัพธ์เต็มเมื่อคุณไพพ์คำสั่งod)

คุณสามารถเห็นสิ่งนี้ดีกว่าด้วย

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

ตั้งแต่นั้นจะสิ้นสุดของข้อความที่ถูกเขียนทับ:

georgen,o

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


ชัดเจนพอขอบคุณ ฉันโชคดี / โชคไม่ดีที่ใช้คำสุดท้ายในการทดสอบของฉันที่สามารถเขียนทับสองคำก่อนหน้าได้อย่างสมบูรณ์
George Vasiliou

2
โปรดทราบว่านี้ไม่ได้ทำอะไรกับมันbashแม้ว่า; ทั้งหมดขึ้นอยู่กับเทอร์มินัลว่าจะ "แสดง" การขึ้นบรรทัดใหม่หรือวิธีแสดงอักขระที่ถูกเขียนทับ ตัวอย่างเช่นมันจะสมบูรณ์ใช้ได้สำหรับสถานีที่จะแสดง-\r|เป็นสิ่งที่คล้ายกับเครื่องหมายบวกมากกว่าเพียงแค่ไปป์
chepner

@chepner ดีใจที่รู้! ขอบคุณสำหรับการแบ่งปัน. ฉันคิดว่านี่เป็นเพียงพฤติกรรมทุบตี
George Vasiliou

@GeorgeVasiliou Nope bashเพียงเขียนไบต์ไปยังไฟล์ มันขึ้นอยู่กับใครก็ตามที่อ่านไบต์เหล่านั้นเพื่อตีความมัน
chepner

nitpick: printfซึ่งเป็นทุบตีในตัวคำสั่ง (แม้ว่าจะยังมีอยู่เป็นปฏิบัติการแบบสแตนด์อโลน) ตีความ\r(ลำดับของไบต์ที่สอง: 0x5cและ0x72และผลิตที่กลับรถ (byte เดียว: 0x0d.) แล้วใช่ขั้ว ตีความไบต์0x0dในลักษณะพิเศษ แต่ก็ไม่ได้แปลความหมายสายเดิม\r.
ซูซานDupéron

6

ในโลกของ Unix การคืนรถ (เข้ารหัสทั่วไป\rในภาษาการเขียนโปรแกรม) เป็นอักขระควบคุมที่ไม่มีการทำเครื่องหมาย คุณสามารถให้การขึ้นบรรทัดใหม่ภายในบรรทัดข้อความเช่นอักขระอื่น ๆ นอกเหนือจากการป้อนบรรทัด (หรือเรียกว่าการขึ้นบรรทัดใหม่ ) ซึ่งทำเครื่องหมายจุดสิ้นสุดของบรรทัด

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

กลับรถเป็นตัวละครที่ควบคุม เมื่อคุณพิมพ์ไปที่เทอร์มินัลแทนที่จะแสดงglyphเทอร์มินัลจะมีเอฟเฟกต์พิเศษบางอย่าง สำหรับการขึ้นบรรทัดใหม่เอฟเฟกต์พิเศษคือการเลื่อนเคอร์เซอร์ไปที่จุดเริ่มต้นของบรรทัดปัจจุบัน ดังนั้นหากคุณพิมพ์บรรทัดที่มีการขึ้นบรรทัดใหม่อยู่ตรงกลางเอฟเฟกต์คือการเขียนครึ่งหลังในช่วงครึ่งแรก

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

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


0

คุณสามารถดูการขึ้นบรรทัดใหม่ในตัวแปร bash โดยใช้printfฟังก์ชันที่มี%qรูปแบบ

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

แหล่งที่มาและอ่านเพิ่มเติม:

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