AWDP 国赛加油啊!!
全全的waf喂满我
1 2 3 4 5 6 7 8 9 10 11 12 function wafrce($str){ return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str); } function wafsqli($str){ return !preg_match("/select|and|\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleexml|extractvalue|+|regex|copy|read|file|create|grand|dir|insert|link|server|drop|=|>|<|;|\"|\'|\^|\|/i", $str); } function wafxss($str){ return !preg_match("/\'|http|\"|\`|cookie|<|>|script/i", $str); }
1 mv -f explorer.php $(dirname `find / -name 'explorer.php' 2>/dev/null`)/explorer.php
用find命令从根目录查找名为explorer.php
的文件,然后返回他的路径名(dirname)
2>/dev/null
的作用是避免返回一些错误的信息,比如说查找过程中会返回权限不足等错误
防御技巧 SQL注入 加过滤 –黑名单1 2 3 4 5 6 7 8 9 10 $filter = "regexp|from|count|procedure|and|ascii|substr|substring|left|right|union|if|case|pow|exp|order|sleep|benchmark|into|load|outfile|dumpfile|load_file|join|show|select|update|set|concat|delete|alter|insert|create|union|or|drop|not|for|join|is|between|group_concat|like|where|user|ascii|greatest|mid|substr|left|right|char|hex|ord|case|limit|conv|table|mysql_history|flag|count|rpad|\&|\*|\.|-" ;if ((preg_match ("/" .$filter ."/is" ,$username )== 1 ) || (preg_match ("/" .$filter ."/is" ,$password )== 1 )){ die (); } if (preg_match ('/\'|\"|^|\||&|,|#|-| |*|\\|union|select|hex|load|flag|and|if|elf|case|sleep|benchmark|lock|/i' ,$password )){ die ("GUN" ); }
转义字符 编辑php.ini
1 magic_quotes_gpc=on #php5.4的更高版本中,这个选项被去掉了。
magic_quotes_gpc 函数在php中的作用是判断解析用户提示的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”{单引号(’)、双引号(”)与 NULL(NULL 字符)等字符都会被加上反斜线。},以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的错误。
addslashes() 函数 addslashes(string)
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。 预定义字符是:单引号(’)双引号(”)反斜杠(\)NULL
1 2 $username = addslashes ($username );$password = addslashes ($password );
PS:PHP 5.4 之前 PHP 指令 magic_quotes_gpc 默认是 on, 实际上所有的 GET、POST 和 COOKIE 数据都用被 addslashes() 了。 不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义。 遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。
报错 (防报错注入)
php
1 php代码开头添加语句:error_reporting (0 );
设置参数化查询 首先,使用 prepare()
方法准备了一个带有占位符的 SQL 查询语句。然后,使用 **bind_param()**
方法将用户输入的变量绑定到查询语句的占位符上,确保了变量值不会被解释为 SQL 代码。最后,使用**execute()
**方法执行查询。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php error_reporting (0 );include 'dbConnect.php' ; $username = $_GET ['username' ];$password = $_GET ['password' ]; if (isset ($username ) && isset ($password )) { $sql = "SELECT * FROM users WHERE username = ? AND password = ?" ; $stmt = $mysqli ->prepare ($sql ); $stmt ->bind_param ("ss" , $username , $password ); $stmt ->execute (); $result = $stmt ->get_result (); if (!$result ) { die ($mysqli ->error); } $data = $result ->fetch_all (); if (!empty ($data )) { echo '登录成功!' ; } else { echo "用户名或密码错误" ; } $stmt ->close (); } ?>
PDO预处理 这算是个sql注入的通防了
1 $link =new PDO ("mysql:host=$servername ;dbname=$database " ,$username ,$password );
第208行处利用了PDO预处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $stmt =new PDO ("mysql:host=$server ;dbname=$dbname " ,$username ,$password );$stmt =$conn ->prepare ("SELECT * FROM users WHERE username =:name AND password =" passwd"); $stmt ->bindParam(':name',$name );$stmt ->bindParam(':passwd',$passwd );$exe =$stmt ->execute();if(!$exe ){ die('error'); } $result =$stmt ->fetchAll();if(!empty($result )){ echo " 登陆成功"; } else { echo " 用户名或密码错误"; }
反序列化
PHP7 新特性 为 unserialize() 提供过滤
这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。
php
1 2 3 4 5 6 7 8 9 10 11 12 <?php $data = unserialize ($foo , ["allowed_classes" => false ]);$data = unserialize ($foo , ["allowed_classes" => ["MyClass" , "MyClass2" ]);$data = unserialize ($foo , ["allowed_classes" => true ]);?>
php_serialize 在5.5版本后新加的一种规则,5.4及之前版本,如果设置成php_serialize会报错。
php
1 2 3 4 5 6 正确设置序列化及反序列化时使用的处理器 ini_set (‘session.serialize_handler’, ‘php_serialize’); ini_set (‘session.serialize_handler’, ‘php’); 两者处理session的方式不同,错误使用会形成基于session的反序化漏洞
php
1 2 3 4 5 $filter = "phar|zip|compress.bzip2|compress.zlib" ;if (preg_match ("/" .$filter ."/is" ,$name )== 1 ){ die (); }
PS:如果不将 compress.bzip2 伪协议进行过滤,有时候漏洞代码仅将phar过滤,但是可以被 compress.bzip2 绕过。
下面举一个具有漏洞代码的栗子
php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php error_reporting (0 );highlight_file ("file_contrary.php" );$filename =$_GET ['filename' ];if (preg_match ("/\bphar\b/A" , $filename )) { echo "stop hacking!\n" ; } else { class comrare { public $haha = 'xxxx' ; function __wakeup ( ) { eval ($this ->haha); } } imagecreatefromjpeg ($_GET ['filename' ]); } ?> compress.bzip2 绕过 payload:file_contrary.php?filename=compress.bzip2:
特殊函数主要是基于魔法函数、phar拓展php利用函数、序列函数。
1 disable_functions=fileatime,filectime,file_exists,file_get_contents,file_put_content,filegroup,fileinode,filemtime,fileowner,fileperms,is_dir,is_executable,is_file,is_link,is_readable,is_writable,is_writeable,fopen,readfile,unlink,parse_ini_file,file,copy,stat,serialize,unserialize,__construct,__destruct,__toString,__sleep,__wakeup,__get,__set,__isset,__unset,__invoke,
JAVA
对所有传入的反序列化对象,在反序列化过程开始前,对类型名称做一个检查,不符合白名单的类不进行反序列化操作。
禁止 JVM 执行外部命令 Runtime.exec
Java 一般来说安全性问题较少,出现的一些问题大部分是利用反射,最终用Runtime.exec(String cmd)函数来执行外部命令的。
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 SecurityManager originalSecurityManager = System.getSecurityManager(); if (originalSecurityManager == null ) { SecurityManager sm = new SecurityManager () { private void check (Permission perm) { if (perm instanceof java.io.FilePermission) { String actions = perm.getActions(); if (actions != null && actions.contains("execute" )) { throw new SecurityException ("execute denied!" ); } } if (perm instanceof java.lang.RuntimePermission) { String name = perm.getName(); if (name != null && name.contains("setSecurityManager" )) { throw new SecurityException ("System.setSecurityManager denied!" ); } } } @Override public void checkPermission (Permission perm) { check(perm); } @Override public void checkPermission (Permission perm, Object context) { check(perm); } }; System.setSecurityManager(sm); }
文件上传 Upload Limit
php
1 2 3 4 5 6 if (($_FILES ["Up10defile" ]["type" ]=="image/gif" )&&(substr ($_FILES ["Up10defile" ]["name" ], strrpos ($_FILES ["Up10defile" ]["name" ], '.' )+1 ))=='gif' )&&($_FILES ["file" ]["size" ]<1024000 ){} else { die (); }
在不存在文件包含漏洞的情况下,该方法能最有效的防御攻击者上传执行木马
php
1 2 3 4 5 6 7 8 9 10 if (file_exists ("upload_file/" . $_FILES ["Up10defile" ]["name" ])){ echo $_FILES ["Up10defile" ]["name" ] . " already exists. " ; } else { move_uploaded_file ($_FILES ["Up10defile" ]["tmp_name" ], "upload_file/" .$_FILES ["Up10defile" ]["name" ].".gif" ); echo "Stored in: " . "upload_file/" . $_FILES ["Up10defile" ]["name" ].".gif" ; }
后缀过滤 语言 默认(服务器)可解析后缀 盲猜绕过可解析后缀 asp.net 【IIS】 asp,aspx,asa,asax,ascx,ashx,asmx,cer,aSp,aSpx,aSa,aSax,aScx,aShx,aSmx,cEr php .php .html .htm【apache】 php,php5,php4,php3,php2,pHp,pHp5,pHp4,pHp3,pHp2,html,htm,phtml,pht,Html,Htm,pHtml jsp .jsp, .jspx【tomcat】 jsp,jspa,jspx,jsw,jsv,jspf,jtml,jSp,jSpx,jSpa,jSw,jSv,jSpf,jHtml控制php脚本能访问的目录
使用open_basedir选项能够控制PHP脚本只能访问指定的目录,这样能够避免PHP脚本访问不应该访问的文件,一定程序上显示了phpshell的危害,我们一般可以设置为只能访问网站目录:
open_basedir = /usr/www
关闭危险函数
disable_functions = system, passthru, exec, shell_exec, popen, phpinfo, escapeshellarg, escapeshellcmd, proc_close, proc_open, dl
如果你要禁止任何文件和目录的操作,那么可以关闭很多文件操作 disable_functions = chdir, chroot, dir, getcwd, opendir, readdir, scandir, fopen, unlink, delete, copy, mkdir, rmdir, rename, file, file_get_contents, fputs, fwrite, chgrp,chmod, chown unlink, delete, copy, mkdir, rmdir, rename, file, file_get_contents, fputs, fwrite, chgrp,chmod, chown
文件上传waf实例,设置白名单,+只允许一个.存在(避免apach
解析漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <?php header("Content-type: text/html;charset=utf-8"); error_reporting(1); define("WWW_ROOT",$_SERVER['DOCUMENT_ROOT']); define("APP_ROOT",str_replace('\\','/',dirname(__FILE__))); define("APP_URL_ROOT",str_replace(WWW_ROOT,"",APP_ROOT)); define("UPLOAD_PATH", "upload"); ?> <?php $is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".jpg",".png",".jpeg"); //【修改点一】 $file_name = trim($_FILES['upload_file']['name']); $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //转换为小写 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //收尾去空 if (in_array($file_ext, $deny_ext)&&substr_count($_FILES['upload_file']['name'], '.')===1) {//【修改点二】 $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } } ?> <div id ="upload_panel" > <form enctype ="multipart/form-data" method ="post" onsubmit ="return checkFile()" > <p > 请选择要上传的图片:<p > <input class ="input_file" type ="file" name ="upload_file" /> <input class ="button" type ="submit" name ="submit" value ="上传" /> </form > <div id ="msg" > <?php if($msg != null){ echo "提示:".$msg; } ?> </div > <div id ="img" > <?php if($is_upload){ echo '<img src="'.$img_path.'" width="250px" />'; } ?> </div > </div >
文件包含 LFI
php
1 2 3 4 5 6 7 8 9 10 $filename = $_GET ['filename' ];$pattern = "\/|\.\.\/|\.\/|etc|var|php|jpg|jpeg|png|bmp|gif" ;if (preg_match ("/" .$pattern ."/is" ,$filename )== 1 ){ echo "die00000000000000000000000000000" ; die (); } include ($filename );
RFI
php
1 2 3 4 5 6 7 8 9 10 $filename = $_GET ['filename' ];$pattern = "\/|\.\.\/|\.\/|etc|var|php|jpg|jpeg|png|bmp|gif" ;if (preg_match ("/" .$pattern ."/is" ,$filename )== 1 ){ echo "die00000000000000000000000000000" ; die (); } include ($filename );
php
1 2 allow_url_fopen = off (是否允许打开远程文件) allow_url_include = off(是否允许include /require 远程文件)
php 伪协议
php
1 2 3 4 5 6 7 8 9 10 $filename = $_GET ['filename' ];$pattern = "\/|\.\.\/|\.\/|etc|var|php|jpg|jpeg|png|bmp|gif|file|http|ftp|php|zlib|data|glob|phar|ssh2|rar|ogg|expect|zip|compress|filter|input" ;if (preg_match ("/" .$pattern ."/is" ,$filename )== 1 ){ echo "die00000000000000000000000000000" ; die (); } include ($filename );
任意文件读取 防御 常见的利用函数
1 file_get_contents()、highlight_file()、fopen()、readfile()、fread()、fgetss()、fgets()、parse_ini_file()、show_source()、file()
设置禁用函数或者目录限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php $filename = $_GET['filename']; $pattern = "\/|\.\.\/|\.\/|etc|var|file|http|ftp|php|zlib|data|glob|phar|ssh2|rar|ogg|expect|zip|compress|filter|input"; if(preg_match("/".$pattern."/is",$filename)== 1){ echo "die00000000000000000000000000000"; die(); } echo file_get_contents($filename); ?>
1 open_basedir="/var/www/html"
任意代码执行RCE 1 2 3 4 PHP代码执行函数: eval()、assert()、preg_replace()、create_function()、array_map()、call_user_func()、call_user_func_array()、array_filter()、uasort()、等 PHP命令执行函数: system()、exec()、shell_exec()、pcntl_exec()、popen()、proc_popen()、passthru()、等
命令大全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 more:一页一页的显示档案内容 less:与 more 类似 head:查看头几行 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 tail:查看尾几行 nl:显示的时候,顺便输出行号 od:以二进制的方式读取档案内容 vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看 sort:可以查看 uniq:可以查看 file -f:报错出具体内容 sh /flag 2>%261 //报错出文件内容 paste 它被用来将文件按列以tab作为分隔符拼接在一起随后输出到标准输出(standard output)。 grep f /flag 输出f所在行的内容 cut -c 1-50 /flag 截取1-50位进行输出 strings 查看文件文本形式 type flag rev [^b] 代表不是b的其他字符
对于php正则匹配e模式的代码执行
preg_replace() 函数不再支持 “\e” (PREG_REPLACE_EVAL). 应当使用 preg_replace_callback() 替代。
修补 preg_replace() 漏洞需要将修饰符/e去掉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php $a=$_GET['cc']; $pattern = "eval|assert|passthru|pcntl_exec|exec|system|escapeshellcmd|popen|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|ob_start"; if(preg_match("/".$pattern."/is",$cc)== 1){ die(); } $bb="phpinfo()"; call_user_func($cc,$bb); ?>
php
1 disable_functions=call_user_func,call_user_func_array,array_map,array_filter,ob_start,phpinfo,eval ,assert,passthru,pcntl_exec,exec,system,escapeshellcmd,popen,chroot,scandir,chgrp,chown,shell_exec
设置禁用函数php.ini中找到disable_functions=中间用,分隔
1 2 3 4 5 6 7 $a=$_GET['db']; $pattern = "call_user_func|call_user_func_array|array_map|array_filter|ob_start|phpinfo|eval|assert|passthru|pcntl_exec|exec|system|escapeshellcmd|popen|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|ob_start"; if(preg_match("/".$pattern."/is",$db)== 1){ die(); }
对于自增RCE的waf
XSS Defense xss最好的防守方式就是过滤掉<、>、javascript或者直接html实体化编码
XSS 防御基本都是对用户输入以及客户端显示进行过滤转义
HttpOnly 最早是由微软提出,并在 IE6 中实现的,至今已经逐渐成为一个标准。浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。
HttpOnly 主要是为了解决XSS中的Cookie劫持攻击。
php
1 2 3 4 5 6 7 8 9 10 <?php if ( array_key_exists ( "name" , $_GET ) && $_GET [ 'name' ] != NULL ) { checkToken ( $_REQUEST [ 'user_token' ], $_SESSION [ 'session_token' ], 'index.php' ); $name = htmlspecialchars ( $_GET [ 'name' ] ); echo "<pre>Hello ${name}</pre>" ; } ?>
使用htmlspecialchars函数把预定义的字符 &、””、’、<、>、/ 转换为 HTML 实体,防止浏览器将其作为HTML元素。
1 2 3 4 5 6 & --> & < --> < > --> > " --> " ' --> ' / --> /
它的语法如下:
1 2 3 4 5 6 7 8 htmlspecialchars(string,flags,character-set,double_encode) 其中第二个参数flags需要重要注意,很多开发者就是因为没有注意到这个参数导致使用htmlspecialchars()函数过滤XSS时被绕过。因为flags参数对于引号的编码如下: 可用的引号类型: ENT_COMPAT - 默认。仅编码双引号。 ENT_QUOTES - 编码双引号和单引号。 ENT_NOQUOTES - 不编码任何引号。 默认是只编码双引号的
使用htmlspecialchars函数,解决了XSS,但是要注意的是,如果htmlspecialchars函数使用不当,攻击者就可以通过编码的方式绕过函数进行XSS注入,尤其是DOM型的XSS。
JavascriptEncode 与 HtmlEncode 的编码方式不同,它需要使用(\)对特殊字符进行转义。
PS:在对不可信数据做编码的时候,不能图方便使用反斜杠\
对特殊字符进行简单转义,比如将双引号 ”
转义成 \”
,这样做是不可靠的,因为浏览器在对页面做解析的时候,会先进行HTML解析,然后才是JavaScript解析,所以双引号很可能会被当做HTML字符进行HTML解析,这时双引号就可以突破代码的值部分,使得攻击者可以继续进行XSS攻击;另外,输出的变量的时候,变量值必须在引号内部,避免安全问题;更加严格的方式,对除了数字和字母以外的所有字符,使用十六进制\xhh 的方式进行编码
waf
1 $filter = "/xml|extractvalue|regexp|copy|read|file|create|grand|dir|insert|link|server|drop|=|>|<|;|select|union|flag|ascii|subm|right|\'|\^|\||\ /i";
XXE Defense:使用开发语言提供的禁用外部实体的方法
PHP 1 libxml_disable_entity_loader(true);
JAVA 1 2 3 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false);
Python 1 2 from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
目录穿越 一般存在于文件包含中,也简单写一下吧
1 2 3 4 5 6 7 8 9 10 11 12 <?php $action = (isset($_GET['action']) ? $_GET['action'] : 'home.php'); $deny_ext = array("..","../"); if (in_array($action, $deny_ext)){ if (file_exists($action)) { include $action; } else { echo "File not found!"; } } ?>
SSTI 因为render_template_string函数在渲染模板的时候使用了%s来动态的替换字符串,在渲染的时候会把 {undefined{**}} 包裹的内容当做变量解析替换,所以我们可以直接把render_template_string方法改成render_template方法,这样就不会出现SSTI的问题了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from flask import Flask,request from jinja2 import Template import re app = Flask(__name__) @app.route("/") def index(): name = request.args.get('name','CTFer<!--?name=CTFer') if not re.findall(r"'|_|\\x|\\u|{{|\+|attr|\.| |class|init|globals|popen|system|lipsum|session|env|exec|shell_exec|flag|passthru|proc_popen|\{|set|\[|]|\(|%7b|eval|1|2|3|4|5|6|7|8|9",name): t = Template("hello "+name) return t.render() else: t = Template("Hacker!!!") return t.render() if __name__ == "__main__": app.run(host="0.0.0.0",port=5000)
若果flask中存在cookie伪造的,可以修改sercet_key直接把 SECRET_KEY 改为一个又长又乱的随机字符串即可,可以使用 uuid/guid 生成器 来生成
对于ssti的题目,一般题目会有过滤,但是对于一些过滤不严格仍旧会有机会,有时候在原过滤上接着加会不管用可以在过滤的后面再套一层
1 2 3 4 5 6 filter_list = ["{", "(", "lipsum", "attr"] for i in filter_list: if i in word: word = "Hacker!" if not waf(word): word = "Hacker!"
去年国赛某ssti–fix
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @app.route("/", methods=["GET", "POST"]) def index(): ip, port = re.findall(pattern,request.host).pop() if request.method == 'POST' and request.form.get("word"): word = request.form.get("word") if not waf(word): word = "Hacker!" else: word = "" #针对ssti的{{ {%进行过滤 if "{{" int word or "{%" in word: word = "Hacker!" #针对结果进行过滤 result = render_template_string(content % (str(ip), str(port), str(word))) if "flag{" in result: word = "Hacker!" return render_template_string(content % (str(ip), str(port), str(word)))
java版ssti--Thymeleaf模板渲染
1 127.0.0.1/hello?name=__%24%7Bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7D__%3A%3A.x
基于其他语言的过滤 GO 1 2 3 4 5 6 7 filterList := []string{"apple", "banana", "cherry"} str := "ana" // 匹配包含"ana"的字符串 for _, s := range filterList { if strings.Contains(s, str) { fmt.Println("Hacker!") } }
NodeJS 1 2 3 4 5 6 7 8 9 const keywords = ["flag", "exec", "read", "open", "ls", "cat"]; for (const i of keywords) { if (code.includes(i)) { result = "Hacker!" }else{ result = vm.run((code)); } }
去年国赛题的修复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const {VM} = require("vm2"); const vm = new VM(); const code = ` aVM2_INTERNAL_TMPNAME = {}; function stack() { new Error().stack; stack(); } try { stack(); } catch (a$tmpname) { a$tmpname.constructor.constructor('return process')().mainModule.require('child_process').execSync('touch pwned'); } ` console.log(vm.run(code));
添加waf
1 2 3 4 5 6 const a = ["exec","fork","spawn","cat","tac","flag","constructor","proto"]; for (let i = 0; i < a.length; i++) { if(code.includes(a[i])){ throw new Error("waf"); } }
或者如果匹配到flag{就返回异常
1 2 3 4 result = vm.run((code)); if(result.includes("flag{")){ throw new Error("waf!"); }