[SCTF2019]Flag Shop

[SCTF2019]Flag Shop

考点

  • ruby代码审计

  • ruby erb模板注入

wp

给了uid,金坷垃,flag价格三个参数,同时三个按钮,抓包。

buy flag按钮是POST请求/shop,在后端判断金坷垃是否够买flag

reset是GET请求/api/auth,返回新的cookie,auth=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJhOTNkMDI3MS1iYjZlLTQyNTEtOGQ5Mi1lZjgxOWY1MTgxODQiLCJqa2wiOjIwfQ.F4fAw7T3hcalQsKyKjkLs6zbylPHTKEj6s9pJ7_XEcA,然后请求/shop获取主页,最后请求/api/info,获取用户uid和金坷垃

work是GET请求/work?name=bot&do=bot%20is%20working,随机增加金坷垃,然后请求/shop获取主页,最后请求/api/info,获取用户uid和金坷垃

把cookie放在jwt.io看一下

需要密钥才能修改,尝试jwt-crack破解未果

扫目录,发现robots.txt,提示访问/filebak,得到源码

第一种方法

查一下sinatra是ruby的一个Web框架,erb是ruby自带的模板渲染包,如果输入可控,它会导致模板注入。

枚举当前类的可用方法

Ruby ERB模板注入读取文件的payload:<%= File.open('/etc/passwd').read %>

看给的代码,在访问work时,有两个判断

一个是传入SECRET参数,params[:SECRET].nil?判断是否传入SECRET参数,然后匹配SECRET中的小写字母和数字并返回,再用#{}获取这个变量,最后和ENV["SECRET"]进行匹配。

#{var}在Ruby中进行变量替换。例如

match是进行匹配。例如

另外是传入do和name参数,满足name[0:7] is working==do,然后使用ERB渲染name

也就是说,传入的name不超过7个字符,并且符合这种形式name=1234567&do=1234567 is working。而ERB模板渲染的字符<%=%>就用了5个,只有两个字符可用。

使用<%=1%>测试,URL编码之后再传入

这里先进行两次匹配操作,还能够进行模板注入,可以通过模板注入返回全局变量

输出

可以得到结论

$~ 返回最后一次匹配到的内容

$` 返回最后一次未匹配到内容前面的部分

$' 返回最后一次未匹配到内容后面的部分

得到payload:GET /work?name=%3c%25%3d%24'%25%3e&do=%3c%25%3d%24'%25%3e%20is%20working&SECRET=

得到密钥

jkl改成10000000000000000000000000000重新加密

更改cookie再点击buy flag,在cookie中返回flag

第二种方法

前面提到,传入的name不超过7个字符,并且符合这种形式name=1234567&do=1234567 is working。而ERB模板渲染的字符<%=%>就用了5个,那只剩下两个字符可用。

对于这点,可以使用数组绕过。Ruby中存在数据类型自动强制转换机制。

结果

如果传入数组,那就从原本的7个字符,变成了7个数组长度

payload:

小结

最后更新于