打开题目网站,长这样:

很容易想到ping命令注入。
#正常思路
先按照题目实例输入:
loli.club
发现没有任何回显。
常规输入:
127.0.0.1
发现有回显,也就是有了注入点。

继续注入,尝试:
127.0.0.1;ls

结果显示Invalid URL。判断本题是对常见字符做了一些过滤,不想一个个去测试,启动burp suite,进行过滤。

测试了一圈,发现常见的字符如:; && || ' () 等都给过滤了,这里通过已经过滤掉的字符可以发现,单纯的系统命令注入走不通。
尝试其他思路。
#宽字符绕过
UTF-8里,单字节字符必须是0x00-0x7F。
0x80-0xFF是多字节的开头。
正常组成一个GBK汉字需要形如:0xdf+0x5c(反斜杠)。
我们这里只传入0xdf,没有后面的 \\ ,编码阶段直接报错。
修改url参数为:%df

(这里注意:如果直接在页面输入框中传%df,会对%再次进行url编码,也就是说实际变成%25df,并不是我们想要的参数。)
页面回显:

拉到页面最底部,发现有信息:

DEBUG=True:Django的调式模式开启,开发环境常用,会暴露详细错误信息、代码行、堆栈跟踪等详细信息。
DEBUG=False:调用自定义/默认的错误页面模板,而非调试详情页。
settings file:Django项目的核心配置文件(通常是settings.py)。
1.全局搜索Python Path

找到根目录的绝对路径:/opt/api
2.继续搜索DATABASES

发现数据库信息:/opt/api/database.sqlite3
直接访问失败。
3.再次进行代码审计

发现:GET方法是前端页面,/api/ping是POST核心接口。
利用点
PHP 5.5.0 前,curl发起POST请求时,支持@前缀+文件完整路径(可用来构造命令注入/路径遍历)。
PHP 5.5.0及以后,@前缀被默认禁用,官方推荐改用更安全的CURLFile类。
我们这里构造payload:
@/opt/api/database.sqlite3
之后通过全局搜索,成功发现flag。
Congratulations!

【个人理解,如有不妥,欢迎交流指正。】

