flag shop

知識點:Ruby ERB SSTI
備注:Ruby 摸得少,搜了一個下午都沒搜到 Ruby 的全局變量 – -后來結束了和出題人 evoA 師傅一聊才知道得用美元符號的全局變量,哭了。在這里也還是寫寫 WriteUp 記錄下。
步驟:
1、打開靶機,發現是這樣一個頁面。
2、看下頁面源碼,主要關注后面這一段,先獲取信息,失敗就去請求 auth。

auth 之后會得到一個 jwt token。看來之后的請求我們也得帶上這個。

2、掃下敏感文件,有 robots.txt。

3、訪問一下這個路徑,是源碼。
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(xx)
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
4、可以看到 /work 那里有 ERB 模板,還直接把可控參數 name 拼進去了,那么這里我們就可以傳入一些構造過的參數,來達到我們的目的了。比如 name=<%=1%>,就會得 1。

5、 繼續看看源碼,同時注意有這樣一段意義不明的代碼。似乎得傳入 SECRET 參數。那么就一起帶上。
unless params[:SECRET].nil?
if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
puts ENV["FLAG"]
end
end
5、對照 Ruby 全局變量表 ,不斷 fuzz,發現$`有東西,


回溯到源碼看看
unless params[:SECRET].nil?
if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
puts ENV["FLAG"]
end
end
其在模板渲染之前之前有個匹配,就是這里。要是 SECRET 參數存在則對其進行匹配,用傳入的這個值去和 ENV["SECRET"] 匹配,匹配上了就往終端輸出 FLAG。意義不明的代碼,但這里既然有匹配,就可以用全局變量讀出來了,也就是用 $` 來讀取匹配前的內容。
那么這里讀出來的就是 ENV 的 SECRET 的一部分了。
6、然后我們 SECRET 不傳試試,這樣括號里的匹配就不進行,只進行括號外的 ENV[“SECRET”] 的匹配,再用全局變量 $` 就可以讀出 ENV[“SECRET”] 了。


7、拿到了 secret 之后,到 jwt.io 偽造一下 cookie 里的 auth 里存的 jwt 令牌。jkl 設置為 2000000000000000000000000000 。

8、置 cookie,買 flag。


9、然后再解析一下新的 jwt token。


10、Flag 到手~
2019SCTF-Writeup