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 注入
$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);

image-20240524171032310

第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

// 将所有的对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => false]);

// 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]);

// 默认情况下所有的类都是可接受的,等同于省略第二个参数
$data = unserialize($foo, ["allowed_classes" => true]);

?>
  • 限制 Session 反序列化

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的反序化漏洞
  • 限制 phar 拓展 php 反序列化

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://upload_file/shell.gif.gif/a
  • 配置php.ini禁用特殊函数

特殊函数主要是基于魔法函数、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
SecurityManager sm = new SecurityManager() {
private void check(Permission perm) {
// 禁止exec
if (perm instanceof java.io.FilePermission) {
String actions = perm.getActions();
if (actions != null && actions.contains("execute")) {
throw new SecurityException("execute denied!");
}
}
// 禁止设置新的SecurityManager,保护自己
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模式的代码执行

  • PHP7 新特性

preg_replace() 函数不再支持 “\e” (PREG_REPLACE_EVAL). 应当使用 preg_replace_callback() 替代。

  • preg_replace()

修补 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 的使用

HttpOnly 最早是由微软提出,并在 IE6 中实现的,至今已经逐渐成为一个标准。浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。

HttpOnly 主要是为了解决XSS中的Cookie劫持攻击。

  • htmlspecialchars() 转义函数

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。

  • JavaScript 编码

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!");
}