มาลองตรวจสอบและเพิ่มความปลอดภัยให้เซิร์ฟเวอร์ด้วย CIS Benchmark

28 พฤษภาคม 2019

พิชญะ โมริโมโต
พิชญะ โมริโมโตหัวหน้าทีมทดสอบเจาะแฮกระบบ (lead penetration tester) ของบริษัท สยามถนัดแฮก, เป็นที่ปรึกษาด้านความปลอดภัยให้หน่วยงานเอกชน, เป็นที่รู้จักกันในฐานะ หนึ่งในแอดมินกลุ่ม 2600 Thailand และเป็นหนึ่งในคนเขียนบทความลงเพจ สอนแฮกเว็บแบบแมว ๆ

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

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

1.ไม่สามารถตั้งค่ามา ตั้งแต่ต้นได้

การตั้งค่านั้น ไม่สามารถทำได้โดยผู้พัฒนาโปรแกรมตั้งมาเอง ตัวอย่างเช่นของ MySQL สำหรับระบบเว็บที่สร้างจาก LAMP stack (Linux Apache MySQL PHP) ยุคนึงเว็บเหล่านี้มักจะถูกแฮก ด้วยการที่แฮกเกอร์เจาะระบบผ่านช่องโหว่ SQL Injection แล้วถ้าเจาะได้เป็นสิทธิ์สูงสุด (root) แฮกเกอร์อาจสามารถใช้ความสามารถของ MySQL ในการเขียนไฟล์ web backdoor ด้วยคำสั่ง INTO OUTFILE เข้ามาคุมเครื่องเซิร์ฟเวอร์ได้ ในมุมผู้ดูแลระบบสามารถช่วยตั้งค่า MySQL ให้ลดความเสี่ยงของปัญหานี้ได้ ดีที่สุดคือการให้เว็บใช้ user ของ MySQL เป็นสิทธิ์ต่ำที่สุดที่ยังทำให้เว็บใช้งานได้ (เข้าถึงข้อมูลตัวเองได้เท่านั้น โดยไม่เป็น root และไม่มี file_priv) ซึ่งเป็นอะไรที่ไม่สามารถตั้งค่ามาได้ตั้งแต่ต้น

2.การทำให้ปลอดภัยอาจไปปิดฟีเจอร์ที่จำเป็นต้องใช้

หลาย ๆ ครั้งการตั้งค่าระบบให้ปลอดภัยขึ้น อาจเป็นการปิดความสามารถบางอย่างของระบบไปด้วย เพื่อลดจุดที่แฮกเกอร์จะเข้ามาลองโจมตี (attack surface) ดังนั้นผู้พัฒนาซอฟต์แวร์จึงไม่อาจรู้ได้ล่วงหน้าว่า ความสามารถไหนจะถูกใช้งานในแต่ละกรณี

3.เราอาจไม่รู้ว่าการตั้งค่าที่ปลอดภัยต้องทำอะไรบ้าง

จากข้อแรก ก็ยังมีท่าอื่นอีกที่ช่วยลดความเสี่ยงได้อีกอย่าง การใช้การตั้งค่า system variable ของ MySQL (ตอนรัน mysqld หรือใน my.cnf) ชื่อ secure_file_priv ในการกำหนดว่าคำสั่ง SQL ว่าควรจะอ่านหรือเขียนไฟล์ได้ที่โฟลเดอร์ไหนได้บ้างเท่านั้น ตัวอย่างนี้จะดูซับซ้อนขึ้นมาหน่อยแล้ว ว่าคนจะตั้งก็ต้องพอมีความรู้ว่าความเสี่ยงของการโดนแฮกมีอะไรบ้าง

ตัวอย่าง

