这是一道ruby题... bkp真会玩,web只有rb和py
题目首页只有一句话 浏览/flag 和/source
妹的 我当然浏览/flag 然后...
2333 进入正题 看源码 不要怕 每一行我都在后面解释了~
require 'nokogiri'
require 'open-uri'
require 'sinatra'
require 'shellwords'
require 'base64'
require 'fileutils'
set :bind, "0.0.0.0"
set :port, 5300
cdir = Dir.pwd
get '/' do
str = "welcome to the automatic resource inliner, we inline all images"
str << " go to /example.com to get an inlined version of example.com"
str << " flag is in /flag"
str << " source is in /source"
str
end
get '/source' do
IO.read "/home/optiproxy/optiproxy.rb"
end
get '/flag' do
str = "I mean, /flag on the file system... If you're looking here, I question"
str << " your skills"
str
end
get '/:url' do
url = params[:url]
main_dir = Dir.pwd
temp_dir = ""
dir = Dir.mktmpdir "inliner"
Dir.chdir dir
temp_dir = dir
exec = "timeout 5 wget -T 2 --page-requisites #{Shellwords.shellescape url}"
`#{exec}`
my_dir = Dir.glob ("**/")
Dir.chdir my_dir[0]
index_file = "index.html"
html_file = IO.read index_file
doc = Nokogiri::HTML(open(index_file))
doc.xpath('//img').each do |img|
header = img.xpath('preceding::h2[1]').text
image = img['src']
img_data = ""
uri_scheme = URI(image).scheme
begin
if (uri_scheme == "http" or uri_scheme == "https")
url = image
else
url = "http://#{url}/#{image}"
end
img_data = open(url).read
b64d = "data:image/png;base64," + Base64.strict_encode64(img_data)
img['src'] = b64d
rescue
# gotta catch 'em all
puts "lole"
next
end
end
puts dir
FileUtils.rm_rf dir
Dir.chdir main_dir
doc.to_html
end
这篇准备给自己以后研究ruby的时候用 所以会写的很详细
对于一个完全不会的语言,我的想法就是本地测试。
- apt-get install ruby
- apt-get install rails
搭建完成 如果第2步出现require什么错误 apt-get install ruby-dev
(环境加测试搞了一个下午...)
require加载模块
set :bind, "0.0.0.0"
set :port, 5300
cdir = Dir.pwd
绑定地址端口 然后把当前目录给cdir(puts相当于print)
get do end 就不讲了..
get '/:url' do
url = params[:url]
main_dir = Dir.pwd
temp_dir = ""
这个段卡了很久 最后发现/后面的所有字符被传给url
dir = Dir.mktmpdir "inliner"
Dir.chdir dir
temp_dir = dir
在/tmp下创建一个临时文件(用的sinatra模块)再进入该路径
exec = "timeout 5 wget -T 2 --page-requisites #{Shellwords.shellescape url}"
`#{exec}`
这句好理解 调用系统命令wget Shellwords.shellescape用来防止命令注入
讲讲这个--page-requisites参数
简单的说就是下载网站的静态文件 比如js,img,css 来试一下
可以看到建立了一个文件夹 不但下载了主页 还建立了对应的文件夹 下载了css
my_dir = Dir.glob ("**/")
Dir.chdir my_dir[0]
index_file = "index.html"
html_file = IO.read index_file
doc = Nokogiri::HTML(open(index_file))
glob和php里的glob函数一样 这里匹配wget下来的文件夹,然后进入,读index.html
最后一句 Nokogiri::HTML 是一个解析html文件的模块
这个操作相当于把doc当做index.html的资源句柄(简单的理解就是把index.html的内容给doc)
doc.xpath('//img').each do |img|
header = img.xpath('preceding::h2[1]').text
image = img['src']
img_data = ""
uri_scheme = URI(image).scheme
在doc(也就是index.html)中搜索img标签,然后在img标签里找一个文本给header 这个不管。
把img的src给image,把image作为一个uri来解析,取它的scheme,也就是冒号前的协议。
接着
begin
if (uri_scheme == "http" or uri_scheme == "https")
url = image
else
url = "http://#{url}/#{image}"
end
img_data = open(url).read
b64d = "data:image/png;base64," + Base64.strict_encode64(img_data)
img['src'] = b64d
打开img的url(用的是open-uri模块的open方法) 然后把图片内容用base64转码输出到src
rescue
# gotta catch 'em all
puts "lole"
next
抛出异常就跳过 next相当于continue
puts dir
FileUtils.rm_rf dir
Dir.chdir main_dir
doc.to_html
输出,删除临时目录,转回主目录,输出网页。
源码理解了,再重新整体看一遍。
命令注入应该是不行了,再结合那个base64输出,联想到isg的那个任意文件读取然后用图片base64返回
思路非常明确 尝试简化一下代码然后读取/etc/passwd
完美! 于是问题就变成怎么绕过这段代码
if (uri_scheme == "http" or uri_scheme == "https")
url = image
else
url = "http://#{url}/#{image}"
end
img_data = open(url).read
这里卡了很久很久 怎么在有http开头的情况下读取本地文件
最后找到了这篇文章(基友给的 他搜的ruby uri scheme vuln 我搜的open-uri bug.. 论搜索姿势的重要性)
http://sakurity.com/blog/2015/02/28/openuri.html
根据文中给出的姿势 只要能在服务器端创建一个名为http:
的文件夹 就可以用
http:/../../../../../etc/passwd
这种姿势读取 那么怎么创建?
没想到?
还记得wget --page-requisites么..
这就是真相~
最后姿势
解下base64,flag到手 用基友的图
BKPCTF{maybe dont inline everything.}
ps flag为啥在hackbar? 有解码功能~