[SCTF2019]Flag Shop——瞧,这是个新来的

31 篇文章 3 订阅
8 篇文章 0 订阅

[SCTF2019]Flag Shop

一.前言

这几天一直有事,导致之前的比赛的WP也没看,然后靶场这方面的学习也没推进下去,终于找了个时间的空挡做了道关于Ruby的模板注入。为了这道题我甚至抽出了我本就不多的时间去学了学Ruby的语法,话说学完Ruby之后,我的感触是他与Python等脚本语言很像,但是它的语法中字里行间都透露着Java等语言的关系。关于这次的SSTI题目,与其他的SSTI有着很大的不同。

二.正文

老样子,我们先看题目
请添加图片描述
题目的意思很简单就是我们要通过足够的jinkela来购买flag。但是我们发现我们的初始金额数是不够的,那怎么办呢?我们可以通过点击work选项来增加jinkela的数量,但是通过work所获得的jinkela数量有限。可是那又怎么样呢?我们只要点的多,我们总会达到那个数字的(bushi。
咳咳,咱们言归正传,我们扫描一下目录发现有robots.txt文件,我们访问一下看看。
请添加图片描述
我们直接访问一下/filebak目录,里面是这个网站的源码。

require 'sinatra'
require 'sinatra/cookies'
require 'sinatra/json'
require 'jwt'
require 'securerandom'
require 'erb'

set :public_folder, File.dirname(__FILE__) + '/static'

FLAGPRICE = 1000000000000000000000000000
ENV["SECRET"] = SecureRandom.hex(64)

configure do
  enable :logging
  file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
  file.sync = true
  use Rack::CommonLogger, file
end

get "/" do
  redirect '/shop', 302
end

get "/filebak" do
  content_type :text
  erb IO.binread __FILE__
end

get "/api/auth" do
  payload = { uid: SecureRandom.uuid , jkl: 20}
  auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
  cookies[:auth] = auth
end

get "/api/info" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
end

get "/shop" do
  erb :shop
end

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

post "/shop" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }

  if auth[0]["jkl"] < FLAGPRICE then

    json({title: "error",message: "no enough jkl"})
  else

    auth << {flag: ENV["FLAG"]}
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    json({title: "success",message: "jkl is good thing"})
  end
end


def islogin
  if cookies[:auth].nil? then
    redirect to('/shop')
  end
end

我们发现这个源码中有JWT,我们抓一个包试试看。
在这里插入图片描述
我们拿着这个JWT去解密。
在这里插入图片描述
我们发现这个网站的jinkela数量是通过JWT进行传递的,所以我们只要能够得到这道题的加密密钥,从而伪造JWT,就行了。那么,我们该如何拿到密钥呢?从上面的整个代码中着重看如下代码。

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

这里涉及到了一些关于Ruby ERB模板注入的知识,具体的就不细说了,原理都差不多,只是语法的区别。
ERB模板注入链接
我们要通过<%=%>进行模板注入,我们想要得到SECRET但是在<%=%>中我们不能直接写SECRET,因为params[:name][0,7]的存在导致我们只能在模板内写入2个字符。但是幸运的是,Ruby为我们提供了预定义字符。

$’ 最后一次模式匹配中匹配部分之后的字符串

让我们看看运行到这句话之前的最后一个模式匹配在哪里?

unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end

就是在匹配SECRET,这个预定义字符的作用是将匹配之后的字符进行返回。什么意思呢?我来举个例子

hello world //我设置匹配字符为e
llo world//这就是返回值

我们要想得到完整的SECRET,那就必须传进去一个空的SECRET,让最后的返回值是完整的。
所以我们如此构造payload

?name=<%=$'%>&do=<%=$' is working%>&SECRET=

请添加图片描述
结果如下
请添加图片描述
我们拿着这个密钥去伪造JWT
请添加图片描述
我们把这个伪造的JWT发过去。
请添加图片描述
我们看到服务端又给我返回了一个新的JWT,我们这次把他解密看看。
请添加图片描述
返回了flag.

三.后记

虽然这段忙的时间还没有过去,但是总有时间是可以腾出来的。之后就应该开始SSRF的学习了,SSTI也要告一段落了,应该和SQL一样把他们放在比赛中继续磨练了。总之当下的问题是先熬过这段艰苦的时光。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值