ตัวอย่างเช่น ช่องโหว่ (ของเว็บ) บางครั้งก็อาจเกิดจากการตั้งค่า MySQL ไม่ปลอดภัยร่วมด้วยอย่าง กรณีของ การแฮกเว็บด้วยท่า SQL Column Truncation ที่ถูกนำเสนอครั้งแรก[https://web.archive.org/web/20081121190045/http://www.suspekt.org/2008/08/18/mysql-and-sql-column-truncation-vulnerabilities] โดยเซเลปคนนึงของวงการ iOS & PHP Hacking อย่าง I0n1c (Stefan Esser) ซึ่งเกิดจากการที่ถ้าเว็บมีการพยายามใส่ค่าที่ “ยาว” เกินกว่าที่เรากำหนดไว้ใน data field ของฐานข้อมูล ตัว MySQL อาจจะตัด ส่วนที่ยาวเกินทิ้งแล้วเอาส่วนที่ไม่เกินไปเก็บ (ในระบบจะมีการ log ข้อความ warning แต่ยอมให้ทำได้) ทำให้ในบางกรณี เว็บอาจโดนแฮกได้ ลองคิดกันเล่น ๆ ว่าเอ๊ะ เว็บจะโดนแฮกได้ยังไง?

ถ้ามีเว็บ มีระบบสมัครสมาชิก มีฐานข้อมูลมี column ชื่อ username สำหรับเก็บชื่อแล้วก็มี user ชื่อ adminในระบบ แล้วทีนี้เรากำหนดความยาวของค่า username ว่าต้องยาวไม่เกิน 20 ตัว ปรากฏว่าถ้ามีแฮกเกอร์ไปสมัครเว็บนี้แล้วใช้ชื่อว่า admin ตามด้วย space 15 ตัว ตามด้วยตัว a

admin               a

จะทำให้ระบบตัดตัว a ออก (เพราะเป็นตัวที่เกิน 20 ตัว) ดังนั้นในระบบจึงจะมี ผู้ใช้งาน 2 คนชื่อ admin กับ admin ตามด้วย space อีก 15 ตัวนั้นเอง ต่อมาถ้าเว็บหรือ MySQL มีการตัด (trim) ค่า space นี้ออกตอนนำมาใช้ ก็มีโอกาสที่จะยอมให้แฮกเกอร์เข้าสู่ระบบเป็น admin จริง ๆ คนแรก ได้ คือใช้รหัสผ่านตัวเองเข้าสู่ระบบแต่ตอน query ขึ้นมาไปเจอ row แรกของ admin คนเดิมซะอย่างงั้น ช่องโหว่นี้เคยเกิดขึ้นจริง ใครสนใจไปอ่านต่อได้ที่ Invision Power Board 1.x?/2.x/3.x – Admin Takeover [https://www.exploit-db.com/exploits/25441]

ซึ่ง MySQL สามารถตั้งค่าให้ไม่ยอมรับค่าที่ยาวเกินขนาด column แทนการตัดส่วนที่ยาวเกินออกแล้วใส่เข้าฐานข้อมูลเลยได้โดยการเปิด Strict Mode [https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-strict] จากการกำหนด system variable ชื่อ sql_mode เป็น STRICT_ALL_TABLES

แล้วถ้าเราไม่รู้ว่าการแฮกเว็บมีท่าชื่อ SQL Column Truncation เราจะมาตั้งค่า MySQL เราเป็น Strict Mode รึเปล่า? คำตอบคือ… อาจจะทำก็ได้เพราะโลกเรามีองค์กร ไม่แสวงหาผลกำไรชื่อว่า Center for Internet Security (CIS) ที่มีผู้เชี่ยวชาญด้านความปลอดภัยคอมพิวเตอร์ มาร่วมกันออกคู่มือแนวทางการตั้งค่าระบบชื่อว่า CIS Benchmark อย่างของ MySQL ก็มี Oracle MySQL Benchmark ให้ดาวน์โหลดได้ที่ https://www.cisecurity.org/benchmark/oracle_mysql/

เมื่อสมัครแล้ว ดาวน์โหลดและเปิดไฟล์ขึ้นมาไล่อ่านดูจะพบว่ามีคำแนะนำข้อ 4.9 ให้ตั้งค่า sql_mode เป็น STRICT_ALL_TABLES ไว้เรียบร้อยแล้วจ้า พร้อมทั้งบอกวิธีการตรวจสอบว่าเคยตั้งค่าไปแล้วรึยัง (หัวข้อ Audit)

ดังนั้นเราจึงสามารถนำคำแนะนำที่ดาวน์โหลดฟรีจากเอกสาร CIS Benchmark มาปรับใช้ ในการตั้งค่าระบบของเราได้ แม้ว่าเราอาจจะไม่รู้ท่าแฮก ของแฮกเกอร์ทั้งหมดก็ได้นอกจาก MySQL แล้วก็ยังมีอีกเยอะ ส่วนใหญ่จะแบ่งเป็นตามระบบปฏิบัติการที่ใช้เช่น Windows Server, Red Hat (RHEL), CentOS, Debian, Ubuntu เป็นต้น

วิธีการอ่านคำแนะนำของ CIS Benchmark

ไล่ทีละข้อ ตรวจสอบตามวิธีในหัวข้อ Audit ได้เลย ถ้าอันไหนไม่ตรงหรือยังไม่ได้ทำก็ทำตามในหัวข้อ Remediation โดยจะมีคำแนะนำ 2 แบบคือ

  1. Scored เป็นคำแนะนำที่ถ้าทำตามจะได้คะแนนสำหรับใช้คำนวณนำไปรวมเป็นคะแนนสุดท้าย ว่าระบบปลอดภัยตามที่แนะนำมากน้อยแค่ไหน
  2. Not Scored เป็นคำแนะนำที่ต่อให้ทำ หรือไม่ทำ ก็ไม่มีผลต่อคะแนนที่สุดท้ายที่ใช้ประเมินความปลอดภัยระบบตาม CIS Benchmark (แต่ยังแนะนำให้ทำอยู่)

คำเตือน: อย่างที่บอกไปในข้อ 2. การตั้งค่าระบบให้ปลอดภัยอาจไปปิดฟีเจอร์ที่ต้องใช้ ดังนั้นเราจึงจำเป็นต้องทำความเข้าใจระบบพร้อมกับค่าที่เราจะตั้งด้วยเพื่อป้องกันปัญหาอื่น ๆ ที่อาจตามมาได้ เช่นตั้งค่าแล้วระบบอาจจะล่มได้ เป็นต้น

ความน่าปวดหัวของมานั่งทำ hardening

การตั้งค่าระบบให้ปลอดภัยโดนแฮกยากขึ้น เราจะเรียกว่าเป็นการทำ hardening ผู้เขียนเข้าใจธรรมชาติของคนทำงานไอทีดี บางคนแค่ทำให้ระบบใช้งานได้ งานก็ล้นมืออยู่แล้ว ทำงานเอกสารอื่น ๆ ก็แทบไม่มีเวลาไปทำอะไร (ยังไม่นับเพื่อนเรียกไปช่วยซ่อมคอมฯให้หน่อยอีก) แล้วไหนจะต้องมานั่งทำ hardening ตาม CIS Benchmark อีกเหรอ?

ปัญหาของการทำ hardening ในโลกไอที ก็คือ ผู้ดูแลระบบ 1 คนดูแลเซิร์ฟเวอร์ 10 เครื่อง 100 เครื่อง หรือมากกว่า แถมบางทีก็จำไม่ได้แล้วว่าแต่ละเครื่องตั้งค่าอะไรไปบ้าง ตั้งเหมือนกันบ้างต่างกันบ้าง อะไรหายหรือเกินไปบ้าง ดังนั้นการจะเข้าไปตั้งค่าระบบให้ปลอดภัยทุกเครื่องด้วยมือปวดหัวแน่นอน ยังไม่รวมตั้งแล้วคนอื่นใช้นั้นใช้นี่ไม่ได้อีก ปกติถ้าขี้เกียจก็อาจจะตั้งแบบปิด security เอาให้ใช้ได้ก็พอ หรือทำเป็น docker/iso/vm image ไว้เป็นแม่แบบของเซิร์ฟเวอร์ที่ต้องใช้แล้วก็ clone ไปใช้ทุกที่เอาซึ่งก็ทำได้เช่นกัน

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

ผู้เขียนขอแนะนำ Ansible เป็นอีกตัวช่วยที่คนดูแลเซิร์ฟเวอร์ควรรู้

Ansible คือโปรแกรมเอาไว้ทำ configuration management โดยการเขียนกฏการตั้งค่าต่าง ๆ ของเครื่องไว้เป็นแม่แบบ จากนั้นสั่งให้เอาการตั้งค่าเหล่านี้ไปทำงานจริงบนเครื่องปลายทางที่เรากำหนดไว้ ซึ่งสามารถนำมาประยุกต์ใช้กับการ hardening ได้เพราะเราก็นำค่าต่าง ๆ จาก CIS Benchmark ที่เหมาะสมกับองค์กรเรามาสร้างเป็นแม่แบบไว้ครั้งเดียว จากนั้นก็ใช้ Ansible ยิงเข้าไปตั้งค่าเครื่องที่ต้องการ เวลาต้องการตั้งค่าใหม่ ปรับเปลี่ยน หรือตรวจสอบการตั้งค่าก็เข้ามาอ่านและแก้ไขได้โดยง่าย ในบทความนี้ผู้เขียนจะไม่ได้อธิบาย Ansible โดยละเอียด playbook, role, galaxy ต่าง ๆ คืออะไร ถ้าผู้อ่านไม่คุ้นเคยควรศึกษาหาข้อมูลเพิ่มเติม Ansible เบื้องต้น ก่อนอ่านต่อ

ทดสอบใช้งาน Ansible เพื่อทำ hardening อย่างง่าย ๆ

สำหรับผู้อ่านที่ใช้ MacOS สามารถติดตั้งได้ผ่าน brew โดยการพิมพ์คำสั่ง

$ brew install ansible

น่าเสียดายว่า Ansible ยังไม่สามารถสั่งการจากเครื่องที่เป็น Windows โดยตรงได้ (สามารถทำได้ทางอ้อมคือผ่านพวก cygwin หรือ Windows Subsystem for Linux (WSL) ใน Windows 10) ส่วนสำหรับ Linux Distro ต่าง ๆ สามารถดูวิธีติดตั้งได้ที่
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html

ส่วนการตั้งค่าสามารถดูตัวอย่างได้จากที่เคยมีคนทำไว้แล้วเช่น
Ubuntu 16.04 LTS
https://github.com/florianutz/Ubuntu1604-CIS

โดยผู้อ่านควรรีวิวการแก้ไขทั้งหมดก่อนการจะนำไปใช้เสมอ ในตัวอย่างนี้จะทดสอบการนำไปใช้งานอย่างง่ายด้วยคำสั่งดังต่อไปนี้ ขั้นแรกสร้างไฟล์ hosts และทดสอบว่าสามารถใช้ ansible เข้าได้ (ping)

$ cat /etc/ansible/hosts
[ubuntu]
ubuntu1604 ansible_ssh_host=1.2.3.4 ansible_user=root ansible_connection=ssh 
$ ansible --list-host all
  hosts (1):
    ubuntu1604
$ ansible -m ping ubuntu1604
ubuntu1604 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

จากนั้น ติดตั้งตัว roles ของ CIS Benchmark อันเดียวกับในลิงก์ github ด้านบน, สร้าง Ansible Playbook และทำการใช้งานตัว CIS Benchmark กับเซิร์ฟเวอร์ที่เรากำหนดไว้ในไฟล์ hosts

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

$ ansible-galaxy install florianutz.ubuntu1604-cis
- downloading role 'ubuntu1604-cis', owned by florianutz
- downloading role from https://github.com/florianutz/Ubuntu1604-CIS/archive/2.0.3.tar.gz
- extracting florianutz.ubuntu1604-cis to /Users/pichaya/.ansible/roles/florianutz.ubuntu1604-cis
- florianutz.ubuntu1604-cis (2.0.3) was installed successfully
$ cat cis-playbook.yml
- name: Ubuntu 16.04 CIS Benchmark
  hosts: all
  become: yes
  roles:
    - florianutz.ubuntu1604-cis
$ ansible-playbook cis-playbook.yml

เริ่มม

การตั้งค่าต่าง ๆ ตามคำแนะนำของ CIS Benchmark ก็จะถูกนำไปใช้ เป็นสถานะ changed สีเหลือง ส่วนถ้าเซิร์ฟเวอร์ทำการตั้งค่านั้นอยู่แล้ว จะเป็นสถานะ ok สีเขียว

หลังจากรันเสร็จเรียบร้อยก็ได้ recap สรุปมาว่าได้แก้ไขไปกี่จุด สามารถนำไปรันซ้ำได้เพื่อให้แน่ใจว่าเซิร์ฟเวอร์ต่าง ๆ ของเรามีการตั้งค่าที่ปลอดภัยตามที่กำหนดไว้

ตัวอย่างการกำหนดค่า configuration ของ Ansible

เมื่อเราใช้ Ansible Galaxy ติดตั้ง Roles มาแล้วไฟล์จะอยู่ที่

~/.ansible/roles/florianutz.ubuntu1604-cis/

ตัวอย่างเช่น

File: ~/.ansible/roles/florianutz.ubuntu1604-cis/tasks/section6.yml

เป็นการตรวจสอบพร้อมกับทำการแก้ไขทันที (ถ้าไม่ตรง) ว่าสิทธิ์ของไฟล์ /etc/passwd ในเซิร์ฟเวอร์กำหนดเป็น 0644 และสิทธิ์ของไฟล์ /etc/shadow ต้องถูกกำหนดเป็น 0000

มาดูอีกตัวอย่างเป็นการตั้งค่าในไฟล์บ้าง

File: ~/.ansible/roles/florianutz.ubuntu1604-cis/tasks/section5.yml

จะพบว่า CIS Benchmark ข้อนี้เมื่อนำไปใช้กับ Ansible จะทำการตรวจสอบว่าการตั้งค่าของ OpenSSH service ที่ไฟล์ /etc/ssh/sshd_config มีการใช้ SSH protocol version 2 รึเปล่า (เพราะ 1 ไม่ปลอดภัยแล้ว) และตรวจสอบอีกว่ามีการตั้งค่า LogLevel เป็น INFO รึยัง สามารถดูคู่มือเพิ่มเติมของการตั้งค่านี้ได้ที่ https://docs.ansible.com/ansible/latest/

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

บทความที่เกี่ยวข้อง